/// <summary> /// Load bitmap data to Paint.NET surface. /// </summary> /// <param name="header">The bitmap header to convert.</param> /// <param name="offset">The offset of the header in the stream.</param> /// <param name="source">The source stream.</param> /// <param name="surface">Paint.NET surface.</param> unsafe static void LoadBitmapToSurface(SBMHeader header, UInt32 offset, Stream source, Surface surface) { UInt32 lastPos = (UInt32)source.Position; source.Seek(offset + header.headerLength, SeekOrigin.Begin); UInt32 compressedSize = header.bitmapSize - header.headerLength; UInt32 stride = (UInt32)MbmFile.GetStride(header.sizeInPixel.Width, (Byte)(header.bitsPerPixel)); UInt32 realSize = (UInt32)header.sizeInPixel.Height * stride; byte[] decompressedData = new byte[realSize]; MemoryStream destinationStream = new MemoryStream(decompressedData, 0, (int)realSize); destinationStream.Seek(0, SeekOrigin.Begin); switch (header.compression) { case BitmapCompression comp when(comp <= BitmapCompression.ThirtyTwoABitsRLE && comp > BitmapCompression.None): Algorithm.RLEDecompressor.Decompress(destinationStream, source, (int)compressedSize, comp); break; default: source.Read(decompressedData, 0, (int)realSize); break; } destinationStream.Seek(0, SeekOrigin.Begin); for (int y = 0; y < header.sizeInPixel.Height; y++) { destinationStream.Seek(stride * y, SeekOrigin.Begin); ColorBgra *rowData = surface.GetRowAddress(y); // Convert to PDN representation switch (header.bitsPerPixel) { // These case are generally easy // Each channel is represent by 8 bits case UInt32 i when(i % 8 == 0): for (int x = 0; x < header.sizeInPixel.Width; x++) { rowData[x].R = (i >= 8) ? (Byte)destinationStream.ReadByte() : (Byte)0; rowData[x].G = (i >= 16) ? (Byte)destinationStream.ReadByte() : (Byte)0; rowData[x].B = (i >= 24) ? (Byte)destinationStream.ReadByte() : (Byte)0; rowData[x].A = (i >= 32) ? (Byte)destinationStream.ReadByte() : (Byte)255; } break; default: throw new MbmException(String.Format("Unhandled converting {0} bits per pixel to Paint.NET surface", header.bitsPerPixel)); } } source.Seek(lastPos, SeekOrigin.Begin); }
static Document LoadIndex(MbmFile file, Stream source, int index) { SBMHeader header = file.GetBitmapHeader(index); UInt32 headerOffset = file.GetBitmapHeaderOffset(index); Document doc = new Document(header.sizeInPixel); // Create background layer BitmapLayer layer = Layer.CreateBackgroundLayer(header.sizeInPixel.Width, header.sizeInPixel.Height, "Bitmap"); Surface surface = layer.Surface; LoadBitmapToSurface(header, headerOffset, source, surface); doc.Layers.Add(layer); return(doc); }
SBMHeader ReadSingleBitmapHeader(MbmBinaryReader input, UInt32 offset) { SBMHeader bitmapHeader = new SBMHeader(); // Seek to trailer UInt32 lastPos = input.Tell(); input.Seek(offset); bitmapHeader.bitmapSize = input.ReadUInt32(); bitmapHeader.headerLength = input.ReadUInt32(); bitmapHeader.sizeInPixel = input.ReadSize(); bitmapHeader.sizeInTwips = input.ReadSize(); bitmapHeader.bitsPerPixel = input.ReadUInt32(); bitmapHeader.colorMode = (BitmapColor)input.ReadUInt32(); bitmapHeader.paletteSize = input.ReadUInt32(); bitmapHeader.compression = (BitmapCompression)input.ReadUInt32(); input.Seek(lastPos); return(bitmapHeader); }
public static void Save(Document input, Stream output, Surface scratchSurface, UInt32 bpp, BitmapColor colorMode) { // Flatten the image first input.Flatten(scratchSurface); // Build up SBM Header SBMHeader header = new SBMHeader(); header.headerLength = 40; header.sizeInPixel.Width = input.Width; header.sizeInPixel.Height = input.Height; header.sizeInTwips.Width = input.Width * 15; header.sizeInTwips.Height = input.Height * 15; header.colorMode = colorMode; header.bitsPerPixel = bpp; // Determine what compression to use BitmapCompression compressionToUse = ChooseBestCompressionMode(input.Width, input.Height, bpp, colorMode); header.compression = compressionToUse; Int32 stride = MbmFile.GetStride(input.Width, (Byte)bpp); byte[] rawBitmapData = new byte[stride * input.Height]; byte[] compressedBitmapData = null; MemoryStream bitmapStream = new MemoryStream(rawBitmapData, 0, rawBitmapData.Length); ReadRawBitmapData(scratchSurface, bitmapStream, (Byte)bpp); bitmapStream.Seek(0, SeekOrigin.Begin); switch (compressionToUse) { case BitmapCompression comp when(comp >= BitmapCompression.ByteRLE && comp <= BitmapCompression.ThirtyTwoABitsRLE): compressedBitmapData = new byte[stride * input.Height]; MemoryStream compressedDestStream = new MemoryStream(compressedBitmapData, 0, compressedBitmapData.Length); compressedDestStream.Seek(0, SeekOrigin.Begin); Algorithm.RLECompressor.Compress(compressedDestStream, bitmapStream, stride * input.Height, compressionToUse); header.bitmapSize = (UInt32)(40 + compressedDestStream.Position); break; case BitmapCompression.None: header.bitmapSize = (UInt32)(40 + stride * input.Height); break; default: throw new MbmException(String.Format("Unsupported bitmap compression type {0}", compressionToUse.ToString())); } output.Seek(/*sizeof(MbmHeader)*/ 20, SeekOrigin.Begin); MbmBinaryWriter writer = new MbmBinaryWriter(output); // Try to write our header writer.WriteUInt32(header.bitmapSize); writer.WriteUInt32(header.headerLength); writer.WriteSize(header.sizeInPixel); writer.WriteSize(header.sizeInTwips); writer.WriteUInt32(header.bitsPerPixel); writer.WriteUInt32((UInt32)header.colorMode); writer.WriteUInt32(header.paletteSize); writer.WriteUInt32((UInt32)header.compression); // Write data switch (compressionToUse) { case BitmapCompression comp when(comp >= BitmapCompression.ByteRLE && comp <= BitmapCompression.ThirtyTwoABitsRLE): output.Write(compressedBitmapData, 0, (int)(header.bitmapSize - header.headerLength)); break; case BitmapCompression.None: output.Write(rawBitmapData, 0, rawBitmapData.Length); break; default: break; } // Write trailer UInt32 trailerOffset = writer.Tell(); writer.WriteUInt32(1); writer.WriteUInt32(20); // Seek back and write our header writer.Seek(0); writer.WriteUInt32(MbmHeader.directFileStoreUIDNum); writer.WriteUInt32(MbmHeader.multiBitmapUIDNum); writer.WriteUInt32(0); writer.WriteUInt32(0); // Checksum writer.WriteUInt32(trailerOffset); }