/// <summary> /// Reads the scanlines within the image. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <param name="dataStream">The <see cref="MemoryStream"/> containing data.</param> /// <param name="pixels"> The pixel data.</param> private void ReadScanlines <TColor, TPacked>(MemoryStream dataStream, PixelAccessor <TColor, TPacked> pixels) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct { this.bytesPerPixel = this.CalculateBytesPerPixel(); this.bytesPerScanline = this.CalculateScanlineLength() + 1; this.bytesPerSample = 1; if (this.header.BitDepth >= 8) { this.bytesPerSample = this.header.BitDepth / 8; } dataStream.Position = 0; using (ZlibInflateStream compressedStream = new ZlibInflateStream(dataStream)) { using (MemoryStream decompressedStream = new MemoryStream()) { compressedStream.CopyTo(decompressedStream); decompressedStream.Flush(); decompressedStream.Position = 0; this.DecodePixelData(decompressedStream, pixels); //byte[] decompressedBytes = decompressedStream.ToArray(); //this.DecodePixelData(decompressedBytes, pixels); } //byte[] decompressedBytes = compressedStream.ToArray(); //this.DecodePixelData(decompressedBytes, pixels); } }
/// <summary> /// Reads the scanlines within the image. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <param name="dataStream">The <see cref="MemoryStream"/> containing data.</param> /// <param name="pixels"> The pixel data.</param> private void ReadScanlines <TColor, TPacked>(MemoryStream dataStream, PixelAccessor <TColor, TPacked> pixels) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct, IEquatable <TPacked> { this.bytesPerPixel = this.CalculateBytesPerPixel(); this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1; this.bytesPerSample = 1; if (this.header.BitDepth >= 8) { this.bytesPerSample = this.header.BitDepth / 8; } dataStream.Position = 0; using (ZlibInflateStream compressedStream = new ZlibInflateStream(dataStream)) { if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) { this.DecodeInterlacedPixelData(compressedStream, pixels); } else { this.DecodePixelData(compressedStream, pixels); } } }
/// <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); 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; 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(); } }