Browse Source

Merge pull request #1861 from SixLabors/js/png-decode-to-type

Png - Preserve Pixel Format for Non-generic decode.
pull/1898/head
James Jackson-South 4 years ago
committed by GitHub
parent
commit
ecd3db2271
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 114
      src/ImageSharp/Formats/Png/PngDecoder.cs
  2. 144
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  3. 225
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

114
src/ImageSharp/Formats/Png/PngDecoder.cs

@ -20,37 +20,137 @@ namespace SixLabors.ImageSharp.Formats.Png
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var decoder = new PngDecoderCore(configuration, this); PngDecoderCore decoder = new(configuration, this);
return decoder.Decode<TPixel>(configuration, stream); return decoder.Decode<TPixel>(configuration, stream);
} }
/// <inheritdoc /> /// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(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<L16>(configuration, stream)
: this.Decode<La32>(configuration, stream);
}
return !meta.HasTransparency
? this.Decode<L8>(configuration, stream)
: this.Decode<La16>(configuration, stream);
case PngColorType.Rgb:
if (bits == PngBitDepth.Bit16)
{
return !meta.HasTransparency
? this.Decode<Rgb48>(configuration, stream)
: this.Decode<Rgba64>(configuration, stream);
}
return !meta.HasTransparency
? this.Decode<Rgb24>(configuration, stream)
: this.Decode<Rgba32>(configuration, stream);
case PngColorType.Palette:
return this.Decode<Rgba32>(configuration, stream);
case PngColorType.GrayscaleWithAlpha:
return (bits == PngBitDepth.Bit16)
? this.Decode<La32>(configuration, stream)
: this.Decode<La16>(configuration, stream);
case PngColorType.RgbWithAlpha:
return (bits == PngBitDepth.Bit16)
? this.Decode<Rgba64>(configuration, stream)
: this.Decode<Rgba32>(configuration, stream);
default:
return this.Decode<Rgba32>(configuration, stream);
}
}
/// <inheritdoc/> /// <inheritdoc/>
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken) public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var decoder = new PngDecoderCore(configuration, this); PngDecoderCore decoder = new(configuration, this);
return decoder.DecodeAsync<TPixel>(configuration, stream, cancellationToken); return decoder.DecodeAsync<TPixel>(configuration, stream, cancellationToken);
} }
/// <inheritdoc /> /// <inheritdoc />
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) public async Task<Image> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
=> await this.DecodeAsync<Rgba32>(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<L16>(configuration, stream, cancellationToken).ConfigureAwait(false)
: await this.DecodeAsync<La32>(configuration, stream, cancellationToken).ConfigureAwait(false);
}
return !meta.HasTransparency
? await this.DecodeAsync<L8>(configuration, stream, cancellationToken).ConfigureAwait(false)
: await this.DecodeAsync<La16>(configuration, stream, cancellationToken).ConfigureAwait(false);
case PngColorType.Rgb:
if (bits == PngBitDepth.Bit16)
{
return !meta.HasTransparency
? await this.DecodeAsync<Rgb48>(configuration, stream, cancellationToken).ConfigureAwait(false)
: await this.DecodeAsync<Rgba64>(configuration, stream, cancellationToken).ConfigureAwait(false);
}
return !meta.HasTransparency
? await this.DecodeAsync<Rgb24>(configuration, stream, cancellationToken).ConfigureAwait(false)
: await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false);
case PngColorType.Palette:
return await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false);
case PngColorType.GrayscaleWithAlpha:
return (bits == PngBitDepth.Bit16)
? await this.DecodeAsync<La32>(configuration, stream, cancellationToken).ConfigureAwait(false)
: await this.DecodeAsync<La16>(configuration, stream, cancellationToken).ConfigureAwait(false);
case PngColorType.RgbWithAlpha:
return (bits == PngBitDepth.Bit16)
? await this.DecodeAsync<Rgba64>(configuration, stream, cancellationToken).ConfigureAwait(false)
: await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false);
default:
return await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false);
}
}
/// <inheritdoc/> /// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream) public IImageInfo Identify(Configuration configuration, Stream stream)
{ {
var decoder = new PngDecoderCore(configuration, this); PngDecoderCore decoder = new(configuration, this);
return decoder.Identify(configuration, stream); return decoder.Identify(configuration, stream);
} }
/// <inheritdoc/> /// <inheritdoc/>
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
{ {
var decoder = new PngDecoderCore(configuration, this); PngDecoderCore decoder = new(configuration, this);
return decoder.IdentifyAsync(configuration, stream, cancellationToken); return decoder.IdentifyAsync(configuration, stream, cancellationToken);
} }
} }

144
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -37,6 +37,11 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
private readonly bool ignoreMetadata; private readonly bool ignoreMetadata;
/// <summary>
/// Gets or sets a value indicating whether to read the IHDR and tRNS chunks only.
/// </summary>
private readonly bool colorMetadataOnly;
/// <summary> /// <summary>
/// Used the manage memory allocations. /// Used the manage memory allocations.
/// </summary> /// </summary>
@ -77,11 +82,6 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
private byte[] paletteAlpha; private byte[] paletteAlpha;
/// <summary>
/// A value indicating whether the end chunk has been reached.
/// </summary>
private bool isEndChunkReached;
/// <summary> /// <summary>
/// Previous scanline processed. /// Previous scanline processed.
/// </summary> /// </summary>
@ -124,13 +124,21 @@ namespace SixLabors.ImageSharp.Formats.Png
this.ignoreMetadata = options.IgnoreMetadata; 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;
}
/// <inheritdoc/> /// <inheritdoc/>
public Configuration Configuration { get; } public Configuration Configuration { get; }
/// <summary> /// <summary>
/// Gets the dimensions of the image. /// Gets the dimensions of the image.
/// </summary> /// </summary>
public Size Dimensions => new Size(this.header.Width, this.header.Height); public Size Dimensions => new(this.header.Width, this.header.Height);
/// <inheritdoc/> /// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken) public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
@ -143,7 +151,7 @@ namespace SixLabors.ImageSharp.Formats.Png
Image<TPixel> image = null; Image<TPixel> image = null;
try try
{ {
while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) while (this.TryReadChunk(out PngChunk chunk))
{ {
try try
{ {
@ -168,12 +176,12 @@ namespace SixLabors.ImageSharp.Formats.Png
break; break;
case PngChunkType.Palette: case PngChunkType.Palette:
var pal = new byte[chunk.Length]; byte[] pal = new byte[chunk.Length];
chunk.Data.GetSpan().CopyTo(pal); chunk.Data.GetSpan().CopyTo(pal);
this.palette = pal; this.palette = pal;
break; break;
case PngChunkType.Transparency: case PngChunkType.Transparency:
var alpha = new byte[chunk.Length]; byte[] alpha = new byte[chunk.Length];
chunk.Data.GetSpan().CopyTo(alpha); chunk.Data.GetSpan().CopyTo(alpha);
this.paletteAlpha = alpha; this.paletteAlpha = alpha;
this.AssignTransparentMarkers(alpha, pngMetadata); this.AssignTransparentMarkers(alpha, pngMetadata);
@ -190,15 +198,14 @@ namespace SixLabors.ImageSharp.Formats.Png
case PngChunkType.Exif: case PngChunkType.Exif:
if (!this.ignoreMetadata) if (!this.ignoreMetadata)
{ {
var exifData = new byte[chunk.Length]; byte[] exifData = new byte[chunk.Length];
chunk.Data.GetSpan().CopyTo(exifData); chunk.Data.GetSpan().CopyTo(exifData);
metadata.ExifProfile = new ExifProfile(exifData); metadata.ExifProfile = new ExifProfile(exifData);
} }
break; break;
case PngChunkType.End: case PngChunkType.End:
this.isEndChunkReached = true; goto EOF;
break;
case PngChunkType.ProprietaryApple: case PngChunkType.ProprietaryApple:
PngThrowHelper.ThrowInvalidChunkType("Proprietary Apple PNG detected! This PNG file is not conform to the specification and cannot be decoded."); PngThrowHelper.ThrowInvalidChunkType("Proprietary Apple PNG detected! This PNG file is not conform to the specification and cannot be decoded.");
break; break;
@ -210,6 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
} }
EOF:
if (image is null) if (image is null)
{ {
PngThrowHelper.ThrowNoData(); PngThrowHelper.ThrowNoData();
@ -233,7 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.currentStream.Skip(8); this.currentStream.Skip(8);
try try
{ {
while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) while (this.TryReadChunk(out PngChunk chunk))
{ {
try try
{ {
@ -243,35 +251,89 @@ namespace SixLabors.ImageSharp.Formats.Png
this.ReadHeaderChunk(pngMetadata, chunk.Data.GetSpan()); this.ReadHeaderChunk(pngMetadata, chunk.Data.GetSpan());
break; break;
case PngChunkType.Physical: case PngChunkType.Physical:
if (this.colorMetadataOnly)
{
this.SkipChunkDataAndCrc(chunk);
break;
}
this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan()); this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan());
break; break;
case PngChunkType.Gamma: case PngChunkType.Gamma:
if (this.colorMetadataOnly)
{
this.SkipChunkDataAndCrc(chunk);
break;
}
this.ReadGammaChunk(pngMetadata, chunk.Data.GetSpan()); this.ReadGammaChunk(pngMetadata, chunk.Data.GetSpan());
break; break;
case PngChunkType.Data: case PngChunkType.Data:
// Spec says tRNS must be before IDAT so safe to exit.
if (this.colorMetadataOnly)
{
goto EOF;
}
this.SkipChunkDataAndCrc(chunk); 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; break;
case PngChunkType.Text: case PngChunkType.Text:
if (this.colorMetadataOnly)
{
this.SkipChunkDataAndCrc(chunk);
break;
}
this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan()); this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan());
break; break;
case PngChunkType.CompressedText: case PngChunkType.CompressedText:
if (this.colorMetadataOnly)
{
this.SkipChunkDataAndCrc(chunk);
break;
}
this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan()); this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan());
break; break;
case PngChunkType.InternationalText: case PngChunkType.InternationalText:
if (this.colorMetadataOnly)
{
this.SkipChunkDataAndCrc(chunk);
break;
}
this.ReadInternationalTextChunk(pngMetadata, chunk.Data.GetSpan()); this.ReadInternationalTextChunk(pngMetadata, chunk.Data.GetSpan());
break; break;
case PngChunkType.Exif: case PngChunkType.Exif:
if (this.colorMetadataOnly)
{
this.SkipChunkDataAndCrc(chunk);
break;
}
if (!this.ignoreMetadata) if (!this.ignoreMetadata)
{ {
var exifData = new byte[chunk.Length]; byte[] exifData = new byte[chunk.Length];
chunk.Data.GetSpan().CopyTo(exifData); chunk.Data.GetSpan().CopyTo(exifData);
metadata.ExifProfile = new ExifProfile(exifData); metadata.ExifProfile = new ExifProfile(exifData);
} }
break; break;
case PngChunkType.End: case PngChunkType.End:
this.isEndChunkReached = true; goto EOF;
break;
} }
} }
finally finally
@ -279,19 +341,20 @@ namespace SixLabors.ImageSharp.Formats.Png
chunk.Data?.Dispose(); // Data is rented in ReadChunkData() 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 finally
{ {
this.scanline?.Dispose(); this.scanline?.Dispose();
this.previousScanline?.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> /// <summary>
@ -364,11 +427,10 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="pngMetadata">The metadata to read to.</param> /// <param name="pngMetadata">The metadata to read to.</param>
/// <param name="data">The data containing physical data.</param> /// <param name="data">The data containing physical data.</param>
private void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan<byte> data) private void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan<byte> data)
{
// The value is encoded as a 4-byte unsigned integer, representing gamma times 100000. // 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. // 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;
}
/// <summary> /// <summary>
/// Initializes the image and various buffers needed for processing /// Initializes the image and various buffers needed for processing
@ -477,19 +539,17 @@ namespace SixLabors.ImageSharp.Formats.Png
private void ReadScanlines<TPixel>(PngChunk chunk, ImageFrame<TPixel> image, PngMetadata pngMetadata) private void ReadScanlines<TPixel>(PngChunk chunk, ImageFrame<TPixel> image, PngMetadata pngMetadata)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) using var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk);
{ deframeStream.AllocateNewBytes(chunk.Length, true);
deframeStream.AllocateNewBytes(chunk.Length, true); DeflateStream dataStream = deframeStream.CompressedStream;
DeflateStream dataStream = deframeStream.CompressedStream;
if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
{ {
this.DecodeInterlacedPixelData(dataStream, image, pngMetadata); this.DecodeInterlacedPixelData(dataStream, image, pngMetadata);
} }
else else
{ {
this.DecodePixelData(dataStream, image, pngMetadata); this.DecodePixelData(dataStream, image, pngMetadata);
}
} }
} }
@ -919,7 +979,7 @@ namespace SixLabors.ImageSharp.Formats.Png
int zeroIndex = data.IndexOf((byte)0); int zeroIndex = data.IndexOf((byte)0);
// Keywords are restricted to 1 to 79 bytes in length. // 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; return;
} }
@ -1146,8 +1206,10 @@ namespace SixLabors.ImageSharp.Formats.Png
PngChunkType type = this.ReadChunkType(); PngChunkType type = this.ReadChunkType();
// NOTE: Reading the chunk data is the responsible of the caller // NOTE: Reading the Data chunk is the responsible of the caller
if (type == PngChunkType.Data) // 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); chunk = new PngChunk(length, type);

225
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

@ -1,7 +1,9 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.IO; using System.IO;
using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor; using Microsoft.DotNet.RemoteExecutor;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
@ -19,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[Trait("Format", "Png")] [Trait("Format", "Png")]
public partial class PngDecoderTests 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(); private static PngDecoder PngDecoder => new();
@ -62,16 +64,51 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
TestImages.Png.Bad.ZlibZtxtBadHeader, TestImages.Png.Bad.ZlibZtxtBadHeader,
}; };
public static readonly TheoryData<string, Type> PixelFormatRange = new()
{
{ TestImages.Png.Gray4Bpp, typeof(Image<L8>) },
{ TestImages.Png.L16Bit, typeof(Image<L16>) },
{ TestImages.Png.Gray1BitTrans, typeof(Image<La16>) },
{ TestImages.Png.Gray2BitTrans, typeof(Image<La16>) },
{ TestImages.Png.Gray4BitTrans, typeof(Image<La16>) },
{ TestImages.Png.GrayA8Bit, typeof(Image<La16>) },
{ TestImages.Png.GrayAlpha16Bit, typeof(Image<La32>) },
{ TestImages.Png.Palette8Bpp, typeof(Image<Rgba32>) },
{ TestImages.Png.PalettedTwoColor, typeof(Image<Rgba32>) },
{ TestImages.Png.Rainbow, typeof(Image<Rgb24>) },
{ TestImages.Png.Rgb24BppTrans, typeof(Image<Rgba32>) },
{ TestImages.Png.Kaboom, typeof(Image<Rgba32>) },
{ TestImages.Png.Rgb48Bpp, typeof(Image<Rgb48>) },
{ TestImages.Png.Rgb48BppTrans, typeof(Image<Rgba64>) },
{ TestImages.Png.Rgba64Bpp, typeof(Image<Rgba64>) },
};
[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] [Theory]
[WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)]
public void Decode<TPixel>(TestImageProvider<TPixel> provider) public void Decode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -80,11 +117,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decode_GrayWithAlpha<TPixel>(TestImageProvider<TPixel> provider) public void Decode_GrayWithAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -94,11 +129,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decode_Interlaced<TPixel>(TestImageProvider<TPixel> provider) public void Decode_Interlaced<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -111,11 +144,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decode_Indexed<TPixel>(TestImageProvider<TPixel> provider) public void Decode_Indexed<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -124,11 +155,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decode_48Bpp<TPixel>(TestImageProvider<TPixel> provider) public void Decode_48Bpp<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -137,11 +166,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decode_64Bpp<TPixel>(TestImageProvider<TPixel> provider) public void Decode_64Bpp<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -152,11 +179,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decoder_L8bitInterlaced<TPixel>(TestImageProvider<TPixel> provider) public void Decoder_L8bitInterlaced<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -164,11 +189,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decode_L16Bit<TPixel>(TestImageProvider<TPixel> provider) public void Decode_L16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -177,23 +200,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decode_GrayAlpha16Bit<TPixel>(TestImageProvider<TPixel> provider) public void Decode_GrayAlpha16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
[WithFile(TestImages.Png.GrayA8BitInterlaced, PixelTypes)] [WithFile(TestImages.Png.GrayA8BitInterlaced, TestPixelTypes)]
public void Decoder_CanDecode_Grey8bitInterlaced_WithAlpha<TPixel>(TestImageProvider<TPixel> provider) public void Decoder_CanDecode_Grey8bitInterlaced_WithAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -201,23 +220,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Decoder_CanDecode_CorruptedImages<TPixel>(TestImageProvider<TPixel> provider) public void Decoder_CanDecode_CorruptedImages<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
[WithFile(TestImages.Png.Splash, PixelTypes)] [WithFile(TestImages.Png.Splash, TestPixelTypes)]
public void Decoder_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider) public void Decoder_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
} }
[Theory] [Theory]
@ -231,10 +246,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
public void Identify(string imagePath, int expectedPixelSize) public void Identify(string imagePath, int expectedPixelSize)
{ {
var testFile = TestFile.Create(imagePath); var testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false)) using var stream = new MemoryStream(testFile.Bytes, false);
{ Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel);
Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel);
}
} }
[Theory] [Theory]
@ -245,10 +258,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider);
}
}); });
Assert.NotNull(ex); Assert.NotNull(ex);
Assert.Contains("PNG Image does not contain a data chunk", ex.Message); 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( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider);
}
}); });
Assert.NotNull(ex); Assert.NotNull(ex);
Assert.Contains("Invalid or unsupported bit depth", ex.Message); Assert.Contains("Invalid or unsupported bit depth", ex.Message);
@ -281,10 +290,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider);
}
}); });
Assert.NotNull(ex); Assert.NotNull(ex);
Assert.Contains("Invalid or unsupported color type", ex.Message); Assert.Contains("Invalid or unsupported color type", ex.Message);
@ -299,11 +306,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
}); });
Assert.Null(ex); Assert.Null(ex);
} }
@ -317,11 +322,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
}); });
Assert.Null(ex); Assert.Null(ex);
} }
@ -335,11 +338,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
}); });
Assert.Null(ex); Assert.Null(ex);
} }
@ -353,15 +354,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider);
// We don't have another x-plat reference decoder that can be compared for this image. // We don't have another x-plat reference decoder that can be compared for this image.
if (TestEnvironment.IsWindows) if (TestEnvironment.IsWindows)
{ {
image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance);
}
} }
}); });
Assert.Null(ex); Assert.Null(ex);
@ -376,11 +375,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact);
image.CompareToOriginal(provider, ImageComparer.Exact);
}
}); });
Assert.Null(ex); Assert.Null(ex);
} }
@ -394,15 +391,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
System.Exception ex = Record.Exception( System.Exception ex = Record.Exception(
() => () =>
{ {
using (Image<TPixel> image = provider.GetImage(PngDecoder)) using Image<TPixel> image = provider.GetImage(PngDecoder);
{ image.DebugSave(provider);
image.DebugSave(provider);
// We don't have another x-plat reference decoder that can be compared for this image. // We don't have another x-plat reference decoder that can be compared for this image.
if (TestEnvironment.IsWindows) if (TestEnvironment.IsWindows)
{ {
image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance);
}
} }
}); });
Assert.NotNull(ex); Assert.NotNull(ex);

Loading…
Cancel
Save