Ejemplo n.º 1
0
        public Png(Stream s)
        {
            if (!Verify(s))
            {
                throw new InvalidDataException("PNG Signature is bogus");
            }

            s.Position += 8;
            var headerParsed = false;
            var isPaletted   = false;
            var is24Bit      = false;
            var data         = new List <byte>();

            for (;;)
            {
                var length  = IPAddress.NetworkToHostOrder(s.ReadInt32());
                var type    = Encoding.UTF8.GetString(s.ReadBytes(4));
                var content = s.ReadBytes(length);
                /*var crc = */ s.ReadInt32();

                if (!headerParsed && type != "IHDR")
                {
                    throw new InvalidDataException("Invalid PNG file - header does not appear first.");
                }

                using (var ms = new MemoryStream(content))
                {
                    switch (type)
                    {
                    case "IHDR":
                    {
                        if (headerParsed)
                        {
                            throw new InvalidDataException("Invalid PNG file - duplicate header.");
                        }
                        Width  = IPAddress.NetworkToHostOrder(ms.ReadInt32());
                        Height = IPAddress.NetworkToHostOrder(ms.ReadInt32());

                        var bitDepth  = ms.ReadUInt8();
                        var colorType = (PngColorType)ms.ReadByte();
                        isPaletted = IsPaletted(bitDepth, colorType);
                        is24Bit    = colorType == PngColorType.Color;

                        var dataLength = Width * Height;
                        if (!isPaletted)
                        {
                            dataLength *= 4;
                        }

                        Data = new byte[dataLength];

                        var compression = ms.ReadByte();
                        /*var filter = */ ms.ReadByte();
                        var interlace = ms.ReadByte();

                        if (compression != 0)
                        {
                            throw new InvalidDataException("Compression method not supported");
                        }

                        if (interlace != 0)
                        {
                            throw new InvalidDataException("Interlacing not supported");
                        }

                        headerParsed = true;

                        break;
                    }

                    case "PLTE":
                    {
                        Palette = new Color[256];
                        for (var i = 0; i < length / 3; i++)
                        {
                            var r = ms.ReadByte(); var g = ms.ReadByte(); var b = ms.ReadByte();
                            Palette[i] = Color.FromArgb(r, g, b);
                        }

                        break;
                    }

                    case "tRNS":
                    {
                        if (Palette == null)
                        {
                            throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
                        }

                        for (var i = 0; i < length; i++)
                        {
                            Palette[i] = Color.FromArgb(ms.ReadByte(), Palette[i]);
                        }

                        break;
                    }

                    case "IDAT":
                    {
                        data.AddRange(content);

                        break;
                    }

                    case "tEXt":
                    {
                        var key = ms.ReadASCIIZ();
                        EmbeddedData.Add(key, ms.ReadASCII(length - key.Length - 1));

                        break;
                    }

                    case "IEND":
                    {
                        using (var ns = new MemoryStream(data.ToArray()))
                        {
                            using (var ds = new InflaterInputStream(ns))
                            {
                                var pxStride   = isPaletted ? 1 : is24Bit ? 3 : 4;
                                var srcStride  = Width * pxStride;
                                var destStride = Width * (isPaletted ? 1 : 4);

                                var prevLine = new byte[srcStride];
                                for (var y = 0; y < Height; y++)
                                {
                                    var filter = (PngFilter)ds.ReadByte();
                                    var line   = ds.ReadBytes(srcStride);

                                    for (var i = 0; i < srcStride; i++)
                                    {
                                        line[i] = i < pxStride
                                                                                                ? UnapplyFilter(filter, line[i], 0, prevLine[i], 0)
                                                                                                : UnapplyFilter(filter, line[i], line[i - pxStride], prevLine[i], prevLine[i - pxStride]);
                                    }

                                    if (is24Bit)
                                    {
                                        // Fold alpha channel into RGB data
                                        for (var i = 0; i < line.Length / 3; i++)
                                        {
                                            Array.Copy(line, 3 * i, Data, y * destStride + 4 * i, 3);
                                            Data[y * destStride + 4 * i + 3] = 255;
                                        }
                                    }
                                    else
                                    {
                                        Array.Copy(line, 0, Data, y * destStride, line.Length);
                                    }

                                    prevLine = line;
                                }
                            }
                        }

                        if (isPaletted && Palette == null)
                        {
                            throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
                        }

                        return;
                    }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public Png(Stream s)
        {
            if (!Verify(s))
            {
                throw new InvalidDataException("PNG Signature is bogus");
            }

            s.Position += 8;
            var headerParsed = false;
            var data         = new List <byte>();

            Type = SpriteFrameType.Rgba32;

            while (true)
            {
                var length  = IPAddress.NetworkToHostOrder(s.ReadInt32());
                var type    = Encoding.UTF8.GetString(s.ReadBytes(4));
                var content = s.ReadBytes(length);
                /*var crc = */
                s.ReadInt32();

                if (!headerParsed && type != "IHDR")
                {
                    throw new InvalidDataException("Invalid PNG file - header does not appear first.");
                }

                using (var ms = new MemoryStream(content))
                {
                    switch (type)
                    {
                    case "IHDR":
                    {
                        if (headerParsed)
                        {
                            throw new InvalidDataException("Invalid PNG file - duplicate header.");
                        }
                        Width  = IPAddress.NetworkToHostOrder(ms.ReadInt32());
                        Height = IPAddress.NetworkToHostOrder(ms.ReadInt32());

                        var bitDepth  = ms.ReadUInt8();
                        var colorType = (PngColorType)ms.ReadByte();
                        if (IsPaletted(bitDepth, colorType))
                        {
                            Type = SpriteFrameType.Indexed8;
                        }
                        else if (colorType == PngColorType.Color)
                        {
                            Type = SpriteFrameType.Rgb24;
                        }

                        Data = new byte[Width * Height * PixelStride];

                        var compression = ms.ReadByte();
                        /*var filter = */
                        ms.ReadByte();
                        var interlace = ms.ReadByte();

                        if (compression != 0)
                        {
                            throw new InvalidDataException("Compression method not supported");
                        }

                        if (interlace != 0)
                        {
                            throw new InvalidDataException("Interlacing not supported");
                        }

                        headerParsed = true;

                        break;
                    }

                    case "PLTE":
                    {
                        Palette = new Color[256];
                        for (var i = 0; i < length / 3; i++)
                        {
                            var r = ms.ReadByte(); var g = ms.ReadByte(); var b = ms.ReadByte();
                            Palette[i] = Color.FromArgb(r, g, b);
                        }

                        break;
                    }

                    case "tRNS":
                    {
                        if (Palette == null)
                        {
                            throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
                        }

                        for (var i = 0; i < length; i++)
                        {
                            Palette[i] = Color.FromArgb(ms.ReadByte(), Palette[i]);
                        }

                        break;
                    }

                    case "IDAT":
                    {
                        data.AddRange(content);

                        break;
                    }

                    case "tEXt":
                    {
                        var key = ms.ReadASCIIZ();
                        EmbeddedData.Add(key, ms.ReadASCII(length - key.Length - 1));

                        break;
                    }

                    case "IEND":
                    {
                        using (var ns = new MemoryStream(data.ToArray()))
                        {
                            using (var ds = new InflaterInputStream(ns))
                            {
                                var pxStride  = PixelStride;
                                var rowStride = Width * pxStride;

                                var prevLine = new byte[rowStride];
                                for (var y = 0; y < Height; y++)
                                {
                                    var filter = (PngFilter)ds.ReadByte();
                                    var line   = ds.ReadBytes(rowStride);

                                    for (var i = 0; i < rowStride; i++)
                                    {
                                        line[i] = i < pxStride
                                                                                                        ? UnapplyFilter(filter, line[i], 0, prevLine[i], 0)
                                                                                                        : UnapplyFilter(filter, line[i], line[i - pxStride], prevLine[i], prevLine[i - pxStride]);
                                    }

                                    Array.Copy(line, 0, Data, y * rowStride, rowStride);

                                    prevLine = line;
                                }
                            }
                        }

                        if (Type == SpriteFrameType.Indexed8 && Palette == null)
                        {
                            throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
                        }

                        return;
                    }
                    }
                }
            }
        }