/// <summary> /// Reads the raw image information from the specified stream. /// </summary> /// <param name="stream">The <see cref="Stream"/> containing image data.</param> public IImageInfo Identify(Stream stream) { var metadata = new ImageMetadata(); PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); this.currentStream = stream; this.currentStream.Skip(8); 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: this.SkipChunkDataAndCrc(chunk); break; case PngChunkType.Text: this.ReadTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.End: this.isEndChunkReached = true; break; } } finally { chunk.Data?.Dispose(); // Data is rented in ReadChunkData() } } } finally { this.scanline?.Dispose(); this.previousScanline?.Dispose(); } if (this.header.Width == 0 && this.header.Height == 0) { PngThrowHelper.ThrowNoHeader(); } return(new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), this.header.Width, this.header.Height, metadata)); }
/// <summary> /// Decodes the image from the specified stream to the <see cref="ImageFrame{TPixel}"/>. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="configuration">The configuration for the image.</param> /// <param name="stream">The <see cref="Stream"/> containing image data.</param> /// <returns>The decoded image.</returns> public Image <TPixel> Decode <TPixel>(Configuration configuration, Stream stream) where TPixel : unmanaged, IPixel <TPixel> { var decoder = new PngDecoderCore(configuration, this); try { return(decoder.Decode <TPixel>(stream)); } catch (InvalidMemoryOperationException ex) { Size dims = decoder.Dimensions; PngThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); // Not reachable, as the previous statement will throw a exception. return(null); } }
/// <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); } this.ReadScanlines(chunk, image.Frames.RootFrame, pngMetadata); break; case PngChunkType.Palette: var pal = new byte[chunk.Length]; Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); this.palette = pal; break; case PngChunkType.Transparency: var 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(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.CompressedText: this.ReadCompressedTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.InternationalText: this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.Exif: if (!this.ignoreMetadata) { var 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) { PngThrowHelper.ThrowNoData(); } return(image); } finally { this.scanline?.Dispose(); this.previousScanline?.Dispose(); } }
/// <inheritdoc/> public IImageInfo Identify(BufferedReadStream stream) { var metadata = new ImageMetadata(); PngMetadata pngMetadata = metadata.GetPngMetadata(); this.currentStream = stream; this.currentStream.Skip(8); 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: this.SkipChunkDataAndCrc(chunk); break; case PngChunkType.Text: this.ReadTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.CompressedText: this.ReadCompressedTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.InternationalText: this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.Exif: if (!this.ignoreMetadata) { var 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() } } } finally { this.scanline?.Dispose(); this.previousScanline?.Dispose(); } if (this.header.Width == 0 && this.header.Height == 0) { PngThrowHelper.ThrowNoHeader(); } return(new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), this.header.Width, this.header.Height, metadata)); }