/// <summary>
        /// Loads a Portable Network Graphics image.
        /// </summary>
        /// <param name="stream">The stream containing the image.</param>
        /// <param name="rasterImage">The image storage.</param>
        /// <exception cref="InvalidOperationException">If the stream represents an invalid or unsupported image format.</exception>
        public static void Load(Stream stream, RasterImage rasterImage)
        {
            var decoder = new BinaryDecoder(stream);

            if (decoder.ReadByte() != 137 || decoder.ReadByte() != 80 || decoder.ReadByte() != 78 || decoder.ReadByte() != 71)
            {
                throw new InvalidOperationException(Resources.FormatMessage(Resources.Key.InvalidFileMarker, "Portable Network Graphics"));
            }
            decoder.Skip(8);
            if (decoder.ReadByte() != 'I' || decoder.ReadByte() != 'H' || decoder.ReadByte() != 'D' || decoder.ReadByte() != 'R')
            {
                throw new InvalidOperationException(Resources.GetMessage(Resources.Key.InvalidHeader));
            }

            var width  = decoder.ReadInt32BigEndian();
            var height = decoder.ReadInt32BigEndian();

            rasterImage.Size = (width, height);

            var colorDepth   = decoder.ReadByte();
            var colorType    = decoder.ReadByte();
            var bitsPerPixel = GetBitsPerPixel(rasterImage, colorDepth, colorType);

            if (decoder.ReadByte() != 0 || decoder.ReadByte() != 0)
            {
                throw new InvalidOperationException(Resources.GetMessage(Resources.Key.InvalidFormat));
            }
            if (decoder.ReadByte() != 0)
            {
                throw new InvalidOperationException(Resources.GetMessage(Resources.Key.InterlacedPNGNotSupported));
            }
            decoder.Skip(4);

            using var inflateStream = new DeflateStream(new PortableNetworkGraphicsDataStream(decoder), CompressionMode.Decompress);
            var dataLength = (width * height * bitsPerPixel + 7) / 8;

            byte[] data;
            if (rasterImage.Data.Length >= dataLength)
            {
                data = rasterImage.Data;
            }
            else
            {
                data = new byte[dataLength];
            }
            var bytesPerPixel  = (bitsPerPixel + 7) / 8;
            var bytesPerLine   = (width * bitsPerPixel + 7) / 8;
            var bitPadding     = bytesPerLine * 8 - width * bitsPerPixel;
            var removePaddings = bitsPerPixel < 8 && bitPadding != 0;

            var previousLine = new byte[bytesPerLine];
            var currentLine  = new byte[bytesPerLine];

            for (int y = 0; y < height; y++)
            {
                var filterType = inflateStream.ReadByte();
                var offset     = 0;
                var count      = bytesPerLine;
                for (;;)
                {
                    var read = inflateStream.Read(currentLine, offset, count);
                    if (read == 0)
                    {
                        throw new EndOfStreamException();
                    }
                    offset += read;
                    count  -= read;
                    if (count == 0)
                    {
                        break;
                    }
                }
                switch (filterType)
                {
                case 0:
                    break;

                case 1:
                    for (int i = bytesPerPixel; i < bytesPerLine; i++)
                    {
                        currentLine[i] += currentLine[i - bytesPerPixel];
                    }
                    break;

                case 2:
                    for (int i = 0; i < bytesPerLine; i++)
                    {
                        currentLine[i] += previousLine[i];
                    }
                    break;

                case 3:
                    for (int i = 0; i < bytesPerPixel; i++)
                    {
                        currentLine[i] += (byte)(previousLine[i] >> 1);
                    }
                    for (int i = bytesPerPixel; i < bytesPerLine; i++)
                    {
                        currentLine[i] += (byte)((currentLine[i - bytesPerPixel] + previousLine[i]) >> 1);
                    }
                    break;

                case 4:
                    for (int i = 0; i < bytesPerPixel; i++)
                    {
                        currentLine[i] += (byte)ComputePredictor(0, previousLine[i], 0);
                    }
                    for (int i = bytesPerPixel; i < bytesPerLine; i++)
                    {
                        currentLine[i] += (byte)ComputePredictor(currentLine[i - bytesPerPixel], previousLine[i], previousLine[i - bytesPerPixel]);
                    }
                    break;

                default:
                    throw new InvalidOperationException(Resources.GetMessage(Resources.Key.InvalidFormat));
                }

                if (removePaddings)
                {
                    throw new NotImplementedException();
                }
                else
                {
                    Array.Copy(currentLine, 0, data, bytesPerLine * y, bytesPerLine);
                }
                var t = previousLine;
                previousLine = currentLine;
                currentLine  = t;
            }

            rasterImage.Data = data;
        }