Browse Source

Added tests for different output color types (except ycck)

pull/2120/head
Dmitry Pentin 4 years ago
parent
commit
c6d127ee22
  1. 6
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs
  2. 1
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
  3. 66
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs
  4. 205
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  5. 45
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  6. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_Cmyk-Q100.jpg
  7. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_Luminance-Q100.jpg
  8. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_Rgb-Q100.jpg
  9. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio410-Q100.jpg
  10. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio411-Q100.jpg
  11. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio420-Q100.jpg
  12. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio422-Q100.jpg
  13. 3
      tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio444-Q100.jpg

6
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs

@ -41,12 +41,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
for (int i = 0; i < c0.Length; i++) for (int i = 0; i < c0.Length; i++)
{ {
float r = rLane[i];
float g = gLane[i];
float b = bLane[i];
// luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b) // luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b)
float luma = (0.299f * r) + (0.587f * g) + (0.114f * b); float luma = (0.299f * rLane[i]) + (0.587f * gLane[i]) + (0.114f * bLane[i]);
c0[i] = luma; c0[i] = luma;
} }
} }

1
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components namespace SixLabors.ImageSharp.Formats.Jpeg.Components

66
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs

@ -2,8 +2,12 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using Xunit; using Xunit;
@ -13,6 +17,68 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Trait("Format", "Jpg")] [Trait("Format", "Jpg")]
public partial class JpegEncoderTests public partial class JpegEncoderTests
{ {
[Fact]
public void Encode_PreservesIptcProfile()
{
// arrange
using var input = new Image<Rgba32>(1, 1);
input.Metadata.IptcProfile = new IptcProfile();
input.Metadata.IptcProfile.SetValue(IptcTag.Byline, "unit_test");
// act
using var memStream = new MemoryStream();
input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream);
IptcProfile actual = output.Metadata.IptcProfile;
Assert.NotNull(actual);
IEnumerable<IptcValue> values = input.Metadata.IptcProfile.Values;
Assert.Equal(values, actual.Values);
}
[Fact]
public void Encode_PreservesExifProfile()
{
// arrange
using var input = new Image<Rgba32>(1, 1);
input.Metadata.ExifProfile = new ExifProfile();
input.Metadata.ExifProfile.SetValue(ExifTag.Software, "unit_test");
// act
using var memStream = new MemoryStream();
input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream);
ExifProfile actual = output.Metadata.ExifProfile;
Assert.NotNull(actual);
IReadOnlyList<IExifValue> values = input.Metadata.ExifProfile.Values;
Assert.Equal(values, actual.Values);
}
[Fact]
public void Encode_PreservesIccProfile()
{
// arrange
using var input = new Image<Rgba32>(1, 1);
input.Metadata.IccProfile = new IccProfile(IccTestDataProfiles.Profile_Random_Array);
// act
using var memStream = new MemoryStream();
input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream);
IccProfile actual = output.Metadata.IccProfile;
Assert.NotNull(actual);
IccProfile values = input.Metadata.IccProfile;
Assert.Equal(values.Entries, actual.Entries);
}
[Theory] [Theory]
[WithFile(TestImages.Jpeg.Issues.ValidExifArgumentNullExceptionOnEncode, PixelTypes.Rgba32)] [WithFile(TestImages.Jpeg.Issues.ValidExifArgumentNullExceptionOnEncode, PixelTypes.Rgba32)]
public void Encode_WithValidExifProfile_DoesNotThrowException<TPixel>(TestImageProvider<TPixel> provider) public void Encode_WithValidExifProfile_DoesNotThrowException<TPixel>(TestImageProvider<TPixel> provider)

205
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -1,15 +1,11 @@
// 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.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
@ -63,6 +59,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{ TestImages.Jpeg.Baseline.GammaDalaiLamaGray, 72, 72, PixelResolutionUnit.PixelsPerInch } { TestImages.Jpeg.Baseline.GammaDalaiLamaGray, 72, 72, PixelResolutionUnit.PixelsPerInch }
}; };
[Fact]
public void Quality_1_And_100_Are_Not_Identical()
{
var options = new JpegEncoder
{
Quality = 1
};
var testFile = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora);
using (Image<Rgba32> input = testFile.CreateRgba32Image())
using (var memStream0 = new MemoryStream())
using (var memStream1 = new MemoryStream())
{
input.SaveAsJpeg(memStream0, options);
options.Quality = 100;
input.SaveAsJpeg(memStream1, options);
Assert.NotEqual(memStream0.ToArray(), memStream1.ToArray());
}
}
[Theory] [Theory]
[WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegEncodingColor.Luminance)] [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegEncodingColor.Luminance)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegEncodingColor.YCbCrRatio444)] [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegEncodingColor.YCbCrRatio444)]
@ -169,36 +188,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestJpegEncoderCore(provider, colorType, 100, comparer); TestJpegEncoderCore(provider, colorType, 100, comparer);
} }
/// <summary> [Theory]
/// Anton's SUPER-SCIENTIFIC tolerance threshold calculation [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.L8, JpegEncodingColor.Luminance)]
/// </summary> [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, JpegEncodingColor.Rgb)]
private static ImageComparer GetComparer(int quality, JpegEncodingColor? colorType) [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, JpegEncodingColor.Cmyk)]
{ [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)]
float tolerance = 0.015f; // ~1.5% [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio422)]
[WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio420)]
if (quality < 50) [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio411)]
{ [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio410)]
tolerance *= 4.5f; public void EncodeBaseline_WorksWithAllColorTypes<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType)
}
else if (quality < 75 || colorType == JpegEncodingColor.YCbCrRatio420)
{
tolerance *= 2.0f;
if (colorType == JpegEncodingColor.YCbCrRatio420)
{
tolerance *= 2.0f;
}
}
return ImageComparer.Tolerant(tolerance);
}
private static void TestJpegEncoderCore<TPixel>(
TestImageProvider<TPixel> provider,
JpegEncodingColor colorType = JpegEncodingColor.YCbCrRatio420,
int quality = 100,
ImageComparer comparer = null)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// all reference output images are saved with quality=100
const int quality = 100;
using Image<TPixel> image = provider.GetImage(); using Image<TPixel> image = provider.GetImage();
// There is no alpha in Jpeg! // There is no alpha in Jpeg!
@ -211,33 +215,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}; };
string info = $"{colorType}-Q{quality}"; string info = $"{colorType}-Q{quality}";
comparer ??= GetComparer(quality, colorType); ImageComparer comparer = GetComparer(quality, colorType);
// Does DebugSave & load reference CompareToReferenceInput(): // Does DebugSave & load reference CompareToReferenceInput():
image.VerifyEncoder(provider, "jpeg", info, encoder, comparer, referenceImageExtension: "png"); image.VerifyEncoder(provider, "jpeg", info, encoder, comparer, referenceImageExtension: "jpg");
}
[Fact]
public void Quality_1_And_100_Are_Not_Identical()
{
var options = new JpegEncoder
{
Quality = 1
};
var testFile = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora);
using (Image<Rgba32> input = testFile.CreateRgba32Image())
using (var memStream0 = new MemoryStream())
using (var memStream1 = new MemoryStream())
{
input.SaveAsJpeg(memStream0, options);
options.Quality = 100;
input.SaveAsJpeg(memStream1, options);
Assert.NotEqual(memStream0.ToArray(), memStream1.ToArray());
}
} }
[Theory] [Theory]
@ -263,68 +244,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
} }
} }
[Fact]
public void Encode_PreservesIptcProfile()
{
// arrange
using var input = new Image<Rgba32>(1, 1);
input.Metadata.IptcProfile = new IptcProfile();
input.Metadata.IptcProfile.SetValue(IptcTag.Byline, "unit_test");
// act
using var memStream = new MemoryStream();
input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream);
IptcProfile actual = output.Metadata.IptcProfile;
Assert.NotNull(actual);
IEnumerable<IptcValue> values = input.Metadata.IptcProfile.Values;
Assert.Equal(values, actual.Values);
}
[Fact]
public void Encode_PreservesExifProfile()
{
// arrange
using var input = new Image<Rgba32>(1, 1);
input.Metadata.ExifProfile = new ExifProfile();
input.Metadata.ExifProfile.SetValue(ExifTag.Software, "unit_test");
// act
using var memStream = new MemoryStream();
input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream);
ExifProfile actual = output.Metadata.ExifProfile;
Assert.NotNull(actual);
IReadOnlyList<IExifValue> values = input.Metadata.ExifProfile.Values;
Assert.Equal(values, actual.Values);
}
[Fact]
public void Encode_PreservesIccProfile()
{
// arrange
using var input = new Image<Rgba32>(1, 1);
input.Metadata.IccProfile = new IccProfile(IccTestDataProfiles.Profile_Random_Array);
// act
using var memStream = new MemoryStream();
input.Save(memStream, JpegEncoder);
// assert
memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream);
IccProfile actual = output.Metadata.IccProfile;
Assert.NotNull(actual);
IccProfile values = input.Metadata.IccProfile;
Assert.Equal(values.Entries, actual.Entries);
}
[Theory] [Theory]
[InlineData(JpegEncodingColor.YCbCrRatio420)] [InlineData(JpegEncodingColor.YCbCrRatio420)]
[InlineData(JpegEncodingColor.YCbCrRatio444)] [InlineData(JpegEncodingColor.YCbCrRatio444)]
@ -354,5 +273,53 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
await image.SaveAsync(pausedStream, encoder, cts.Token); await image.SaveAsync(pausedStream, encoder, cts.Token);
}); });
} }
/// <summary>
/// Anton's SUPER-SCIENTIFIC tolerance threshold calculation
/// </summary>
private static ImageComparer GetComparer(int quality, JpegEncodingColor? colorType)
{
float tolerance = 0.015f; // ~1.5%
if (quality < 50)
{
tolerance *= 4.5f;
}
else if (quality < 75 || colorType == JpegEncodingColor.YCbCrRatio420)
{
tolerance *= 2.0f;
if (colorType == JpegEncodingColor.YCbCrRatio420)
{
tolerance *= 2.0f;
}
}
return ImageComparer.Tolerant(tolerance);
}
private static void TestJpegEncoderCore<TPixel>(
TestImageProvider<TPixel> provider,
JpegEncodingColor colorType = JpegEncodingColor.YCbCrRatio420,
int quality = 100,
ImageComparer comparer = null)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
// There is no alpha in Jpeg!
image.Mutate(c => c.MakeOpaque());
var encoder = new JpegEncoder
{
Quality = quality,
ColorType = colorType
};
string info = $"{colorType}-Q{quality}";
comparer ??= GetComparer(quality, colorType);
// Does DebugSave & load reference CompareToReferenceInput():
image.VerifyEncoder(provider, "jpeg", info, encoder, comparer, referenceImageExtension: "png");
}
} }
} }

45
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -129,13 +129,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
foreach (PngInterlaceMode interlaceMode in InterlaceMode) foreach (PngInterlaceMode interlaceMode in InterlaceMode)
{ {
TestPngEncoderCore( TestPngEncoderCore(
provider, provider,
pngColorType, pngColorType,
PngFilterMethod.Adaptive, PngFilterMethod.Adaptive,
PngBitDepth.Bit8, PngBitDepth.Bit8,
interlaceMode, interlaceMode,
appendPixelType: true, appendPixelType: true,
appendPngColorType: true); appendPngColorType: true);
} }
} }
@ -204,14 +204,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
foreach (PngInterlaceMode interlaceMode in InterlaceMode) foreach (PngInterlaceMode interlaceMode in InterlaceMode)
{ {
TestPngEncoderCore( TestPngEncoderCore(
provider, provider,
pngColorType, pngColorType,
(PngFilterMethod)filterMethod[0], (PngFilterMethod)filterMethod[0],
pngBitDepth, pngBitDepth,
interlaceMode, interlaceMode,
appendPngColorType: true, appendPngColorType: true,
appendPixelType: true, appendPixelType: true,
appendPngBitDepth: true); appendPngBitDepth: true);
} }
} }
} }
@ -314,13 +314,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
foreach (PngInterlaceMode interlaceMode in InterlaceMode) foreach (PngInterlaceMode interlaceMode in InterlaceMode)
{ {
TestPngEncoderCore( TestPngEncoderCore(
provider, provider,
PngColorType.Palette, PngColorType.Palette,
PngFilterMethod.Adaptive, PngFilterMethod.Adaptive,
PngBitDepth.Bit8, PngBitDepth.Bit8,
interlaceMode, interlaceMode,
paletteSize: paletteSize, paletteSize: paletteSize,
appendPaletteSize: true); appendPaletteSize: true);
} }
} }
@ -615,7 +615,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType);
// Compare to the Magick reference decoder.
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
// We compare using both our decoder and the reference decoder as pixel transformation // We compare using both our decoder and the reference decoder as pixel transformation

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_Cmyk-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:acf150308d03dcf9e538eca4f5b1a4895e217c8e7fe7a3bbb7f94a32bc54c794
size 1600914

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_Luminance-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fe9bcfac7e958c5195000a5c935766690c87a161e2ad87b765c0ba5c4d7a6ce8
size 425003

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_Rgb-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1fc1c157e3170aa13d39a7c8429f70c32c200d84122295b346e5ca7b4808e172
size 757505

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio410-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8be680ee7a03074c8747dbfffa9175d19120d43ada9406b99110370dd3cda228
size 491941

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio411-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b594036290443faedb7ec11ec57ab4727d3ddc68fd09b7ac5a0a121691b499a4
size 542610

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio420-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9df47aa652d31050034e301df65ec327aee9d2ee2ea051a3ef7f4f5915641681
size 561591

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio422-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:06e0b522c1e8bedf5d03f7a0bec00ef474a886def8bbd514c6f4eba6af97880d
size 652375

3
tests/Images/External/ReferenceOutput/JpegEncoderTests/EncodeBaseline_WorksWithAllColorTypes_Rgb24_Calliphora_YCbCrRatio444-Q100.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d9bc290239d1739febabeda84191c6fadb206638c7f1cc13240681a0c6596ecb
size 810044
Loading…
Cancel
Save