Exemplo n.º 1
0
    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;
            }
        }
    }
Exemplo n.º 2
0
    private static void WriteChunk(MemoryStream stream, string type, byte[] data)
    {
        PNGChunkHeader header = new PNGChunkHeader {
            Length = data.Length,
        };

        for (int i = 0; i < 4; i++)
        {
            header.Type[i] = (byte)type[i];
        }
        PNGChunkFooter footer = new PNGChunkFooter {
            CRC = Crc32(header.ToBytes().Concat(data).ToArray(), 4),
        };

        stream.Write(header.ToBytes(true));
        stream.Write(data);
        stream.Write(footer.ToBytes(true));
    }