Example #1
0
 /// <summary>
 /// Read the PNG image from the bytes.
 /// </summary>
 /// <param name="bytes">The bytes of the PNG data to be read.</param>
 /// <param name="settings">Settings to apply when opening the PNG.</param>
 /// <returns>The <see cref="Png"/> data from the bytes.</returns>
 public static Png Open(byte[] bytes, PngOpenerSettings settings)
 {
     using (var memoryStream = new MemoryStream(bytes))
     {
         return(PngOpener.Open(memoryStream, settings));
     }
 }
Example #2
0
 /// <summary>
 /// Read the PNG from the file path.
 /// </summary>
 /// <param name="filePath">The path to the PNG file to open.</param>
 /// <param name="settings">Settings to apply when opening the PNG.</param>
 /// <remarks>This will open the file to obtain a <see cref="FileStream"/> so will lock the file during reading.</remarks>
 /// <returns>The <see cref="Png"/> data from the file.</returns>
 public static Png Open(string filePath, PngOpenerSettings settings)
 {
     using (var fileStream = File.OpenRead(filePath))
     {
         return(Open(fileStream, settings));
     }
 }
Example #3
0
        public static Png Open(Stream stream, PngOpenerSettings settings)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanRead)
            {
                throw new ArgumentException($"The provided stream of type {stream.GetType().FullName} was not readable.");
            }

            var validHeader = HasValidHeader(stream);

            if (!validHeader.IsValid)
            {
                throw new ArgumentException($"The provided stream did not start with the PNG header. Got {validHeader}.");
            }

            var crc         = new byte[4];
            var imageHeader = ReadImageHeader(stream, crc);

            var hasEncounteredImageEnd = false;

            Palette palette = null;

            using (var output = new MemoryStream())
            {
                using (var memoryStream = new MemoryStream())
                {
                    while (TryReadChunkHeader(stream, out var header))
                    {
                        if (hasEncounteredImageEnd)
                        {
                            if (settings?.DisallowTrailingData == true)
                            {
                                throw new InvalidOperationException($"Found another chunk {header} after already reading the IEND chunk.");
                            }

                            break;
                        }

                        var bytes = new byte[header.Length];
                        var read  = stream.Read(bytes, 0, bytes.Length);
                        if (read != bytes.Length)
                        {
                            throw new InvalidOperationException($"Did not read {header.Length} bytes for the {header} header, only found: {read}.");
                        }

                        if (header.IsCritical)
                        {
                            switch (header.Name)
                            {
                            case "PLTE":
                                if (header.Length % 3 != 0)
                                {
                                    throw new InvalidOperationException($"Palette data must be multiple of 3, got {header.Length}.");
                                }

                                // Ignore palette data unless the header.ColorType indicates that the image is paletted.
                                if (imageHeader.ColorType.HasFlag(ColorType.PaletteUsed))
                                {
                                    palette = new Palette(bytes);
                                }

                                break;

                            case "IDAT":
                                memoryStream.Write(bytes, 0, bytes.Length);
                                break;

                            case "IEND":
                                hasEncounteredImageEnd = true;
                                break;

                            default:
                                throw new NotSupportedException($"Encountered critical header {header} which was not recognised.");
                            }
                        }

                        read = stream.Read(crc, 0, crc.Length);
                        if (read != 4)
                        {
                            throw new InvalidOperationException($"Did not read 4 bytes for the CRC, only found: {read}.");
                        }

                        var result    = (int)Crc32.Calculate(Encoding.ASCII.GetBytes(header.Name), bytes);
                        var crcActual = (crc[0] << 24) + (crc[1] << 16) + (crc[2] << 8) + crc[3];

                        if (result != crcActual)
                        {
                            throw new InvalidOperationException($"CRC calculated {result} did not match file {crcActual} for chunk: {header.Name}.");
                        }

                        settings?.ChunkVisitor?.Visit(stream, imageHeader, header, bytes, crc);
                    }

                    memoryStream.Flush();
                    memoryStream.Seek(2, SeekOrigin.Begin);

                    using (var deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress))
                    {
                        deflateStream.CopyTo(output);
                        deflateStream.Close();
                    }
                }

                var bytesOut = output.ToArray();

                var(bytesPerPixel, samplesPerPixel) = Decoder.GetBytesAndSamplesPerPixel(imageHeader);

                bytesOut = Decoder.Decode(bytesOut, imageHeader, bytesPerPixel, samplesPerPixel);

                return(new Png(imageHeader, new RawPngData(bytesOut, bytesPerPixel, palette, imageHeader)));
            }
        }
Example #4
0
 /// <summary>
 /// Read the PNG image from the stream.
 /// </summary>
 /// <param name="stream">The stream containing PNG data to be read.</param>
 /// <param name="settings">Settings to apply when opening the PNG.</param>
 /// <returns>The <see cref="Png"/> data from the stream.</returns>
 public static Png Open(Stream stream, PngOpenerSettings settings)
 => PngOpener.Open(stream, settings);