Browse Source

Add tests for arithmetic coding

pull/2073/head
Brian Popow 4 years ago
parent
commit
c988208b4f
  1. 3
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs
  2. 27
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  3. 16
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
  4. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
  5. 12
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
  6. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  7. 1
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
  8. 11
      tests/ImageSharp.Tests/TestImages.cs
  9. 3
      tests/Images/Input/Jpg/baseline/Calliphora-arithmetic-grayscale.jpg
  10. 3
      tests/Images/Input/Jpg/baseline/Calliphora-arithmetic-interleaved.jpg
  11. 3
      tests/Images/Input/Jpg/baseline/Calliphora-arithmetic-restart.jpg
  12. 3
      tests/Images/Input/Jpg/baseline/Calliphora_arithmetic.jpg
  13. 3
      tests/Images/Input/Jpg/progressive/Calliphora-arithmetic-progressive-interleaved.jpg

3
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs

@ -117,8 +117,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
public int Receive(int nbits)
{
this.CheckBits();
int bits = Extend(this.GetBits(nbits), nbits);
return bits;
return Extend(this.GetBits(nbits), nbits);
}
[MethodImpl(InliningOptions.ShortMethod)]

27
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -105,6 +105,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
private List<ArithmeticDecodingTable> arithmeticDecodingTables;
/// <summary>
/// The restart interval.
/// </summary>
private int? resetInterval;
/// <summary>
/// Initializes a new instance of the <see cref="JpegDecoderCore" /> class.
/// </summary>
@ -292,6 +297,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{
bool metadataOnly = spectralConverter == null;
this.scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, cancellationToken);
this.Metadata = new ImageMetadata();
// Check for the Start Of Image marker.
@ -324,7 +331,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
case JpegConstants.Markers.SOF0:
case JpegConstants.Markers.SOF1:
case JpegConstants.Markers.SOF2:
this.scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, cancellationToken);
this.ProcessStartOfFrameMarker(stream, remaining, fileMarker, ComponentType.Huffman, metadataOnly);
break;
@ -333,6 +339,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
case JpegConstants.Markers.SOF13:
case JpegConstants.Markers.SOF14:
this.scanDecoder = new ArithmeticScanDecoder(stream, spectralConverter, cancellationToken);
if (this.resetInterval.HasValue)
{
this.scanDecoder.ResetInterval = this.resetInterval.Value;
}
this.ProcessStartOfFrameMarker(stream, remaining, fileMarker, ComponentType.Arithmetic, metadataOnly);
break;
@ -871,6 +882,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
}
/// <summary>
/// Processes a DAC marker, decoding the arithmetic tables.
/// </summary>
/// <param name="stream">The input stream.</param>
/// <param name="remaining">The remaining bytes in the segment block.</param>
private void ProcessArithmeticTable(BufferedReadStream stream, int remaining)
{
this.arithmeticDecodingTables ??= new List<ArithmeticDecodingTable>(4);
@ -1297,7 +1313,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.DRI), remaining);
}
this.scanDecoder.ResetInterval = this.ReadUint16(stream);
// Save the reset interval, because it can come before or after the SOF marker.
// If the reset interval comes after the SOF marker, the scanDecoder has not been created.
this.resetInterval = this.ReadUint16(stream);
if (this.scanDecoder != null)
{
this.scanDecoder.ResetInterval = this.resetInterval.Value;
}
}
/// <summary>

16
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs

@ -3,7 +3,7 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
// ReSharper disable InconsistentNaming
@ -49,6 +49,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// .Dispose();
}
[Theory]
[WithFile(TestImages.Jpeg.Baseline.ArithmeticCoding01, PixelTypes.Rgb24)]
[WithFile(TestImages.Jpeg.Baseline.ArithmeticCoding02, PixelTypes.Rgb24)]
[WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingGray, PixelTypes.Rgb24)]
[WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingInterleaved, PixelTypes.Rgb24)]
[WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingWithRestart, PixelTypes.Rgb24)]
public void DecodeJpeg_WithArithmeticCoding<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(JpegDecoder);
image.DebugSave(provider);
image.CompareToOriginal(provider, ImageComparer.Tolerant(0.002f), ReferenceDecoder);
}
[Theory]
[WithFileCollection(nameof(UnrecoverableTestJpegs), PixelTypes.Rgba32)]
public void UnrecoverableImage_Throws_InvalidImageContentException<TPixel>(TestImageProvider<TPixel> provider)

4
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs

@ -72,10 +72,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Issues.Fuzz.NullReferenceException823,
TestImages.Jpeg.Issues.MalformedUnsupportedComponentCount,
// Arithmetic coding
TestImages.Jpeg.Baseline.ArithmeticCoding,
TestImages.Jpeg.Baseline.ArithmeticCodingProgressive,
// Lossless jpeg
TestImages.Jpeg.Baseline.Lossless
};

12
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs

@ -4,6 +4,7 @@
using Microsoft.DotNet.RemoteExecutor;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
// ReSharper disable InconsistentNaming
@ -29,6 +30,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
appendPixelTypeToFileName: false);
}
[Theory]
[WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingProgressive01, PixelTypes.Rgb24)]
[WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingProgressive02, PixelTypes.Rgb24)]
public void DecodeProgressiveJpeg_WithArithmeticCoding<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(JpegDecoder);
image.DebugSave(provider);
image.CompareToOriginal(provider, ImageComparer.Tolerant(0.004f), ReferenceDecoder);
}
[Theory]
[WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgb24)]
public void DecodeProgressiveJpeg_WithLimitedAllocatorBufferCapacity(TestImageProvider<Rgb24> provider)

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

@ -13,7 +13,7 @@ using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
using Xunit.Abstractions;
@ -24,6 +24,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Trait("Format", "Jpg")]
public partial class JpegDecoderTests
{
private static MagickReferenceDecoder ReferenceDecoder => new();
public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.Bgr24 | PixelTypes.RgbaVector;
private const float BaselineTolerance = 0.001F / 100;

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

@ -85,7 +85,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// internal scan decoder which we substitute to assert spectral correctness
var debugConverter = new DebugSpectralConverter<TPixel>();
var scanDecoder = new HuffmanScanDecoder(bufferedStream, debugConverter, cancellationToken: default);
// This would parse entire image
decoder.ParseStream(bufferedStream, debugConverter, cancellationToken: default);

11
tests/ImageSharp.Tests/TestImages.cs

@ -214,14 +214,21 @@ namespace SixLabors.ImageSharp.Tests
public const string App13WithEmptyIptc = "Jpg/baseline/iptc-psAPP13-wIPTCempty.jpg";
public const string HistogramEqImage = "Jpg/baseline/640px-Unequalized_Hawkes_Bay_NZ.jpg";
public const string ForestBridgeDifferentComponentsQuality = "Jpg/baseline/forest_bridge.jpg";
public const string ArithmeticCoding = "Jpg/baseline/arithmetic_coding.jpg";
public const string ArithmeticCodingProgressive = "Jpg/progressive/arithmetic_progressive.jpg";
public const string Lossless = "Jpg/baseline/lossless.jpg";
public const string Winter444_Interleaved = "Jpg/baseline/winter444_interleaved.jpg";
public const string Metadata = "Jpg/baseline/Metadata-test-file.jpg";
public const string ExtendedXmp = "Jpg/baseline/extended-xmp.jpg";
public const string GrayscaleSampling2x2 = "Jpg/baseline/grayscale_sampling22.jpg";
// Jpeg's with arithmetic coding.
public const string ArithmeticCoding01 = "Jpg/baseline/Calliphora_arithmetic.jpg";
public const string ArithmeticCoding02 = "Jpg/baseline/arithmetic_coding.jpg";
public const string ArithmeticCodingProgressive01 = "Jpg/progressive/arithmetic_progressive.jpg";
public const string ArithmeticCodingProgressive02 = "Jpg/progressive/Calliphora-arithmetic-progressive-interleaved.jpg";
public const string ArithmeticCodingGray = "Jpg/baseline/Calliphora-arithmetic-grayscale.jpg";
public const string ArithmeticCodingInterleaved = "Jpg/baseline/Calliphora-arithmetic-interleaved.jpg";
public const string ArithmeticCodingWithRestart = "Jpg/baseline/Calliphora-arithmetic-restart.jpg";
public static readonly string[] All =
{
Cmyk, Ycck, Exif, Floorplan,

3
tests/Images/Input/Jpg/baseline/Calliphora-arithmetic-grayscale.jpg

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

3
tests/Images/Input/Jpg/baseline/Calliphora-arithmetic-interleaved.jpg

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

3
tests/Images/Input/Jpg/baseline/Calliphora-arithmetic-restart.jpg

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

3
tests/Images/Input/Jpg/baseline/Calliphora_arithmetic.jpg

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

3
tests/Images/Input/Jpg/progressive/Calliphora-arithmetic-progressive-interleaved.jpg

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