Browse Source

OrigJpegDecoder -> GolangJpegDecoder + test cleanup

pull/571/head
Anton Firszov 8 years ago
parent
commit
87da33dab1
  1. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoder.cs
  2. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs
  3. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs
  4. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs
  5. 126
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs
  6. 56
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  7. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs
  8. 10
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

2
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoder.cs → src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoder.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary> /// <summary>
/// Image decoder for generating an image out of a jpg stream. /// Image decoder for generating an image out of a jpg stream.
/// </summary> /// </summary>
internal sealed class OrigJpegDecoder : IImageDecoder, IJpegDecoderOptions, IImageInfoDetector internal sealed class GolangJpegDecoder : IImageDecoder, IJpegDecoderOptions, IImageInfoDetector
{ {
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs

@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using (var memoryStream = new MemoryStream(this.jpegBytes)) using (var memoryStream = new MemoryStream(this.jpegBytes))
{ {
using (var image = Image.Load<Rgba32>(memoryStream, new OrigJpegDecoder())) using (var image = Image.Load<Rgba32>(memoryStream, new GolangJpegDecoder()))
{ {
return new CoreSize(image.Width, image.Height); return new CoreSize(image.Width, image.Height);
} }

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Description = "DecodeJpegMultiple - ImageSharp")] [Benchmark(Description = "DecodeJpegMultiple - ImageSharp")]
public void DecodeJpegImageSharpOrig() public void DecodeJpegImageSharpOrig()
{ {
this.ForEachStream(ms => Image.Load<Rgba32>(ms, new OrigJpegDecoder())); this.ForEachStream(ms => Image.Load<Rgba32>(ms, new GolangJpegDecoder()));
} }
[Benchmark(Description = "DecodeJpegMultiple - ImageSharp PDFJs")] [Benchmark(Description = "DecodeJpegMultiple - ImageSharp PDFJs")]

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs

@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using (var memoryStream = new MemoryStream(this.jpegBytes)) using (var memoryStream = new MemoryStream(this.jpegBytes))
{ {
var decoder = new OrigJpegDecoder(); var decoder = new GolangJpegDecoder();
return decoder.Identify(Configuration.Default, memoryStream); return decoder.Identify(Configuration.Default, memoryStream);
} }

126
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs

@ -11,6 +11,7 @@ using Xunit;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Formats.Jpg namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{ {
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
@ -50,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{ {
TestMetaDataImpl( TestMetaDataImpl(
useIdentify, useIdentify,
OrigJpegDecoder, GolangJpegDecoder,
imagePath, imagePath,
expectedPixelSize, expectedPixelSize,
exifProfilePresent, exifProfilePresent,
@ -75,6 +76,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
iccProfilePresent); iccProfilePresent);
} }
private static void TestImageInfo(string imagePath, IImageDecoder decoder, bool useIdentify, Action<IImageInfo> test)
{
var testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
{
IImageInfo imageInfo = useIdentify
? ((IImageInfoDetector)decoder).Identify(Configuration.Default, stream)
: decoder.Decode<Rgba32>(Configuration.Default, stream);
test(imageInfo);
}
}
private static void TestMetaDataImpl( private static void TestMetaDataImpl(
bool useIdentify, bool useIdentify,
IImageDecoder decoder, IImageDecoder decoder,
@ -83,51 +96,50 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
bool exifProfilePresent, bool exifProfilePresent,
bool iccProfilePresent) bool iccProfilePresent)
{ {
var testFile = TestFile.Create(imagePath); TestImageInfo(
using (var stream = new MemoryStream(testFile.Bytes, false)) imagePath,
{ decoder,
IImageInfo imageInfo = useIdentify useIdentify,
? ((IImageInfoDetector)decoder).Identify(Configuration.Default, stream) imageInfo =>
: decoder.Decode<Rgba32>(Configuration.Default, stream); {
Assert.NotNull(imageInfo);
Assert.NotNull(imageInfo.PixelType);
Assert.NotNull(imageInfo); if (useIdentify)
Assert.NotNull(imageInfo.PixelType); {
Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel);
if (useIdentify) }
{ else
Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel); {
} // When full Image<TPixel> decoding is performed, BitsPerPixel will match TPixel
else int bpp32 = Unsafe.SizeOf<Rgba32>() * 8;
{ Assert.Equal(bpp32, imageInfo.PixelType.BitsPerPixel);
// When full Image<TPixel> decoding is performed, BitsPerPixel will match TPixel }
int bpp32 = Unsafe.SizeOf<Rgba32>() * 8;
Assert.Equal(bpp32, imageInfo.PixelType.BitsPerPixel);
}
ExifProfile exifProfile = imageInfo.MetaData.ExifProfile; ExifProfile exifProfile = imageInfo.MetaData.ExifProfile;
if (exifProfilePresent) if (exifProfilePresent)
{ {
Assert.NotNull(exifProfile); Assert.NotNull(exifProfile);
Assert.NotEmpty(exifProfile.Values); Assert.NotEmpty(exifProfile.Values);
} }
else else
{ {
Assert.Null(exifProfile); Assert.Null(exifProfile);
} }
IccProfile iccProfile = imageInfo.MetaData.IccProfile; IccProfile iccProfile = imageInfo.MetaData.IccProfile;
if (iccProfilePresent) if (iccProfilePresent)
{ {
Assert.NotNull(iccProfile); Assert.NotNull(iccProfile);
Assert.NotEmpty(iccProfile.Entries); Assert.NotEmpty(iccProfile.Entries);
} }
else else
{ {
Assert.Null(iccProfile); Assert.Null(iccProfile);
} }
} });
} }
[Theory] [Theory]
@ -154,5 +166,37 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
} }
} }
} }
[Theory]
[InlineData(false)]
[InlineData(true)]
public void Decoder_Reads_Correct_Resolution_From_Jfif(bool useIdentify)
{
TestImageInfo(TestImages.Jpeg.Baseline.Floorplan, DefaultJpegDecoder, useIdentify,
imageInfo =>
{
Assert.Equal(300, imageInfo.MetaData.HorizontalResolution);
Assert.Equal(300, imageInfo.MetaData.VerticalResolution);
});
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void Decoder_Reads_Correct_Resolution_From_Exif(bool useIdentify)
{
TestImageInfo(TestImages.Jpeg.Baseline.Jpeg420Exif, DefaultJpegDecoder, useIdentify,
imageInfo =>
{
Assert.Equal(72, imageInfo.MetaData.HorizontalResolution);
Assert.Equal(72, imageInfo.MetaData.VerticalResolution);
});
using (Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Jpeg420Exif).CreateImage())
{
Assert.Equal(72, image.MetaData.HorizontalResolution);
Assert.Equal(72, image.MetaData.VerticalResolution);
}
}
} }
} }

56
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -115,10 +115,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private ITestOutputHelper Output { get; } private ITestOutputHelper Output { get; }
private static OrigJpegDecoder OrigJpegDecoder => new OrigJpegDecoder(); private static GolangJpegDecoder GolangJpegDecoder => new GolangJpegDecoder();
private static PdfJsJpegDecoder PdfJsJpegDecoder => new PdfJsJpegDecoder(); private static PdfJsJpegDecoder PdfJsJpegDecoder => new PdfJsJpegDecoder();
private static JpegDecoder DefaultJpegDecoder => new JpegDecoder();
[Fact] [Fact]
public void ParseStream_BasicPropertiesAreCorrect1_PdfJs() public void ParseStream_BasicPropertiesAreCorrect1_PdfJs()
{ {
@ -151,7 +153,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// For 32 bit test enviroments: // For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling(); provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
IImageDecoder decoder = useOldDecoder ? (IImageDecoder)OrigJpegDecoder : PdfJsJpegDecoder; IImageDecoder decoder = useOldDecoder ? (IImageDecoder)GolangJpegDecoder : PdfJsJpegDecoder;
using (Image<TPixel> image = provider.GetImage(decoder)) using (Image<TPixel> image = provider.GetImage(decoder))
{ {
image.DebugSave(provider); image.DebugSave(provider);
@ -176,7 +178,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// For 32 bit test enviroments: // For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling(); provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
using (Image<TPixel> image = provider.GetImage(OrigJpegDecoder)) using (Image<TPixel> image = provider.GetImage(GolangJpegDecoder))
{ {
image.DebugSave(provider); image.DebugSave(provider);
provider.Utility.TestName = DecodeBaselineJpegOutputName; provider.Utility.TestName = DecodeBaselineJpegOutputName;
@ -240,11 +242,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory] [Theory]
[WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)] [WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_Orig<TPixel>(TestImageProvider<TPixel> provider) public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_Golang<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
// TODO: We need a public ImageDecoderException class in ImageSharp! // TODO: We need a public ImageDecoderException class in ImageSharp!
Assert.ThrowsAny<Exception>(() => provider.GetImage(OrigJpegDecoder)); Assert.ThrowsAny<Exception>(() => provider.GetImage(GolangJpegDecoder));
}
[Theory]
[WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
// TODO: We need a public ImageDecoderException class in ImageSharp!
Assert.ThrowsAny<Exception>(() => provider.GetImage(PdfJsJpegDecoder));
} }
public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg"; public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
@ -254,15 +265,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void DecodeProgressiveJpeg_Orig<TPixel>(TestImageProvider<TPixel> provider) public void DecodeProgressiveJpeg_Orig<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (SkipTest(provider)) if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
{ {
// skipping to avoid OutOfMemoryException on CI
return; return;
} }
// For 32 bit test enviroments: // For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling(); provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
using (Image<TPixel> image = provider.GetImage(OrigJpegDecoder)) using (Image<TPixel> image = provider.GetImage(GolangJpegDecoder))
{ {
image.DebugSave(provider); image.DebugSave(provider);
@ -281,7 +293,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void DecodeProgressiveJpeg_PdfJs<TPixel>(TestImageProvider<TPixel> provider) public void DecodeProgressiveJpeg_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess) if (SkipTest(provider))
{ {
// skipping to avoid OutOfMemoryException on CI // skipping to avoid OutOfMemoryException on CI
return; return;
@ -329,7 +341,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.Output.WriteLine(provider.SourceFileOrDescription); this.Output.WriteLine(provider.SourceFileOrDescription);
provider.Utility.TestName = testName; provider.Utility.TestName = testName;
using (Image<TPixel> image = provider.GetImage(OrigJpegDecoder)) using (Image<TPixel> image = provider.GetImage(GolangJpegDecoder))
{ {
string d = this.GetDifferenceInPercentageString(image, provider); string d = this.GetDifferenceInPercentageString(image, provider);
@ -365,7 +377,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 75)] [WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 75)]
[WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)] [WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)]
[WithSolidFilledImages(8, 8, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)] [WithSolidFilledImages(8, 8, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)]
public void DecodeGenerated_Orig<TPixel>( public void DecodeGenerated<TPixel>(
TestImageProvider<TPixel> provider, TestImageProvider<TPixel> provider,
JpegSubsample subsample, JpegSubsample subsample,
int quality) int quality)
@ -383,30 +395,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
} }
} }
var mirror = Image.Load<TPixel>(data, OrigJpegDecoder); var mirror = Image.Load<TPixel>(data, GolangJpegDecoder);
mirror.DebugSave(provider, $"_{subsample}_Q{quality}"); mirror.DebugSave(provider, $"_{subsample}_Q{quality}");
} }
[Fact]
public void Decoder_Reads_Correct_Resolution_From_Jfif()
{
using (Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage())
{
Assert.Equal(300, image.MetaData.HorizontalResolution);
Assert.Equal(300, image.MetaData.VerticalResolution);
}
}
[Fact]
public void Decoder_Reads_Correct_Resolution_From_Exif()
{
using (Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Jpeg420Exif).CreateImage())
{
Assert.Equal(72, image.MetaData.HorizontalResolution);
Assert.Equal(72, image.MetaData.VerticalResolution);
}
}
// DEBUG ONLY! // DEBUG ONLY!
// The PDF.js output should be saved by "tests\ImageSharp.Tests\Formats\Jpg\pdfjs\jpeg-converter.htm" // The PDF.js output should be saved by "tests\ImageSharp.Tests\Formats\Jpg\pdfjs\jpeg-converter.htm"
// into "\tests\Images\ActualOutput\JpegDecoderTests\" // into "\tests\Images\ActualOutput\JpegDecoderTests\"

2
tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs

@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
//[MemberData(nameof(DecodeJpegData))] //[MemberData(nameof(DecodeJpegData))]
public void DecodeJpeg_Original(string fileName) public void DecodeJpeg_Original(string fileName)
{ {
this.DecodeJpegBenchmarkImpl(fileName, new OrigJpegDecoder()); this.DecodeJpegBenchmarkImpl(fileName, new GolangJpegDecoder());
} }
// [Theory] // Benchmark, enable manually // [Theory] // Benchmark, enable manually

10
tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public static readonly string[] AllTestJpegs = BaselineTestJpegs.Concat(ProgressiveTestJpegs).ToArray(); public static readonly string[] AllTestJpegs = BaselineTestJpegs.Concat(ProgressiveTestJpegs).ToArray();
[Theory] [Theory(Skip = "Debug only, enable manually!")]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)] [WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void PdfJsDecoder_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider) public void PdfJsDecoder_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
} }
} }
[Theory] [Theory(Skip = "Debug only, enable manually!")]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)] [WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void OriginalDecoder_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider) public void OriginalDecoder_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
LibJpegTools.SpectralData imageSharpData) LibJpegTools.SpectralData imageSharpData)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription); LibJpegTools.SpectralData libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription);
bool equality = libJpegData.Equals(imageSharpData); bool equality = libJpegData.Equals(imageSharpData);
this.Output.WriteLine("Spectral data equality: " + equality); this.Output.WriteLine("Spectral data equality: " + equality);
@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory] [Theory]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)] [WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void VerifySpectralResults_OriginalDecoder<TPixel>(TestImageProvider<TPixel> provider) public void VerifySpectralCorrectness_Golang<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (!TestEnvironment.IsWindows) if (!TestEnvironment.IsWindows)
@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return; return;
} }
var decoder = new GolangJpegDecoderCore(Configuration.Default, new JpegDecoder()); var decoder = new GolangJpegDecoderCore(Configuration.Default, new GolangJpegDecoder());
byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes; byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes;

Loading…
Cancel
Save