/// <inheritdoc/>
        protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span <byte> buffer)
        {
            long pos = stream.Position;

            using (var deframeStream = new ZlibInflateStream(
                       stream,
                       () =>
            {
                int left = (int)(byteCount - (stream.Position - pos));
                return(left > 0 ? left : 0);
            }))
            {
                deframeStream.AllocateNewBytes(byteCount, true);
                DeflateStream dataStream = deframeStream.CompressedStream;

                int totalRead = 0;
                while (totalRead < buffer.Length)
                {
                    int bytesRead = dataStream.Read(buffer, totalRead, buffer.Length - totalRead);
                    if (bytesRead <= 0)
                    {
                        break;
                    }

                    totalRead += bytesRead;
                }
            }

            if (this.Predictor == TiffPredictor.Horizontal)
            {
                HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
            }
        }
Exemple #2
0
        /// <summary>
        /// Decodes the stream to the image.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="stream">The stream containing image data. </param>
        /// <exception cref="ImageFormatException">
        /// Thrown if the stream does not contain and end chunk.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown if the image is larger than the maximum allowable size.
        /// </exception>
        /// <returns>The decoded image</returns>
        public Image <TPixel> Decode <TPixel>(Stream stream)
            where TPixel : struct, IPixel <TPixel>
        {
            var         metaData    = new ImageMetaData();
            PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance);

            this.currentStream = stream;
            this.currentStream.Skip(8);
            Image <TPixel> image = null;

            try
            {
                while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk))
                {
                    try
                    {
                        switch (chunk.Type)
                        {
                        case PngChunkType.Header:
                            this.ReadHeaderChunk(pngMetaData, chunk.Data.Array);
                            break;

                        case PngChunkType.Physical:
                            this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan());
                            break;

                        case PngChunkType.Gamma:
                            this.ReadGammaChunk(pngMetaData, chunk.Data.GetSpan());
                            break;

                        case PngChunkType.Data:
                            if (image is null)
                            {
                                this.InitializeImage(metaData, out image);
                            }

                            using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk))
                            {
                                deframeStream.AllocateNewBytes(chunk.Length);
                                this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame, pngMetaData);
                            }

                            break;

                        case PngChunkType.Palette:
                            byte[] pal = new byte[chunk.Length];
                            Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length);
                            this.palette = pal;
                            break;

                        case PngChunkType.Transparency:
                            byte[] alpha = new byte[chunk.Length];
                            Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length);
                            this.paletteAlpha = alpha;
                            this.AssignTransparentMarkers(alpha, pngMetaData);
                            break;

                        case PngChunkType.Text:
                            this.ReadTextChunk(metaData, chunk.Data.Array.AsSpan(0, chunk.Length));
                            break;

                        case PngChunkType.Exif:
                            if (!this.ignoreMetadata)
                            {
                                byte[] exifData = new byte[chunk.Length];
                                Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length);
                                metaData.ExifProfile = new ExifProfile(exifData);
                            }

                            break;

                        case PngChunkType.End:
                            this.isEndChunkReached = true;
                            break;
                        }
                    }
                    finally
                    {
                        chunk.Data?.Dispose(); // Data is rented in ReadChunkData()
                    }
                }

                if (image is null)
                {
                    throw new ImageFormatException("PNG Image does not contain a data chunk");
                }

                return(image);
            }
            finally
            {
                this.scanline?.Dispose();
                this.previousScanline?.Dispose();
            }
        }
Exemple #3
0
        /// <summary>
        /// Decodes the stream to the image.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="stream">The stream containing image data. </param>
        /// <exception cref="ImageFormatException">
        /// Thrown if the stream does not contain and end chunk.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown if the image is larger than the maximum allowable size.
        /// </exception>
        /// <returns>The decoded image</returns>
        public Image <TPixel> Decode <TPixel>(Stream stream)
            where TPixel : struct, IPixel <TPixel>
        {
            var metadata = new ImageMetaData();

            this.currentStream = stream;
            this.currentStream.Skip(8);
            Image <TPixel> image = null;

            try
            {
                using (var deframeStream = new ZlibInflateStream(this.currentStream))
                {
                    PngChunk currentChunk;
                    while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
                    {
                        try
                        {
                            switch (currentChunk.Type)
                            {
                            case PngChunkTypes.Header:
                                this.ReadHeaderChunk(currentChunk.Data);
                                this.ValidateHeader();
                                break;

                            case PngChunkTypes.Physical:
                                this.ReadPhysicalChunk(metadata, currentChunk.Data);
                                break;

                            case PngChunkTypes.Data:
                                if (image == null)
                                {
                                    this.InitializeImage(metadata, out image);
                                }

                                deframeStream.AllocateNewBytes(currentChunk.Length);
                                this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame);
                                stream.Read(this.crcBuffer, 0, 4);
                                break;

                            case PngChunkTypes.Palette:
                                byte[] pal = new byte[currentChunk.Length];
                                Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length);
                                this.palette = pal;
                                break;

                            case PngChunkTypes.PaletteAlpha:
                                byte[] alpha = new byte[currentChunk.Length];
                                Buffer.BlockCopy(currentChunk.Data, 0, alpha, 0, currentChunk.Length);
                                this.paletteAlpha = alpha;
                                this.AssignTransparentMarkers(alpha);
                                break;

                            case PngChunkTypes.Text:
                                this.ReadTextChunk(metadata, currentChunk.Data, currentChunk.Length);
                                break;

                            case PngChunkTypes.End:
                                this.isEndChunkReached = true;
                                break;
                            }
                        }
                        finally
                        {
                            // Data is rented in ReadChunkData()
                            if (currentChunk.Data != null)
                            {
                                ArrayPool <byte> .Shared.Return(currentChunk.Data);
                            }
                        }
                    }
                }

                return(image);
            }
            finally
            {
                this.scanline?.Dispose();
                this.previousScanline?.Dispose();
            }
        }