|
|
|
@ -9,7 +9,6 @@ using SixLabors.ImageSharp.Formats; |
|
|
|
using SixLabors.ImageSharp.Formats.Png; |
|
|
|
using SixLabors.ImageSharp.MetaData; |
|
|
|
using SixLabors.ImageSharp.PixelFormats; |
|
|
|
using SixLabors.ImageSharp.Processing; |
|
|
|
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
|
|
|
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; |
|
|
|
|
|
|
|
@ -19,10 +18,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png |
|
|
|
{ |
|
|
|
public class PngEncoderTests |
|
|
|
{ |
|
|
|
// This is bull. Failing online for no good reason.
|
|
|
|
// The images are an exact match. Maybe the submodule isn't updating?
|
|
|
|
private const float ToleranceThresholdForPaletteEncoder = 1.3F / 100; |
|
|
|
|
|
|
|
public static readonly TheoryData<string, PngBitDepth> PngBitDepthFiles = |
|
|
|
new TheoryData<string, PngBitDepth> |
|
|
|
{ |
|
|
|
@ -137,19 +132,32 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.Rgb)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.RgbWithAlpha)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.RgbWithAlpha)] |
|
|
|
public void WorksWithBitDepth16<TPixel>(TestImageProvider<TPixel> provider, PngColorType pngColorType) |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Rgb, PngBitDepth.Bit8)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.Rgb, PngBitDepth.Bit16)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit1)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit2)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit4)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit8)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit1)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit2)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit4)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit8)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgb48, PngColorType.Grayscale, PngBitDepth.Bit16)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] |
|
|
|
[WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit16)] |
|
|
|
public void WorksWithAllBitDepths<TPixel>(TestImageProvider<TPixel> provider, PngColorType pngColorType, PngBitDepth pngBitDepth) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
TestPngEncoderCore( |
|
|
|
provider, |
|
|
|
pngColorType, |
|
|
|
PngFilterMethod.Adaptive, |
|
|
|
PngBitDepth.Bit16, |
|
|
|
pngBitDepth, |
|
|
|
appendPngColorType: true, |
|
|
|
appendPixelType: true); |
|
|
|
appendPixelType: true, |
|
|
|
appendPngBitDepth: true); |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
@ -166,87 +174,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png |
|
|
|
appendPaletteSize: true); |
|
|
|
} |
|
|
|
|
|
|
|
private static bool HasAlpha(PngColorType pngColorType) => |
|
|
|
pngColorType == PngColorType.GrayscaleWithAlpha || pngColorType == PngColorType.RgbWithAlpha; |
|
|
|
|
|
|
|
private static void TestPngEncoderCore<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider, |
|
|
|
PngColorType pngColorType, |
|
|
|
PngFilterMethod pngFilterMethod, |
|
|
|
PngBitDepth bitDepth, |
|
|
|
int compressionLevel = 6, |
|
|
|
int paletteSize = 255, |
|
|
|
bool appendPngColorType = false, |
|
|
|
bool appendPngFilterMethod = false, |
|
|
|
bool appendPixelType = false, |
|
|
|
bool appendCompressionLevel = false, |
|
|
|
bool appendPaletteSize = false) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
using (Image<TPixel> image = provider.GetImage()) |
|
|
|
{ |
|
|
|
if (!HasAlpha(pngColorType)) |
|
|
|
{ |
|
|
|
image.Mutate(c => c.MakeOpaque()); |
|
|
|
} |
|
|
|
|
|
|
|
var encoder = new PngEncoder |
|
|
|
{ |
|
|
|
ColorType = pngColorType, |
|
|
|
FilterMethod = pngFilterMethod, |
|
|
|
CompressionLevel = compressionLevel, |
|
|
|
BitDepth = bitDepth, |
|
|
|
Quantizer = new WuQuantizer(paletteSize) |
|
|
|
}; |
|
|
|
|
|
|
|
string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; |
|
|
|
string pngFilterMethodInfo = appendPngFilterMethod ? pngFilterMethod.ToString() : string.Empty; |
|
|
|
string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : string.Empty; |
|
|
|
string paletteSizeInfo = appendPaletteSize ? $"_PaletteSize-{paletteSize}" : string.Empty; |
|
|
|
string debugInfo = $"{pngColorTypeInfo}{pngFilterMethodInfo}{compressionLevelInfo}{paletteSizeInfo}"; |
|
|
|
//string referenceInfo = $"{pngColorTypeInfo}";
|
|
|
|
|
|
|
|
// Does DebugSave & load reference CompareToReferenceInput():
|
|
|
|
string actualOutputFile = ((ITestImageProvider)provider).Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); |
|
|
|
|
|
|
|
if (TestEnvironment.IsMono) |
|
|
|
{ |
|
|
|
// There are bugs in mono's System.Drawing implementation, reference decoders are not always reliable!
|
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); |
|
|
|
string referenceOutputFile = ((ITestImageProvider)provider).Utility.GetReferenceOutputFileName("png", debugInfo, appendPixelType, true); |
|
|
|
|
|
|
|
bool referenceOutputFileExists = File.Exists(referenceOutputFile); |
|
|
|
|
|
|
|
using (var actualImage = Image.Load<TPixel>(actualOutputFile, referenceDecoder)) |
|
|
|
{ |
|
|
|
// TODO: Do we still need the reference output files?
|
|
|
|
Image<TPixel> referenceImage = referenceOutputFileExists |
|
|
|
? Image.Load<TPixel>(referenceOutputFile, referenceDecoder) |
|
|
|
: image; |
|
|
|
|
|
|
|
float paletteToleranceHack = 80f / paletteSize; |
|
|
|
paletteToleranceHack *= paletteToleranceHack; |
|
|
|
ImageComparer comparer = pngColorType == PngColorType.Palette |
|
|
|
? ImageComparer.Tolerant(ToleranceThresholdForPaletteEncoder * paletteToleranceHack) |
|
|
|
: ImageComparer.Exact; |
|
|
|
try |
|
|
|
{ |
|
|
|
comparer.VerifySimilarity(referenceImage, actualImage); |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
if (referenceOutputFileExists) |
|
|
|
{ |
|
|
|
referenceImage.Dispose(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[WithBlankImages(1, 1, PixelTypes.Rgba32)] |
|
|
|
public void WritesFileMarker<TPixel>(TestImageProvider<TPixel> provider) |
|
|
|
@ -321,5 +248,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static void TestPngEncoderCore<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider, |
|
|
|
PngColorType pngColorType, |
|
|
|
PngFilterMethod pngFilterMethod, |
|
|
|
PngBitDepth bitDepth, |
|
|
|
int compressionLevel = 6, |
|
|
|
int paletteSize = 255, |
|
|
|
bool appendPngColorType = false, |
|
|
|
bool appendPngFilterMethod = false, |
|
|
|
bool appendPixelType = false, |
|
|
|
bool appendCompressionLevel = false, |
|
|
|
bool appendPaletteSize = false, |
|
|
|
bool appendPngBitDepth = false) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
using (Image<TPixel> image = provider.GetImage()) |
|
|
|
{ |
|
|
|
var encoder = new PngEncoder |
|
|
|
{ |
|
|
|
ColorType = pngColorType, |
|
|
|
FilterMethod = pngFilterMethod, |
|
|
|
CompressionLevel = compressionLevel, |
|
|
|
BitDepth = bitDepth, |
|
|
|
Quantizer = new WuQuantizer(paletteSize) |
|
|
|
}; |
|
|
|
|
|
|
|
string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; |
|
|
|
string pngFilterMethodInfo = appendPngFilterMethod ? pngFilterMethod.ToString() : string.Empty; |
|
|
|
string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : string.Empty; |
|
|
|
string paletteSizeInfo = appendPaletteSize ? $"_PaletteSize-{paletteSize}" : string.Empty; |
|
|
|
string pngBitDepthInfo = appendPngBitDepth ? bitDepth.ToString() : string.Empty; |
|
|
|
string debugInfo = $"{pngColorTypeInfo}{pngFilterMethodInfo}{compressionLevelInfo}{paletteSizeInfo}{pngBitDepthInfo}"; |
|
|
|
|
|
|
|
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); |
|
|
|
|
|
|
|
// Compare to the Magick reference decoder.
|
|
|
|
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); |
|
|
|
|
|
|
|
// We compare using both our decoder and the reference decoder as pixel transformation
|
|
|
|
// occurrs within the encoder itself leaving the input image unaffected.
|
|
|
|
// This means we are benefiting from testing our decoder also.
|
|
|
|
using (var imageSharpImage = Image.Load<TPixel>(actualOutputFile, new PngDecoder())) |
|
|
|
using (var referenceImage = Image.Load<TPixel>(actualOutputFile, referenceDecoder)) |
|
|
|
{ |
|
|
|
ImageComparer.Exact.VerifySimilarity(referenceImage, imageSharpImage); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |