Browse Source

Merge pull request #571 from SixLabors/js/swap-jpeg-decoders

Swap jpeg decoders
pull/579/head
James Jackson-South 8 years ago
committed by GitHub
parent
commit
d566c27f4b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
  2. 3
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
  3. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
  4. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
  5. 10
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
  6. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
  7. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs
  8. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
  9. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs
  10. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
  11. 7
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
  12. 7
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
  13. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs
  14. 7
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
  15. 5
      src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
  16. 7
      src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
  17. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
  18. 3
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
  19. 5
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs
  20. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
  21. 18
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
  22. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
  23. 8
      src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs
  24. 2
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs
  25. 2
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs
  26. 2
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs
  27. 2
      src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs
  28. 12
      src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs
  29. 4
      src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs
  30. 2
      src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
  31. 5
      src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs
  32. 5
      src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt
  33. 9
      src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
  34. 3
      src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs
  35. 3
      src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
  36. 36
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bits.cs
  37. 62
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs
  38. 28
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/DecoderThrowHelper.cs
  39. 21
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs
  40. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponentScan.cs
  41. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangDecoderErrorCode.cs
  42. 12
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangHuffmanTree.cs
  43. 11
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs
  44. 8
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.DataPointers.cs
  45. 67
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.cs
  46. 80
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs
  47. 6
      src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoder.cs
  48. 81
      src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs
  49. 189
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegConstants.cs
  50. 69
      src/ImageSharp/Formats/Jpeg/JpegConstants.cs
  51. 6
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  52. 1
      src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
  53. 74
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  54. 5
      src/ImageSharp/Formats/Jpeg/JpegFormat.cs
  55. 9
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
  56. 13
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
  57. 149
      src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
  58. 11
      src/ImageSharp/ImageSharp.csproj
  59. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs
  60. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs
  61. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs
  62. 12
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
  63. 17
      tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
  64. 4
      tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs
  65. 3
      tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs
  66. 28
      tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs
  67. 2
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs
  68. 2
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
  69. 2
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
  70. 4
      tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
  71. 2
      tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs
  72. 28
      tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs
  73. 18
      tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
  74. 89
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
  75. 72
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
  76. 120
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs
  77. 81
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
  78. 266
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  79. 25
      tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
  80. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs
  81. 139
      tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs
  82. 2
      tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
  83. 5
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs
  84. 16
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
  85. 2
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
  86. 12
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
  87. 28
      tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs
  88. 6
      tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs
  89. 9
      tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs
  90. 8
      tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs
  91. 2
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
  92. 4
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs
  93. 4
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs
  94. 2
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs
  95. 2
      tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs
  96. 5
      tests/ImageSharp.Tests/Image/ImageCloneTests.cs
  97. 5
      tests/ImageSharp.Tests/TestImages.cs
  98. 2
      tests/Images/External
  99. BIN
      tests/Images/Input/Jpg/issues/Issue159-MissingFF00-Progressive-Bedroom.jpg
  100. 0
      tests/Images/Input/Jpg/issues/Issue517-No-EOI-Progressive.jpg

2
src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs → src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs

@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
/// <summary> /// <summary>
/// Represents a Jpeg block with <see cref="short"/> coefficiens. /// Represents a Jpeg block with <see cref="short"/> coefficiens.

3
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs → src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs

@ -3,10 +3,11 @@
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
internal partial struct Block8x8F internal partial struct Block8x8F
{ {

2
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs → src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs

@ -5,7 +5,7 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
// <auto-generated /> // <auto-generated />
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
internal partial struct Block8x8F internal partial struct Block8x8F
{ {

2
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt → src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt

@ -18,7 +18,7 @@ using System.Runtime.CompilerServices;
<# <#
char[] coordz = {'X', 'Y', 'Z', 'W'}; char[] coordz = {'X', 'Y', 'Z', 'W'};
#> #>
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
internal partial struct Block8x8F internal partial struct Block8x8F
{ {

10
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs → src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs

@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
using System.Text; using System.Text;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
/// <summary> /// <summary>
/// Represents a Jpeg block with <see cref="float"/> coefficients. /// Represents a Jpeg block with <see cref="float"/> coefficients.
@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{ {
float val = result[i]; float val = result[i];
val /= value; val /= value;
result[i] = (float)val; result[i] = val;
} }
return result; return result;
@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{ {
float val = result[i]; float val = result[i];
val += value; val += value;
result[i] = (float)val; result[i] = val;
} }
return result; return result;
@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{ {
float val = result[i]; float val = result[i];
val -= value; val -= value;
result[i] = (float)val; result[i] = val;
} }
return result; return result;
@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
public void Clear() public void Clear()
{ {
// The cheapest way to do this in C#: // The cheapest way to do this in C#:
this = default(Block8x8F); this = default;
} }
/// <summary> /// <summary>

4
src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs

@ -4,7 +4,7 @@
using System; using System;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Provides information about the Adobe marker segment. /// Provides information about the Adobe marker segment.
@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
return true; return true;
} }
marker = default(AdobeMarker); marker = default;
return false; return false;
} }

6
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs

@ -4,18 +4,18 @@
using System; using System;
using System.Numerics; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
internal class FromCmyk : ColorConverters.JpegColorConverter internal class FromCmyk : JpegColorConverter
{ {
public FromCmyk() public FromCmyk()
: base(JpegColorSpace.Cmyk) : base(JpegColorSpace.Cmyk)
{ {
} }
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRgba(ComponentValues values, Span<Vector4> result)
{ {
// TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()! // TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()!
ReadOnlySpan<float> cVals = values.Component0; ReadOnlySpan<float> cVals = values.Component0;

6
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs

@ -4,18 +4,18 @@
using System; using System;
using System.Numerics; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
internal class FromGrayscale : ColorConverters.JpegColorConverter internal class FromGrayscale : JpegColorConverter
{ {
public FromGrayscale() public FromGrayscale()
: base(JpegColorSpace.Grayscale) : base(JpegColorSpace.Grayscale)
{ {
} }
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRgba(ComponentValues values, Span<Vector4> result)
{ {
// TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()! // TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()!
ReadOnlySpan<float> yVals = values.Component0; ReadOnlySpan<float> yVals = values.Component0;

6
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs

@ -4,18 +4,18 @@
using System; using System;
using System.Numerics; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
internal class FromRgb : ColorConverters.JpegColorConverter internal class FromRgb : JpegColorConverter
{ {
public FromRgb() public FromRgb()
: base(JpegColorSpace.RGB) : base(JpegColorSpace.RGB)
{ {
} }
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRgba(ComponentValues values, Span<Vector4> result)
{ {
// TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()! // TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()!
ReadOnlySpan<float> rVals = values.Component0; ReadOnlySpan<float> rVals = values.Component0;

6
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs

@ -4,18 +4,18 @@
using System; using System;
using System.Numerics; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
internal class FromYCbCrBasic : ColorConverters.JpegColorConverter internal class FromYCbCrBasic : JpegColorConverter
{ {
public FromYCbCrBasic() public FromYCbCrBasic()
: base(JpegColorSpace.YCbCr) : base(JpegColorSpace.YCbCr)
{ {
} }
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRgba(ComponentValues values, Span<Vector4> result)
{ {
ConvertCore(values, result); ConvertCore(values, result);
} }

7
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs

@ -5,20 +5,21 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Common.Tuples;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
internal class FromYCbCrSimd : ColorConverters.JpegColorConverter internal class FromYCbCrSimd : JpegColorConverter
{ {
public FromYCbCrSimd() public FromYCbCrSimd()
: base(JpegColorSpace.YCbCr) : base(JpegColorSpace.YCbCr)
{ {
} }
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRgba(ComponentValues values, Span<Vector4> result)
{ {
int remainder = result.Length % 8; int remainder = result.Length % 8;
int simdCount = result.Length - remainder; int simdCount = result.Length - remainder;

7
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs

@ -5,14 +5,15 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Common.Tuples;
// ReSharper disable ImpureMethodCallOnReadonlyValueField // ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
internal class FromYCbCrSimdAvx2 : ColorConverters.JpegColorConverter internal class FromYCbCrSimdAvx2 : JpegColorConverter
{ {
public FromYCbCrSimdAvx2() public FromYCbCrSimdAvx2()
: base(JpegColorSpace.YCbCr) : base(JpegColorSpace.YCbCr)
@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.IsAvx2CompatibleArchitecture; public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.IsAvx2CompatibleArchitecture;
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRgba(ComponentValues values, Span<Vector4> result)
{ {
int remainder = result.Length % 8; int remainder = result.Length % 8;
int simdCount = result.Length - remainder; int simdCount = result.Length - remainder;

4
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Numerics; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
{ {
} }
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRgba(ComponentValues values, Span<Vector4> result)
{ {
// TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()! // TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()!
ReadOnlySpan<float> yVals = values.Component0; ReadOnlySpan<float> yVals = values.Component0;

7
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs

@ -5,10 +5,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
/// <summary> /// <summary>
/// Encapsulates the conversion of Jpeg channels to RGBA values packed in <see cref="Vector4"/> buffer. /// Encapsulates the conversion of Jpeg channels to RGBA values packed in <see cref="Vector4"/> buffer.
@ -55,13 +56,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
/// </summary> /// </summary>
/// <param name="values">The input as a stack-only <see cref="ComponentValues"/> struct</param> /// <param name="values">The input as a stack-only <see cref="ComponentValues"/> struct</param>
/// <param name="result">The destination buffer of <see cref="Vector4"/> values</param> /// <param name="result">The destination buffer of <see cref="Vector4"/> values</param>
public abstract void ConvertToRGBA(ComponentValues values, Span<Vector4> result); public abstract void ConvertToRgba(ComponentValues values, Span<Vector4> result);
/// <summary> /// <summary>
/// Returns the <see cref="JpegColorConverter"/> for the YCbCr colorspace that matches the current CPU architecture. /// Returns the <see cref="JpegColorConverter"/> for the YCbCr colorspace that matches the current CPU architecture.
/// </summary> /// </summary>
private static JpegColorConverter GetYCbCrConverter() => private static JpegColorConverter GetYCbCrConverter() =>
FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdAvx2() : new FromYCbCrSimd(); JpegColorConverter.FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimdAvx2() : new JpegColorConverter.FromYCbCrSimd();
/// <summary> /// <summary>
/// A stack-only struct to reference the input buffers using <see cref="ReadOnlySpan{T}"/>-s. /// A stack-only struct to reference the input buffers using <see cref="ReadOnlySpan{T}"/>-s.

5
src/ImageSharp/Formats/Jpeg/Common/Decoder/IJpegComponent.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs

@ -1,7 +1,10 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Common interface to represent raw Jpeg components. /// Common interface to represent raw Jpeg components.

7
src/ImageSharp/Formats/Jpeg/Common/Decoder/IRawJpegData.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs

@ -1,13 +1,16 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <inheritdoc /> /// <inheritdoc />
/// <summary> /// <summary>
/// Represents decompressed, unprocessed jpeg data with spectral space <see cref="T:SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.IJpegComponent" />-s. /// Represents decompressed, unprocessed jpeg data with spectral space <see cref="IJpegComponent" />-s.
/// </summary> /// </summary>
internal interface IRawJpegData : IDisposable internal interface IRawJpegData : IDisposable
{ {

2
src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs

@ -3,7 +3,7 @@
using System; using System;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Provides information about the JFIF marker segment /// Provides information about the JFIF marker segment

3
src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs

@ -2,10 +2,11 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Encapsulates the implementation of processing "raw" <see cref="IBuffer{T}"/>-s into Jpeg image channels. /// Encapsulates the implementation of processing "raw" <see cref="IBuffer{T}"/>-s into Jpeg image channels.

5
src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorSpace.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs

@ -1,4 +1,7 @@
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Identifies the colorspace of a Jpeg image /// Identifies the colorspace of a Jpeg image

6
src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs

@ -1,8 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System; using System;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Encapsulates postprocessing data for one component for <see cref="JpegImagePostProcessor"/>. /// Encapsulates postprocessing data for one component for <see cref="JpegImagePostProcessor"/>.

18
src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs

@ -1,12 +1,18 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Encapsulates the execution od post-processing algorithms to be applied on a <see cref="IRawJpegData"/> to produce a valid <see cref="Image{TPixel}"/>: <br/> /// Encapsulates the execution od post-processing algorithms to be applied on a <see cref="IRawJpegData"/> to produce a valid <see cref="Image{TPixel}"/>: <br/>
@ -36,9 +42,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
private readonly IBuffer<Vector4> rgbaBuffer; private readonly IBuffer<Vector4> rgbaBuffer;
/// <summary> /// <summary>
/// The <see cref="ColorConverters.JpegColorConverter"/> corresponding to the current <see cref="JpegColorSpace"/> determined by <see cref="IRawJpegData.ColorSpace"/>. /// The <see cref="JpegColorConverter"/> corresponding to the current <see cref="JpegColorSpace"/> determined by <see cref="IRawJpegData.ColorSpace"/>.
/// </summary> /// </summary>
private ColorConverters.JpegColorConverter colorConverter; private readonly JpegColorConverter colorConverter;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JpegImagePostProcessor"/> class. /// Initializes a new instance of the <see cref="JpegImagePostProcessor"/> class.
@ -54,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryManager, this, c)).ToArray(); this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryManager, this, c)).ToArray();
this.rgbaBuffer = memoryManager.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width); this.rgbaBuffer = memoryManager.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width);
this.colorConverter = ColorConverters.JpegColorConverter.GetConverter(rawJpeg.ColorSpace); this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
} }
/// <summary> /// <summary>
@ -148,8 +154,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
{ {
int y = yy - this.PixelRowCounter; int y = yy - this.PixelRowCounter;
var values = new ColorConverters.JpegColorConverter.ComponentValues(buffers, y); var values = new JpegColorConverter.ComponentValues(buffers, y);
this.colorConverter.ConvertToRGBA(values, this.rgbaBuffer.Span); this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.Span);
Span<TPixel> destRow = destination.GetPixelRowSpan(yy); Span<TPixel> destRow = destination.GetPixelRowSpan(yy);

2
src/ImageSharp/Formats/Jpeg/Common/Decoder/ProfileResolver.cs → src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Text; using System.Text;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
/// <summary> /// <summary>
/// Provides methods for identifying metadata and color profiles within jpeg images. /// Provides methods for identifying metadata and color profiles within jpeg images.

8
src/ImageSharp/Formats/Jpeg/GolangPort/Components/BlockQuad.cs → src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs

@ -1,18 +1,16 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components
{ {
/// <summary> /// <summary>
/// Poor man's stackalloc: Contains a value-type <see cref="float"/> buffer sized for 4 <see cref="Common.Block8x8F"/> instances. /// Poor man's stackalloc: Contains a value-type <see cref="float"/> buffer sized for 4 <see cref="Block8x8F"/> instances.
/// Useful for decoder/encoder operations allocating a block for each Jpeg component. /// Useful for decoder/encoder operations allocating a block for each Jpeg component.
/// </summary> /// </summary>
internal unsafe struct BlockQuad internal unsafe struct BlockQuad
{ {
/// <summary> /// <summary>
/// The value-type <see cref="float"/> buffer sized for 4 <see cref="Common.Block8x8F"/> instances. /// The value-type <see cref="float"/> buffer sized for 4 <see cref="Block8x8F"/> instances.
/// </summary> /// </summary>
public fixed float Data[4 * Block8x8F.Size]; public fixed float Data[4 * Block8x8F.Size];
} }

2
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffIndex.cs → src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{ {
/// <summary> /// <summary>
/// Enumerates the Huffman tables /// Enumerates the Huffman tables

2
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanLut.cs → src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{ {
/// <summary> /// <summary>
/// A compiled look-up table representation of a huffmanSpec. /// A compiled look-up table representation of a huffmanSpec.

2
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanSpec.cs → src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{ {
/// <summary> /// <summary>
/// The Huffman encoding specifications. /// The Huffman encoding specifications.

2
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/QuantIndex.cs → src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{ {
/// <summary> /// <summary>
/// Enumerates the quantization tables /// Enumerates the quantization tables

12
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/RgbToYCbCrTables.cs → src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs

@ -3,9 +3,7 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
{ {
/// <summary> /// <summary>
/// Provides 8-bit lookup tables for converting from Rgb to YCbCr colorspace. /// Provides 8-bit lookup tables for converting from Rgb to YCbCr colorspace.
@ -68,7 +66,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
/// <returns>The intialized <see cref="RgbToYCbCrTables"/></returns> /// <returns>The intialized <see cref="RgbToYCbCrTables"/></returns>
public static RgbToYCbCrTables Create() public static RgbToYCbCrTables Create()
{ {
RgbToYCbCrTables tables = default(RgbToYCbCrTables); RgbToYCbCrTables tables = default;
for (int i = 0; i <= 255; i++) for (int i = 0; i <= 255; i++)
{ {
@ -123,11 +121,5 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
{ {
return (int)((x * (1L << ScaleBits)) + 0.5F); return (int)((x * (1L << ScaleBits)) + 0.5F);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int RightShift(int x)
{
return x >> ScaleBits;
}
} }
} }

4
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/YCbCrForwardConverter{TPixel}.cs → src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs

@ -1,10 +1,10 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{ {
/// <summary> /// <summary>
/// On-stack worker struct to efficiently encapsulate the TPixel -> Rgb24 -> YCbCr conversion chain of 8x8 pixel blocks. /// On-stack worker struct to efficiently encapsulate the TPixel -> Rgb24 -> YCbCr conversion chain of 8x8 pixel blocks.

2
src/ImageSharp/Formats/Jpeg/Common/FastFloatingPointDCT.cs → src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs

@ -5,7 +5,7 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
/// <summary> /// <summary>
/// Contains inaccurate, but fast forward and inverse DCT implementations. /// Contains inaccurate, but fast forward and inverse DCT implementations.

5
src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.cs → src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs

@ -1,11 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
// <auto-generated /> // <auto-generated />
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
internal unsafe partial struct GenericBlock8x8<T> internal unsafe partial struct GenericBlock8x8<T>
{ {

5
src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.tt → src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt

@ -11,11 +11,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
// <auto-generated /> // <auto-generated />
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
internal unsafe partial struct GenericBlock8x8<T> internal unsafe partial struct GenericBlock8x8<T>
{ {

9
src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.cs → src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs

@ -1,13 +1,16 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
/// <summary> /// <summary>
/// A generic 8x8 block implementation, useful for manipulating custom 8x8 pixel data. /// A generic 8x8 block implementation, useful for manipulating custom 8x8 pixel data.
@ -18,8 +21,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{ {
public const int Size = 64; public const int Size = 64;
public const int SizeInBytes = Size * 3;
/// <summary> /// <summary>
/// FOR TESTING ONLY! /// FOR TESTING ONLY!
/// Gets or sets a <see cref="Rgb24"/> value at the given index /// Gets or sets a <see cref="Rgb24"/> value at the given index

3
src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs → src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs

@ -3,9 +3,10 @@
using System; using System;
using System.Numerics; using System.Numerics;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
/// <summary> /// <summary>
/// Extension methods for <see cref="Size"/> /// Extension methods for <see cref="Size"/>

3
src/ImageSharp/Formats/Jpeg/Common/ZigZag.cs → src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs

@ -1,10 +1,11 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
/// <summary> /// <summary>
/// Holds the Jpeg UnZig array in a value/stack type. /// Holds the Jpeg UnZig array in a value/stack type.

36
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bits.cs

@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnsureNBits(int n, ref InputProcessor inputProcessor) public void EnsureNBits(int n, ref InputProcessor inputProcessor)
{ {
OrigDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor); GolangDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor);
errorCode.EnsureNoError(); errorCode.EnsureNoError();
} }
@ -46,17 +46,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at /// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at
/// least n. For best performance (avoiding function calls inside hot loops), /// least n. For best performance (avoiding function calls inside hot loops),
/// the caller is the one responsible for first checking that bits.UnreadBits &lt; n. /// the caller is the one responsible for first checking that bits.UnreadBits &lt; n.
/// This method does not throw. Returns <see cref="OrigDecoderErrorCode"/> instead. /// This method does not throw. Returns <see cref="GolangDecoderErrorCode"/> instead.
/// </summary> /// </summary>
/// <param name="n">The number of bits to ensure.</param> /// <param name="n">The number of bits to ensure.</param>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param> /// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <returns>Error code</returns> /// <returns>Error code</returns>
public OrigDecoderErrorCode EnsureNBitsUnsafe(int n, ref InputProcessor inputProcessor) public GolangDecoderErrorCode EnsureNBitsUnsafe(int n, ref InputProcessor inputProcessor)
{ {
while (true) while (true)
{ {
OrigDecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref inputProcessor); GolangDecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref inputProcessor);
if (errorCode != OrigDecoderErrorCode.NoError || this.UnreadBits >= n) if (errorCode != GolangDecoderErrorCode.NoError || this.UnreadBits >= n)
{ {
return errorCode; return errorCode;
} }
@ -67,8 +67,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==8 /// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==8
/// </summary> /// </summary>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param> /// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <returns>A <see cref="OrigDecoderErrorCode"/></returns> /// <returns>A <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode Ensure8BitsUnsafe(ref InputProcessor inputProcessor) public GolangDecoderErrorCode Ensure8BitsUnsafe(ref InputProcessor inputProcessor)
{ {
return this.EnsureBitsStepImpl(ref inputProcessor); return this.EnsureBitsStepImpl(ref inputProcessor);
} }
@ -77,8 +77,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==1 /// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==1
/// </summary> /// </summary>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param> /// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <returns>A <see cref="OrigDecoderErrorCode"/></returns> /// <returns>A <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode Ensure1BitUnsafe(ref InputProcessor inputProcessor) public GolangDecoderErrorCode Ensure1BitUnsafe(ref InputProcessor inputProcessor)
{ {
return this.EnsureBitsStepImpl(ref inputProcessor); return this.EnsureBitsStepImpl(ref inputProcessor);
} }
@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReceiveExtend(int t, ref InputProcessor inputProcessor) public int ReceiveExtend(int t, ref InputProcessor inputProcessor)
{ {
OrigDecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, ref inputProcessor, out int x); GolangDecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, ref inputProcessor, out int x);
errorCode.EnsureNoError(); errorCode.EnsureNoError();
return x; return x;
} }
@ -103,13 +103,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="t">Byte</param> /// <param name="t">Byte</param>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param> /// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <param name="x">Read bits value</param> /// <param name="x">Read bits value</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, ref InputProcessor inputProcessor, out int x) public GolangDecoderErrorCode ReceiveExtendUnsafe(int t, ref InputProcessor inputProcessor, out int x)
{ {
if (this.UnreadBits < t) if (this.UnreadBits < t)
{ {
OrigDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref inputProcessor); GolangDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref inputProcessor);
if (errorCode != OrigDecoderErrorCode.NoError) if (errorCode != GolangDecoderErrorCode.NoError)
{ {
x = int.MaxValue; x = int.MaxValue;
return errorCode; return errorCode;
@ -126,14 +126,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
x += ((-1) << t) + 1; x += ((-1) << t) + 1;
} }
return OrigDecoderErrorCode.NoError; return GolangDecoderErrorCode.NoError;
} }
private OrigDecoderErrorCode EnsureBitsStepImpl(ref InputProcessor inputProcessor) private GolangDecoderErrorCode EnsureBitsStepImpl(ref InputProcessor inputProcessor)
{ {
OrigDecoderErrorCode errorCode = inputProcessor.Bytes.ReadByteStuffedByteUnsafe(inputProcessor.InputStream, out int c); GolangDecoderErrorCode errorCode = inputProcessor.Bytes.ReadByteStuffedByteUnsafe(inputProcessor.InputStream, out int c);
if (errorCode != OrigDecoderErrorCode.NoError) if (errorCode != GolangDecoderErrorCode.NoError)
{ {
return errorCode; return errorCode;
} }

62
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs

@ -77,8 +77,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
/// <param name="inputStream">Input stream</param> /// <param name="inputStream">Input stream</param>
/// <param name="x">The result byte as <see cref="int"/></param> /// <param name="x">The result byte as <see cref="int"/></param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out int x) public GolangDecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out int x)
{ {
// Take the fast path if bytes.buf contains at least two bytes. // Take the fast path if bytes.buf contains at least two bytes.
if (this.I + 2 <= this.J) if (this.I + 2 <= this.J)
@ -86,50 +86,50 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
x = this.BufferAsInt[this.I]; x = this.BufferAsInt[this.I];
this.I++; this.I++;
this.UnreadableBytes = 1; this.UnreadableBytes = 1;
if (x != OrigJpegConstants.Markers.XFFInt) if (x != JpegConstants.Markers.XFFInt)
{ {
return OrigDecoderErrorCode.NoError; return GolangDecoderErrorCode.NoError;
} }
if (this.BufferAsInt[this.I] != 0x00) if (this.BufferAsInt[this.I] != 0x00)
{ {
return OrigDecoderErrorCode.MissingFF00; return GolangDecoderErrorCode.MissingFF00;
} }
this.I++; this.I++;
this.UnreadableBytes = 2; this.UnreadableBytes = 2;
x = OrigJpegConstants.Markers.XFF; x = JpegConstants.Markers.XFF;
return OrigDecoderErrorCode.NoError; return GolangDecoderErrorCode.NoError;
} }
this.UnreadableBytes = 0; this.UnreadableBytes = 0;
OrigDecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x); GolangDecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 1; this.UnreadableBytes = 1;
if (errorCode != OrigDecoderErrorCode.NoError) if (errorCode != GolangDecoderErrorCode.NoError)
{ {
return errorCode; return errorCode;
} }
if (x != OrigJpegConstants.Markers.XFF) if (x != JpegConstants.Markers.XFF)
{ {
return OrigDecoderErrorCode.NoError; return GolangDecoderErrorCode.NoError;
} }
errorCode = this.ReadByteAsIntUnsafe(inputStream, out x); errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 2; this.UnreadableBytes = 2;
if (errorCode != OrigDecoderErrorCode.NoError) if (errorCode != GolangDecoderErrorCode.NoError)
{ {
return errorCode; return errorCode;
} }
if (x != 0x00) if (x != 0x00)
{ {
return OrigDecoderErrorCode.MissingFF00; return GolangDecoderErrorCode.MissingFF00;
} }
x = OrigJpegConstants.Markers.XFF; x = JpegConstants.Markers.XFF;
return OrigDecoderErrorCode.NoError; return GolangDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -140,25 +140,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte ReadByte(Stream inputStream) public byte ReadByte(Stream inputStream)
{ {
OrigDecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out byte result); GolangDecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out byte result);
errorCode.EnsureNoError(); errorCode.EnsureNoError();
return result; return result;
} }
/// <summary> /// <summary>
/// Extracts the next byte, whether buffered or not buffered into the result out parameter. It does not care about byte stuffing. /// Extracts the next byte, whether buffered or not buffered into the result out parameter. It does not care about byte stuffing.
/// This method does not throw on format error, it returns a <see cref="OrigDecoderErrorCode"/> instead. /// This method does not throw on format error, it returns a <see cref="GolangDecoderErrorCode"/> instead.
/// </summary> /// </summary>
/// <param name="inputStream">Input stream</param> /// <param name="inputStream">Input stream</param>
/// <param name="result">The result <see cref="byte"/> as out parameter</param> /// <param name="result">The result <see cref="byte"/> as out parameter</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReadByteUnsafe(Stream inputStream, out byte result) public GolangDecoderErrorCode ReadByteUnsafe(Stream inputStream, out byte result)
{ {
OrigDecoderErrorCode errorCode = OrigDecoderErrorCode.NoError; GolangDecoderErrorCode errorCode = GolangDecoderErrorCode.NoError;
while (this.I == this.J) while (this.I == this.J)
{ {
errorCode = this.FillUnsafe(inputStream); errorCode = this.FillUnsafe(inputStream);
if (errorCode != OrigDecoderErrorCode.NoError) if (errorCode != GolangDecoderErrorCode.NoError)
{ {
result = 0; result = 0;
return errorCode; return errorCode;
@ -176,15 +176,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
/// <param name="inputStream">The input stream</param> /// <param name="inputStream">The input stream</param>
/// <param name="result">The result <see cref="int"/></param> /// <param name="result">The result <see cref="int"/></param>
/// <returns>A <see cref="OrigDecoderErrorCode"/></returns> /// <returns>A <see cref="GolangDecoderErrorCode"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public OrigDecoderErrorCode ReadByteAsIntUnsafe(Stream inputStream, out int result) public GolangDecoderErrorCode ReadByteAsIntUnsafe(Stream inputStream, out int result)
{ {
OrigDecoderErrorCode errorCode = OrigDecoderErrorCode.NoError; GolangDecoderErrorCode errorCode = GolangDecoderErrorCode.NoError;
while (this.I == this.J) while (this.I == this.J)
{ {
errorCode = this.FillUnsafe(inputStream); errorCode = this.FillUnsafe(inputStream);
if (errorCode != OrigDecoderErrorCode.NoError) if (errorCode != GolangDecoderErrorCode.NoError)
{ {
result = 0; result = 0;
return errorCode; return errorCode;
@ -206,18 +206,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Fill(Stream inputStream) public void Fill(Stream inputStream)
{ {
OrigDecoderErrorCode errorCode = this.FillUnsafe(inputStream); GolangDecoderErrorCode errorCode = this.FillUnsafe(inputStream);
errorCode.EnsureNoError(); errorCode.EnsureNoError();
} }
/// <summary> /// <summary>
/// Fills up the bytes buffer from the underlying stream. /// Fills up the bytes buffer from the underlying stream.
/// It should only be called when there are no unread bytes in bytes. /// It should only be called when there are no unread bytes in bytes.
/// This method does not throw <see cref="EOFException"/>, returns a <see cref="OrigDecoderErrorCode"/> instead! /// This method does not throw <see cref="EOFException"/>, returns a <see cref="GolangDecoderErrorCode"/> instead!
/// </summary> /// </summary>
/// <param name="inputStream">Input stream</param> /// <param name="inputStream">Input stream</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode FillUnsafe(Stream inputStream) public GolangDecoderErrorCode FillUnsafe(Stream inputStream)
{ {
if (this.I != this.J) if (this.I != this.J)
{ {
@ -239,7 +239,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
int n = inputStream.Read(this.Buffer, this.J, this.Buffer.Length - this.J); int n = inputStream.Read(this.Buffer, this.J, this.Buffer.Length - this.J);
if (n == 0) if (n == 0)
{ {
return OrigDecoderErrorCode.UnexpectedEndOfStream; return GolangDecoderErrorCode.UnexpectedEndOfStream;
} }
this.J += n; this.J += n;
@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.BufferAsInt[i] = this.Buffer[i]; this.BufferAsInt[i] = this.Buffer[i];
} }
return OrigDecoderErrorCode.NoError; return GolangDecoderErrorCode.NoError;
} }
} }
} }

28
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/DecoderThrowHelper.cs

@ -12,22 +12,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
internal static class DecoderThrowHelper internal static class DecoderThrowHelper
{ {
/// <summary> /// <summary>
/// Throws an exception that belongs to the given <see cref="OrigDecoderErrorCode"/> /// Throws an exception that belongs to the given <see cref="GolangDecoderErrorCode"/>
/// </summary> /// </summary>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param> /// <param name="errorCode">The <see cref="GolangDecoderErrorCode"/></param>
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowExceptionForErrorCode(this OrigDecoderErrorCode errorCode) public static void ThrowExceptionForErrorCode(this GolangDecoderErrorCode errorCode)
{ {
// REMARK: If this method throws for an image that is expected to be decodable, // REMARK: If this method throws for an image that is expected to be decodable,
// consider using the ***Unsafe variant of the parsing method that asks for ThrowExceptionForErrorCode() // consider using the ***Unsafe variant of the parsing method that asks for ThrowExceptionForErrorCode()
// then verify the error code + implement fallback logic manually! // then verify the error code + implement fallback logic manually!
switch (errorCode) switch (errorCode)
{ {
case OrigDecoderErrorCode.NoError: case GolangDecoderErrorCode.NoError:
throw new ArgumentException("ThrowExceptionForErrorCode() called with NoError!", nameof(errorCode)); throw new ArgumentException("ThrowExceptionForErrorCode() called with NoError!", nameof(errorCode));
case OrigDecoderErrorCode.MissingFF00: case GolangDecoderErrorCode.MissingFF00:
throw new MissingFF00Exception(); throw new MissingFF00Exception();
case OrigDecoderErrorCode.UnexpectedEndOfStream: case GolangDecoderErrorCode.UnexpectedEndOfStream:
throw new EOFException(); throw new EOFException();
default: default:
throw new ArgumentOutOfRangeException(nameof(errorCode), errorCode, null); throw new ArgumentOutOfRangeException(nameof(errorCode), errorCode, null);
@ -35,26 +35,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
/// <summary> /// <summary>
/// Throws an exception if the given <see cref="OrigDecoderErrorCode"/> defines an error. /// Throws an exception if the given <see cref="GolangDecoderErrorCode"/> defines an error.
/// </summary> /// </summary>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param> /// <param name="errorCode">The <see cref="GolangDecoderErrorCode"/></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void EnsureNoError(this OrigDecoderErrorCode errorCode) public static void EnsureNoError(this GolangDecoderErrorCode errorCode)
{ {
if (errorCode != OrigDecoderErrorCode.NoError) if (errorCode != GolangDecoderErrorCode.NoError)
{ {
ThrowExceptionForErrorCode(errorCode); ThrowExceptionForErrorCode(errorCode);
} }
} }
/// <summary> /// <summary>
/// Throws an exception if the given <see cref="OrigDecoderErrorCode"/> is <see cref="OrigDecoderErrorCode.UnexpectedEndOfStream"/>. /// Throws an exception if the given <see cref="GolangDecoderErrorCode"/> is <see cref="GolangDecoderErrorCode.UnexpectedEndOfStream"/>.
/// </summary> /// </summary>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param> /// <param name="errorCode">The <see cref="GolangDecoderErrorCode"/></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void EnsureNoEOF(this OrigDecoderErrorCode errorCode) public static void EnsureNoEOF(this GolangDecoderErrorCode errorCode)
{ {
if (errorCode == OrigDecoderErrorCode.UnexpectedEndOfStream) if (errorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{ {
errorCode.ThrowExceptionForErrorCode(); errorCode.ThrowExceptionForErrorCode();
} }

21
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs

@ -3,8 +3,9 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -14,9 +15,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// Represents a single color component /// Represents a single color component
/// </summary> /// </summary>
internal class OrigComponent : IDisposable, IJpegComponent internal class GolangComponent : IDisposable, IJpegComponent
{ {
public OrigComponent(byte identifier, int index) public GolangComponent(byte identifier, int index)
{ {
this.Identifier = identifier; this.Identifier = identifier;
this.Index = index; this.Index = index;
@ -56,8 +57,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Initializes <see cref="SpectralBlocks"/> /// Initializes <see cref="SpectralBlocks"/>
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param> /// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void InitializeDerivedData(MemoryManager memoryManager, OrigJpegDecoderCore decoder) public void InitializeDerivedData(MemoryManager memoryManager, GolangJpegDecoderCore decoder)
{ {
// For 4-component images (either CMYK or YCbCrK), we only support two // For 4-component images (either CMYK or YCbCrK), we only support two
// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22]. // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
@ -76,7 +77,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
else else
{ {
OrigComponent c0 = decoder.Components[0]; GolangComponent c0 = decoder.Components[0];
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors); this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
} }
@ -86,8 +87,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// Initializes all component data except <see cref="SpectralBlocks"/>. /// Initializes all component data except <see cref="SpectralBlocks"/>.
/// </summary> /// </summary>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param> /// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void InitializeCoreData(OrigJpegDecoderCore decoder) public void InitializeCoreData(GolangJpegDecoderCore decoder)
{ {
// Section B.2.2 states that "the value of C_i shall be different from // Section B.2.2 states that "the value of C_i shall be different from
// the values of C_1 through C_(i-1)". // the values of C_1 through C_(i-1)".
@ -102,7 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
this.QuantizationTableIndex = decoder.Temp[8 + (3 * i)]; this.QuantizationTableIndex = decoder.Temp[8 + (3 * i)];
if (this.QuantizationTableIndex > OrigJpegDecoderCore.MaxTq) if (this.QuantizationTableIndex > GolangJpegDecoderCore.MaxTq)
{ {
throw new ImageFormatException("Bad Tq value"); throw new ImageFormatException("Bad Tq value");
} }

2
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponentScan.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponentScan.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Represents a component scan /// Represents a component scan
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct OrigComponentScan internal struct GolangComponentScan
{ {
/// <summary> /// <summary>
/// Gets or sets the component index. /// Gets or sets the component index.

2
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigDecoderErrorCode.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangDecoderErrorCode.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// Represents "recoverable" decoder errors. /// Represents "recoverable" decoder errors.
/// </summary> /// </summary>
internal enum OrigDecoderErrorCode internal enum GolangDecoderErrorCode
{ {
/// <summary> /// <summary>
/// NoError /// NoError

12
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangHuffmanTree.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -12,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Represents a Huffman tree /// Represents a Huffman tree
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal unsafe struct OrigHuffmanTree internal unsafe struct GolangHuffmanTree
{ {
/// <summary> /// <summary>
/// The index of the AC table row /// The index of the AC table row
@ -95,12 +93,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public FixedInt32Buffer16 Indices; public FixedInt32Buffer16 Indices;
/// <summary> /// <summary>
/// Creates and initializes an array of <see cref="OrigHuffmanTree" /> instances of size <see cref="NumberOfTrees" /> /// Creates and initializes an array of <see cref="GolangHuffmanTree" /> instances of size <see cref="NumberOfTrees" />
/// </summary> /// </summary>
/// <returns>An array of <see cref="OrigHuffmanTree" /> instances representing the Huffman tables</returns> /// <returns>An array of <see cref="GolangHuffmanTree" /> instances representing the Huffman tables</returns>
public static OrigHuffmanTree[] CreateHuffmanTrees() public static GolangHuffmanTree[] CreateHuffmanTrees()
{ {
return new OrigHuffmanTree[NumberOfTrees]; return new GolangHuffmanTree[NumberOfTrees];
} }
/// <summary> /// <summary>

11
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.ComputationData.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs

@ -2,14 +2,15 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
/// <content> /// <content>
/// Conains the definition of <see cref="ComputationData"/> /// Conains the definition of <see cref="ComputationData"/>
/// </content> /// </content>
internal unsafe partial struct OrigJpegScanDecoder internal unsafe partial struct GolangJpegScanDecoder
{ {
/// <summary> /// <summary>
/// Holds the "large" data blocks needed for computations. /// Holds the "large" data blocks needed for computations.
@ -28,14 +29,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public ZigZag Unzig; public ZigZag Unzig;
/// <summary> /// <summary>
/// The buffer storing the <see cref="OrigComponentScan"/>-s for each component /// The buffer storing the <see cref="GolangComponentScan"/>-s for each component
/// </summary> /// </summary>
public fixed byte ScanData[3 * OrigJpegDecoderCore.MaxComponents]; public fixed byte ScanData[3 * GolangJpegDecoderCore.MaxComponents];
/// <summary> /// <summary>
/// The DC values for each component /// The DC values for each component
/// </summary> /// </summary>
public fixed int Dc[OrigJpegDecoderCore.MaxComponents]; public fixed int Dc[GolangJpegDecoderCore.MaxComponents];
/// <summary> /// <summary>
/// Creates and initializes a new <see cref="ComputationData"/> instance /// Creates and initializes a new <see cref="ComputationData"/> instance

8
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.DataPointers.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.DataPointers.cs

@ -1,14 +1,14 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
/// <content> /// <content>
/// Conains the definition of <see cref="DataPointers"/> /// Conains the definition of <see cref="DataPointers"/>
/// </content> /// </content>
internal unsafe partial struct OrigJpegScanDecoder internal unsafe partial struct GolangJpegScanDecoder
{ {
/// <summary> /// <summary>
/// Contains pointers to the memory regions of <see cref="ComputationData"/> so they can be easily passed around to pointer based utility methods of <see cref="Block8x8F"/> /// Contains pointers to the memory regions of <see cref="ComputationData"/> so they can be easily passed around to pointer based utility methods of <see cref="Block8x8F"/>
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// Pointer to <see cref="ComputationData.ScanData"/> as Scan* /// Pointer to <see cref="ComputationData.ScanData"/> as Scan*
/// </summary> /// </summary>
public OrigComponentScan* ComponentScan; public GolangComponentScan* ComponentScan;
/// <summary> /// <summary>
/// Pointer to <see cref="ComputationData.Dc"/> /// Pointer to <see cref="ComputationData.Dc"/>
@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
this.Block = &basePtr->Block; this.Block = &basePtr->Block;
this.Unzig = basePtr->Unzig.Data; this.Unzig = basePtr->Unzig.Data;
this.ComponentScan = (OrigComponentScan*)basePtr->ScanData; this.ComponentScan = (GolangComponentScan*)basePtr->ScanData;
this.Dc = basePtr->Dc; this.Dc = basePtr->Dc;
} }
} }

67
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.cs

@ -3,9 +3,8 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Memory;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
@ -29,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// For baseline JPEGs, these parameters are hard-coded to 0/63/0/0. /// For baseline JPEGs, these parameters are hard-coded to 0/63/0/0.
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal unsafe partial struct OrigJpegScanDecoder internal unsafe partial struct GolangJpegScanDecoder
{ {
// The JpegScanDecoder members should be ordered in a way that results in optimal memory layout. // The JpegScanDecoder members should be ordered in a way that results in optimal memory layout.
#pragma warning disable SA1202 // ElementsMustBeOrderedByAccess #pragma warning disable SA1202 // ElementsMustBeOrderedByAccess
@ -110,12 +109,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private byte expectedRst; private byte expectedRst;
/// <summary> /// <summary>
/// Initializes a default-constructed <see cref="OrigJpegScanDecoder"/> instance for reading data from <see cref="OrigJpegDecoderCore"/>-s stream. /// Initializes a default-constructed <see cref="GolangJpegScanDecoder"/> instance for reading data from <see cref="GolangJpegDecoderCore"/>-s stream.
/// </summary> /// </summary>
/// <param name="p">Pointer to <see cref="OrigJpegScanDecoder"/> on the stack</param> /// <param name="p">Pointer to <see cref="GolangJpegScanDecoder"/> on the stack</param>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param> /// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
/// <param name="remaining">The remaining bytes in the segment block.</param> /// <param name="remaining">The remaining bytes in the segment block.</param>
public static void InitStreamReading(OrigJpegScanDecoder* p, OrigJpegDecoderCore decoder, int remaining) public static void InitStreamReading(GolangJpegScanDecoder* p, GolangJpegDecoderCore decoder, int remaining)
{ {
p->data = ComputationData.Create(); p->data = ComputationData.Create();
p->pointers = new DataPointers(&p->data); p->pointers = new DataPointers(&p->data);
@ -123,8 +122,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
/// <summary> /// <summary>
/// Read Huffman data from Jpeg scans in <see cref="OrigJpegDecoderCore.InputStream"/>, /// Read Huffman data from Jpeg scans in <see cref="GolangJpegDecoderCore.InputStream"/>,
/// and decode it as <see cref="Block8x8"/> into <see cref="OrigComponent.SpectralBlocks"/>. /// and decode it as <see cref="Block8x8"/> into <see cref="GolangComponent.SpectralBlocks"/>.
/// ///
/// The blocks are traversed one MCU at a time. For 4:2:0 chroma /// The blocks are traversed one MCU at a time. For 4:2:0 chroma
/// subsampling, there are four Y 8x8 blocks in every 16x16 MCU. /// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
@ -149,14 +148,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// 0 1 2 /// 0 1 2
/// 3 4 5 /// 3 4 5
/// </summary> /// </summary>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param> /// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void DecodeBlocks(OrigJpegDecoderCore decoder) public void DecodeBlocks(GolangJpegDecoderCore decoder)
{ {
decoder.InputProcessor.ResetErrorState(); decoder.InputProcessor.ResetErrorState();
this.blockCounter = 0; this.blockCounter = 0;
this.mcuCounter = 0; this.mcuCounter = 0;
this.expectedRst = OrigJpegConstants.Markers.RST0; this.expectedRst = JpegConstants.Markers.RST0;
for (int my = 0; my < decoder.MCUCountY; my++) for (int my = 0; my < decoder.MCUCountY; my++)
{ {
@ -177,12 +176,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
} }
private void DecodeBlocksAtMcuIndex(OrigJpegDecoderCore decoder, int mx, int my) private void DecodeBlocksAtMcuIndex(GolangJpegDecoderCore decoder, int mx, int my)
{ {
for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++) for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++)
{ {
this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex; this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
OrigComponent component = decoder.Components[this.ComponentIndex]; GolangComponent component = decoder.Components[this.ComponentIndex];
this.hi = component.HorizontalSamplingFactor; this.hi = component.HorizontalSamplingFactor;
int vi = component.VerticalSamplingFactor; int vi = component.VerticalSamplingFactor;
@ -223,7 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
} }
private void ProcessRSTMarker(OrigJpegDecoderCore decoder) private void ProcessRSTMarker(GolangJpegDecoderCore decoder)
{ {
// Attempt to look for RST[0-7] markers to resynchronize from corrupt input. // Attempt to look for RST[0-7] markers to resynchronize from corrupt input.
if (!decoder.InputProcessor.ReachedEOF) if (!decoder.InputProcessor.ReachedEOF)
@ -262,15 +261,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
this.expectedRst++; this.expectedRst++;
if (this.expectedRst == OrigJpegConstants.Markers.RST7 + 1) if (this.expectedRst == JpegConstants.Markers.RST7 + 1)
{ {
this.expectedRst = OrigJpegConstants.Markers.RST0; this.expectedRst = JpegConstants.Markers.RST0;
} }
} }
} }
} }
private void Reset(OrigJpegDecoderCore decoder) private void Reset(GolangJpegDecoderCore decoder)
{ {
decoder.InputProcessor.ResetHuffmanDecoder(); decoder.InputProcessor.ResetHuffmanDecoder();
@ -285,15 +284,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
private void ResetDcValues() private void ResetDcValues()
{ {
Unsafe.InitBlock(this.pointers.Dc, default(byte), sizeof(int) * OrigJpegDecoderCore.MaxComponents); Unsafe.InitBlock(this.pointers.Dc, default, sizeof(int) * GolangJpegDecoderCore.MaxComponents);
} }
/// <summary> /// <summary>
/// The implementation part of <see cref="InitStreamReading"/> as an instance method. /// The implementation part of <see cref="InitStreamReading"/> as an instance method.
/// </summary> /// </summary>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/></param> /// <param name="decoder">The <see cref="GolangJpegDecoderCore"/></param>
/// <param name="remaining">The remaining bytes</param> /// <param name="remaining">The remaining bytes</param>
private void InitStreamReadingImpl(OrigJpegDecoderCore decoder, int remaining) private void InitStreamReadingImpl(GolangJpegDecoderCore decoder, int remaining)
{ {
if (decoder.ComponentCount == 0) if (decoder.ComponentCount == 0)
{ {
@ -360,10 +359,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
/// <param name="decoder">The decoder</param> /// <param name="decoder">The decoder</param>
/// <param name="scanIndex">The index of the scan</param> /// <param name="scanIndex">The index of the scan</param>
private void DecodeBlock(OrigJpegDecoderCore decoder, int scanIndex) private void DecodeBlock(GolangJpegDecoderCore decoder, int scanIndex)
{ {
Block8x8* b = this.pointers.Block; Block8x8* b = this.pointers.Block;
int huffmannIdx = (OrigHuffmanTree.AcTableIndex * OrigHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector; int huffmannIdx = (GolangHuffmanTree.AcTableIndex * GolangHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
if (this.ah != 0) if (this.ah != 0)
{ {
this.Refine(ref decoder.InputProcessor, ref decoder.HuffmanTrees[huffmannIdx], 1 << this.al); this.Refine(ref decoder.InputProcessor, ref decoder.HuffmanTrees[huffmannIdx], 1 << this.al);
@ -377,7 +376,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
zig++; zig++;
// Decode the DC coefficient, as specified in section F.2.2.1. // Decode the DC coefficient, as specified in section F.2.2.1.
int huffmanIndex = (OrigHuffmanTree.DcTableIndex * OrigHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector; int huffmanIndex = (GolangHuffmanTree.DcTableIndex * GolangHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector;
decoder.InputProcessor.DecodeHuffmanUnsafe( decoder.InputProcessor.DecodeHuffmanUnsafe(
ref decoder.HuffmanTrees[huffmanIndex], ref decoder.HuffmanTrees[huffmanIndex],
out int value); out int value);
@ -467,7 +466,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private void DecodeEobRun(int count, ref InputProcessor processor) private void DecodeEobRun(int count, ref InputProcessor processor)
{ {
processor.DecodeBitsUnsafe(count, out int bitsResult); processor.DecodeBitsUnsafe(count, out int bitsResult);
if (processor.LastErrorCode != OrigDecoderErrorCode.NoError) if (processor.LastErrorCode != GolangDecoderErrorCode.NoError)
{ {
return; return;
} }
@ -475,7 +474,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.eobRun |= bitsResult; this.eobRun |= bitsResult;
} }
private void InitComponentScan(OrigJpegDecoderCore decoder, int i, ref OrigComponentScan currentComponentScan, ref int totalHv) private void InitComponentScan(GolangJpegDecoderCore decoder, int i, ref GolangComponentScan currentComponentScan, ref int totalHv)
{ {
// Component selector. // Component selector.
int cs = decoder.Temp[1 + (2 * i)]; int cs = decoder.Temp[1 + (2 * i)];
@ -500,11 +499,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
private void ProcessComponentImpl( private void ProcessComponentImpl(
OrigJpegDecoderCore decoder, GolangJpegDecoderCore decoder,
int i, int i,
ref OrigComponentScan currentComponentScan, ref GolangComponentScan currentComponentScan,
ref int totalHv, ref int totalHv,
OrigComponent currentComponent) GolangComponent currentComponent)
{ {
// Section B.2.3 states that "the value of Cs_j shall be different from // Section B.2.3 states that "the value of Cs_j shall be different from
// the values of Cs_1 through Cs_(j-1)". Since we have previously // the values of Cs_1 through Cs_(j-1)". Since we have previously
@ -522,13 +521,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
totalHv += currentComponent.HorizontalSamplingFactor * currentComponent.VerticalSamplingFactor; totalHv += currentComponent.HorizontalSamplingFactor * currentComponent.VerticalSamplingFactor;
currentComponentScan.DcTableSelector = (byte)(decoder.Temp[2 + (2 * i)] >> 4); currentComponentScan.DcTableSelector = (byte)(decoder.Temp[2 + (2 * i)] >> 4);
if (currentComponentScan.DcTableSelector > OrigHuffmanTree.MaxTh) if (currentComponentScan.DcTableSelector > GolangHuffmanTree.MaxTh)
{ {
throw new ImageFormatException("Bad DC table selector value"); throw new ImageFormatException("Bad DC table selector value");
} }
currentComponentScan.AcTableSelector = (byte)(decoder.Temp[2 + (2 * i)] & 0x0f); currentComponentScan.AcTableSelector = (byte)(decoder.Temp[2 + (2 * i)] & 0x0f);
if (currentComponentScan.AcTableSelector > OrigHuffmanTree.MaxTh) if (currentComponentScan.AcTableSelector > GolangHuffmanTree.MaxTh)
{ {
throw new ImageFormatException("Bad AC table selector value"); throw new ImageFormatException("Bad AC table selector value");
} }
@ -540,7 +539,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="bp">The <see cref="InputProcessor"/> instance</param> /// <param name="bp">The <see cref="InputProcessor"/> instance</param>
/// <param name="h">The Huffman tree</param> /// <param name="h">The Huffman tree</param>
/// <param name="delta">The low transform offset</param> /// <param name="delta">The low transform offset</param>
private void Refine(ref InputProcessor bp, ref OrigHuffmanTree h, int delta) private void Refine(ref InputProcessor bp, ref GolangHuffmanTree h, int delta)
{ {
Block8x8* b = this.pointers.Block; Block8x8* b = this.pointers.Block;
@ -560,7 +559,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (bit) if (bit)
{ {
int stuff = (int)Block8x8.GetScalarAt(b, 0); int stuff = Block8x8.GetScalarAt(b, 0);
// int stuff = (int)b[0]; // int stuff = (int)b[0];
stuff |= delta; stuff |= delta;

80
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs

@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
/// <summary> /// <summary>
/// Encapsulates stream reading and processing data and operations for <see cref="OrigJpegDecoderCore"/>. /// Encapsulates stream reading and processing data and operations for <see cref="GolangJpegDecoderCore"/>.
/// It's a value type for imporved data locality, and reduced number of CALLVIRT-s /// It's a value type for imporved data locality, and reduced number of CALLVIRT-s
/// </summary> /// </summary>
internal struct InputProcessor : IDisposable internal struct InputProcessor : IDisposable
@ -27,14 +27,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Initializes a new instance of the <see cref="InputProcessor"/> struct. /// Initializes a new instance of the <see cref="InputProcessor"/> struct.
/// </summary> /// </summary>
/// <param name="inputStream">The input <see cref="Stream"/></param> /// <param name="inputStream">The input <see cref="Stream"/></param>
/// <param name="temp">Temporal buffer, same as <see cref="OrigJpegDecoderCore.Temp"/></param> /// <param name="temp">Temporal buffer, same as <see cref="GolangJpegDecoderCore.Temp"/></param>
public InputProcessor(Stream inputStream, byte[] temp) public InputProcessor(Stream inputStream, byte[] temp)
{ {
this.Bits = default(Bits); this.Bits = default;
this.Bytes = Bytes.Create(); this.Bytes = Bytes.Create();
this.InputStream = inputStream; this.InputStream = inputStream;
this.Temp = temp; this.Temp = temp;
this.LastErrorCode = OrigDecoderErrorCode.NoError; this.LastErrorCode = GolangDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -43,20 +43,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public Stream InputStream { get; } public Stream InputStream { get; }
/// <summary> /// <summary>
/// Gets the temporary buffer, same instance as <see cref="OrigJpegDecoderCore.Temp"/> /// Gets the temporary buffer, same instance as <see cref="GolangJpegDecoderCore.Temp"/>
/// </summary> /// </summary>
public byte[] Temp { get; } public byte[] Temp { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether an unexpected EOF reached in <see cref="InputStream"/>. /// Gets a value indicating whether an unexpected EOF reached in <see cref="InputStream"/>.
/// </summary> /// </summary>
public bool ReachedEOF => this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream; public bool ReachedEOF => this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream;
public bool HasError => this.LastErrorCode != OrigDecoderErrorCode.NoError; public bool HasError => this.LastErrorCode != GolangDecoderErrorCode.NoError;
public OrigDecoderErrorCode LastErrorCode { get; private set; } public GolangDecoderErrorCode LastErrorCode { get; private set; }
public void ResetErrorState() => this.LastErrorCode = OrigDecoderErrorCode.NoError; public void ResetErrorState() => this.LastErrorCode = GolangDecoderErrorCode.NoError;
/// <summary> /// <summary>
/// If errorCode indicates unexpected EOF, sets <see cref="ReachedEOF"/> to true and returns false. /// If errorCode indicates unexpected EOF, sets <see cref="ReachedEOF"/> to true and returns false.
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <returns>A <see cref="bool"/> indicating whether EOF reached</returns> /// <returns>A <see cref="bool"/> indicating whether EOF reached</returns>
public bool CheckEOFEnsureNoError() public bool CheckEOFEnsureNoError()
{ {
if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream) if (this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{ {
return false; return false;
} }
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <returns>A <see cref="bool"/> indicating whether EOF reached</returns> /// <returns>A <see cref="bool"/> indicating whether EOF reached</returns>
public bool CheckEOF() public bool CheckEOF()
{ {
if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream) if (this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{ {
return false; return false;
} }
@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public OrigDecoderErrorCode ReadByteUnsafe(out byte result) public GolangDecoderErrorCode ReadByteUnsafe(out byte result)
{ {
this.LastErrorCode = this.Bytes.ReadByteUnsafe(this.InputStream, out result); this.LastErrorCode = this.Bytes.ReadByteUnsafe(this.InputStream, out result);
return this.LastErrorCode; return this.LastErrorCode;
@ -117,13 +117,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// TODO: This method (and also the usages) could be optimized by batching! /// TODO: This method (and also the usages) could be optimized by batching!
/// </summary> /// </summary>
/// <param name="result">The decoded bit as a <see cref="bool"/></param> /// <param name="result">The decoded bit as a <see cref="bool"/></param>
/// <returns>The <see cref="OrigDecoderErrorCode" /></returns> /// <returns>The <see cref="GolangDecoderErrorCode" /></returns>
public OrigDecoderErrorCode DecodeBitUnsafe(out bool result) public GolangDecoderErrorCode DecodeBitUnsafe(out bool result)
{ {
if (this.Bits.UnreadBits == 0) if (this.Bits.UnreadBits == 0)
{ {
this.LastErrorCode = this.Bits.Ensure1BitUnsafe(ref this); this.LastErrorCode = this.Bits.Ensure1BitUnsafe(ref this);
if (this.LastErrorCode != OrigDecoderErrorCode.NoError) if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{ {
result = false; result = false;
return this.LastErrorCode; return this.LastErrorCode;
@ -133,18 +133,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
result = (this.Bits.Accumulator & this.Bits.Mask) != 0; result = (this.Bits.Accumulator & this.Bits.Mask) != 0;
this.Bits.UnreadBits--; this.Bits.UnreadBits--;
this.Bits.Mask >>= 1; this.Bits.Mask >>= 1;
return this.LastErrorCode = OrigDecoderErrorCode.NoError; return this.LastErrorCode = GolangDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
/// Reads exactly length bytes into data. It does not care about byte stuffing. /// Reads exactly length bytes into data. It does not care about byte stuffing.
/// Does not throw on errors, returns <see cref="OrigJpegDecoderCore"/> instead! /// Does not throw on errors, returns <see cref="GolangJpegDecoderCore"/> instead!
/// </summary> /// </summary>
/// <param name="data">The data to write to.</param> /// <param name="data">The data to write to.</param>
/// <param name="offset">The offset in the source buffer</param> /// <param name="offset">The offset in the source buffer</param>
/// <param name="length">The number of bytes to read</param> /// <param name="length">The number of bytes to read</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReadFullUnsafe(byte[] data, int offset, int length) public GolangDecoderErrorCode ReadFullUnsafe(byte[] data, int offset, int length)
{ {
// Unread the overshot bytes, if any. // Unread the overshot bytes, if any.
if (this.Bytes.UnreadableBytes != 0) if (this.Bytes.UnreadableBytes != 0)
@ -157,8 +157,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.Bytes.UnreadableBytes = 0; this.Bytes.UnreadableBytes = 0;
} }
this.LastErrorCode = OrigDecoderErrorCode.NoError; this.LastErrorCode = GolangDecoderErrorCode.NoError;
while (length > 0 && this.LastErrorCode == OrigDecoderErrorCode.NoError) while (length > 0 && this.LastErrorCode == GolangDecoderErrorCode.NoError)
{ {
if (this.Bytes.J - this.Bytes.I >= length) if (this.Bytes.J - this.Bytes.I >= length)
{ {
@ -185,13 +185,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
/// <param name="count">The number of bits to decode.</param> /// <param name="count">The number of bits to decode.</param>
/// <param name="result">The <see cref="uint" /> result</param> /// <param name="result">The <see cref="uint" /> result</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode DecodeBitsUnsafe(int count, out int result) public GolangDecoderErrorCode DecodeBitsUnsafe(int count, out int result)
{ {
if (this.Bits.UnreadBits < count) if (this.Bits.UnreadBits < count)
{ {
this.LastErrorCode = this.Bits.EnsureNBitsUnsafe(count, ref this); this.LastErrorCode = this.Bits.EnsureNBitsUnsafe(count, ref this);
if (this.LastErrorCode != OrigDecoderErrorCode.NoError) if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{ {
result = 0; result = 0;
return this.LastErrorCode; return this.LastErrorCode;
@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
result = result & ((1 << count) - 1); result = result & ((1 << count) - 1);
this.Bits.UnreadBits -= count; this.Bits.UnreadBits -= count;
this.Bits.Mask >>= count; this.Bits.Mask >>= count;
return this.LastErrorCode = OrigDecoderErrorCode.NoError; return this.LastErrorCode = GolangDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -210,8 +210,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
/// <param name="huffmanTree">The huffman value</param> /// <param name="huffmanTree">The huffman value</param>
/// <param name="result">The decoded <see cref="byte" /></param> /// <param name="result">The decoded <see cref="byte" /></param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode DecodeHuffmanUnsafe(ref OrigHuffmanTree huffmanTree, out int result) public GolangDecoderErrorCode DecodeHuffmanUnsafe(ref GolangHuffmanTree huffmanTree, out int result)
{ {
result = 0; result = 0;
@ -224,9 +224,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
this.LastErrorCode = this.Bits.Ensure8BitsUnsafe(ref this); this.LastErrorCode = this.Bits.Ensure8BitsUnsafe(ref this);
if (this.LastErrorCode == OrigDecoderErrorCode.NoError) if (this.LastErrorCode == GolangDecoderErrorCode.NoError)
{ {
int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - OrigHuffmanTree.LutSizeLog2)) & 0xFF; int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - GolangHuffmanTree.LutSizeLog2)) & 0xFF;
int v = huffmanTree.Lut[lutIndex]; int v = huffmanTree.Lut[lutIndex];
if (v != 0) if (v != 0)
@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
int code = 0; int code = 0;
for (int i = 0; i < OrigHuffmanTree.MaxCodeLength; i++) for (int i = 0; i < GolangHuffmanTree.MaxCodeLength; i++)
{ {
if (this.Bits.UnreadBits == 0) if (this.Bits.UnreadBits == 0)
{ {
@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (code <= huffmanTree.MaxCodes[i]) if (code <= huffmanTree.MaxCodes[i])
{ {
result = huffmanTree.GetValue(code, i); result = huffmanTree.GetValue(code, i);
return this.LastErrorCode = OrigDecoderErrorCode.NoError; return this.LastErrorCode = GolangDecoderErrorCode.NoError;
} }
code <<= 1; code <<= 1;
@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
DecoderThrowHelper.ThrowImageFormatException.BadHuffmanCode(); DecoderThrowHelper.ThrowImageFormatException.BadHuffmanCode();
// DUMMY RETURN! C# doesn't know we have thrown an exception! // DUMMY RETURN! C# doesn't know we have thrown an exception!
return OrigDecoderErrorCode.NoError; return GolangDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -295,11 +295,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// Skips the next n bytes. /// Skips the next n bytes.
/// Does not throw, returns <see cref="OrigDecoderErrorCode"/> instead! /// Does not throw, returns <see cref="GolangDecoderErrorCode"/> instead!
/// </summary> /// </summary>
/// <param name="count">The number of bytes to ignore.</param> /// <param name="count">The number of bytes to ignore.</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode SkipUnsafe(int count) public GolangDecoderErrorCode SkipUnsafe(int count)
{ {
// Unread the overshot bytes, if any. // Unread the overshot bytes, if any.
if (this.Bytes.UnreadableBytes != 0) if (this.Bytes.UnreadableBytes != 0)
@ -328,13 +328,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
this.LastErrorCode = this.Bytes.FillUnsafe(this.InputStream); this.LastErrorCode = this.Bytes.FillUnsafe(this.InputStream);
if (this.LastErrorCode != OrigDecoderErrorCode.NoError) if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{ {
return this.LastErrorCode; return this.LastErrorCode;
} }
} }
return this.LastErrorCode = OrigDecoderErrorCode.NoError; return this.LastErrorCode = GolangDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -374,8 +374,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
/// <param name="t">Byte</param> /// <param name="t">Byte</param>
/// <param name="x">Read bits value</param> /// <param name="x">Read bits value</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, out int x) public GolangDecoderErrorCode ReceiveExtendUnsafe(int t, out int x)
{ {
this.LastErrorCode = this.Bits.ReceiveExtendUnsafe(t, ref this, out x); this.LastErrorCode = this.Bits.ReceiveExtendUnsafe(t, ref this, out x);
return this.LastErrorCode; return this.LastErrorCode;
@ -386,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
public void ResetHuffmanDecoder() public void ResetHuffmanDecoder()
{ {
this.Bits = default(Bits); this.Bits = default;
} }
} }
} }

6
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.
@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
using (var decoder = new OrigJpegDecoderCore(configuration, this)) using (var decoder = new GolangJpegDecoderCore(configuration, this))
{ {
return decoder.Decode<TPixel>(stream); return decoder.Decode<TPixel>(stream);
} }
@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
using (var decoder = new OrigJpegDecoderCore(configuration, this)) using (var decoder = new GolangJpegDecoderCore(configuration, this))
{ {
return decoder.Identify(stream); return decoder.Identify(stream);
} }

81
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs → src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs

@ -3,8 +3,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary> /// <summary>
/// Performs the jpeg decoding operation. /// Performs the jpeg decoding operation.
/// </summary> /// </summary>
internal sealed unsafe class OrigJpegDecoderCore : IRawJpegData internal sealed unsafe class GolangJpegDecoderCore : IRawJpegData
{ {
/// <summary> /// <summary>
/// The maximum number of color components /// The maximum number of color components
@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
#pragma warning disable SA1401 // FieldsMustBePrivate #pragma warning disable SA1401 // FieldsMustBePrivate
/// <summary> /// <summary>
/// Encapsulates stream reading and processing data and operations for <see cref="OrigJpegDecoderCore"/>. /// Encapsulates stream reading and processing data and operations for <see cref="GolangJpegDecoderCore"/>.
/// It's a value type for improved data locality, and reduced number of CALLVIRT-s /// It's a value type for improved data locality, and reduced number of CALLVIRT-s
/// </summary> /// </summary>
public InputProcessor InputProcessor; public InputProcessor InputProcessor;
@ -79,11 +80,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private AdobeMarker adobe; private AdobeMarker adobe;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="OrigJpegDecoderCore" /> class. /// Initializes a new instance of the <see cref="GolangJpegDecoderCore" /> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration.</param> /// <param name="configuration">The configuration.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
public OrigJpegDecoderCore(Configuration configuration, IJpegDecoderOptions options) public GolangJpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
{ {
this.IgnoreMetadata = options.IgnoreMetadata; this.IgnoreMetadata = options.IgnoreMetadata;
this.configuration = configuration ?? Configuration.Default; this.configuration = configuration ?? Configuration.Default;
@ -96,12 +97,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary> /// <summary>
/// Gets the component array /// Gets the component array
/// </summary> /// </summary>
public OrigComponent[] Components { get; private set; } public GolangComponent[] Components { get; private set; }
/// <summary> /// <summary>
/// Gets the huffman trees /// Gets the huffman trees
/// </summary> /// </summary>
public OrigHuffmanTree[] HuffmanTrees { get; private set; } public GolangHuffmanTree[] HuffmanTrees { get; private set; }
/// <inheritdoc /> /// <inheritdoc />
public Block8x8F[] QuantizationTables { get; private set; } public Block8x8F[] QuantizationTables { get; private set; }
@ -209,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{ {
if (this.Components != null) if (this.Components != null)
{ {
foreach (OrigComponent component in this.Components) foreach (GolangComponent component in this.Components)
{ {
component?.Dispose(); component?.Dispose();
} }
@ -219,7 +220,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
/// <summary> /// <summary>
/// Read metadata from stream and read the blocks in the scans into <see cref="OrigComponent.SpectralBlocks"/>. /// Read metadata from stream and read the blocks in the scans into <see cref="GolangComponent.SpectralBlocks"/>.
/// </summary> /// </summary>
/// <param name="stream">The stream</param> /// <param name="stream">The stream</param>
/// <param name="metadataOnly">Whether to decode metadata only.</param> /// <param name="metadataOnly">Whether to decode metadata only.</param>
@ -231,14 +232,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
if (!metadataOnly) if (!metadataOnly)
{ {
this.HuffmanTrees = OrigHuffmanTree.CreateHuffmanTrees(); this.HuffmanTrees = GolangHuffmanTree.CreateHuffmanTrees();
this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.QuantizationTables = new Block8x8F[MaxTq + 1];
} }
// Check for the Start Of Image marker. // Check for the Start Of Image marker.
this.InputProcessor.ReadFull(this.Temp, 0, 2); this.InputProcessor.ReadFull(this.Temp, 0, 2);
if (this.Temp[0] != OrigJpegConstants.Markers.XFF || this.Temp[1] != OrigJpegConstants.Markers.SOI) if (this.Temp[0] != JpegConstants.Markers.XFF || this.Temp[1] != JpegConstants.Markers.SOI)
{ {
throw new ImageFormatException("Missing SOI marker."); throw new ImageFormatException("Missing SOI marker.");
} }
@ -302,12 +303,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
// End Of Image. // End Of Image.
if (marker == OrigJpegConstants.Markers.EOI) if (marker == JpegConstants.Markers.EOI)
{ {
break; break;
} }
if (marker >= OrigJpegConstants.Markers.RST0 && marker <= OrigJpegConstants.Markers.RST7) if (marker >= JpegConstants.Markers.RST0 && marker <= JpegConstants.Markers.RST7)
{ {
// Figures B.2 and B.16 of the specification suggest that restart markers should // Figures B.2 and B.16 of the specification suggest that restart markers should
// only occur between Entropy Coded Segments and not after the final ECS. // only occur between Entropy Coded Segments and not after the final ECS.
@ -329,14 +330,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
switch (marker) switch (marker)
{ {
case OrigJpegConstants.Markers.SOF0: case JpegConstants.Markers.SOF0:
case OrigJpegConstants.Markers.SOF1: case JpegConstants.Markers.SOF1:
case OrigJpegConstants.Markers.SOF2: case JpegConstants.Markers.SOF2:
this.IsProgressive = marker == OrigJpegConstants.Markers.SOF2; this.IsProgressive = marker == JpegConstants.Markers.SOF2;
this.ProcessStartOfFrameMarker(remaining, metadataOnly); this.ProcessStartOfFrameMarker(remaining, metadataOnly);
break; break;
case OrigJpegConstants.Markers.DHT: case JpegConstants.Markers.DHT:
if (metadataOnly) if (metadataOnly)
{ {
this.InputProcessor.Skip(remaining); this.InputProcessor.Skip(remaining);
@ -347,7 +348,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
break; break;
case OrigJpegConstants.Markers.DQT: case JpegConstants.Markers.DQT:
if (metadataOnly) if (metadataOnly)
{ {
this.InputProcessor.Skip(remaining); this.InputProcessor.Skip(remaining);
@ -358,7 +359,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
break; break;
case OrigJpegConstants.Markers.SOS: case JpegConstants.Markers.SOS:
if (!metadataOnly) if (!metadataOnly)
{ {
this.ProcessStartOfScanMarker(remaining); this.ProcessStartOfScanMarker(remaining);
@ -377,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
break; break;
case OrigJpegConstants.Markers.DRI: case JpegConstants.Markers.DRI:
if (metadataOnly) if (metadataOnly)
{ {
this.InputProcessor.Skip(remaining); this.InputProcessor.Skip(remaining);
@ -388,21 +389,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
break; break;
case OrigJpegConstants.Markers.APP0: case JpegConstants.Markers.APP0:
this.ProcessApplicationHeaderMarker(remaining); this.ProcessApplicationHeaderMarker(remaining);
break; break;
case OrigJpegConstants.Markers.APP1: case JpegConstants.Markers.APP1:
this.ProcessApp1Marker(remaining); this.ProcessApp1Marker(remaining);
break; break;
case OrigJpegConstants.Markers.APP2: case JpegConstants.Markers.APP2:
this.ProcessApp2Marker(remaining); this.ProcessApp2Marker(remaining);
break; break;
case OrigJpegConstants.Markers.APP14: case JpegConstants.Markers.APP14:
this.ProcessApp14Marker(remaining); this.ProcessApp14Marker(remaining);
break; break;
default: default:
if ((marker >= OrigJpegConstants.Markers.APP0 && marker <= OrigJpegConstants.Markers.APP15) if ((marker >= JpegConstants.Markers.APP0 && marker <= JpegConstants.Markers.APP15)
|| marker == OrigJpegConstants.Markers.COM) || marker == JpegConstants.Markers.COM)
{ {
this.InputProcessor.Skip(remaining); this.InputProcessor.Skip(remaining);
} }
@ -680,12 +681,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
if (!metadataOnly) if (!metadataOnly)
{ {
this.Components = new OrigComponent[this.ComponentCount]; this.Components = new GolangComponent[this.ComponentCount];
for (int i = 0; i < this.ComponentCount; i++) for (int i = 0; i < this.ComponentCount; i++)
{ {
byte componentIdentifier = this.Temp[6 + (3 * i)]; byte componentIdentifier = this.Temp[6 + (3 * i)];
var component = new OrigComponent(componentIdentifier, i); var component = new GolangComponent(componentIdentifier, i);
component.InitializeCoreData(this); component.InitializeCoreData(this);
this.Components[i] = component; this.Components[i] = component;
} }
@ -697,7 +698,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.ColorSpace = this.DeduceJpegColorSpace(); this.ColorSpace = this.DeduceJpegColorSpace();
foreach (OrigComponent component in this.Components) foreach (GolangComponent component in this.Components)
{ {
component.InitializeDerivedData(this.configuration.MemoryManager, this); component.InitializeDerivedData(this.configuration.MemoryManager, this);
} }
@ -721,18 +722,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InputProcessor.ReadFull(this.Temp, 0, 17); this.InputProcessor.ReadFull(this.Temp, 0, 17);
int tc = this.Temp[0] >> 4; int tc = this.Temp[0] >> 4;
if (tc > OrigHuffmanTree.MaxTc) if (tc > GolangHuffmanTree.MaxTc)
{ {
throw new ImageFormatException("Bad Tc value"); throw new ImageFormatException("Bad Tc value");
} }
int th = this.Temp[0] & 0x0f; int th = this.Temp[0] & 0x0f;
if (th > OrigHuffmanTree.MaxTh) if (th > GolangHuffmanTree.MaxTh)
{ {
throw new ImageFormatException("Bad Th value"); throw new ImageFormatException("Bad Th value");
} }
int huffTreeIndex = (tc * OrigHuffmanTree.ThRowSize) + th; int huffTreeIndex = (tc * GolangHuffmanTree.ThRowSize) + th;
this.HuffmanTrees[huffTreeIndex].ProcessDefineHuffmanTablesMarkerLoop( this.HuffmanTrees[huffTreeIndex].ProcessDefineHuffmanTablesMarkerLoop(
ref this.InputProcessor, ref this.InputProcessor,
this.Temp, this.Temp,
@ -766,9 +767,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </exception> /// </exception>
private void ProcessStartOfScanMarker(int remaining) private void ProcessStartOfScanMarker(int remaining)
{ {
var scan = default(OrigJpegScanDecoder); var scan = default(GolangJpegScanDecoder);
OrigJpegScanDecoder.InitStreamReading(&scan, this, remaining); GolangJpegScanDecoder.InitStreamReading(&scan, this, remaining);
this.InputProcessor.Bits = default(Bits); this.InputProcessor.Bits = default;
scan.DecodeBlocks(this); scan.DecodeBlocks(this);
} }
@ -779,19 +780,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
case 1: case 1:
return JpegColorSpace.Grayscale; return JpegColorSpace.Grayscale;
case 3: case 3:
if (!this.isAdobe || this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformYCbCr) if (!this.isAdobe || this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
{ {
return JpegColorSpace.YCbCr; return JpegColorSpace.YCbCr;
} }
if (this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformUnknown) if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{ {
return JpegColorSpace.RGB; return JpegColorSpace.RGB;
} }
break; break;
case 4: case 4:
if (this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformYcck) if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
{ {
return JpegColorSpace.Ycck; return JpegColorSpace.Ycck;
} }

189
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegConstants.cs

@ -1,189 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
/// <summary>
/// Defines jpeg constants defined in the specification.
/// </summary>
internal static class OrigJpegConstants
{
/// <summary>
/// The maximum allowable length in each dimension of a jpeg image.
/// </summary>
public const ushort MaxLength = 65535;
/// <summary>
/// The list of mimetypes that equate to a jpeg.
/// </summary>
public static readonly IEnumerable<string> MimeTypes = new[] { "image/jpeg", "image/pjpeg" };
/// <summary>
/// The list of file extensions that equate to a jpeg.
/// </summary>
public static readonly IEnumerable<string> FileExtensions = new[] { "jpg", "jpeg", "jfif" };
/// <summary>
/// Describes common Jpeg markers
/// </summary>
internal static class Markers
{
/// <summary>
/// Marker prefix. Next byte is a marker.
/// </summary>
public const byte XFF = 0xff;
/// <summary>
/// Same as <see cref="XFF"/> but of type <see cref="int"/>
/// </summary>
public const int XFFInt = XFF;
/// <summary>
/// Start of Image
/// </summary>
public const byte SOI = 0xd8;
/// <summary>
/// Start of Frame (baseline DCT)
/// <remarks>
/// Indicates that this is a baseline DCT-based JPEG, and specifies the width, height, number of components,
/// and component subsampling (e.g., 4:2:0).
/// </remarks>
/// </summary>
public const byte SOF0 = 0xc0;
/// <summary>
/// Start Of Frame (Extended Sequential DCT)
/// <remarks>
/// Indicates that this is a progressive DCT-based JPEG, and specifies the width, height, number of components,
/// and component subsampling (e.g., 4:2:0).
/// </remarks>
/// </summary>
public const byte SOF1 = 0xc1;
/// <summary>
/// Start Of Frame (progressive DCT)
/// <remarks>
/// Indicates that this is a progressive DCT-based JPEG, and specifies the width, height, number of components,
/// and component subsampling (e.g., 4:2:0).
/// </remarks>
/// </summary>
public const byte SOF2 = 0xc2;
/// <summary>
/// Define Huffman Table(s)
/// <remarks>
/// Specifies one or more Huffman tables.
/// </remarks>
/// </summary>
public const byte DHT = 0xc4;
/// <summary>
/// Define Quantization Table(s)
/// <remarks>
/// Specifies one or more quantization tables.
/// </remarks>
/// </summary>
public const byte DQT = 0xdb;
/// <summary>
/// Define Restart Interval
/// <remarks>
/// Specifies the interval between RSTn markers, in macroblocks. This marker is followed by two bytes
/// indicating the fixed size so it can be treated like any other variable size segment.
/// </remarks>
/// </summary>
public const byte DRI = 0xdd;
/// <summary>
/// Define First Restart
/// <remarks>
/// Inserted every r macroblocks, where r is the restart interval set by a DRI marker.
/// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
/// </remarks>
/// </summary>
public const byte RST0 = 0xd0;
/// <summary>
/// Define Eigth Restart
/// <remarks>
/// Inserted every r macroblocks, where r is the restart interval set by a DRI marker.
/// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
/// </remarks>
/// </summary>
public const byte RST7 = 0xd7;
/// <summary>
/// Start of Scan
/// <remarks>
/// Begins a top-to-bottom scan of the image. In baseline DCT JPEG images, there is generally a single scan.
/// Progressive DCT JPEG images usually contain multiple scans. This marker specifies which slice of data it
/// will contain, and is immediately followed by entropy-coded data.
/// </remarks>
/// </summary>
public const byte SOS = 0xda;
/// <summary>
/// Comment
/// <remarks>
/// Contains a text comment.
/// </remarks>
/// </summary>
public const byte COM = 0xfe;
/// <summary>
/// End of Image
/// </summary>
public const byte EOI = 0xd9;
/// <summary>
/// Application specific marker for marking the jpeg format.
/// <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html"/>
/// </summary>
public const byte APP0 = 0xe0;
/// <summary>
/// Application specific marker for marking where to store metadata.
/// </summary>
public const byte APP1 = 0xe1;
/// <summary>
/// Application specific marker for marking where to store ICC profile information.
/// </summary>
public const byte APP2 = 0xe2;
/// <summary>
/// Application specific marker used by Adobe for storing encoding information for DCT filters.
/// </summary>
public const byte APP14 = 0xee;
/// <summary>
/// Application specific marker used by GraphicConverter to store JPEG quality.
/// </summary>
public const byte APP15 = 0xef;
}
/// <summary>
/// Describes Adobe specific markers <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe"/>
/// </summary>
internal static class Adobe
{
/// <summary>
/// The color transform is unknown.(RGB or CMYK)
/// </summary>
public const int ColorTransformUnknown = 0;
/// <summary>
/// The color transform is YCbCr (luminance, red chroma, blue chroma)
/// </summary>
public const int ColorTransformYCbCr = 1;
/// <summary>
/// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
/// </summary>
public const int ColorTransformYcck = 2;
}
}
}

69
src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegConstants.cs → src/ImageSharp/Formats/Jpeg/JpegConstants.cs

@ -1,23 +1,45 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
/// <summary> /// <summary>
/// Contains jpeg constant values /// Contains jpeg constant values defined in the specification.
/// </summary> /// </summary>
internal static class PdfJsJpegConstants internal static class JpegConstants
{ {
/// <summary>
/// The maximum allowable length in each dimension of a jpeg image.
/// </summary>
public const ushort MaxLength = 65535;
/// <summary>
/// The list of mimetypes that equate to a jpeg.
/// </summary>
public static readonly IEnumerable<string> MimeTypes = new[] { "image/jpeg", "image/pjpeg" };
/// <summary>
/// The list of file extensions that equate to a jpeg.
/// </summary>
public static readonly IEnumerable<string> FileExtensions = new[] { "jpg", "jpeg", "jfif" };
/// <summary> /// <summary>
/// Contains marker specific constants /// Contains marker specific constants
/// </summary> /// </summary>
public static class Markers // ReSharper disable InconsistentNaming
internal static class Markers
{ {
/// <summary> /// <summary>
/// The prefix used for all markers. /// The prefix used for all markers.
/// </summary> /// </summary>
public const byte Prefix = 0xFF; public const byte XFF = 0xFF;
/// <summary>
/// Same as <see cref="XFF"/> but of type <see cref="int"/>
/// </summary>
public const int XFFInt = XFF;
/// <summary> /// <summary>
/// The Start of Image marker /// The Start of Image marker
@ -161,7 +183,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// <summary> /// <summary>
/// Define Restart Interval /// Define Restart Interval
/// <remarks> /// <remarks>
/// Specifies the interval between RSTn markers, in macroblocks.This marker is followed by two bytes indicating the fixed size so it can be treated like any other variable size segment. /// Specifies the interval between RSTn markers, in macroblocks.This marker is followed by two bytes indicating the fixed size so
/// it can be treated like any other variable size segment.
/// </remarks> /// </remarks>
/// </summary> /// </summary>
public const byte DRI = 0xDD; public const byte DRI = 0xDD;
@ -193,27 +216,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// </remarks> /// </remarks>
/// </summary> /// </summary>
public const byte RST7 = 0xD7; public const byte RST7 = 0xD7;
}
/// <summary>
/// Contains Adobe specific constants
/// </summary>
internal static class Adobe
{
/// <summary> /// <summary>
/// Contains Adobe specific markers /// The color transform is unknown.(RGB or CMYK)
/// </summary> /// </summary>
public static class Adobe public const byte ColorTransformUnknown = 0;
{
/// <summary>
/// The color transform is unknown.(RGB or CMYK)
/// </summary>
public const byte ColorTransformUnknown = 0;
/// <summary> /// <summary>
/// The color transform is YCbCr (luminance, red chroma, blue chroma) /// The color transform is YCbCr (luminance, red chroma, blue chroma)
/// </summary> /// </summary>
public const byte ColorTransformYCbCr = 1; public const byte ColorTransformYCbCr = 1;
/// <summary> /// <summary>
/// The color transform is YCCK (luminance, red chroma, blue chroma, keyline) /// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
/// </summary> /// </summary>
public const byte ColorTransformYcck = 2; public const byte ColorTransformYcck = 2;
}
} }
} }
} }

6
src/ImageSharp/Formats/Jpeg/JpegDecoder.cs

@ -3,7 +3,7 @@
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg namespace SixLabors.ImageSharp.Formats.Jpeg
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
using (var decoder = new OrigJpegDecoderCore(configuration, this)) using (var decoder = new PdfJsJpegDecoderCore(configuration, this))
{ {
return decoder.Decode<TPixel>(stream); return decoder.Decode<TPixel>(stream);
} }
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
Guard.NotNull(stream, "stream"); Guard.NotNull(stream, "stream");
using (var decoder = new OrigJpegDecoderCore(configuration, this)) using (var decoder = new PdfJsJpegDecoderCore(configuration, this))
{ {
return decoder.Identify(stream); return decoder.Identify(stream);
} }

1
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg namespace SixLabors.ImageSharp.Formats.Jpeg

74
src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs → src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -1,19 +1,16 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Buffers;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc; using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
/// <summary> /// <summary>
/// Image encoder for writing an image to a stream as a jpeg. /// Image encoder for writing an image to a stream as a jpeg.
@ -58,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </summary> /// </summary>
private static readonly byte[] SosHeaderYCbCr = private static readonly byte[] SosHeaderYCbCr =
{ {
OrigJpegConstants.Markers.XFF, OrigJpegConstants.Markers.SOS, JpegConstants.Markers.XFF, JpegConstants.Markers.SOS,
// Marker // Marker
0x00, 0x0c, 0x00, 0x0c,
@ -104,11 +101,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
}; };
/// <summary>
/// Lookup tables for converting Rgb to YCbCr
/// </summary>
private static RgbToYCbCrTables rgbToYCbCrTables = RgbToYCbCrTables.Create();
/// <summary> /// <summary>
/// A scratch buffer to reduce allocations. /// A scratch buffer to reduce allocations.
/// </summary> /// </summary>
@ -190,7 +182,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
ushort max = OrigJpegConstants.MaxLength; ushort max = JpegConstants.MaxLength;
if (image.Width >= max || image.Height >= max) if (image.Width >= max || image.Height >= max)
{ {
throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}."); throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}.");
@ -234,8 +226,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.WriteStartOfScan(image); this.WriteStartOfScan(image);
// Write the End Of Image marker. // Write the End Of Image marker.
this.buffer[0] = OrigJpegConstants.Markers.XFF; this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.EOI; this.buffer[1] = JpegConstants.Markers.EOI;
stream.Write(this.buffer, 0, 2); stream.Write(this.buffer, 0, 2);
stream.Flush(); stream.Flush();
} }
@ -382,18 +374,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{ {
// TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
// (Partially done with YCbCrForwardConverter<TPixel>) // (Partially done with YCbCrForwardConverter<TPixel>)
Block8x8F temp1 = default(Block8x8F); Block8x8F temp1 = default;
Block8x8F temp2 = default(Block8x8F); Block8x8F temp2 = default;
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable; Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable; Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
ZigZag unzig = ZigZag.CreateUnzigTable(); var unzig = ZigZag.CreateUnzigTable();
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;
YCbCrForwardConverter<TPixel> pixelConverter = YCbCrForwardConverter<TPixel>.Create(); var pixelConverter = YCbCrForwardConverter<TPixel>.Create();
for (int y = 0; y < pixels.Height; y += 8) for (int y = 0; y < pixels.Height; y += 8)
{ {
@ -437,12 +429,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void WriteApplicationHeader(short horizontalResolution, short verticalResolution) private void WriteApplicationHeader(short horizontalResolution, short verticalResolution)
{ {
// Write the start of image marker. Markers are always prefixed with with 0xff. // Write the start of image marker. Markers are always prefixed with with 0xff.
this.buffer[0] = OrigJpegConstants.Markers.XFF; this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.SOI; this.buffer[1] = JpegConstants.Markers.SOI;
// Write the JFIF headers // Write the JFIF headers
this.buffer[2] = OrigJpegConstants.Markers.XFF; this.buffer[2] = JpegConstants.Markers.XFF;
this.buffer[3] = OrigJpegConstants.Markers.APP0; // Application Marker this.buffer[3] = JpegConstants.Markers.APP0; // Application Marker
this.buffer[4] = 0x00; this.buffer[4] = 0x00;
this.buffer[5] = 0x10; this.buffer[5] = 0x10;
this.buffer[6] = 0x4a; // J this.buffer[6] = 0x4a; // J
@ -502,7 +494,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC); this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC);
// Emit the AC components. // Emit the AC components.
HuffIndex h = (HuffIndex)((2 * (int)index) + 1); var h = (HuffIndex)((2 * (int)index) + 1);
int runLength = 0; int runLength = 0;
for (int zig = 1; zig < Block8x8F.Size; zig++) for (int zig = 1; zig < Block8x8F.Size; zig++)
@ -556,7 +548,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
markerlen += 1 + 16 + s.Values.Length; markerlen += 1 + 16 + s.Values.Length;
} }
this.WriteMarkerHeader(OrigJpegConstants.Markers.DHT, markerlen); this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen);
for (int i = 0; i < specs.Length; i++) for (int i = 0; i < specs.Length; i++)
{ {
HuffmanSpec spec = specs[i]; HuffmanSpec spec = specs[i];
@ -590,7 +582,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{ {
// Marker + quantization table lengths // Marker + quantization table lengths
int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.Size)); int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.Size));
this.WriteMarkerHeader(OrigJpegConstants.Markers.DQT, markerlen); this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen);
// Loop through and collect the tables as one array. // Loop through and collect the tables as one array.
// This allows us to reduce the number of writes to the stream. // This allows us to reduce the number of writes to the stream.
@ -627,8 +619,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
int length = data.Length + 2; int length = data.Length + 2;
this.buffer[0] = OrigJpegConstants.Markers.XFF; this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.APP1; // Application Marker this.buffer[1] = JpegConstants.Markers.APP1; // Application Marker
this.buffer[2] = (byte)((length >> 8) & 0xFF); this.buffer[2] = (byte)((length >> 8) & 0xFF);
this.buffer[3] = (byte)(length & 0xFF); this.buffer[3] = (byte)(length & 0xFF);
@ -686,8 +678,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
dataLength -= length; dataLength -= length;
this.buffer[0] = OrigJpegConstants.Markers.XFF; this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.APP2; // Application Marker this.buffer[1] = JpegConstants.Markers.APP2; // Application Marker
int markerLength = length + 16; int markerLength = length + 16;
this.buffer[2] = (byte)((markerLength >> 8) & 0xFF); this.buffer[2] = (byte)((markerLength >> 8) & 0xFF);
this.buffer[3] = (byte)(markerLength & 0xFF); this.buffer[3] = (byte)(markerLength & 0xFF);
@ -759,7 +751,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
// Length (high byte, low byte), 8 + components * 3. // Length (high byte, low byte), 8 + components * 3.
int markerlen = 8 + (3 * componentCount); int markerlen = 8 + (3 * componentCount);
this.WriteMarkerHeader(OrigJpegConstants.Markers.SOF0, markerlen); this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen);
this.buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported this.buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported
this.buffer[1] = (byte)(height >> 8); this.buffer[1] = (byte)(height >> 8);
this.buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported this.buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
@ -827,20 +819,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
// TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
Block8x8F b = default(Block8x8F); Block8x8F b = default;
BlockQuad cb = default(BlockQuad); BlockQuad cb = default;
BlockQuad cr = default(BlockQuad); BlockQuad cr = default;
Block8x8F* cbPtr = (Block8x8F*)cb.Data; var cbPtr = (Block8x8F*)cb.Data;
Block8x8F* crPtr = (Block8x8F*)cr.Data; var crPtr = (Block8x8F*)cr.Data;
Block8x8F temp1 = default(Block8x8F); Block8x8F temp1 = default;
Block8x8F temp2 = default(Block8x8F); Block8x8F temp2 = default;
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable; Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable; Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
ZigZag unzig = ZigZag.CreateUnzigTable(); var unzig = ZigZag.CreateUnzigTable();
var pixelConverter = YCbCrForwardConverter<TPixel>.Create(); var pixelConverter = YCbCrForwardConverter<TPixel>.Create();
@ -902,7 +894,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void WriteMarkerHeader(byte marker, int length) private void WriteMarkerHeader(byte marker, int length)
{ {
// Markers are always prefixed with with 0xff. // Markers are always prefixed with with 0xff.
this.buffer[0] = OrigJpegConstants.Markers.XFF; this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = marker; this.buffer[1] = marker;
this.buffer[2] = (byte)(length >> 8); this.buffer[2] = (byte)(length >> 8);
this.buffer[3] = (byte)(length & 0xff); this.buffer[3] = (byte)(length & 0xff);

5
src/ImageSharp/Formats/Jpeg/JpegFormat.cs

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Collections.Generic; using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
namespace SixLabors.ImageSharp.Formats.Jpeg namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
@ -18,9 +17,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public string DefaultMimeType => "image/jpeg"; public string DefaultMimeType => "image/jpeg";
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> MimeTypes => OrigJpegConstants.MimeTypes; public IEnumerable<string> MimeTypes => JpegConstants.MimeTypes;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> FileExtensions => OrigJpegConstants.FileExtensions; public IEnumerable<string> FileExtensions => JpegConstants.FileExtensions;
} }
} }

9
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs

@ -4,8 +4,9 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -36,9 +37,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
public byte Id { get; } public byte Id { get; }
/// <summary> /// <summary>
/// Gets or sets Pred TODO: What does pred stand for? /// Gets or sets DC coefficient predictor
/// </summary> /// </summary>
public int Pred { get; set; } public int DcPredictor { get; set; }
/// <summary> /// <summary>
/// Gets the horizontal sampling factor. /// Gets the horizontal sampling factor.

13
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs

@ -7,7 +7,8 @@ using System.Diagnostics;
#endif #endif
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{ {
@ -107,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < components.Length; i++) for (int i = 0; i < components.Length; i++)
{ {
PdfJsFrameComponent c = components[i]; PdfJsFrameComponent c = components[i];
c.Pred = 0; c.DcPredictor = 0;
} }
this.eobrun = 0; this.eobrun = 0;
@ -136,7 +137,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
byte marker = fileMarker.Marker; byte marker = fileMarker.Marker;
// RSTn - We've already read the bytes and altered the position so no need to skip // RSTn - We've already read the bytes and altered the position so no need to skip
if (marker >= PdfJsJpegConstants.Markers.RST0 && marker <= PdfJsJpegConstants.Markers.RST7) if (marker >= JpegConstants.Markers.RST0 && marker <= JpegConstants.Markers.RST7)
{ {
continue; continue;
} }
@ -452,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
this.endOfStreamReached = true; this.endOfStreamReached = true;
return false; return false;
case PdfJsJpegConstants.Markers.Prefix: case JpegConstants.Markers.XFF:
int nextByte = stream.ReadByte(); int nextByte = stream.ReadByte();
if (nextByte == -0x1) if (nextByte == -0x1)
@ -618,7 +619,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
} }
} }
Unsafe.Add(ref blockDataRef, offset) = (short)(component.Pred += diff); Unsafe.Add(ref blockDataRef, offset) = (short)(component.DcPredictor += diff);
int k = 1; int k = 1;
while (k < 64) while (k < 64)
@ -673,7 +674,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
} }
} }
Unsafe.Add(ref blockDataRef, offset) = (short)(component.Pred += diff << this.successiveState); Unsafe.Add(ref blockDataRef, offset) = (short)(component.DcPredictor += diff << this.successiveState);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

149
src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs

@ -7,8 +7,9 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components; using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
@ -93,15 +94,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// </summary> /// </summary>
public PdfJsFrame Frame { get; private set; } public PdfJsFrame Frame { get; private set; }
/// <inheritdoc/>
public Size ImageSizeInPixels { get; private set; }
/// <summary>
/// Gets the number of MCU blocks in the image as <see cref="Size"/>.
/// </summary>
public Size ImageSizeInMCU { get; private set; }
/// <summary> /// <summary>
/// Gets the image width /// Gets the image width
/// </summary> /// </summary>
public int ImageWidth { get; private set; } public int ImageWidth => this.ImageSizeInPixels.Width;
/// <summary> /// <summary>
/// Gets the image height /// Gets the image height
/// </summary> /// </summary>
public int ImageHeight { get; private set; } public int ImageHeight => this.ImageSizeInPixels.Height;
/// <summary> /// <summary>
/// Gets the color depth, in number of bits per pixel. /// Gets the color depth, in number of bits per pixel.
@ -123,17 +132,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// </summary> /// </summary>
public ImageMetaData MetaData { get; private set; } public ImageMetaData MetaData { get; private set; }
/// <inheritdoc/>
public Size ImageSizeInPixels => new Size(this.ImageWidth, this.ImageHeight);
/// <inheritdoc/> /// <inheritdoc/>
public int ComponentCount { get; private set; } public int ComponentCount { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>
public JpegColorSpace ColorSpace { get; private set; } public JpegColorSpace ColorSpace { get; private set; }
/// <summary>
/// Gets the components.
/// </summary>
public PdfJsFrameComponent[] Components => this.Frame.Components;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<IJpegComponent> Components => this.Frame.Components; IEnumerable<IJpegComponent> IRawJpegData.Components => this.Components;
/// <inheritdoc/> /// <inheritdoc/>
public Block8x8F[] QuantizationTables { get; private set; } public Block8x8F[] QuantizationTables { get; private set; }
@ -150,20 +161,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
if (value == 0) if (value == 0)
{ {
return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, stream.Length - 2); return new PdfJsFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
} }
if (marker[0] == PdfJsJpegConstants.Markers.Prefix) if (marker[0] == JpegConstants.Markers.XFF)
{ {
// According to Section B.1.1.2: // According to Section B.1.1.2:
// "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code 0xFF." // "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code 0xFF."
int m = marker[1]; int m = marker[1];
while (m == PdfJsJpegConstants.Markers.Prefix) while (m == JpegConstants.Markers.XFF)
{ {
int suffix = stream.ReadByte(); int suffix = stream.ReadByte();
if (suffix == -1) if (suffix == -1)
{ {
return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, stream.Length - 2); return new PdfJsFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
} }
m = suffix; m = suffix;
@ -213,7 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
// Check for the Start Of Image marker. // Check for the Start Of Image marker.
this.InputStream.Read(this.markerBuffer, 0, 2); this.InputStream.Read(this.markerBuffer, 0, 2);
var fileMarker = new PdfJsFileMarker(this.markerBuffer[1], 0); var fileMarker = new PdfJsFileMarker(this.markerBuffer[1], 0);
if (fileMarker.Marker != PdfJsJpegConstants.Markers.SOI) if (fileMarker.Marker != JpegConstants.Markers.SOI)
{ {
throw new ImageFormatException("Missing SOI marker."); throw new ImageFormatException("Missing SOI marker.");
} }
@ -230,7 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.acHuffmanTables = new PdfJsHuffmanTables(); this.acHuffmanTables = new PdfJsHuffmanTables();
} }
while (fileMarker.Marker != PdfJsJpegConstants.Markers.EOI) while (fileMarker.Marker != JpegConstants.Markers.EOI)
{ {
if (!fileMarker.Invalid) if (!fileMarker.Invalid)
{ {
@ -239,13 +250,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
switch (fileMarker.Marker) switch (fileMarker.Marker)
{ {
case PdfJsJpegConstants.Markers.SOF0: case JpegConstants.Markers.SOF0:
case PdfJsJpegConstants.Markers.SOF1: case JpegConstants.Markers.SOF1:
case PdfJsJpegConstants.Markers.SOF2: case JpegConstants.Markers.SOF2:
this.ProcessStartOfFrameMarker(remaining, fileMarker, metadataOnly); this.ProcessStartOfFrameMarker(remaining, fileMarker, metadataOnly);
break; break;
case PdfJsJpegConstants.Markers.SOS: case JpegConstants.Markers.SOS:
if (!metadataOnly) if (!metadataOnly)
{ {
this.ProcessStartOfScanMarker(); this.ProcessStartOfScanMarker();
@ -258,7 +269,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
return; return;
} }
case PdfJsJpegConstants.Markers.DHT: case JpegConstants.Markers.DHT:
if (metadataOnly) if (metadataOnly)
{ {
this.InputStream.Skip(remaining); this.InputStream.Skip(remaining);
@ -270,7 +281,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
break; break;
case PdfJsJpegConstants.Markers.DQT: case JpegConstants.Markers.DQT:
if (metadataOnly) if (metadataOnly)
{ {
this.InputStream.Skip(remaining); this.InputStream.Skip(remaining);
@ -282,7 +293,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
break; break;
case PdfJsJpegConstants.Markers.DRI: case JpegConstants.Markers.DRI:
if (metadataOnly) if (metadataOnly)
{ {
this.InputStream.Skip(remaining); this.InputStream.Skip(remaining);
@ -294,38 +305,38 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
break; break;
case PdfJsJpegConstants.Markers.APP0: case JpegConstants.Markers.APP0:
this.ProcessApplicationHeaderMarker(remaining); this.ProcessApplicationHeaderMarker(remaining);
break; break;
case PdfJsJpegConstants.Markers.APP1: case JpegConstants.Markers.APP1:
this.ProcessApp1Marker(remaining); this.ProcessApp1Marker(remaining);
break; break;
case PdfJsJpegConstants.Markers.APP2: case JpegConstants.Markers.APP2:
this.ProcessApp2Marker(remaining); this.ProcessApp2Marker(remaining);
break; break;
case PdfJsJpegConstants.Markers.APP3: case JpegConstants.Markers.APP3:
case PdfJsJpegConstants.Markers.APP4: case JpegConstants.Markers.APP4:
case PdfJsJpegConstants.Markers.APP5: case JpegConstants.Markers.APP5:
case PdfJsJpegConstants.Markers.APP6: case JpegConstants.Markers.APP6:
case PdfJsJpegConstants.Markers.APP7: case JpegConstants.Markers.APP7:
case PdfJsJpegConstants.Markers.APP8: case JpegConstants.Markers.APP8:
case PdfJsJpegConstants.Markers.APP9: case JpegConstants.Markers.APP9:
case PdfJsJpegConstants.Markers.APP10: case JpegConstants.Markers.APP10:
case PdfJsJpegConstants.Markers.APP11: case JpegConstants.Markers.APP11:
case PdfJsJpegConstants.Markers.APP12: case JpegConstants.Markers.APP12:
case PdfJsJpegConstants.Markers.APP13: case JpegConstants.Markers.APP13:
this.InputStream.Skip(remaining); this.InputStream.Skip(remaining);
break; break;
case PdfJsJpegConstants.Markers.APP14: case JpegConstants.Markers.APP14:
this.ProcessApp14Marker(remaining); this.ProcessApp14Marker(remaining);
break; break;
case PdfJsJpegConstants.Markers.APP15: case JpegConstants.Markers.APP15:
case PdfJsJpegConstants.Markers.COM: case JpegConstants.Markers.COM:
this.InputStream.Skip(remaining); this.InputStream.Skip(remaining);
break; break;
} }
@ -362,11 +373,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
if (this.ComponentCount == 3) if (this.ComponentCount == 3)
{ {
if (this.adobe.Equals(default) || this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformYCbCr) if (this.adobe.Equals(default) || this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
{ {
return JpegColorSpace.YCbCr; return JpegColorSpace.YCbCr;
} }
else if (this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformUnknown)
if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{ {
return JpegColorSpace.RGB; return JpegColorSpace.RGB;
} }
@ -374,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
if (this.ComponentCount == 4) if (this.ComponentCount == 4)
{ {
return this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformYcck return this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck
? JpegColorSpace.Ycck ? JpegColorSpace.Ycck
: JpegColorSpace.Cmyk; : JpegColorSpace.Cmyk;
} }
@ -387,9 +399,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// </summary> /// </summary>
private void AssignResolution() private void AssignResolution()
{ {
this.ImageWidth = this.Frame.SamplesPerLine;
this.ImageHeight = this.Frame.Scanlines;
if (this.jFif.XDensity > 0 && this.jFif.YDensity > 0) if (this.jFif.XDensity > 0 && this.jFif.YDensity > 0)
{ {
this.MetaData.HorizontalResolution = this.jFif.XDensity; this.MetaData.HorizontalResolution = this.jFif.XDensity;
@ -622,59 +631,58 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.Frame = new PdfJsFrame this.Frame = new PdfJsFrame
{ {
Extended = frameMarker.Marker == PdfJsJpegConstants.Markers.SOF1, Extended = frameMarker.Marker == JpegConstants.Markers.SOF1,
Progressive = frameMarker.Marker == PdfJsJpegConstants.Markers.SOF2, Progressive = frameMarker.Marker == JpegConstants.Markers.SOF2,
Precision = this.temp[0], Precision = this.temp[0],
Scanlines = (short)((this.temp[1] << 8) | this.temp[2]), Scanlines = (short)((this.temp[1] << 8) | this.temp[2]),
SamplesPerLine = (short)((this.temp[3] << 8) | this.temp[4]), SamplesPerLine = (short)((this.temp[3] << 8) | this.temp[4]),
ComponentCount = this.temp[5] ComponentCount = this.temp[5]
}; };
this.ImageSizeInPixels = new Size(this.Frame.SamplesPerLine, this.Frame.Scanlines);
int maxH = 0; int maxH = 0;
int maxV = 0; int maxV = 0;
int index = 6; int index = 6;
this.ComponentCount = this.Frame.ComponentCount; this.ComponentCount = this.Frame.ComponentCount;
if (!metadataOnly) if (!metadataOnly)
{ {
// No need to pool this. They max out at 4 // No need to pool this. They max out at 4
this.Frame.ComponentIds = new byte[this.Frame.ComponentCount]; this.Frame.ComponentIds = new byte[this.Frame.ComponentCount];
this.Frame.Components = new PdfJsFrameComponent[this.Frame.ComponentCount]; this.Frame.Components = new PdfJsFrameComponent[this.Frame.ComponentCount];
} this.ColorSpace = this.DeduceJpegColorSpace();
for (int i = 0; i < this.Frame.ComponentCount; i++) for (int i = 0; i < this.Frame.ComponentCount; i++)
{
byte hv = this.temp[index + 1];
int h = hv >> 4;
int v = hv & 15;
if (maxH < h)
{ {
maxH = h; byte hv = this.temp[index + 1];
} int h = hv >> 4;
int v = hv & 15;
if (maxV < v) if (maxH < h)
{ {
maxV = v; maxH = h;
} }
if (maxV < v)
{
maxV = v;
}
if (!metadataOnly)
{
var component = new PdfJsFrameComponent(this.configuration.MemoryManager, this.Frame, this.temp[index], h, v, this.temp[index + 2], i); var component = new PdfJsFrameComponent(this.configuration.MemoryManager, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
this.Frame.Components[i] = component; this.Frame.Components[i] = component;
this.Frame.ComponentIds[i] = component.Id; this.Frame.ComponentIds[i] = component.Id;
}
index += 3;
}
this.Frame.MaxHorizontalFactor = maxH; index += 3;
this.Frame.MaxVerticalFactor = maxV; }
if (!metadataOnly) this.Frame.MaxHorizontalFactor = maxH;
{ this.Frame.MaxVerticalFactor = maxV;
this.ColorSpace = this.DeduceJpegColorSpace();
this.Frame.InitComponents(); this.Frame.InitComponents();
this.ImageSizeInMCU = new Size(this.Frame.McusPerLine, this.Frame.McusPerColumn);
} }
} }
@ -821,7 +829,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
private Image<TPixel> PostProcessIntoImage<TPixel>() private Image<TPixel> PostProcessIntoImage<TPixel>()
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
this.ColorSpace = this.DeduceJpegColorSpace();
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this)) using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this))
{ {
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);

11
src/ImageSharp/ImageSharp.csproj

@ -57,11 +57,11 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Update="Formats\Jpeg\Common\Block8x8F.Generated.tt"> <None Update="Formats\Jpeg\Components\Block8x8F.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator> <Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput> <LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</None> </None>
<None Update="Formats\Jpeg\Common\GenericBlock8x8.Generated.tt"> <None Update="Formats\Jpeg\Components\GenericBlock8x8.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator> <Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>GenericBlock8x8.Generated.cs</LastGenOutput> <LastGenOutput>GenericBlock8x8.Generated.cs</LastGenOutput>
</None> </None>
@ -87,12 +87,12 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Formats\Jpeg\Common\Block8x8F.Generated.cs"> <Compile Update="Formats\Jpeg\Components\Block8x8F.Generated.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon> <DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile> </Compile>
<Compile Update="Formats\Jpeg\Common\GenericBlock8x8.Generated.cs"> <Compile Update="Formats\Jpeg\Components\GenericBlock8x8.Generated.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>GenericBlock8x8.Generated.tt</DependentUpon> <DependentUpon>GenericBlock8x8.Generated.tt</DependentUpon>
@ -123,4 +123,7 @@
<DependentUpon>PorterDuffFunctions.Generated.tt</DependentUpon> <DependentUpon>PorterDuffFunctions.Generated.tt</DependentUpon>
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
</Project> </Project>

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);
} }

12
tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs

@ -1,14 +1,14 @@
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using System; using System;
using System.Numerics; using System.Numerics;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortClr))]
public class YCbCrColorConversion public class YCbCrColorConversion
{ {
@ -57,7 +57,7 @@
JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output); JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output);
} }
private static Buffer2D<float>[] CreateRandomValues( private static Buffer2D<float>[] CreateRandomValues(
int componentCount, int componentCount,
int inputBufferLength, int inputBufferLength,
@ -81,6 +81,6 @@
return buffers; return buffers;
} }
} }
} }

17
tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs

@ -1,13 +1,12 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks namespace SixLabors.ImageSharp.Benchmarks
{ {
@ -104,14 +103,14 @@ namespace SixLabors.ImageSharp.Benchmarks
} }
} }
} }
public struct Result public struct Result
{ {
internal Block8x8F Y; internal Block8x8F Y;
internal Block8x8F Cb; internal Block8x8F Cb;
internal Block8x8F Cr; internal Block8x8F Cr;
} }
// The operation is defined as "RGBA -> YCbCr Transform a stream of bytes into a stream of floats" // The operation is defined as "RGBA -> YCbCr Transform a stream of bytes into a stream of floats"
// We need to benchmark the whole operation, to get true results, not missing any side effects! // We need to benchmark the whole operation, to get true results, not missing any side effects!
private byte[] inputSourceRGB = null; private byte[] inputSourceRGB = null;
@ -200,11 +199,11 @@ namespace SixLabors.ImageSharp.Benchmarks
float* cbPtr = (float*)&result.Cb; float* cbPtr = (float*)&result.Cb;
float* crPtr = (float*)&result.Cr; float* crPtr = (float*)&result.Cr;
// end of code-bloat block :) // end of code-bloat block :)
Vector<int> yCoeffs = new Vector<int>(ScaledCoeffs.Y); Vector<int> yCoeffs = new Vector<int>(ScaledCoeffs.Y);
Vector<int> cbCoeffs = new Vector<int>(ScaledCoeffs.Cb); Vector<int> cbCoeffs = new Vector<int>(ScaledCoeffs.Cb);
Vector<int> crCoeffs = new Vector<int>(ScaledCoeffs.Cr); Vector<int> crCoeffs = new Vector<int>(ScaledCoeffs.Cr);
for (int i = 0; i < this.inputSourceRGB.Length; i++) for (int i = 0; i < this.inputSourceRGB.Length; i++)
{ {
this.inputSourceRGBAsInteger[i] = this.inputSourceRGB[i]; this.inputSourceRGBAsInteger[i] = this.inputSourceRGB[i];
@ -217,7 +216,7 @@ namespace SixLabors.ImageSharp.Benchmarks
Vector<int> y = yCoeffs * rgb; Vector<int> y = yCoeffs * rgb;
Vector<int> cb = cbCoeffs * rgb; Vector<int> cb = cbCoeffs * rgb;
Vector<int> cr = crCoeffs * rgb; Vector<int> cr = crCoeffs * rgb;
*yPtr++ = (y[0] + y[1] + y[2]) >> 10; *yPtr++ = (y[0] + y[1] + y[2]) >> 10;
*cbPtr++ = 128 + ((cb[0] - cb[1] + cb[2]) >> 10); *cbPtr++ = 128 + ((cb[0] - cb[1] + cb[2]) >> 10);
*crPtr++ = 128 + ((cr[0] - cr[1] - cr[2]) >> 10); *crPtr++ = 128 + ((cr[0] - cr[1] - cr[2]) >> 10);
@ -335,7 +334,7 @@ namespace SixLabors.ImageSharp.Benchmarks
*crPtr++ = 128 + ((cr0 - cr1 - cr2) >> 10); *crPtr++ = 128 + ((cr0 - cr1 - cr2) >> 10);
} }
} }
[Benchmark(Description = "Scaled Integer LUT Conversion")] [Benchmark(Description = "Scaled Integer LUT Conversion")]
public unsafe void RgbaToYcbCrScaledIntegerLut() public unsafe void RgbaToYcbCrScaledIntegerLut()
{ {

4
tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs

@ -5,7 +5,9 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.General namespace SixLabors.ImageSharp.Benchmarks.General

3
tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs

@ -6,8 +6,7 @@ using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
namespace SixLabors.ImageSharp.Benchmarks.General namespace SixLabors.ImageSharp.Benchmarks.General
{ {

28
tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit; using Xunit;
@ -25,29 +25,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerReturnsCorrectParsedValue() public void MarkerReturnsCorrectParsedValue()
{ {
bool isAdobe = AdobeMarker.TryParse(this.bytes, out var marker); bool isAdobe = AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
Assert.True(isAdobe); Assert.True(isAdobe);
Assert.Equal(100, marker.DCTEncodeVersion); Assert.Equal(100, marker.DCTEncodeVersion);
Assert.Equal(0, marker.APP14Flags0); Assert.Equal(0, marker.APP14Flags0);
Assert.Equal(0, marker.APP14Flags1); Assert.Equal(0, marker.APP14Flags1);
Assert.Equal(OrigJpegConstants.Adobe.ColorTransformYcck, marker.ColorTransform); Assert.Equal(JpegConstants.Adobe.ColorTransformYcck, marker.ColorTransform);
} }
[Fact] [Fact]
public void MarkerIgnoresIncorrectValue() public void MarkerIgnoresIncorrectValue()
{ {
bool isAdobe = AdobeMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out var marker); bool isAdobe = AdobeMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out AdobeMarker marker);
Assert.False(isAdobe); Assert.False(isAdobe);
Assert.Equal(default(AdobeMarker), marker); Assert.Equal(default, marker);
} }
[Fact] [Fact]
public void MarkerEqualityIsCorrect() public void MarkerEqualityIsCorrect()
{ {
AdobeMarker.TryParse(this.bytes, out var marker); AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes, out var marker2); AdobeMarker.TryParse(this.bytes, out AdobeMarker marker2);
Assert.True(marker.Equals(marker2)); Assert.True(marker.Equals(marker2));
} }
@ -55,8 +55,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerInEqualityIsCorrect() public void MarkerInEqualityIsCorrect()
{ {
AdobeMarker.TryParse(this.bytes, out var marker); AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes2, out var marker2); AdobeMarker.TryParse(this.bytes2, out AdobeMarker marker2);
Assert.False(marker.Equals(marker2)); Assert.False(marker.Equals(marker2));
} }
@ -64,8 +64,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerHashCodeIsReplicable() public void MarkerHashCodeIsReplicable()
{ {
AdobeMarker.TryParse(this.bytes, out var marker); AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes, out var marker2); AdobeMarker.TryParse(this.bytes, out AdobeMarker marker2);
Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode())); Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode()));
} }
@ -73,8 +73,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerHashCodeIsUnique() public void MarkerHashCodeIsUnique()
{ {
AdobeMarker.TryParse(this.bytes, out var marker); AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes2, out var marker2); AdobeMarker.TryParse(this.bytes2, out AdobeMarker marker2);
Assert.False(marker.GetHashCode().Equals(marker2.GetHashCode())); Assert.False(marker.GetHashCode().Equals(marker2.GetHashCode()));
} }

2
tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs

@ -4,7 +4,7 @@
// Uncomment this to turn unit tests into benchmarks: // Uncomment this to turn unit tests into benchmarks:
//#define BENCHMARKING //#define BENCHMARKING
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.Primitives; using SixLabors.Primitives;

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

@ -7,7 +7,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit; using Xunit;

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

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit; using Xunit;

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

@ -1,7 +1,7 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
using System; using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit; using Xunit;
@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var temp = default(Block8x8F); var temp = default(Block8x8F);
var actual = default(Block8x8F); var actual = default(Block8x8F);
FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp); FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
this.CompareBlocks(expected, actual, 1f); this.CompareBlocks(expected, actual, 1f);
} }

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

@ -3,7 +3,7 @@
using System; using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using Xunit; using Xunit;

28
tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit; using Xunit;
@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerReturnsCorrectParsedValue() public void MarkerReturnsCorrectParsedValue()
{ {
bool isJFif = JFifMarker.TryParse(this.bytes, out var marker); bool isJFif = JFifMarker.TryParse(this.bytes, out JFifMarker marker);
Assert.True(isJFif); Assert.True(isJFif);
Assert.Equal(1, marker.MajorVersion); Assert.Equal(1, marker.MajorVersion);
@ -40,26 +40,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerIgnoresIncorrectValue() public void MarkerIgnoresIncorrectValue()
{ {
bool isJFif = JFifMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out var marker); bool isJFif = JFifMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out JFifMarker marker);
Assert.False(isJFif); Assert.False(isJFif);
Assert.Equal(default(JFifMarker), marker); Assert.Equal(default, marker);
} }
[Fact] [Fact]
public void MarkerIgnoresCorrectHeaderButInvalidDensities() public void MarkerIgnoresCorrectHeaderButInvalidDensities()
{ {
bool isJFif = JFifMarker.TryParse(this.bytes3, out var marker); bool isJFif = JFifMarker.TryParse(this.bytes3, out JFifMarker marker);
Assert.False(isJFif); Assert.False(isJFif);
Assert.Equal(default(JFifMarker), marker); Assert.Equal(default, marker);
} }
[Fact] [Fact]
public void MarkerEqualityIsCorrect() public void MarkerEqualityIsCorrect()
{ {
JFifMarker.TryParse(this.bytes, out var marker); JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes, out var marker2); JFifMarker.TryParse(this.bytes, out JFifMarker marker2);
Assert.True(marker.Equals(marker2)); Assert.True(marker.Equals(marker2));
} }
@ -67,8 +67,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerInEqualityIsCorrect() public void MarkerInEqualityIsCorrect()
{ {
JFifMarker.TryParse(this.bytes, out var marker); JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes2, out var marker2); JFifMarker.TryParse(this.bytes2, out JFifMarker marker2);
Assert.False(marker.Equals(marker2)); Assert.False(marker.Equals(marker2));
} }
@ -76,8 +76,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerHashCodeIsReplicable() public void MarkerHashCodeIsReplicable()
{ {
JFifMarker.TryParse(this.bytes, out var marker); JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes, out var marker2); JFifMarker.TryParse(this.bytes, out JFifMarker marker2);
Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode())); Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode()));
} }
@ -85,8 +85,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact] [Fact]
public void MarkerHashCodeIsUnique() public void MarkerHashCodeIsUnique()
{ {
JFifMarker.TryParse(this.bytes, out var marker); JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes2, out var marker2); JFifMarker.TryParse(this.bytes2, out JFifMarker marker2);
Assert.False(marker.GetHashCode().Equals(marker2.GetHashCode())); Assert.False(marker.GetHashCode().Equals(marker2.GetHashCode()));
} }

18
tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

@ -6,8 +6,8 @@ using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using Xunit; using Xunit;
@ -140,13 +140,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter converter = simd ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimd() : new JpegColorConverter.FromYCbCrBasic(); JpegColorConverter converter = simd ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimd() : new JpegColorConverter.FromYCbCrBasic();
// Warm up: // Warm up:
converter.ConvertToRGBA(values, result); converter.ConvertToRgba(values, result);
using (new MeasureGuard(this.Output, $"{converter.GetType().Name} x {times}")) using (new MeasureGuard(this.Output, $"{converter.GetType().Name} x {times}"))
{ {
for (int i = 0; i < times; i++) for (int i = 0; i < times; i++)
{ {
converter.ConvertToRGBA(values, result); converter.ConvertToRgba(values, result);
} }
} }
} }
@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(4, inputBufferLength, seed); JpegColorConverter.ComponentValues values = CreateRandomValues(4, inputBufferLength, seed);
var result = new Vector4[resultBufferLength]; var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result); converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++) for (int i = 0; i < resultBufferLength; i++)
{ {
@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(1, inputBufferLength, seed); JpegColorConverter.ComponentValues values = CreateRandomValues(1, inputBufferLength, seed);
var result = new Vector4[resultBufferLength]; var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result); converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++) for (int i = 0; i < resultBufferLength; i++)
{ {
@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(3, inputBufferLength, seed); JpegColorConverter.ComponentValues values = CreateRandomValues(3, inputBufferLength, seed);
var result = new Vector4[resultBufferLength]; var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result); converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++) for (int i = 0; i < resultBufferLength; i++)
{ {
@ -244,7 +244,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(4, inputBufferLength, seed); JpegColorConverter.ComponentValues values = CreateRandomValues(4, inputBufferLength, seed);
var result = new Vector4[resultBufferLength]; var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result); converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++) for (int i = 0; i < resultBufferLength; i++)
{ {
@ -320,7 +320,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(componentCount, inputBufferLength, seed); JpegColorConverter.ComponentValues values = CreateRandomValues(componentCount, inputBufferLength, seed);
var result = new Vector4[resultBufferLength]; var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result); converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++) for (int i = 0; i < resultBufferLength; i++)
{ {

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

@ -0,0 +1,89 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
public partial class JpegDecoderTests
{
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_Orig<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (SkipTest(provider))
{
return;
}
// For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
using (Image<TPixel> image = provider.GetImage(GolangJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeBaselineJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
provider.Configuration.MemoryManager.ReleaseRetainedResources();
}
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
{
// skipping to avoid OutOfMemoryException on CI
return;
}
using (Image<TPixel> image = provider.GetImage(PdfJsJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeBaselineJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
}
[Theory]
[WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_Golang<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
// TODO: We need a public ImageDecoderException class in ImageSharp!
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));
}
[Theory(Skip = "Debug only, enable manually!")]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void CompareJpegDecoders_Baseline<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
this.CompareJpegDecodersImpl(provider, DecodeBaselineJpegOutputName);
}
}
}

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

@ -0,0 +1,72 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
public partial class JpegDecoderTests
{
public static string[] BaselineTestJpegs =
{
TestImages.Jpeg.Baseline.Calliphora,
TestImages.Jpeg.Baseline.Cmyk, TestImages.Jpeg.Baseline.Ycck,
TestImages.Jpeg.Baseline.Jpeg400,
TestImages.Jpeg.Baseline.Testorig420,
// BUG: The following image has a high difference compared to the expected output:
// TestImages.Jpeg.Baseline.Jpeg420Small,
TestImages.Jpeg.Baseline.Jpeg444,
TestImages.Jpeg.Baseline.Bad.BadEOF,
TestImages.Jpeg.Issues.MultiHuffmanBaseline394,
TestImages.Jpeg.Baseline.MultiScanBaselineCMYK,
TestImages.Jpeg.Baseline.Bad.BadRST
};
public static string[] ProgressiveTestJpegs =
{
TestImages.Jpeg.Progressive.Fb,
TestImages.Jpeg.Progressive.Progress,
TestImages.Jpeg.Progressive.Festzug,
TestImages.Jpeg.Progressive.Bad.BadEOF,
TestImages.Jpeg.Issues.BadCoeffsProgressive178,
TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159,
TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159,
TestImages.Jpeg.Issues.BadZigZagProgressive385,
TestImages.Jpeg.Progressive.Bad.ExifUndefType,
TestImages.Jpeg.Issues.NoEoiProgressive517,
TestImages.Jpeg.Issues.BadRstProgressive518,
TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159,
};
/// <summary>
/// Golang decoder is unable to decode these
/// </summary>
public static string[] PdfJsOnly =
{
TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518,
TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159
};
private static readonly Dictionary<string, float> CustomToleranceValues =
new Dictionary<string, float>
{
// Baseline:
[TestImages.Jpeg.Baseline.Calliphora] = 0.00002f / 100,
[TestImages.Jpeg.Baseline.Bad.BadEOF] = 0.38f / 100,
[TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100,
[TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100,
// Progressive:
[TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159] = 0.34f / 100,
[TestImages.Jpeg.Issues.BadCoeffsProgressive178] = 0.38f / 100,
[TestImages.Jpeg.Progressive.Bad.BadEOF] = 0.3f / 100,
[TestImages.Jpeg.Progressive.Festzug] = 0.02f / 100,
[TestImages.Jpeg.Progressive.Fb] = 0.16f / 100,
[TestImages.Jpeg.Progressive.Progress] = 0.31f / 100,
[TestImages.Jpeg.Issues.BadZigZagProgressive385] = 0.23f / 100,
[TestImages.Jpeg.Progressive.Bad.ExifUndefType] = 0.011f / 100,
};
}
}

120
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,31 @@ 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);
});
}
} }
} }

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

@ -0,0 +1,81 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Linq;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
public partial class JpegDecoderTests
{
public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
[Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
public void DecodeProgressiveJpeg_Orig<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
{
// skipping to avoid OutOfMemoryException on CI
return;
}
// Golang decoder is unable to decode these:
if (PdfJsOnly.Any(fn => fn.Contains(provider.SourceFileOrDescription)))
{
return;
}
// For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
using (Image<TPixel> image = provider.GetImage(GolangJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeProgressiveJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
provider.Configuration.MemoryManager.ReleaseRetainedResources();
}
[Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
public void DecodeProgressiveJpeg_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (SkipTest(provider))
{
// skipping to avoid OutOfMemoryException on CI
return;
}
using (Image<TPixel> image = provider.GetImage(PdfJsJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeProgressiveJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
}
[Theory(Skip = "Debug only, enable manually!")]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
public void CompareJpegDecoders_Progressive<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
this.CompareJpegDecodersImpl(provider, DecodeProgressiveJpegOutputName);
}
}
}

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

@ -24,59 +24,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// TODO: Scatter test cases into multiple test classes // TODO: Scatter test cases into multiple test classes
public partial class JpegDecoderTests public partial class JpegDecoderTests
{ {
public static string[] BaselineTestJpegs =
{
TestImages.Jpeg.Baseline.Calliphora,
TestImages.Jpeg.Baseline.Cmyk,
TestImages.Jpeg.Baseline.Ycck,
TestImages.Jpeg.Baseline.Jpeg400,
TestImages.Jpeg.Baseline.Testorig420,
// BUG: The following image has a high difference compared to the expected output:
// TestImages.Jpeg.Baseline.Jpeg420Small,
TestImages.Jpeg.Baseline.Jpeg444,
TestImages.Jpeg.Baseline.Bad.BadEOF,
TestImages.Jpeg.Issues.MultiHuffmanBaseline394,
TestImages.Jpeg.Baseline.MultiScanBaselineCMYK,
TestImages.Jpeg.Baseline.Bad.BadRST
};
public static string[] ProgressiveTestJpegs =
{
TestImages.Jpeg.Progressive.Fb, TestImages.Jpeg.Progressive.Progress,
TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF,
TestImages.Jpeg.Issues.BadCoeffsProgressive178,
TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159,
TestImages.Jpeg.Issues.BadZigZagProgressive385,
TestImages.Jpeg.Progressive.Bad.ExifUndefType
};
public static string[] FalsePositiveIssueJpegs =
{
TestImages.Jpeg.Issues.NoEOI517,
TestImages.Jpeg.Issues.BadRST518,
};
private static readonly Dictionary<string, float> CustomToleranceValues = new Dictionary<string, float>
{
// Baseline:
[TestImages.Jpeg.Baseline.Calliphora] = 0.00002f / 100,
[TestImages.Jpeg.Baseline.Bad.BadEOF] = 0.38f / 100,
[TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100,
[TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100,
// Progressive:
[TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159] = 0.34f / 100,
[TestImages.Jpeg.Issues.BadCoeffsProgressive178] = 0.38f / 100,
[TestImages.Jpeg.Progressive.Bad.BadEOF] = 0.3f / 100,
[TestImages.Jpeg.Progressive.Festzug] = 0.02f / 100,
[TestImages.Jpeg.Progressive.Fb] = 0.16f / 100,
[TestImages.Jpeg.Progressive.Progress] = 0.31f / 100,
[TestImages.Jpeg.Issues.BadZigZagProgressive385] = 0.23f / 100,
[TestImages.Jpeg.Progressive.Bad.ExifUndefType] = 0.011f / 100,
};
public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector; public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector;
private const float BaselineTolerance = 0.001F / 100; private const float BaselineTolerance = 0.001F / 100;
@ -115,10 +62,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 +100,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);
@ -163,142 +112,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
provider.Configuration.MemoryManager.ReleaseRetainedResources(); provider.Configuration.MemoryManager.ReleaseRetainedResources();
} }
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_Orig<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (SkipTest(provider))
{
return;
}
// For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
using (Image<TPixel> image = provider.GetImage(OrigJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeBaselineJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
provider.Configuration.MemoryManager.ReleaseRetainedResources();
}
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
{
// skipping to avoid OutOfMemoryException on CI
return;
}
using (Image<TPixel> image = provider.GetImage(PdfJsJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeBaselineJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
}
/// <summary>
/// Only <see cref="PdfJsJpegDecoder"/> can decode these images.
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
/// <param name="provider">The test image provider</param>
[Theory]
[WithFileCollection(nameof(FalsePositiveIssueJpegs), PixelTypes.Rgba32)]
public void DecodeFalsePositiveJpeg_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
{
// skipping to avoid OutOfMemoryException on CI
return;
}
using (Image<TPixel> image = provider.GetImage(PdfJsJpegDecoder))
{
image.DebugSave(provider);
image.CompareToReferenceOutput(
ImageComparer.Tolerant(BaselineTolerance),
provider,
appendPixelTypeToFileName: true);
}
}
[Theory]
[WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)]
public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_Orig<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
// TODO: We need a public ImageDecoderException class in ImageSharp!
Assert.ThrowsAny<Exception>(() => provider.GetImage(OrigJpegDecoder));
}
public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
[Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
public void DecodeProgressiveJpeg_Orig<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (SkipTest(provider))
{
return;
}
// For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
using (Image<TPixel> image = provider.GetImage(OrigJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeProgressiveJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
provider.Configuration.MemoryManager.ReleaseRetainedResources();
}
[Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
public void DecodeProgressiveJpeg_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
{
// skipping to avoid OutOfMemoryException on CI
return;
}
using (Image<TPixel> image = provider.GetImage(PdfJsJpegDecoder))
{
image.DebugSave(provider);
provider.Utility.TestName = DecodeProgressiveJpegOutputName;
image.CompareToReferenceOutput(
this.GetImageComparer(provider),
provider,
appendPixelTypeToFileName: false);
}
}
private string GetDifferenceInPercentageString<TPixel>(Image<TPixel> image, TestImageProvider<TPixel> provider) private string GetDifferenceInPercentageString<TPixel>(Image<TPixel> image, TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
@ -321,15 +134,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private void CompareJpegDecodersImpl<TPixel>(TestImageProvider<TPixel> provider, string testName) private void CompareJpegDecodersImpl<TPixel>(TestImageProvider<TPixel> provider, string testName)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (TestEnvironment.RunsOnCI) // Debug only test
{
return;
}
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);
@ -343,70 +151,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
} }
} }
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void CompareJpegDecoders_Baseline<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
this.CompareJpegDecodersImpl(provider, DecodeBaselineJpegOutputName);
}
[Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
public void CompareJpegDecoders_Progressive<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
this.CompareJpegDecodersImpl(provider, DecodeProgressiveJpegOutputName);
}
[Theory]
[WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio420, 75)]
[WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio420, 100)]
[WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 75)]
[WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)]
[WithSolidFilledImages(8, 8, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)]
public void DecodeGenerated_Orig<TPixel>(
TestImageProvider<TPixel> provider,
JpegSubsample subsample,
int quality)
where TPixel : struct, IPixel<TPixel>
{
byte[] data;
using (Image<TPixel> image = provider.GetImage())
{
var encoder = new JpegEncoder { Subsample = subsample, Quality = quality };
data = new byte[65536];
using (var ms = new MemoryStream(data))
{
image.Save(ms, encoder);
}
}
var mirror = Image.Load<TPixel>(data, OrigJpegDecoder);
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\"

25
tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs

@ -1,8 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
@ -21,16 +22,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Baseline.Ycck, TestImages.Jpeg.Baseline.Ycck,
TestImages.Jpeg.Baseline.Jpeg400, TestImages.Jpeg.Baseline.Jpeg400,
TestImages.Jpeg.Baseline.Testorig420, TestImages.Jpeg.Baseline.Testorig420,
TestImages.Jpeg.Baseline.Jpeg420Small,
TestImages.Jpeg.Baseline.Jpeg444, TestImages.Jpeg.Baseline.Jpeg444,
TestImages.Jpeg.Baseline.Bad.BadEOF,
};
public static string[] ProgressiveTestJpegs =
{
TestImages.Jpeg.Progressive.Fb, TestImages.Jpeg.Progressive.Progress,
TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF,
TestImages.Jpeg.Progressive.Bad.ExifUndefType,
}; };
public JpegImagePostProcessorTests(ITestOutputHelper output) public JpegImagePostProcessorTests(ITestOutputHelper output)
@ -47,7 +39,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{ {
image.DebugSave(provider, $"-C{cp.Component.Index}-"); image.DebugSave(provider, $"-C{cp.Component.Index}-");
} }
} }
[Theory] [Theory]
@ -57,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
string imageFile = provider.SourceFileOrDescription; string imageFile = provider.SourceFileOrDescription;
using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile)) using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryManager, decoder)) using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryManager, decoder))
using (var imageFrame = new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, decoder.ImageWidth, decoder.ImageHeight)) using (var imageFrame = new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, decoder.ImageWidth, decoder.ImageHeight))
{ {
@ -70,16 +61,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
SaveBuffer(cp[2], provider); SaveBuffer(cp[2], provider);
} }
} }
[Theory] [Theory]
[WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32)] [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32)]
[WithFile(TestImages.Jpeg.Baseline.Testorig420, PixelTypes.Rgba32)]
public void PostProcess<TPixel>(TestImageProvider<TPixel> provider) public void PostProcess<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
string imageFile = provider.SourceFileOrDescription; string imageFile = provider.SourceFileOrDescription;
using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile)) using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryManager, decoder)) using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryManager, decoder))
using (var image = new Image<Rgba32>(decoder.ImageWidth, decoder.ImageHeight)) using (var image = new Image<Rgba32>(decoder.ImageWidth, decoder.ImageHeight))
{ {
@ -97,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ImageSimilarityReport report = ImageComparer.Exact.CompareImagesOrFrames(referenceImage, image); ImageSimilarityReport report = ImageComparer.Exact.CompareImagesOrFrames(referenceImage, image);
this.Output.WriteLine($"*** {imageFile} ***"); this.Output.WriteLine($"*** {imageFile} ***");
this.Output.WriteLine($"Difference: "+ report.DifferencePercentageString); this.Output.WriteLine($"Difference: {report.DifferencePercentageString}");
// ReSharper disable once PossibleInvalidOperationException // ReSharper disable once PossibleInvalidOperationException
Assert.True(report.TotalNormalizedDifference.Value < 0.005f); Assert.True(report.TotalNormalizedDifference.Value < 0.005f);

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

139
tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs

@ -2,11 +2,12 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Text; using System.Text;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -29,20 +30,35 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(TestImages.Jpeg.Baseline.Jpeg400, JpegColorSpace.Grayscale)] [InlineData(TestImages.Jpeg.Baseline.Jpeg400, JpegColorSpace.Grayscale)]
[InlineData(TestImages.Jpeg.Baseline.Ycck, JpegColorSpace.Ycck)] [InlineData(TestImages.Jpeg.Baseline.Ycck, JpegColorSpace.Ycck)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegColorSpace.Cmyk)] [InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegColorSpace.Cmyk)]
public void ColorSpace_IsDeducedCorrectly(string imageFile, object expectedColorSpaceValue) public void ColorSpace_IsDeducedCorrectlyGolang(string imageFile, object expectedColorSpaceValue)
{ {
var expecteColorSpace = (JpegColorSpace)expectedColorSpaceValue; var expecteColorSpace = (JpegColorSpace)expectedColorSpaceValue;
using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile, false)) using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(imageFile))
{
Assert.Equal(expecteColorSpace, decoder.ColorSpace);
}
}
[Theory]
[InlineData(TestImages.Jpeg.Baseline.Testorig420, JpegColorSpace.YCbCr)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg400, JpegColorSpace.Grayscale)]
[InlineData(TestImages.Jpeg.Baseline.Ycck, JpegColorSpace.Ycck)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegColorSpace.Cmyk)]
public void ColorSpace_IsDeducedCorrectlyPdfJs(string imageFile, object expectedColorSpaceValue)
{
var expecteColorSpace = (JpegColorSpace)expectedColorSpaceValue;
using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
{ {
Assert.Equal(expecteColorSpace, decoder.ColorSpace); Assert.Equal(expecteColorSpace, decoder.ColorSpace);
} }
} }
[Fact] [Fact]
public void ComponentScalingIsCorrect_1ChannelJpeg() public void ComponentScalingIsCorrect_1ChannelJpegGolang()
{ {
using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(TestImages.Jpeg.Baseline.Jpeg400, false)) using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(TestImages.Jpeg.Baseline.Jpeg400))
{ {
Assert.Equal(1, decoder.ComponentCount); Assert.Equal(1, decoder.ComponentCount);
Assert.Equal(1, decoder.Components.Length); Assert.Equal(1, decoder.Components.Length);
@ -52,11 +68,53 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(expectedSizeInBlocks, decoder.ImageSizeInMCU); Assert.Equal(expectedSizeInBlocks, decoder.ImageSizeInMCU);
var uniform1 = new Size(1, 1); var uniform1 = new Size(1, 1);
OrigComponent c0 = decoder.Components[0]; GolangComponent c0 = decoder.Components[0];
VerifyJpeg.VerifyComponent(c0, expectedSizeInBlocks, uniform1, uniform1); VerifyJpeg.VerifyComponent(c0, expectedSizeInBlocks, uniform1, uniform1);
} }
} }
[Fact]
public void ComponentScalingIsCorrect_1ChannelJpegPdfJs()
{
using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(TestImages.Jpeg.Baseline.Jpeg400))
{
Assert.Equal(1, decoder.ComponentCount);
Assert.Equal(1, decoder.Components.Length);
Size expectedSizeInBlocks = decoder.ImageSizeInPixels.DivideRoundUp(8);
Assert.Equal(expectedSizeInBlocks, decoder.ImageSizeInMCU);
var uniform1 = new Size(1, 1);
PdfJsFrameComponent c0 = decoder.Components[0];
VerifyJpeg.VerifyComponent(c0, expectedSizeInBlocks, uniform1, uniform1);
}
}
[Theory]
[InlineData(TestImages.Jpeg.Baseline.Jpeg444)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg420Small)]
[InlineData(TestImages.Jpeg.Baseline.Testorig420)]
[InlineData(TestImages.Jpeg.Baseline.Ycck)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk)]
public void PrintComponentDataGolang(string imageFile)
{
var sb = new StringBuilder();
using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(imageFile))
{
sb.AppendLine(imageFile);
sb.AppendLine($"Size:{decoder.ImageSizeInPixels} MCU:{decoder.ImageSizeInMCU}");
GolangComponent c0 = decoder.Components[0];
GolangComponent c1 = decoder.Components[1];
sb.AppendLine($"Luma: SAMP: {c0.SamplingFactors} BLOCKS: {c0.SizeInBlocks}");
sb.AppendLine($"Chroma: {c1.SamplingFactors} BLOCKS: {c1.SizeInBlocks}");
}
this.Output.WriteLine(sb.ToString());
}
[Theory] [Theory]
[InlineData(TestImages.Jpeg.Baseline.Jpeg444)] [InlineData(TestImages.Jpeg.Baseline.Jpeg444)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)] [InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)]
@ -64,16 +122,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(TestImages.Jpeg.Baseline.Testorig420)] [InlineData(TestImages.Jpeg.Baseline.Testorig420)]
[InlineData(TestImages.Jpeg.Baseline.Ycck)] [InlineData(TestImages.Jpeg.Baseline.Ycck)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk)] [InlineData(TestImages.Jpeg.Baseline.Cmyk)]
public void PrintComponentData(string imageFile) public void PrintComponentDataPdfJs(string imageFile)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile, false)) using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
{ {
sb.AppendLine(imageFile); sb.AppendLine(imageFile);
sb.AppendLine($"Size:{decoder.ImageSizeInPixels} MCU:{decoder.ImageSizeInMCU}"); sb.AppendLine($"Size:{decoder.ImageSizeInPixels} MCU:{decoder.ImageSizeInMCU}");
OrigComponent c0 = decoder.Components[0]; PdfJsFrameComponent c0 = decoder.Components[0];
OrigComponent c1 = decoder.Components[1]; PdfJsFrameComponent c1 = decoder.Components[1];
sb.AppendLine($"Luma: SAMP: {c0.SamplingFactors} BLOCKS: {c0.SizeInBlocks}"); sb.AppendLine($"Luma: SAMP: {c0.SamplingFactors} BLOCKS: {c0.SizeInBlocks}");
sb.AppendLine($"Chroma: {c1.SamplingFactors} BLOCKS: {c1.SizeInBlocks}"); sb.AppendLine($"Chroma: {c1.SamplingFactors} BLOCKS: {c1.SizeInBlocks}");
@ -94,23 +152,64 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory] [Theory]
[MemberData(nameof(ComponentVerificationData))] [MemberData(nameof(ComponentVerificationData))]
public void ComponentScalingIsCorrect_MultiChannelJpeg( public void ComponentScalingIsCorrect_MultiChannelJpegGolang(
string imageFile,
int componentCount,
object expectedLumaFactors,
object expectedChromaFactors)
{
var fLuma = (Size)expectedLumaFactors;
var fChroma = (Size)expectedChromaFactors;
using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(imageFile))
{
Assert.Equal(componentCount, decoder.ComponentCount);
Assert.Equal(componentCount, decoder.Components.Length);
GolangComponent c0 = decoder.Components[0];
GolangComponent c1 = decoder.Components[1];
GolangComponent c2 = decoder.Components[2];
var uniform1 = new Size(1, 1);
Size expectedLumaSizeInBlocks = decoder.ImageSizeInMCU.MultiplyBy(fLuma);
Size divisor = fLuma.DivideBy(fChroma);
Size expectedChromaSizeInBlocks = expectedLumaSizeInBlocks.DivideRoundUp(divisor);
VerifyJpeg.VerifyComponent(c0, expectedLumaSizeInBlocks, fLuma, uniform1);
VerifyJpeg.VerifyComponent(c1, expectedChromaSizeInBlocks, fChroma, divisor);
VerifyJpeg.VerifyComponent(c2, expectedChromaSizeInBlocks, fChroma, divisor);
if (componentCount == 4)
{
GolangComponent c3 = decoder.Components[2];
VerifyJpeg.VerifyComponent(c3, expectedLumaSizeInBlocks, fLuma, uniform1);
}
}
}
[Theory]
[MemberData(nameof(ComponentVerificationData))]
public void ComponentScalingIsCorrect_MultiChannelJpegPdfJs(
string imageFile, string imageFile,
int componentCount, int componentCount,
object expectedLumaFactors, object expectedLumaFactors,
object expectedChromaFactors) object expectedChromaFactors)
{ {
Size fLuma = (Size)expectedLumaFactors; var fLuma = (Size)expectedLumaFactors;
Size fChroma = (Size)expectedChromaFactors; var fChroma = (Size)expectedChromaFactors;
using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile, false)) using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
{ {
Assert.Equal(componentCount, decoder.ComponentCount); Assert.Equal(componentCount, decoder.ComponentCount);
Assert.Equal(componentCount, decoder.Components.Length); Assert.Equal(componentCount, decoder.Components.Length);
OrigComponent c0 = decoder.Components[0]; PdfJsFrameComponent c0 = decoder.Components[0];
OrigComponent c1 = decoder.Components[1]; PdfJsFrameComponent c1 = decoder.Components[1];
OrigComponent c2 = decoder.Components[2]; PdfJsFrameComponent c2 = decoder.Components[2];
var uniform1 = new Size(1, 1); var uniform1 = new Size(1, 1);
@ -126,7 +225,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
if (componentCount == 4) if (componentCount == 4)
{ {
OrigComponent c3 = decoder.Components[2]; PdfJsFrameComponent c3 = decoder.Components[2];
VerifyJpeg.VerifyComponent(c3, expectedLumaSizeInBlocks, fLuma, uniform1); VerifyJpeg.VerifyComponent(c3, expectedLumaSizeInBlocks, fLuma, uniform1);
} }
} }

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

@ -3,7 +3,7 @@
using System.Text; using System.Text;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit; using Xunit;

5
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs

@ -1,4 +1,7 @@
using SixLabors.ImageSharp.Formats.Jpeg.Common; // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit; using Xunit;

16
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs

@ -1,8 +1,8 @@
// ReSharper disable InconsistentNaming // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common; // ReSharper disable InconsistentNaming
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit; using Xunit;
@ -36,13 +36,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.CompareBlocks(original, src, 0.1f); this.CompareBlocks(original, src, 0.1f);
} }
// [Fact] // [Fact]
public void LLM_CalcConstants() public void LLM_CalcConstants()
{ {
ReferenceImplementations.LLM_FloatingPoint_DCT.PrintConstants(this.Output); ReferenceImplementations.LLM_FloatingPoint_DCT.PrintConstants(this.Output);
} }
[Theory] [Theory]
[InlineData(42, 1000)] [InlineData(42, 1000)]
[InlineData(1, 1000)] [InlineData(1, 1000)]
@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Block8x8F fExpected = iExpected.AsFloatBlock(); Block8x8F fExpected = iExpected.AsFloatBlock();
Block8x8F fActual = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref fSource); Block8x8F fActual = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref fSource);
this.CompareBlocks(fExpected, fActual, 2); this.CompareBlocks(fExpected, fActual, 2);
} }
@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ReferenceImplementations.AccurateDCT.TransformIDCTInplace(intData); ReferenceImplementations.AccurateDCT.TransformIDCTInplace(intData);
float[] dest = new float[64]; float[] dest = new float[64];
ReferenceImplementations.GT_FloatingPoint_DCT.iDCT8x8GT(floatSrc, dest); ReferenceImplementations.GT_FloatingPoint_DCT.iDCT8x8GT(floatSrc, dest);
this.CompareBlocks(intData.ConvertAllToFloat(), dest, 1f); this.CompareBlocks(intData.ConvertAllToFloat(), dest, 1f);

2
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs

@ -2,7 +2,7 @@
using System; using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit; using Xunit;

12
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,12 +58,12 @@ 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>
{ {
var decoder = new OrigJpegDecoderCore(Configuration.Default, new JpegDecoder()); var decoder = new GolangJpegDecoderCore(Configuration.Default, new JpegDecoder());
byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes; byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes;
@ -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 OrigJpegDecoderCore(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;

28
tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs

@ -9,8 +9,9 @@ using System.IO;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -94,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
double val = rnd.NextDouble(); double val = rnd.NextDouble();
val *= maxValue - minValue; val *= maxValue - minValue;
val += minValue; val += minValue;
result[i * 8 + j] = (float)val; result[i * 8 + j] = (float)val;
} }
} }
@ -111,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
internal void Print8x8Data<T>(Span<T> data) internal void Print8x8Data<T>(Span<T> data)
{ {
StringBuilder bld = new StringBuilder(); var bld = new StringBuilder();
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
for (int j = 0; j < 8; j++) for (int j = 0; j < 8; j++)
@ -145,9 +146,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
} }
internal void CompareBlocks(Block8x8 a, Block8x8 b, int tolerance) => internal void CompareBlocks(Block8x8 a, Block8x8 b, int tolerance) =>
this.CompareBlocks(a.AsFloatBlock(), b.AsFloatBlock(), (float)tolerance + 1e-5f); this.CompareBlocks(a.AsFloatBlock(), b.AsFloatBlock(), tolerance + 1e-5f);
internal void CompareBlocks(Block8x8F a, Block8x8F b, float tolerance) internal void CompareBlocks(Block8x8F a, Block8x8F b, float tolerance)
=> this.CompareBlocks(a.ToArray(), b.ToArray(), tolerance); => this.CompareBlocks(a.ToArray(), b.ToArray(), tolerance);
internal void CompareBlocks(Span<float> a, Span<float> b, float tolerance) internal void CompareBlocks(Span<float> a, Span<float> b, float tolerance)
@ -170,16 +171,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
} }
} }
this.Output.WriteLine("TOTAL DIFF: "+totalDifference); this.Output.WriteLine("TOTAL DIFF: " + totalDifference);
Assert.False(failed); Assert.False(failed);
} }
internal static OrigJpegDecoderCore ParseStream(string testFileName, bool metaDataOnly = false) internal static GolangJpegDecoderCore ParseGolangStream(string testFileName, bool metaDataOnly = false)
{
byte[] bytes = TestFile.Create(testFileName).Bytes;
using (var ms = new MemoryStream(bytes))
{
var decoder = new GolangJpegDecoderCore(Configuration.Default, new JpegDecoder());
decoder.ParseStream(ms, metaDataOnly);
return decoder;
}
}
internal static PdfJsJpegDecoderCore ParsePdfJsStream(string testFileName, bool metaDataOnly = false)
{ {
byte[] bytes = TestFile.Create(testFileName).Bytes; byte[] bytes = TestFile.Create(testFileName).Bytes;
using (var ms = new MemoryStream(bytes)) using (var ms = new MemoryStream(bytes))
{ {
var decoder = new OrigJpegDecoderCore(Configuration.Default, new JpegDecoder()); var decoder = new PdfJsJpegDecoderCore(Configuration.Default, new JpegDecoder());
decoder.ParseStream(ms, metaDataOnly); decoder.ParseStream(ms, metaDataOnly);
return decoder; return decoder;
} }

6
tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs

@ -1,3 +1,5 @@
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
@ -6,8 +8,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components; using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
return result; return result;
} }
public static ComponentData Load(OrigComponent c) public static ComponentData Load(GolangComponent c)
{ {
var result = new ComponentData( var result = new ComponentData(
c.SizeInBlocks.Width, c.SizeInBlocks.Width,

9
tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs

@ -1,8 +1,11 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort; using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
@ -37,9 +40,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
return new SpectralData(destComponents); return new SpectralData(destComponents);
} }
public static SpectralData LoadFromImageSharpDecoder(OrigJpegDecoderCore decoder) public static SpectralData LoadFromImageSharpDecoder(GolangJpegDecoderCore decoder)
{ {
OrigComponent[] srcComponents = decoder.Components; GolangComponent[] srcComponents = decoder.Components;
LibJpegTools.ComponentData[] destComponents = srcComponents.Select(LibJpegTools.ComponentData.Load).ToArray(); LibJpegTools.ComponentData[] destComponents = srcComponents.Select(LibJpegTools.ComponentData.Load).ToArray();
return new SpectralData(destComponents); return new SpectralData(destComponents);

8
tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs

@ -4,7 +4,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{ {
@ -66,14 +66,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
string args = $@"""{sourceFile}"" ""{destFile}"""; string args = $@"""{sourceFile}"" ""{destFile}""";
var process = new Process var process = new Process
{ {
StartInfo = StartInfo =
{ {
FileName = DumpToolFullPath, FileName = DumpToolFullPath,
Arguments = args, Arguments = args,
WindowStyle = ProcessWindowStyle.Hidden WindowStyle = ProcessWindowStyle.Hidden
} }
}; };
process.Start(); process.Start();
process.WaitForExit(); process.WaitForExit();
} }

2
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs

@ -1,6 +1,6 @@
using System; using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{ {

4
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs

@ -3,7 +3,7 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -520,7 +520,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
y[1] = c0 + c3; y[1] = c0 + c3;
y[7] = c0 - c3; y[7] = c0 - c3;
} }
internal static void fDCT2D_llm( internal static void fDCT2D_llm(
Span<float> s, Span<float> s,
Span<float> d, Span<float> d,

4
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs

@ -1,7 +1,7 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
using System; using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{ {
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
result.LoadFrom(temp); result.LoadFrom(temp);
return result; return result;
} }
/// <summary> /// <summary>
/// Performs a forward DCT on an 8x8 block of coefficients, including a level shift. /// Performs a forward DCT on an 8x8 block of coefficients, including a level shift.
/// Leave results scaled up by an overall factor of 8. /// Leave results scaled up by an overall factor of 8.

2
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs

@ -6,7 +6,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{ {

2
tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;

5
tests/ImageSharp.Tests/Image/ImageCloneTests.cs

@ -33,7 +33,10 @@ namespace SixLabors.ImageSharp.Tests
} }
} }
[Theory] /// <summary>
/// https://github.com/SixLabors/ImageSharp/issues/576
/// </summary>
[Theory(Skip = "See https://github.com/SixLabors/ImageSharp/issues/576")]
[WithTestPatternImages(9, 9, PixelTypes.Rgba32)] [WithTestPatternImages(9, 9, PixelTypes.Rgba32)]
public void CloneAs_ToBgr24(TestImageProvider<Rgba32> provider) public void CloneAs_ToBgr24(TestImageProvider<Rgba32> provider)
{ {

5
tests/ImageSharp.Tests/TestImages.cs

@ -130,11 +130,12 @@ namespace SixLabors.ImageSharp.Tests
{ {
public const string CriticalEOF214 = "Jpg/issues/Issue214-CriticalEOF.jpg"; public const string CriticalEOF214 = "Jpg/issues/Issue214-CriticalEOF.jpg";
public const string MissingFF00ProgressiveGirl159 = "Jpg/issues/Issue159-MissingFF00-Progressive-Girl.jpg"; public const string MissingFF00ProgressiveGirl159 = "Jpg/issues/Issue159-MissingFF00-Progressive-Girl.jpg";
public const string MissingFF00ProgressiveBedroom159 = "Jpg/issues/Issue159-MissingFF00-Progressive-Bedroom.jpg";
public const string BadCoeffsProgressive178 = "Jpg/issues/Issue178-BadCoeffsProgressive-Lemon.jpg"; public const string BadCoeffsProgressive178 = "Jpg/issues/Issue178-BadCoeffsProgressive-Lemon.jpg";
public const string BadZigZagProgressive385 = "Jpg/issues/Issue385-BadZigZag-Progressive.jpg"; public const string BadZigZagProgressive385 = "Jpg/issues/Issue385-BadZigZag-Progressive.jpg";
public const string MultiHuffmanBaseline394 = "Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg"; public const string MultiHuffmanBaseline394 = "Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg";
public const string NoEOI517 = "Jpg/issues/Issue517-No-EOI.jpg"; public const string NoEoiProgressive517 = "Jpg/issues/Issue517-No-EOI-Progressive.jpg";
public const string BadRST518 = "Jpg/issues/Issue518-Bad-RST.jpg"; public const string BadRstProgressive518 = "Jpg/issues/Issue518-Bad-RST-Progressive.jpg";
} }
public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray();

2
tests/Images/External

@ -1 +1 @@
Subproject commit 8ab54f8003aff94b3a9662b0be46b0062cad6b74 Subproject commit 8cff7b09d4a3b8d975a35cf04885264e5765e108

BIN
tests/Images/Input/Jpg/issues/Issue159-MissingFF00-Progressive-Bedroom.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

0
tests/Images/Input/Jpg/issues/Issue517-No-EOI.jpg → tests/Images/Input/Jpg/issues/Issue517-No-EOI-Progressive.jpg

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save