public static void Decode(ByteStream data, Bitmap dest) { PNGHeader header = data.Struct <PNGHeader>(true); Debug.Assert(header.Signature == PNGSignature, "Specified file was not a PNG file."); ByteStream idatStream = new ByteStream(); while (true) { PNGChunkHeader chunkHeader = data.Struct <PNGChunkHeader>(true); string chunkType = Encoding.ASCII.GetString(chunkHeader.Type, 4); byte[] chunkBytes = data.Read(chunkHeader.Length); ByteStream chunkData = new ByteStream(chunkBytes); PNGChunkFooter chunkFooter = data.Struct <PNGChunkFooter>(true); Debug.Assert(Crc32(chunkHeader.ToBytes().Concat(chunkBytes).ToArray(), 4) == chunkFooter.CRC, chunkType + " chunk's CRC mismatched!"); switch (chunkType) { case "IHDR": PNGIHDR ihdr = chunkData.Struct <PNGIHDR>(true); Debug.Assert(ihdr.BitDepth == 8 && ihdr.ColorType == 6 && ihdr.CompressionMethod == 0 && ihdr.FilterMethod == 0 && ihdr.InterlaceMethod == 0, "The specified PNG file uses an unsupported format."); dest.Width = ihdr.Width; dest.Height = ihdr.Height; dest.Pixels = new byte[ihdr.Width * ihdr.Height * 4]; break; case "IDAT": idatStream.Write(chunkData.Read(chunkHeader.Length)); break; case "IEND": idatStream.Seek(0, SeekOrigin.Begin); PNGIDATHeader idatHeader = idatStream.Struct <PNGIDATHeader>(true); byte[] idatData; PNGIDATFooter idatFooter; using (MemoryStream target = new MemoryStream()) using (DeflateStream decompressionStream = new DeflateStream(idatStream, CompressionMode.Decompress)) { decompressionStream.CopyTo(target); idatData = target.ToArray(); idatStream.Seek(-4); idatFooter = idatStream.Struct <PNGIDATFooter>(true); } Debug.Assert(idatFooter.CheckValue == Alder32(idatData), "IDAT chunk compression check value mismatch!"); int scanlineSize = dest.Width * 4; for (int scanline = 0; scanline < dest.Height; scanline++) { int offset = scanline * scanlineSize; Array.Copy(idatData, offset + scanline + 1, dest.Pixels, offset, scanlineSize); } return; } } }
public static byte[] Encode(Bitmap bitmap) { WriteStream outStream = new WriteStream(); PNGHeader header = new PNGHeader { Signature = PNGSignature, }; outStream.Write(header, true); WriteChunk(outStream, "IHDR", new PNGIHDR { Width = bitmap.Width, Height = bitmap.Height, BitDepth = 8, ColorType = 6, CompressionMethod = 0, FilterMethod = 0, InterlaceMethod = 0, }.ToBytes(true)); byte[] scanlines = new byte[bitmap.Width * bitmap.Height * 4 + bitmap.Height]; int scanlineSize = bitmap.Width * 4; for (int scanline = 0; scanline < bitmap.Height; scanline++) { int offset = scanline * scanlineSize; Array.Copy(bitmap.Pixels, offset, scanlines, offset + scanline + 1, scanlineSize); } using (MemoryStream idatStream = new MemoryStream()) { idatStream.Write(new PNGIDATHeader() { ZLibMethodFlags = 0x78, AdditionalFlags = 0x1, }.ToBytes(true)); using (DeflateStream compressionStream = new DeflateStream(idatStream, CompressionMode.Compress, true)) compressionStream.Write(scanlines); idatStream.Write(new PNGIDATFooter() { CheckValue = Alder32(scanlines), }.ToBytes(true)); WriteChunk(outStream, "IDAT", idatStream.ToArray()); } WriteChunk(outStream, "IEND", new byte[0]); return(outStream.ToArray()); }