Example #1
0
        private static byte UnapplyFilter(PngFilter filter, byte x, byte a, byte b, byte c)
        {
            switch (filter)
            {
            case PngFilter.None: return(x);

            case PngFilter.Sub: return((byte)(x + a));

            case PngFilter.Up: return((byte)(x + b));

            case PngFilter.Average: return((byte)(x + (a + b) / 2));

            case PngFilter.Paeth: return((byte)(x + UnapplyFilterPaeth(a, b, c)));

            default: throw new InvalidOperationException("Unsupported filter (" + (int)filter + ") specified");
            }
        }
Example #2
0
        static byte UnapplyFilter(PngFilter f, byte x, byte a, byte b, byte c)
        {
            switch (f)
            {
            case PngFilter.None: return(x);

            case PngFilter.Sub: return((byte)(x + a));

            case PngFilter.Up: return((byte)(x + b));

            case PngFilter.Average: return((byte)(x + (a + b) / 2));

            case PngFilter.Paeth: return((byte)(x + Paeth(a, b, c)));

            default:
                throw new InvalidOperationException("Unsupported Filter");
            }
        }
Example #3
0
        public void Apply(FastBitmap bmp)
        {
            var filters = GenerateFilterArray(bmp);

            Stopwatch sw       = Stopwatch.StartNew();
            var       filtered = PngFilter.Encode(bmp, filters);

            SendMessage("Encoded in {0} seconds.", sw.ElapsedMilliseconds / 1000d);

            Chain.Apply(filtered);

            sw.Restart();

            PngFilter.Decode(filtered, filters, bmp);
            SendMessage("Decoded in {0} seconds.", sw.ElapsedMilliseconds / 1000d);

            sw.Stop();
        }
Example #4
0
 static byte UnapplyFilter(PngFilter f, byte x, byte a, byte b, byte c)
 {
     switch (f)
     {
         case PngFilter.None: return x;
         case PngFilter.Sub: return (byte)(x + a);
         case PngFilter.Up: return (byte)(x + b);
         case PngFilter.Average: return (byte)(x + (a + b) / 2);
         case PngFilter.Paeth: return (byte)(x + Paeth(a, b, c));
         default:
             throw new InvalidOperationException("Unsupported Filter");
     }
 }
Example #5
0
        public Png(Stream s)
        {
            byte[] internalBuffer = new byte[8];

            // Check header signature
            s.Read(internalBuffer, 0, Signature.Length);

            for (int i = 0; i < Signature.Length; i++)
            {
                if (internalBuffer[i] != Signature[i])
                {
                    throw new InvalidDataException("Invalid PNG file - header signature mismatch");
                }
            }

            // Load image
            bool           headerParsed = false;
            bool           isPaletted   = false;
            bool           is24Bit      = false;
            RawList <byte> data         = new RawList <byte>();

            EmbeddedData = new Dictionary <string, string>();

            while (true)
            {
                int length = ReadInt32BigEndian(s, ref internalBuffer);
                s.Read(internalBuffer, 0, 4);
                string type = Encoding.ASCII.GetString(internalBuffer, 0, 4);

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

                int blockEndPosition = (int)s.Position + length;

                switch (type)
                {
                case "IHDR": {
                    if (headerParsed)
                    {
                        throw new InvalidDataException("Invalid PNG file - duplicate header");
                    }

                    Width  = ReadInt32BigEndian(s, ref internalBuffer);
                    Height = ReadInt32BigEndian(s, ref internalBuffer);

                    byte         bitDepth  = s.ReadUInt8(ref internalBuffer);
                    PngColorType colorType = (PngColorType)s.ReadUInt8(ref internalBuffer);
                    isPaletted = IsPaletted(bitDepth, colorType);
                    is24Bit    = (colorType == PngColorType.Color);

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

                    Data = new byte[dataLength];

                    byte compression = s.ReadUInt8(ref internalBuffer);
                    /*byte filter = */ s.ReadUInt8(ref internalBuffer);
                    byte interlace = s.ReadUInt8(ref internalBuffer);

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

                    headerParsed = true;
                    break;
                }

                case "PLTE": {
                    Palette = new ColorRgba[256];
                    for (int i = 0; i < length / 3; i++)
                    {
                        byte r = s.ReadUInt8(ref internalBuffer);
                        byte g = s.ReadUInt8(ref internalBuffer);
                        byte b = s.ReadUInt8(ref internalBuffer);
                        Palette[i] = new ColorRgba(r, g, b);
                    }
                    break;
                }

                case "tRNS": {
                    if (Palette == null)
                    {
                        throw new InvalidDataException("Non-palette indexed images are not supported");
                    }
                    for (var i = 0; i < length; i++)
                    {
                        Palette[i].A = s.ReadUInt8(ref internalBuffer);
                    }
                    break;
                }

                case "IDAT": {
                    int newLength = data.Count + length;
                    data.Count = newLength;
                    s.Read(data.Data, newLength - length, length);
                    break;
                }

                case "tEXt": {
                    byte[] content = new byte[length];
                    s.Read(content, 0, length);

                    for (int i = 0; i < length; i++)
                    {
                        if (content[i] == 0)
                        {
                            string key   = Encoding.ASCII.GetString(content, 0, i);
                            string value = Encoding.ASCII.GetString(content, i + 1, length - (i + 1));
                            EmbeddedData.Add(key, value);
                            break;
                        }
                    }
                    break;
                }

                case "IEND": {
                    using (var ms = new MemoryStream(data.Data)) {
                        ms.Position += 2;

                        using (var ds = new DeflateStream(ms, CompressionMode.Decompress, true)) {
                            int pxStride  = (isPaletted ? 1 : (is24Bit ? 3 : 4));
                            int srcStride = Width * pxStride;
                            int dstStride = Width * (isPaletted ? 1 : 4);

                            byte[] buffer     = new byte[srcStride];
                            byte[] bufferPrev = new byte[srcStride];

                            for (var y = 0; y < Height; y++)
                            {
                                // Read filter
                                PngFilter filter = (PngFilter)ds.ReadUInt8(ref internalBuffer);

                                // Read data
                                ds.Read(buffer, 0, srcStride);

                                for (var i = 0; i < srcStride; i++)
                                {
                                    if (i < pxStride)
                                    {
                                        buffer[i] = UnapplyFilter(filter, buffer[i], 0, bufferPrev[i], 0);
                                    }
                                    else
                                    {
                                        buffer[i] = UnapplyFilter(filter, buffer[i], buffer[i - pxStride], bufferPrev[i], bufferPrev[i - pxStride]);
                                    }
                                }

                                if (is24Bit)
                                {
                                    for (var i = 0; i < buffer.Length / 3; i++)
                                    {
                                        Buffer.BlockCopy(buffer, 3 * i, Data, y * dstStride + 4 * i, 3);
                                        Data[y * dstStride + 4 * i + 3] = 255;
                                    }
                                }
                                else
                                {
                                    Buffer.BlockCopy(buffer, 0, Data, y * dstStride, srcStride);
                                }

                                bufferPrev = buffer;
                            }
                        }
                    }
                    return;
                }

                default: {
                    //Console.WriteLine("Unknown PNG section: " + type);
                    s.Position += length;
                    break;
                }
                }

                if (s.Position != blockEndPosition)
                {
                    throw new InvalidDataException("Block " + type + " has incorrect length");
                }

                // Skip CRC
                s.Position += 4;
            }
        }