diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 479c24b7e..04e70c51d 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -20,37 +20,137 @@ namespace SixLabors.ImageSharp.Formats.Png public Image Decode(Configuration configuration, Stream stream) where TPixel : unmanaged, IPixel { - var decoder = new PngDecoderCore(configuration, this); + PngDecoderCore decoder = new(configuration, this); return decoder.Decode(configuration, stream); } /// - public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream); + public Image Decode(Configuration configuration, Stream stream) + { + PngDecoderCore decoder = new(configuration, true); + IImageInfo info = decoder.Identify(configuration, stream); + stream.Position = 0; + + PngMetadata meta = info.Metadata.GetPngMetadata(); + PngColorType color = meta.ColorType.GetValueOrDefault(); + PngBitDepth bits = meta.BitDepth.GetValueOrDefault(); + switch (color) + { + case PngColorType.Grayscale: + if (bits == PngBitDepth.Bit16) + { + return !meta.HasTransparency + ? this.Decode(configuration, stream) + : this.Decode(configuration, stream); + } + + return !meta.HasTransparency + ? this.Decode(configuration, stream) + : this.Decode(configuration, stream); + + case PngColorType.Rgb: + if (bits == PngBitDepth.Bit16) + { + return !meta.HasTransparency + ? this.Decode(configuration, stream) + : this.Decode(configuration, stream); + } + + return !meta.HasTransparency + ? this.Decode(configuration, stream) + : this.Decode(configuration, stream); + + case PngColorType.Palette: + return this.Decode(configuration, stream); + + case PngColorType.GrayscaleWithAlpha: + return (bits == PngBitDepth.Bit16) + ? this.Decode(configuration, stream) + : this.Decode(configuration, stream); + + case PngColorType.RgbWithAlpha: + return (bits == PngBitDepth.Bit16) + ? this.Decode(configuration, stream) + : this.Decode(configuration, stream); + + default: + return this.Decode(configuration, stream); + } + } /// public Task> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - var decoder = new PngDecoderCore(configuration, this); + PngDecoderCore decoder = new(configuration, this); return decoder.DecodeAsync(configuration, stream, cancellationToken); } /// public async Task DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) - => await this.DecodeAsync(configuration, stream, cancellationToken) - .ConfigureAwait(false); + { + PngDecoderCore decoder = new(configuration, true); + IImageInfo info = await decoder.IdentifyAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + stream.Position = 0; + + PngMetadata meta = info.Metadata.GetPngMetadata(); + PngColorType color = meta.ColorType.GetValueOrDefault(); + PngBitDepth bits = meta.BitDepth.GetValueOrDefault(); + switch (color) + { + case PngColorType.Grayscale: + if (bits == PngBitDepth.Bit16) + { + return !meta.HasTransparency + ? await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false) + : await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + } + + return !meta.HasTransparency + ? await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false) + : await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + + case PngColorType.Rgb: + if (bits == PngBitDepth.Bit16) + { + return !meta.HasTransparency + ? await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false) + : await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + } + + return !meta.HasTransparency + ? await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false) + : await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + + case PngColorType.Palette: + return await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + + case PngColorType.GrayscaleWithAlpha: + return (bits == PngBitDepth.Bit16) + ? await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false) + : await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + + case PngColorType.RgbWithAlpha: + return (bits == PngBitDepth.Bit16) + ? await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false) + : await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + + default: + return await this.DecodeAsync(configuration, stream, cancellationToken).ConfigureAwait(false); + } + } /// public IImageInfo Identify(Configuration configuration, Stream stream) { - var decoder = new PngDecoderCore(configuration, this); + PngDecoderCore decoder = new(configuration, this); return decoder.Identify(configuration, stream); } /// public Task IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) { - var decoder = new PngDecoderCore(configuration, this); + PngDecoderCore decoder = new(configuration, this); return decoder.IdentifyAsync(configuration, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index da8481c26..ffaa9d567 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -37,6 +37,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly bool ignoreMetadata; + /// + /// Gets or sets a value indicating whether to read the IHDR and tRNS chunks only. + /// + private readonly bool colorMetadataOnly; + /// /// Used the manage memory allocations. /// @@ -77,11 +82,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// private byte[] paletteAlpha; - /// - /// A value indicating whether the end chunk has been reached. - /// - private bool isEndChunkReached; - /// /// Previous scanline processed. /// @@ -124,13 +124,21 @@ namespace SixLabors.ImageSharp.Formats.Png this.ignoreMetadata = options.IgnoreMetadata; } + internal PngDecoderCore(Configuration configuration, bool colorMetadataOnly) + { + this.Configuration = configuration ?? Configuration.Default; + this.memoryAllocator = this.Configuration.MemoryAllocator; + this.colorMetadataOnly = colorMetadataOnly; + this.ignoreMetadata = true; + } + /// public Configuration Configuration { get; } /// /// Gets the dimensions of the image. /// - public Size Dimensions => new Size(this.header.Width, this.header.Height); + public Size Dimensions => new(this.header.Width, this.header.Height); /// public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) @@ -143,7 +151,7 @@ namespace SixLabors.ImageSharp.Formats.Png Image image = null; try { - while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) + while (this.TryReadChunk(out PngChunk chunk)) { try { @@ -168,12 +176,12 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngChunkType.Palette: - var pal = new byte[chunk.Length]; + byte[] pal = new byte[chunk.Length]; chunk.Data.GetSpan().CopyTo(pal); this.palette = pal; break; case PngChunkType.Transparency: - var alpha = new byte[chunk.Length]; + byte[] alpha = new byte[chunk.Length]; chunk.Data.GetSpan().CopyTo(alpha); this.paletteAlpha = alpha; this.AssignTransparentMarkers(alpha, pngMetadata); @@ -190,15 +198,14 @@ namespace SixLabors.ImageSharp.Formats.Png case PngChunkType.Exif: if (!this.ignoreMetadata) { - var exifData = new byte[chunk.Length]; + byte[] exifData = new byte[chunk.Length]; chunk.Data.GetSpan().CopyTo(exifData); metadata.ExifProfile = new ExifProfile(exifData); } break; case PngChunkType.End: - this.isEndChunkReached = true; - break; + goto EOF; case PngChunkType.ProprietaryApple: PngThrowHelper.ThrowInvalidChunkType("Proprietary Apple PNG detected! This PNG file is not conform to the specification and cannot be decoded."); break; @@ -210,6 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Png } } + EOF: if (image is null) { PngThrowHelper.ThrowNoData(); @@ -233,7 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.currentStream.Skip(8); try { - while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) + while (this.TryReadChunk(out PngChunk chunk)) { try { @@ -243,35 +251,89 @@ namespace SixLabors.ImageSharp.Formats.Png this.ReadHeaderChunk(pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.Physical: + if (this.colorMetadataOnly) + { + this.SkipChunkDataAndCrc(chunk); + break; + } + this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan()); break; case PngChunkType.Gamma: + if (this.colorMetadataOnly) + { + this.SkipChunkDataAndCrc(chunk); + break; + } + this.ReadGammaChunk(pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.Data: + + // Spec says tRNS must be before IDAT so safe to exit. + if (this.colorMetadataOnly) + { + goto EOF; + } + this.SkipChunkDataAndCrc(chunk); + break; + case PngChunkType.Transparency: + byte[] alpha = new byte[chunk.Length]; + chunk.Data.GetSpan().CopyTo(alpha); + this.paletteAlpha = alpha; + this.AssignTransparentMarkers(alpha, pngMetadata); + + if (this.colorMetadataOnly) + { + goto EOF; + } + break; case PngChunkType.Text: + if (this.colorMetadataOnly) + { + this.SkipChunkDataAndCrc(chunk); + break; + } + this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.CompressedText: + if (this.colorMetadataOnly) + { + this.SkipChunkDataAndCrc(chunk); + break; + } + this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.InternationalText: + if (this.colorMetadataOnly) + { + this.SkipChunkDataAndCrc(chunk); + break; + } + this.ReadInternationalTextChunk(pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.Exif: + if (this.colorMetadataOnly) + { + this.SkipChunkDataAndCrc(chunk); + break; + } + if (!this.ignoreMetadata) { - var exifData = new byte[chunk.Length]; + byte[] exifData = new byte[chunk.Length]; chunk.Data.GetSpan().CopyTo(exifData); metadata.ExifProfile = new ExifProfile(exifData); } break; case PngChunkType.End: - this.isEndChunkReached = true; - break; + goto EOF; } } finally @@ -279,19 +341,20 @@ namespace SixLabors.ImageSharp.Formats.Png chunk.Data?.Dispose(); // Data is rented in ReadChunkData() } } + + EOF: + 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); } 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); } /// @@ -364,11 +427,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// The metadata to read to. /// The data containing physical data. private void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan data) - { + // The value is encoded as a 4-byte unsigned integer, representing gamma times 100000. // For example, a gamma of 1/2.2 would be stored as 45455. - pngMetadata.Gamma = BinaryPrimitives.ReadUInt32BigEndian(data) / 100_000F; - } + => pngMetadata.Gamma = BinaryPrimitives.ReadUInt32BigEndian(data) * 1e-5F; /// /// Initializes the image and various buffers needed for processing @@ -477,19 +539,17 @@ namespace SixLabors.ImageSharp.Formats.Png private void ReadScanlines(PngChunk chunk, ImageFrame image, PngMetadata pngMetadata) where TPixel : unmanaged, IPixel { - using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) - { - deframeStream.AllocateNewBytes(chunk.Length, true); - DeflateStream dataStream = deframeStream.CompressedStream; + using var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk); + deframeStream.AllocateNewBytes(chunk.Length, true); + DeflateStream dataStream = deframeStream.CompressedStream; - if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) - { - this.DecodeInterlacedPixelData(dataStream, image, pngMetadata); - } - else - { - this.DecodePixelData(dataStream, image, pngMetadata); - } + if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) + { + this.DecodeInterlacedPixelData(dataStream, image, pngMetadata); + } + else + { + this.DecodePixelData(dataStream, image, pngMetadata); } } @@ -919,7 +979,7 @@ namespace SixLabors.ImageSharp.Formats.Png int zeroIndex = data.IndexOf((byte)0); // Keywords are restricted to 1 to 79 bytes in length. - if (zeroIndex < PngConstants.MinTextKeywordLength || zeroIndex > PngConstants.MaxTextKeywordLength) + if (zeroIndex is < PngConstants.MinTextKeywordLength or > PngConstants.MaxTextKeywordLength) { return; } @@ -1146,8 +1206,10 @@ namespace SixLabors.ImageSharp.Formats.Png PngChunkType type = this.ReadChunkType(); - // NOTE: Reading the chunk data is the responsible of the caller - if (type == PngChunkType.Data) + // NOTE: Reading the Data chunk is the responsible of the caller + // If we're reading color metadata only we're only interested in the IHDR and tRNS chunks. + // We can skip all other chunk data in the stream for better performance. + if (type == PngChunkType.Data || (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency)) { chunk = new PngChunk(length, type); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 543a544d0..d63dad8d4 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System; using System.IO; +using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats.Png; @@ -19,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Trait("Format", "Png")] public partial class PngDecoderTests { - private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; + private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; private static PngDecoder PngDecoder => new(); @@ -62,16 +64,51 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png TestImages.Png.Bad.ZlibZtxtBadHeader, }; + public static readonly TheoryData PixelFormatRange = new() + { + { TestImages.Png.Gray4Bpp, typeof(Image) }, + { TestImages.Png.L16Bit, typeof(Image) }, + { TestImages.Png.Gray1BitTrans, typeof(Image) }, + { TestImages.Png.Gray2BitTrans, typeof(Image) }, + { TestImages.Png.Gray4BitTrans, typeof(Image) }, + { TestImages.Png.GrayA8Bit, typeof(Image) }, + { TestImages.Png.GrayAlpha16Bit, typeof(Image) }, + { TestImages.Png.Palette8Bpp, typeof(Image) }, + { TestImages.Png.PalettedTwoColor, typeof(Image) }, + { TestImages.Png.Rainbow, typeof(Image) }, + { TestImages.Png.Rgb24BppTrans, typeof(Image) }, + { TestImages.Png.Kaboom, typeof(Image) }, + { TestImages.Png.Rgb48Bpp, typeof(Image) }, + { TestImages.Png.Rgb48BppTrans, typeof(Image) }, + { TestImages.Png.Rgba64Bpp, typeof(Image) }, + }; + + [Theory] + [MemberData(nameof(PixelFormatRange))] + public void Decode_NonGeneric_CreatesCorrectImageType(string path, Type type) + { + string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path); + using var image = Image.Load(file); + Assert.IsType(type, image); + } + + [Theory] + [MemberData(nameof(PixelFormatRange))] + public async Task DecodeAsync_NonGeneric_CreatesCorrectImageType(string path, Type type) + { + string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path); + using Image image = await Image.LoadAsync(file); + Assert.IsType(type, image); + } + [Theory] [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] public void Decode(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -80,11 +117,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_GrayWithAlpha(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -94,11 +129,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_Interlaced(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -111,11 +144,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_Indexed(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -124,11 +155,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_48Bpp(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -137,11 +166,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_64Bpp(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -152,11 +179,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decoder_L8bitInterlaced(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -164,11 +189,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_L16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -177,23 +200,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_GrayAlpha16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] - [WithFile(TestImages.Png.GrayA8BitInterlaced, PixelTypes)] + [WithFile(TestImages.Png.GrayA8BitInterlaced, TestPixelTypes)] public void Decoder_CanDecode_Grey8bitInterlaced_WithAlpha(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -201,23 +220,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decoder_CanDecode_CorruptedImages(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] - [WithFile(TestImages.Png.Splash, PixelTypes)] + [WithFile(TestImages.Png.Splash, TestPixelTypes)] public void Decoder_IsNotBoundToSinglePixelType(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } [Theory] @@ -231,10 +246,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Identify(string imagePath, int expectedPixelSize) { var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); - } + using var stream = new MemoryStream(testFile.Bytes, false); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); } [Theory] @@ -245,10 +258,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); }); Assert.NotNull(ex); Assert.Contains("PNG Image does not contain a data chunk", ex.Message); @@ -263,10 +274,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); }); Assert.NotNull(ex); Assert.Contains("Invalid or unsupported bit depth", ex.Message); @@ -281,10 +290,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); }); Assert.NotNull(ex); Assert.Contains("Invalid or unsupported color type", ex.Message); @@ -299,11 +306,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); }); Assert.Null(ex); } @@ -317,11 +322,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); }); Assert.Null(ex); } @@ -335,11 +338,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); }); Assert.Null(ex); } @@ -353,15 +354,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); - // We don't have another x-plat reference decoder that can be compared for this image. - if (TestEnvironment.IsWindows) - { - image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); - } + // We don't have another x-plat reference decoder that can be compared for this image. + if (TestEnvironment.IsWindows) + { + image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); } }); Assert.Null(ex); @@ -376,11 +375,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); - image.CompareToOriginal(provider, ImageComparer.Exact); - } + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); }); Assert.Null(ex); } @@ -394,15 +391,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png System.Exception ex = Record.Exception( () => { - using (Image image = provider.GetImage(PngDecoder)) - { - image.DebugSave(provider); + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); - // We don't have another x-plat reference decoder that can be compared for this image. - if (TestEnvironment.IsWindows) - { - image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); - } + // We don't have another x-plat reference decoder that can be compared for this image. + if (TestEnvironment.IsWindows) + { + image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); } }); Assert.NotNull(ex);