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

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

@ -4,7 +4,7 @@
using System;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <summary>
/// Provides information about the Adobe marker segment.
@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
return true;
}
marker = default(AdobeMarker);
marker = default;
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.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
internal class FromCmyk : ColorConverters.JpegColorConverter
internal class FromCmyk : JpegColorConverter
{
public FromCmyk()
: 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()!
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.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
internal class FromGrayscale : ColorConverters.JpegColorConverter
internal class FromGrayscale : JpegColorConverter
{
public FromGrayscale()
: 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()!
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.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
internal class FromRgb : ColorConverters.JpegColorConverter
internal class FromRgb : JpegColorConverter
{
public FromRgb()
: 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()!
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.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
internal class FromYCbCrBasic : ColorConverters.JpegColorConverter
internal class FromYCbCrBasic : JpegColorConverter
{
public FromYCbCrBasic()
: base(JpegColorSpace.YCbCr)
{
}
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result)
public override void ConvertToRgba(ComponentValues values, Span<Vector4> 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
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 class FromYCbCrSimd : ColorConverters.JpegColorConverter
internal class FromYCbCrSimd : JpegColorConverter
{
public FromYCbCrSimd()
: 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 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Tuples;
// 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 class FromYCbCrSimdAvx2 : ColorConverters.JpegColorConverter
internal class FromYCbCrSimdAvx2 : JpegColorConverter
{
public FromYCbCrSimdAvx2()
: base(JpegColorSpace.YCbCr)
@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
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 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.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
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()!
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.Linq;
using System.Numerics;
using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
/// <summary>
/// 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>
/// <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>
public abstract void ConvertToRGBA(ComponentValues values, Span<Vector4> result);
public abstract void ConvertToRgba(ComponentValues values, Span<Vector4> result);
/// <summary>
/// Returns the <see cref="JpegColorConverter"/> for the YCbCr colorspace that matches the current CPU architecture.
/// </summary>
private static JpegColorConverter GetYCbCrConverter() =>
FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdAvx2() : new FromYCbCrSimd();
JpegColorConverter.FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimdAvx2() : new JpegColorConverter.FromYCbCrSimd();
/// <summary>
/// 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.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <summary>
/// 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.Collections.Generic;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <inheritdoc />
/// <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>
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;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <summary>
/// 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.
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <summary>
/// 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>
/// 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 SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <summary>
/// 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.Linq;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
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>
/// 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;
/// <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>
private ColorConverters.JpegColorConverter colorConverter;
private readonly JpegColorConverter colorConverter;
/// <summary>
/// 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.rgbaBuffer = memoryManager.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width);
this.colorConverter = ColorConverters.JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
}
/// <summary>
@ -148,8 +154,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
{
int y = yy - this.PixelRowCounter;
var values = new ColorConverters.JpegColorConverter.ComponentValues(buffers, y);
this.colorConverter.ConvertToRGBA(values, this.rgbaBuffer.Span);
var values = new JpegColorConverter.ComponentValues(buffers, y);
this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.Span);
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.Text;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <summary>
/// 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.
// Licensed under the Apache License, Version 2.0.
using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
/// <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.
/// </summary>
internal unsafe struct BlockQuad
{
/// <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>
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.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
/// <summary>
/// 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.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
/// <summary>
/// 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.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
/// <summary>
/// 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.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
/// <summary>
/// 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 SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
/// <summary>
/// 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>
public static RgbToYCbCrTables Create()
{
RgbToYCbCrTables tables = default(RgbToYCbCrTables);
RgbToYCbCrTables tables = default;
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);
}
[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.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
/// <summary>
/// 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;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
/// <summary>
/// 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.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
// <auto-generated />
namespace SixLabors.ImageSharp.Formats.Jpeg.Common
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
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.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
// <auto-generated />
namespace SixLabors.ImageSharp.Formats.Jpeg.Common
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
/// <summary>
/// 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 SizeInBytes = Size * 3;
/// <summary>
/// FOR TESTING ONLY!
/// 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.Numerics;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
/// <summary>
/// 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.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
/// <summary>
/// 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)]
public void EnsureNBits(int n, ref InputProcessor inputProcessor)
{
OrigDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor);
GolangDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor);
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
/// 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.
/// This method does not throw. Returns <see cref="OrigDecoderErrorCode"/> instead.
/// This method does not throw. Returns <see cref="GolangDecoderErrorCode"/> instead.
/// </summary>
/// <param name="n">The number of bits to ensure.</param>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <returns>Error code</returns>
public OrigDecoderErrorCode EnsureNBitsUnsafe(int n, ref InputProcessor inputProcessor)
public GolangDecoderErrorCode EnsureNBitsUnsafe(int n, ref InputProcessor inputProcessor)
{
while (true)
{
OrigDecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref inputProcessor);
if (errorCode != OrigDecoderErrorCode.NoError || this.UnreadBits >= n)
GolangDecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref inputProcessor);
if (errorCode != GolangDecoderErrorCode.NoError || this.UnreadBits >= n)
{
return errorCode;
}
@ -67,8 +67,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==8
/// </summary>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <returns>A <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode Ensure8BitsUnsafe(ref InputProcessor inputProcessor)
/// <returns>A <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode Ensure8BitsUnsafe(ref InputProcessor 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
/// </summary>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <returns>A <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode Ensure1BitUnsafe(ref InputProcessor inputProcessor)
/// <returns>A <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode Ensure1BitUnsafe(ref InputProcessor inputProcessor)
{
return this.EnsureBitsStepImpl(ref inputProcessor);
}
@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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();
return x;
}
@ -103,13 +103,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="t">Byte</param>
/// <param name="inputProcessor">The <see cref="InputProcessor"/></param>
/// <param name="x">Read bits value</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, ref InputProcessor inputProcessor, out int x)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode ReceiveExtendUnsafe(int t, ref InputProcessor inputProcessor, out int x)
{
if (this.UnreadBits < t)
{
OrigDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref inputProcessor);
if (errorCode != OrigDecoderErrorCode.NoError)
GolangDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref inputProcessor);
if (errorCode != GolangDecoderErrorCode.NoError)
{
x = int.MaxValue;
return errorCode;
@ -126,14 +126,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
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;
}

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

@ -77,8 +77,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
/// <param name="inputStream">Input stream</param>
/// <param name="x">The result byte as <see cref="int"/></param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out int x)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out int x)
{
// Take the fast path if bytes.buf contains at least two bytes.
if (this.I + 2 <= this.J)
@ -86,50 +86,50 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
x = this.BufferAsInt[this.I];
this.I++;
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)
{
return OrigDecoderErrorCode.MissingFF00;
return GolangDecoderErrorCode.MissingFF00;
}
this.I++;
this.UnreadableBytes = 2;
x = OrigJpegConstants.Markers.XFF;
return OrigDecoderErrorCode.NoError;
x = JpegConstants.Markers.XFF;
return GolangDecoderErrorCode.NoError;
}
this.UnreadableBytes = 0;
OrigDecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
GolangDecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 1;
if (errorCode != OrigDecoderErrorCode.NoError)
if (errorCode != GolangDecoderErrorCode.NoError)
{
return errorCode;
}
if (x != OrigJpegConstants.Markers.XFF)
if (x != JpegConstants.Markers.XFF)
{
return OrigDecoderErrorCode.NoError;
return GolangDecoderErrorCode.NoError;
}
errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 2;
if (errorCode != OrigDecoderErrorCode.NoError)
if (errorCode != GolangDecoderErrorCode.NoError)
{
return errorCode;
}
if (x != 0x00)
{
return OrigDecoderErrorCode.MissingFF00;
return GolangDecoderErrorCode.MissingFF00;
}
x = OrigJpegConstants.Markers.XFF;
return OrigDecoderErrorCode.NoError;
x = JpegConstants.Markers.XFF;
return GolangDecoderErrorCode.NoError;
}
/// <summary>
@ -140,25 +140,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte ReadByte(Stream inputStream)
{
OrigDecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out byte result);
GolangDecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out byte result);
errorCode.EnsureNoError();
return result;
}
/// <summary>
/// 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>
/// <param name="inputStream">Input stream</param>
/// <param name="result">The result <see cref="byte"/> as out parameter</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReadByteUnsafe(Stream inputStream, out byte result)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode ReadByteUnsafe(Stream inputStream, out byte result)
{
OrigDecoderErrorCode errorCode = OrigDecoderErrorCode.NoError;
GolangDecoderErrorCode errorCode = GolangDecoderErrorCode.NoError;
while (this.I == this.J)
{
errorCode = this.FillUnsafe(inputStream);
if (errorCode != OrigDecoderErrorCode.NoError)
if (errorCode != GolangDecoderErrorCode.NoError)
{
result = 0;
return errorCode;
@ -176,15 +176,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
/// <param name="inputStream">The input stream</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)]
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)
{
errorCode = this.FillUnsafe(inputStream);
if (errorCode != OrigDecoderErrorCode.NoError)
if (errorCode != GolangDecoderErrorCode.NoError)
{
result = 0;
return errorCode;
@ -206,18 +206,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Fill(Stream inputStream)
{
OrigDecoderErrorCode errorCode = this.FillUnsafe(inputStream);
GolangDecoderErrorCode errorCode = this.FillUnsafe(inputStream);
errorCode.EnsureNoError();
}
/// <summary>
/// Fills up the bytes buffer from the underlying stream.
/// 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>
/// <param name="inputStream">Input stream</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode FillUnsafe(Stream inputStream)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode FillUnsafe(Stream inputStream)
{
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);
if (n == 0)
{
return OrigDecoderErrorCode.UnexpectedEndOfStream;
return GolangDecoderErrorCode.UnexpectedEndOfStream;
}
this.J += n;
@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
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
{
/// <summary>
/// Throws an exception that belongs to the given <see cref="OrigDecoderErrorCode"/>
/// Throws an exception that belongs to the given <see cref="GolangDecoderErrorCode"/>
/// </summary>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param>
/// <param name="errorCode">The <see cref="GolangDecoderErrorCode"/></param>
[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,
// consider using the ***Unsafe variant of the parsing method that asks for ThrowExceptionForErrorCode()
// then verify the error code + implement fallback logic manually!
switch (errorCode)
{
case OrigDecoderErrorCode.NoError:
case GolangDecoderErrorCode.NoError:
throw new ArgumentException("ThrowExceptionForErrorCode() called with NoError!", nameof(errorCode));
case OrigDecoderErrorCode.MissingFF00:
case GolangDecoderErrorCode.MissingFF00:
throw new MissingFF00Exception();
case OrigDecoderErrorCode.UnexpectedEndOfStream:
case GolangDecoderErrorCode.UnexpectedEndOfStream:
throw new EOFException();
default:
throw new ArgumentOutOfRangeException(nameof(errorCode), errorCode, null);
@ -35,26 +35,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
/// <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>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param>
/// <param name="errorCode">The <see cref="GolangDecoderErrorCode"/></param>
[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);
}
}
/// <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>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param>
/// <param name="errorCode">The <see cref="GolangDecoderErrorCode"/></param>
[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();
}

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.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.Primitives;
@ -14,9 +15,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary>
/// Represents a single color component
/// </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.Index = index;
@ -56,8 +57,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Initializes <see cref="SpectralBlocks"/>
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param>
public void InitializeDerivedData(MemoryManager memoryManager, OrigJpegDecoderCore decoder)
/// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void InitializeDerivedData(MemoryManager memoryManager, GolangJpegDecoderCore decoder)
{
// For 4-component images (either CMYK or YCbCrK), we only support two
// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
@ -76,7 +77,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
else
{
OrigComponent c0 = decoder.Components[0];
GolangComponent c0 = decoder.Components[0];
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
}
@ -86,8 +87,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary>
/// Initializes all component data except <see cref="SpectralBlocks"/>.
/// </summary>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param>
public void InitializeCoreData(OrigJpegDecoderCore decoder)
/// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void InitializeCoreData(GolangJpegDecoderCore decoder)
{
// Section B.2.2 states that "the value of C_i shall be different from
// 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)];
if (this.QuantizationTableIndex > OrigJpegDecoderCore.MaxTq)
if (this.QuantizationTableIndex > GolangJpegDecoderCore.MaxTq)
{
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
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct OrigComponentScan
internal struct GolangComponentScan
{
/// <summary>
/// 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>
/// Represents "recoverable" decoder errors.
/// </summary>
internal enum OrigDecoderErrorCode
internal enum GolangDecoderErrorCode
{
/// <summary>
/// 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.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -12,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Represents a Huffman tree
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct OrigHuffmanTree
internal unsafe struct GolangHuffmanTree
{
/// <summary>
/// The index of the AC table row
@ -95,12 +93,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public FixedInt32Buffer16 Indices;
/// <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>
/// <returns>An array of <see cref="OrigHuffmanTree" /> instances representing the Huffman tables</returns>
public static OrigHuffmanTree[] CreateHuffmanTrees()
/// <returns>An array of <see cref="GolangHuffmanTree" /> instances representing the Huffman tables</returns>
public static GolangHuffmanTree[] CreateHuffmanTrees()
{
return new OrigHuffmanTree[NumberOfTrees];
return new GolangHuffmanTree[NumberOfTrees];
}
/// <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.
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
/// <content>
/// Conains the definition of <see cref="ComputationData"/>
/// </content>
internal unsafe partial struct OrigJpegScanDecoder
internal unsafe partial struct GolangJpegScanDecoder
{
/// <summary>
/// Holds the "large" data blocks needed for computations.
@ -28,14 +29,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public ZigZag Unzig;
/// <summary>
/// The buffer storing the <see cref="OrigComponentScan"/>-s for each component
/// The buffer storing the <see cref="GolangComponentScan"/>-s for each component
/// </summary>
public fixed byte ScanData[3 * OrigJpegDecoderCore.MaxComponents];
public fixed byte ScanData[3 * GolangJpegDecoderCore.MaxComponents];
/// <summary>
/// The DC values for each component
/// </summary>
public fixed int Dc[OrigJpegDecoderCore.MaxComponents];
public fixed int Dc[GolangJpegDecoderCore.MaxComponents];
/// <summary>
/// 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.
// 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
{
/// <content>
/// Conains the definition of <see cref="DataPointers"/>
/// </content>
internal unsafe partial struct OrigJpegScanDecoder
internal unsafe partial struct GolangJpegScanDecoder
{
/// <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"/>
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary>
/// Pointer to <see cref="ComputationData.ScanData"/> as Scan*
/// </summary>
public OrigComponentScan* ComponentScan;
public GolangComponentScan* ComponentScan;
/// <summary>
/// Pointer to <see cref="ComputationData.Dc"/>
@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
this.Block = &basePtr->Block;
this.Unzig = basePtr->Unzig.Data;
this.ComponentScan = (OrigComponentScan*)basePtr->ScanData;
this.ComponentScan = (GolangComponentScan*)basePtr->ScanData;
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.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
// ReSharper disable InconsistentNaming
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.
/// </summary>
[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.
#pragma warning disable SA1202 // ElementsMustBeOrderedByAccess
@ -110,12 +109,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private byte expectedRst;
/// <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>
/// <param name="p">Pointer to <see cref="OrigJpegScanDecoder"/> on the stack</param>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param>
/// <param name="p">Pointer to <see cref="GolangJpegScanDecoder"/> on the stack</param>
/// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</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->pointers = new DataPointers(&p->data);
@ -123,8 +122,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
/// <summary>
/// Read Huffman data from Jpeg scans in <see cref="OrigJpegDecoderCore.InputStream"/>,
/// and decode it as <see cref="Block8x8"/> into <see cref="OrigComponent.SpectralBlocks"/>.
/// Read Huffman data from Jpeg scans in <see cref="GolangJpegDecoderCore.InputStream"/>,
/// 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
/// 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
/// 3 4 5
/// </summary>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param>
public void DecodeBlocks(OrigJpegDecoderCore decoder)
/// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void DecodeBlocks(GolangJpegDecoderCore decoder)
{
decoder.InputProcessor.ResetErrorState();
this.blockCounter = 0;
this.mcuCounter = 0;
this.expectedRst = OrigJpegConstants.Markers.RST0;
this.expectedRst = JpegConstants.Markers.RST0;
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++)
{
this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
OrigComponent component = decoder.Components[this.ComponentIndex];
GolangComponent component = decoder.Components[this.ComponentIndex];
this.hi = component.HorizontalSamplingFactor;
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.
if (!decoder.InputProcessor.ReachedEOF)
@ -262,15 +261,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
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();
@ -285,15 +284,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
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>
/// The implementation part of <see cref="InitStreamReading"/> as an instance method.
/// </summary>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/></param>
/// <param name="decoder">The <see cref="GolangJpegDecoderCore"/></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)
{
@ -360,10 +359,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
/// <param name="decoder">The decoder</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;
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)
{
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++;
// 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(
ref decoder.HuffmanTrees[huffmanIndex],
out int value);
@ -467,7 +466,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private void DecodeEobRun(int count, ref InputProcessor processor)
{
processor.DecodeBitsUnsafe(count, out int bitsResult);
if (processor.LastErrorCode != OrigDecoderErrorCode.NoError)
if (processor.LastErrorCode != GolangDecoderErrorCode.NoError)
{
return;
}
@ -475,7 +474,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
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.
int cs = decoder.Temp[1 + (2 * i)];
@ -500,11 +499,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
private void ProcessComponentImpl(
OrigJpegDecoderCore decoder,
GolangJpegDecoderCore decoder,
int i,
ref OrigComponentScan currentComponentScan,
ref GolangComponentScan currentComponentScan,
ref int totalHv,
OrigComponent currentComponent)
GolangComponent currentComponent)
{
// 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
@ -522,13 +521,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
totalHv += currentComponent.HorizontalSamplingFactor * currentComponent.VerticalSamplingFactor;
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");
}
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");
}
@ -540,7 +539,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="bp">The <see cref="InputProcessor"/> instance</param>
/// <param name="h">The Huffman tree</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;
@ -560,7 +559,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (bit)
{
int stuff = (int)Block8x8.GetScalarAt(b, 0);
int stuff = Block8x8.GetScalarAt(b, 0);
// int stuff = (int)b[0];
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
{
/// <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
/// </summary>
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.
/// </summary>
/// <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)
{
this.Bits = default(Bits);
this.Bits = default;
this.Bytes = Bytes.Create();
this.InputStream = inputStream;
this.Temp = temp;
this.LastErrorCode = OrigDecoderErrorCode.NoError;
this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
/// <summary>
@ -43,20 +43,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public Stream InputStream { get; }
/// <summary>
/// Gets the temporary buffer, same instance as <see cref="OrigJpegDecoderCore.Temp"/>
/// Gets the temporary buffer, same instance as <see cref="GolangJpegDecoderCore.Temp"/>
/// </summary>
public byte[] Temp { get; }
/// <summary>
/// Gets a value indicating whether an unexpected EOF reached in <see cref="InputStream"/>.
/// </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>
/// 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>
public bool CheckEOFEnsureNoError()
{
if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream)
if (this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{
return false;
}
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <returns>A <see cref="bool"/> indicating whether EOF reached</returns>
public bool CheckEOF()
{
if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream)
if (this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{
return false;
}
@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public OrigDecoderErrorCode ReadByteUnsafe(out byte result)
public GolangDecoderErrorCode ReadByteUnsafe(out byte result)
{
this.LastErrorCode = this.Bytes.ReadByteUnsafe(this.InputStream, out result);
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!
/// </summary>
/// <param name="result">The decoded bit as a <see cref="bool"/></param>
/// <returns>The <see cref="OrigDecoderErrorCode" /></returns>
public OrigDecoderErrorCode DecodeBitUnsafe(out bool result)
/// <returns>The <see cref="GolangDecoderErrorCode" /></returns>
public GolangDecoderErrorCode DecodeBitUnsafe(out bool result)
{
if (this.Bits.UnreadBits == 0)
{
this.LastErrorCode = this.Bits.Ensure1BitUnsafe(ref this);
if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{
result = false;
return this.LastErrorCode;
@ -133,18 +133,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
result = (this.Bits.Accumulator & this.Bits.Mask) != 0;
this.Bits.UnreadBits--;
this.Bits.Mask >>= 1;
return this.LastErrorCode = OrigDecoderErrorCode.NoError;
return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
/// <summary>
/// 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>
/// <param name="data">The data to write to.</param>
/// <param name="offset">The offset in the source buffer</param>
/// <param name="length">The number of bytes to read</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReadFullUnsafe(byte[] data, int offset, int length)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode ReadFullUnsafe(byte[] data, int offset, int length)
{
// Unread the overshot bytes, if any.
if (this.Bytes.UnreadableBytes != 0)
@ -157,8 +157,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.Bytes.UnreadableBytes = 0;
}
this.LastErrorCode = OrigDecoderErrorCode.NoError;
while (length > 0 && this.LastErrorCode == OrigDecoderErrorCode.NoError)
this.LastErrorCode = GolangDecoderErrorCode.NoError;
while (length > 0 && this.LastErrorCode == GolangDecoderErrorCode.NoError)
{
if (this.Bytes.J - this.Bytes.I >= length)
{
@ -185,13 +185,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
/// <param name="count">The number of bits to decode.</param>
/// <param name="result">The <see cref="uint" /> result</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode DecodeBitsUnsafe(int count, out int result)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode DecodeBitsUnsafe(int count, out int result)
{
if (this.Bits.UnreadBits < count)
{
this.LastErrorCode = this.Bits.EnsureNBitsUnsafe(count, ref this);
if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{
result = 0;
return this.LastErrorCode;
@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
result = result & ((1 << count) - 1);
this.Bits.UnreadBits -= count;
this.Bits.Mask >>= count;
return this.LastErrorCode = OrigDecoderErrorCode.NoError;
return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
/// <summary>
@ -210,8 +210,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
/// <param name="huffmanTree">The huffman value</param>
/// <param name="result">The decoded <see cref="byte" /></param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode DecodeHuffmanUnsafe(ref OrigHuffmanTree huffmanTree, out int result)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode DecodeHuffmanUnsafe(ref GolangHuffmanTree huffmanTree, out int result)
{
result = 0;
@ -224,9 +224,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
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];
if (v != 0)
@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
int code = 0;
for (int i = 0; i < OrigHuffmanTree.MaxCodeLength; i++)
for (int i = 0; i < GolangHuffmanTree.MaxCodeLength; i++)
{
if (this.Bits.UnreadBits == 0)
{
@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (code <= huffmanTree.MaxCodes[i])
{
result = huffmanTree.GetValue(code, i);
return this.LastErrorCode = OrigDecoderErrorCode.NoError;
return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
code <<= 1;
@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
DecoderThrowHelper.ThrowImageFormatException.BadHuffmanCode();
// DUMMY RETURN! C# doesn't know we have thrown an exception!
return OrigDecoderErrorCode.NoError;
return GolangDecoderErrorCode.NoError;
}
/// <summary>
@ -295,11 +295,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary>
/// Skips the next n bytes.
/// Does not throw, returns <see cref="OrigDecoderErrorCode"/> instead!
/// Does not throw, returns <see cref="GolangDecoderErrorCode"/> instead!
/// </summary>
/// <param name="count">The number of bytes to ignore.</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode SkipUnsafe(int count)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode SkipUnsafe(int count)
{
// Unread the overshot bytes, if any.
if (this.Bytes.UnreadableBytes != 0)
@ -328,13 +328,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
this.LastErrorCode = this.Bytes.FillUnsafe(this.InputStream);
if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{
return this.LastErrorCode;
}
}
return this.LastErrorCode = OrigDecoderErrorCode.NoError;
return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
/// <summary>
@ -374,8 +374,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
/// <param name="t">Byte</param>
/// <param name="x">Read bits value</param>
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, out int x)
/// <returns>The <see cref="GolangDecoderErrorCode"/></returns>
public GolangDecoderErrorCode ReceiveExtendUnsafe(int t, out int x)
{
this.LastErrorCode = this.Bits.ReceiveExtendUnsafe(t, ref this, out x);
return this.LastErrorCode;
@ -386,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
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>
/// Image decoder for generating an image out of a jpg stream.
/// </summary>
internal sealed class OrigJpegDecoder : IImageDecoder, IJpegDecoderOptions, IImageInfoDetector
internal sealed class GolangJpegDecoder : IImageDecoder, IJpegDecoderOptions, IImageInfoDetector
{
/// <summary>
/// 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));
using (var decoder = new OrigJpegDecoderCore(configuration, this))
using (var decoder = new GolangJpegDecoderCore(configuration, this))
{
return decoder.Decode<TPixel>(stream);
}
@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
Guard.NotNull(stream, nameof(stream));
using (var decoder = new OrigJpegDecoderCore(configuration, this))
using (var decoder = new GolangJpegDecoderCore(configuration, this))
{
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.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.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary>
/// Performs the jpeg decoding operation.
/// </summary>
internal sealed unsafe class OrigJpegDecoderCore : IRawJpegData
internal sealed unsafe class GolangJpegDecoderCore : IRawJpegData
{
/// <summary>
/// The maximum number of color components
@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
#pragma warning disable SA1401 // FieldsMustBePrivate
/// <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
/// </summary>
public InputProcessor InputProcessor;
@ -79,11 +80,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private AdobeMarker adobe;
/// <summary>
/// Initializes a new instance of the <see cref="OrigJpegDecoderCore" /> class.
/// Initializes a new instance of the <see cref="GolangJpegDecoderCore" /> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The options.</param>
public OrigJpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
public GolangJpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
{
this.IgnoreMetadata = options.IgnoreMetadata;
this.configuration = configuration ?? Configuration.Default;
@ -96,12 +97,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary>
/// Gets the component array
/// </summary>
public OrigComponent[] Components { get; private set; }
public GolangComponent[] Components { get; private set; }
/// <summary>
/// Gets the huffman trees
/// </summary>
public OrigHuffmanTree[] HuffmanTrees { get; private set; }
public GolangHuffmanTree[] HuffmanTrees { get; private set; }
/// <inheritdoc />
public Block8x8F[] QuantizationTables { get; private set; }
@ -209,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
if (this.Components != null)
{
foreach (OrigComponent component in this.Components)
foreach (GolangComponent component in this.Components)
{
component?.Dispose();
}
@ -219,7 +220,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
/// <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>
/// <param name="stream">The stream</param>
/// <param name="metadataOnly">Whether to decode metadata only.</param>
@ -231,14 +232,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
if (!metadataOnly)
{
this.HuffmanTrees = OrigHuffmanTree.CreateHuffmanTrees();
this.HuffmanTrees = GolangHuffmanTree.CreateHuffmanTrees();
this.QuantizationTables = new Block8x8F[MaxTq + 1];
}
// Check for the Start Of Image marker.
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.");
}
@ -302,12 +303,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
// End Of Image.
if (marker == OrigJpegConstants.Markers.EOI)
if (marker == JpegConstants.Markers.EOI)
{
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
// only occur between Entropy Coded Segments and not after the final ECS.
@ -329,14 +330,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
switch (marker)
{
case OrigJpegConstants.Markers.SOF0:
case OrigJpegConstants.Markers.SOF1:
case OrigJpegConstants.Markers.SOF2:
this.IsProgressive = marker == OrigJpegConstants.Markers.SOF2;
case JpegConstants.Markers.SOF0:
case JpegConstants.Markers.SOF1:
case JpegConstants.Markers.SOF2:
this.IsProgressive = marker == JpegConstants.Markers.SOF2;
this.ProcessStartOfFrameMarker(remaining, metadataOnly);
break;
case OrigJpegConstants.Markers.DHT:
case JpegConstants.Markers.DHT:
if (metadataOnly)
{
this.InputProcessor.Skip(remaining);
@ -347,7 +348,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
break;
case OrigJpegConstants.Markers.DQT:
case JpegConstants.Markers.DQT:
if (metadataOnly)
{
this.InputProcessor.Skip(remaining);
@ -358,7 +359,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
break;
case OrigJpegConstants.Markers.SOS:
case JpegConstants.Markers.SOS:
if (!metadataOnly)
{
this.ProcessStartOfScanMarker(remaining);
@ -377,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
break;
case OrigJpegConstants.Markers.DRI:
case JpegConstants.Markers.DRI:
if (metadataOnly)
{
this.InputProcessor.Skip(remaining);
@ -388,21 +389,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
break;
case OrigJpegConstants.Markers.APP0:
case JpegConstants.Markers.APP0:
this.ProcessApplicationHeaderMarker(remaining);
break;
case OrigJpegConstants.Markers.APP1:
case JpegConstants.Markers.APP1:
this.ProcessApp1Marker(remaining);
break;
case OrigJpegConstants.Markers.APP2:
case JpegConstants.Markers.APP2:
this.ProcessApp2Marker(remaining);
break;
case OrigJpegConstants.Markers.APP14:
case JpegConstants.Markers.APP14:
this.ProcessApp14Marker(remaining);
break;
default:
if ((marker >= OrigJpegConstants.Markers.APP0 && marker <= OrigJpegConstants.Markers.APP15)
|| marker == OrigJpegConstants.Markers.COM)
if ((marker >= JpegConstants.Markers.APP0 && marker <= JpegConstants.Markers.APP15)
|| marker == JpegConstants.Markers.COM)
{
this.InputProcessor.Skip(remaining);
}
@ -680,12 +681,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
if (!metadataOnly)
{
this.Components = new OrigComponent[this.ComponentCount];
this.Components = new GolangComponent[this.ComponentCount];
for (int i = 0; i < this.ComponentCount; i++)
{
byte componentIdentifier = this.Temp[6 + (3 * i)];
var component = new OrigComponent(componentIdentifier, i);
var component = new GolangComponent(componentIdentifier, i);
component.InitializeCoreData(this);
this.Components[i] = component;
}
@ -697,7 +698,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.ColorSpace = this.DeduceJpegColorSpace();
foreach (OrigComponent component in this.Components)
foreach (GolangComponent component in this.Components)
{
component.InitializeDerivedData(this.configuration.MemoryManager, this);
}
@ -721,18 +722,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InputProcessor.ReadFull(this.Temp, 0, 17);
int tc = this.Temp[0] >> 4;
if (tc > OrigHuffmanTree.MaxTc)
if (tc > GolangHuffmanTree.MaxTc)
{
throw new ImageFormatException("Bad Tc value");
}
int th = this.Temp[0] & 0x0f;
if (th > OrigHuffmanTree.MaxTh)
if (th > GolangHuffmanTree.MaxTh)
{
throw new ImageFormatException("Bad Th value");
}
int huffTreeIndex = (tc * OrigHuffmanTree.ThRowSize) + th;
int huffTreeIndex = (tc * GolangHuffmanTree.ThRowSize) + th;
this.HuffmanTrees[huffTreeIndex].ProcessDefineHuffmanTablesMarkerLoop(
ref this.InputProcessor,
this.Temp,
@ -766,9 +767,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </exception>
private void ProcessStartOfScanMarker(int remaining)
{
var scan = default(OrigJpegScanDecoder);
OrigJpegScanDecoder.InitStreamReading(&scan, this, remaining);
this.InputProcessor.Bits = default(Bits);
var scan = default(GolangJpegScanDecoder);
GolangJpegScanDecoder.InitStreamReading(&scan, this, remaining);
this.InputProcessor.Bits = default;
scan.DecodeBlocks(this);
}
@ -779,19 +780,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
case 1:
return JpegColorSpace.Grayscale;
case 3:
if (!this.isAdobe || this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformYCbCr)
if (!this.isAdobe || this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
{
return JpegColorSpace.YCbCr;
}
if (this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformUnknown)
if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
return JpegColorSpace.RGB;
}
break;
case 4:
if (this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformYcck)
if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
{
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.
// Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats.Jpeg
{
/// <summary>
/// Contains jpeg constant values
/// Contains jpeg constant values defined in the specification.
/// </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>
/// Contains marker specific constants
/// </summary>
public static class Markers
// ReSharper disable InconsistentNaming
internal static class Markers
{
/// <summary>
/// The prefix used for all markers.
/// </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>
/// The Start of Image marker
@ -161,7 +183,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// <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.
/// 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;
@ -193,27 +216,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// </remarks>
/// </summary>
public const byte RST7 = 0xD7;
}
/// <summary>
/// Contains Adobe specific constants
/// </summary>
internal static class Adobe
{
/// <summary>
/// Contains Adobe specific markers
/// The color transform is unknown.(RGB or CMYK)
/// </summary>
public static class Adobe
{
/// <summary>
/// The color transform is unknown.(RGB or CMYK)
/// </summary>
public const byte ColorTransformUnknown = 0;
public const byte ColorTransformUnknown = 0;
/// <summary>
/// The color transform is YCbCr (luminance, red chroma, blue chroma)
/// </summary>
public const byte ColorTransformYCbCr = 1;
/// <summary>
/// The color transform is YCbCr (luminance, red chroma, blue chroma)
/// </summary>
public const byte ColorTransformYCbCr = 1;
/// <summary>
/// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
/// </summary>
public const byte ColorTransformYcck = 2;
}
/// <summary>
/// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
/// </summary>
public const byte ColorTransformYcck = 2;
}
}
}

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

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

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

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.PixelFormats;
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.
// Licensed under the Apache License, Version 2.0.
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats;
using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
namespace SixLabors.ImageSharp.Formats.Jpeg
{
/// <summary>
/// Image encoder for writing an image to a stream as a jpeg.
@ -58,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </summary>
private static readonly byte[] SosHeaderYCbCr =
{
OrigJpegConstants.Markers.XFF, OrigJpegConstants.Markers.SOS,
JpegConstants.Markers.XFF, JpegConstants.Markers.SOS,
// Marker
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>
/// A scratch buffer to reduce allocations.
/// </summary>
@ -190,7 +182,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
ushort max = OrigJpegConstants.MaxLength;
ushort max = JpegConstants.MaxLength;
if (image.Width >= max || image.Height >= max)
{
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);
// Write the End Of Image marker.
this.buffer[0] = OrigJpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.EOI;
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.EOI;
stream.Write(this.buffer, 0, 2);
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.)
// (Partially done with YCbCrForwardConverter<TPixel>)
Block8x8F temp1 = default(Block8x8F);
Block8x8F temp2 = default(Block8x8F);
Block8x8F temp1 = default;
Block8x8F temp2 = default;
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
ZigZag unzig = ZigZag.CreateUnzigTable();
var unzig = ZigZag.CreateUnzigTable();
// ReSharper disable once InconsistentNaming
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)
{
@ -437,12 +429,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void WriteApplicationHeader(short horizontalResolution, short verticalResolution)
{
// Write the start of image marker. Markers are always prefixed with with 0xff.
this.buffer[0] = OrigJpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.SOI;
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.SOI;
// Write the JFIF headers
this.buffer[2] = OrigJpegConstants.Markers.XFF;
this.buffer[3] = OrigJpegConstants.Markers.APP0; // Application Marker
this.buffer[2] = JpegConstants.Markers.XFF;
this.buffer[3] = JpegConstants.Markers.APP0; // Application Marker
this.buffer[4] = 0x00;
this.buffer[5] = 0x10;
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);
// Emit the AC components.
HuffIndex h = (HuffIndex)((2 * (int)index) + 1);
var h = (HuffIndex)((2 * (int)index) + 1);
int runLength = 0;
for (int zig = 1; zig < Block8x8F.Size; zig++)
@ -556,7 +548,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
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++)
{
HuffmanSpec spec = specs[i];
@ -590,7 +582,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
// Marker + quantization table lengths
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.
// 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;
this.buffer[0] = OrigJpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.APP1; // Application Marker
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.APP1; // Application Marker
this.buffer[2] = (byte)((length >> 8) & 0xFF);
this.buffer[3] = (byte)(length & 0xFF);
@ -686,8 +678,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
dataLength -= length;
this.buffer[0] = OrigJpegConstants.Markers.XFF;
this.buffer[1] = OrigJpegConstants.Markers.APP2; // Application Marker
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.APP2; // Application Marker
int markerLength = length + 16;
this.buffer[2] = (byte)((markerLength >> 8) & 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.
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[1] = (byte)(height >> 8);
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>
{
// 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 cr = default(BlockQuad);
Block8x8F* cbPtr = (Block8x8F*)cb.Data;
Block8x8F* crPtr = (Block8x8F*)cr.Data;
BlockQuad cb = default;
BlockQuad cr = default;
var cbPtr = (Block8x8F*)cb.Data;
var crPtr = (Block8x8F*)cr.Data;
Block8x8F temp1 = default(Block8x8F);
Block8x8F temp2 = default(Block8x8F);
Block8x8F temp1 = default;
Block8x8F temp2 = default;
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
ZigZag unzig = ZigZag.CreateUnzigTable();
var unzig = ZigZag.CreateUnzigTable();
var pixelConverter = YCbCrForwardConverter<TPixel>.Create();
@ -902,7 +894,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void WriteMarkerHeader(byte marker, int length)
{
// 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[2] = (byte)(length >> 8);
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.
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
namespace SixLabors.ImageSharp.Formats.Jpeg
{
@ -18,9 +17,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public string DefaultMimeType => "image/jpeg";
/// <inheritdoc/>
public IEnumerable<string> MimeTypes => OrigJpegConstants.MimeTypes;
public IEnumerable<string> MimeTypes => JpegConstants.MimeTypes;
/// <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.Runtime.CompilerServices;
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.Primitives;
@ -36,9 +37,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
public byte Id { get; }
/// <summary>
/// Gets or sets Pred TODO: What does pred stand for?
/// Gets or sets DC coefficient predictor
/// </summary>
public int Pred { get; set; }
public int DcPredictor { get; set; }
/// <summary>
/// Gets the horizontal sampling factor.

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

@ -7,7 +7,8 @@ using System.Diagnostics;
#endif
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.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++)
{
PdfJsFrameComponent c = components[i];
c.Pred = 0;
c.DcPredictor = 0;
}
this.eobrun = 0;
@ -136,7 +137,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
byte marker = fileMarker.Marker;
// 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;
}
@ -452,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
this.endOfStreamReached = true;
return false;
case PdfJsJpegConstants.Markers.Prefix:
case JpegConstants.Markers.XFF:
int nextByte = stream.ReadByte();
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;
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)]

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

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

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))
{
var decoder = new OrigJpegDecoder();
var decoder = new GolangJpegDecoder();
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.Numerics;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory;
[Config(typeof(Config.ShortClr))]
public class YCbCrColorConversion
{
@ -57,7 +57,7 @@
JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output);
}
private static Buffer2D<float>[] CreateRandomValues(
int componentCount,
int inputBufferLength,
@ -81,6 +81,6 @@
return buffers;
}
}
}

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

@ -1,13 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks
{
@ -104,14 +103,14 @@ namespace SixLabors.ImageSharp.Benchmarks
}
}
}
public struct Result
{
internal Block8x8F Y;
internal Block8x8F Cb;
internal Block8x8F Cr;
}
// 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!
private byte[] inputSourceRGB = null;
@ -200,11 +199,11 @@ namespace SixLabors.ImageSharp.Benchmarks
float* cbPtr = (float*)&result.Cb;
float* crPtr = (float*)&result.Cr;
// end of code-bloat block :)
Vector<int> yCoeffs = new Vector<int>(ScaledCoeffs.Y);
Vector<int> cbCoeffs = new Vector<int>(ScaledCoeffs.Cb);
Vector<int> crCoeffs = new Vector<int>(ScaledCoeffs.Cr);
for (int i = 0; i < this.inputSourceRGB.Length; i++)
{
this.inputSourceRGBAsInteger[i] = this.inputSourceRGB[i];
@ -217,7 +216,7 @@ namespace SixLabors.ImageSharp.Benchmarks
Vector<int> y = yCoeffs * rgb;
Vector<int> cb = cbCoeffs * rgb;
Vector<int> cr = crCoeffs * rgb;
*yPtr++ = (y[0] + y[1] + y[2]) >> 10;
*cbPtr++ = 128 + ((cb[0] - cb[1] + cb[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);
}
}
[Benchmark(Description = "Scaled Integer LUT Conversion")]
public unsafe void RgbaToYcbCrScaledIntegerLut()
{

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

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

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

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit;
@ -25,29 +25,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
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.Equal(100, marker.DCTEncodeVersion);
Assert.Equal(0, marker.APP14Flags0);
Assert.Equal(0, marker.APP14Flags1);
Assert.Equal(OrigJpegConstants.Adobe.ColorTransformYcck, marker.ColorTransform);
Assert.Equal(JpegConstants.Adobe.ColorTransformYcck, marker.ColorTransform);
}
[Fact]
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.Equal(default(AdobeMarker), marker);
Assert.Equal(default, marker);
}
[Fact]
public void MarkerEqualityIsCorrect()
{
AdobeMarker.TryParse(this.bytes, out var marker);
AdobeMarker.TryParse(this.bytes, out var marker2);
AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes, out AdobeMarker marker2);
Assert.True(marker.Equals(marker2));
}
@ -55,8 +55,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerInEqualityIsCorrect()
{
AdobeMarker.TryParse(this.bytes, out var marker);
AdobeMarker.TryParse(this.bytes2, out var marker2);
AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes2, out AdobeMarker marker2);
Assert.False(marker.Equals(marker2));
}
@ -64,8 +64,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsReplicable()
{
AdobeMarker.TryParse(this.bytes, out var marker);
AdobeMarker.TryParse(this.bytes, out var marker2);
AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes, out AdobeMarker marker2);
Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode()));
}
@ -73,8 +73,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsUnique()
{
AdobeMarker.TryParse(this.bytes, out var marker);
AdobeMarker.TryParse(this.bytes2, out var marker2);
AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
AdobeMarker.TryParse(this.bytes2, out AdobeMarker marker2);
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:
//#define BENCHMARKING
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.Primitives;

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

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

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

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// 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 Xunit;

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

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

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

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

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

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit;
@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
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.Equal(1, marker.MajorVersion);
@ -40,26 +40,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
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.Equal(default(JFifMarker), marker);
Assert.Equal(default, marker);
}
[Fact]
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.Equal(default(JFifMarker), marker);
Assert.Equal(default, marker);
}
[Fact]
public void MarkerEqualityIsCorrect()
{
JFifMarker.TryParse(this.bytes, out var marker);
JFifMarker.TryParse(this.bytes, out var marker2);
JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes, out JFifMarker marker2);
Assert.True(marker.Equals(marker2));
}
@ -67,8 +67,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerInEqualityIsCorrect()
{
JFifMarker.TryParse(this.bytes, out var marker);
JFifMarker.TryParse(this.bytes2, out var marker2);
JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes2, out JFifMarker marker2);
Assert.False(marker.Equals(marker2));
}
@ -76,8 +76,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsReplicable()
{
JFifMarker.TryParse(this.bytes, out var marker);
JFifMarker.TryParse(this.bytes, out var marker2);
JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes, out JFifMarker marker2);
Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode()));
}
@ -85,8 +85,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsUnique()
{
JFifMarker.TryParse(this.bytes, out var marker);
JFifMarker.TryParse(this.bytes2, out var marker2);
JFifMarker.TryParse(this.bytes, out JFifMarker marker);
JFifMarker.TryParse(this.bytes2, out JFifMarker marker2);
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.Conversion;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory;
using Xunit;
@ -140,13 +140,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter converter = simd ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimd() : new JpegColorConverter.FromYCbCrBasic();
// Warm up:
converter.ConvertToRGBA(values, result);
converter.ConvertToRgba(values, result);
using (new MeasureGuard(this.Output, $"{converter.GetType().Name} x {times}"))
{
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);
var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result);
converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(1, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result);
converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(3, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result);
converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@ -244,7 +244,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(4, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result);
converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@ -320,7 +320,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(componentCount, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, result);
converter.ConvertToRgba(values, result);
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
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg;
@ -50,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
TestMetaDataImpl(
useIdentify,
OrigJpegDecoder,
GolangJpegDecoder,
imagePath,
expectedPixelSize,
exifProfilePresent,
@ -75,6 +76,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
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(
bool useIdentify,
IImageDecoder decoder,
@ -83,51 +96,50 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
bool exifProfilePresent,
bool iccProfilePresent)
{
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);
TestImageInfo(
imagePath,
decoder,
useIdentify,
imageInfo =>
{
Assert.NotNull(imageInfo);
Assert.NotNull(imageInfo.PixelType);
Assert.NotNull(imageInfo);
Assert.NotNull(imageInfo.PixelType);
if (useIdentify)
{
Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel);
}
else
{
// When full Image<TPixel> decoding is performed, BitsPerPixel will match TPixel
int bpp32 = Unsafe.SizeOf<Rgba32>() * 8;
Assert.Equal(bpp32, imageInfo.PixelType.BitsPerPixel);
}
if (useIdentify)
{
Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel);
}
else
{
// 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)
{
Assert.NotNull(exifProfile);
Assert.NotEmpty(exifProfile.Values);
}
else
{
Assert.Null(exifProfile);
}
if (exifProfilePresent)
{
Assert.NotNull(exifProfile);
Assert.NotEmpty(exifProfile.Values);
}
else
{
Assert.Null(exifProfile);
}
IccProfile iccProfile = imageInfo.MetaData.IccProfile;
IccProfile iccProfile = imageInfo.MetaData.IccProfile;
if (iccProfilePresent)
{
Assert.NotNull(iccProfile);
Assert.NotEmpty(iccProfile.Entries);
}
else
{
Assert.Null(iccProfile);
}
}
if (iccProfilePresent)
{
Assert.NotNull(iccProfile);
Assert.NotEmpty(iccProfile.Entries);
}
else
{
Assert.Null(iccProfile);
}
});
}
[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
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;
private const float BaselineTolerance = 0.001F / 100;
@ -115,10 +62,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private ITestOutputHelper Output { get; }
private static OrigJpegDecoder OrigJpegDecoder => new OrigJpegDecoder();
private static GolangJpegDecoder GolangJpegDecoder => new GolangJpegDecoder();
private static PdfJsJpegDecoder PdfJsJpegDecoder => new PdfJsJpegDecoder();
private static JpegDecoder DefaultJpegDecoder => new JpegDecoder();
[Fact]
public void ParseStream_BasicPropertiesAreCorrect1_PdfJs()
{
@ -151,7 +100,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
IImageDecoder decoder = useOldDecoder ? (IImageDecoder)OrigJpegDecoder : PdfJsJpegDecoder;
IImageDecoder decoder = useOldDecoder ? (IImageDecoder)GolangJpegDecoder : PdfJsJpegDecoder;
using (Image<TPixel> image = provider.GetImage(decoder))
{
image.DebugSave(provider);
@ -163,142 +112,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
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)
where TPixel : struct, IPixel<TPixel>
{
@ -321,15 +134,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private void CompareJpegDecodersImpl<TPixel>(TestImageProvider<TPixel> provider, string testName)
where TPixel : struct, IPixel<TPixel>
{
if (TestEnvironment.RunsOnCI) // Debug only test
{
return;
}
this.Output.WriteLine(provider.SourceFileOrDescription);
provider.Utility.TestName = testName;
using (Image<TPixel> image = provider.GetImage(OrigJpegDecoder))
using (Image<TPixel> image = provider.GetImage(GolangJpegDecoder))
{
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!
// The PDF.js output should be saved by "tests\ImageSharp.Tests\Formats\Jpg\pdfjs\jpeg-converter.htm"
// into "\tests\Images\ActualOutput\JpegDecoderTests\"

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

@ -1,8 +1,9 @@
// Copyright (c) Six Labors and contributors.
// 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.PdfJsPort;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
@ -21,16 +22,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Baseline.Ycck,
TestImages.Jpeg.Baseline.Jpeg400,
TestImages.Jpeg.Baseline.Testorig420,
TestImages.Jpeg.Baseline.Jpeg420Small,
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)
@ -47,7 +39,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
image.DebugSave(provider, $"-C{cp.Component.Index}-");
}
}
[Theory]
@ -57,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
where TPixel : struct, IPixel<TPixel>
{
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 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);
}
}
[Theory]
[WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32)]
[WithFile(TestImages.Jpeg.Baseline.Testorig420, PixelTypes.Rgba32)]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void PostProcess<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
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 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);
this.Output.WriteLine($"*** {imageFile} ***");
this.Output.WriteLine($"Difference: "+ report.DifferencePercentageString);
this.Output.WriteLine($"Difference: {report.DifferencePercentageString}");
// ReSharper disable once PossibleInvalidOperationException
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))]
public void DecodeJpeg_Original(string fileName)
{
this.DecodeJpegBenchmarkImpl(fileName, new OrigJpegDecoder());
this.DecodeJpegBenchmarkImpl(fileName, new GolangJpegDecoder());
}
// [Theory] // Benchmark, enable manually

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

@ -2,11 +2,12 @@
// Licensed under the Apache License, Version 2.0.
using System.Text;
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;
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.Primitives;
@ -29,20 +30,35 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(TestImages.Jpeg.Baseline.Jpeg400, JpegColorSpace.Grayscale)]
[InlineData(TestImages.Jpeg.Baseline.Ycck, JpegColorSpace.Ycck)]
[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;
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);
}
}
[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.Components.Length);
@ -52,11 +68,53 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(expectedSizeInBlocks, decoder.ImageSizeInMCU);
var uniform1 = new Size(1, 1);
OrigComponent c0 = decoder.Components[0];
GolangComponent c0 = decoder.Components[0];
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]
[InlineData(TestImages.Jpeg.Baseline.Jpeg444)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)]
@ -64,16 +122,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(TestImages.Jpeg.Baseline.Testorig420)]
[InlineData(TestImages.Jpeg.Baseline.Ycck)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk)]
public void PrintComponentData(string imageFile)
public void PrintComponentDataPdfJs(string imageFile)
{
var sb = new StringBuilder();
using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile, false))
using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
{
sb.AppendLine(imageFile);
sb.AppendLine($"Size:{decoder.ImageSizeInPixels} MCU:{decoder.ImageSizeInMCU}");
OrigComponent c0 = decoder.Components[0];
OrigComponent c1 = decoder.Components[1];
PdfJsFrameComponent c0 = decoder.Components[0];
PdfJsFrameComponent c1 = decoder.Components[1];
sb.AppendLine($"Luma: SAMP: {c0.SamplingFactors} BLOCKS: {c0.SizeInBlocks}");
sb.AppendLine($"Chroma: {c1.SamplingFactors} BLOCKS: {c1.SizeInBlocks}");
@ -94,23 +152,64 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[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,
int componentCount,
object expectedLumaFactors,
object expectedChromaFactors)
{
Size fLuma = (Size)expectedLumaFactors;
Size fChroma = (Size)expectedChromaFactors;
var fLuma = (Size)expectedLumaFactors;
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.Components.Length);
OrigComponent c0 = decoder.Components[0];
OrigComponent c1 = decoder.Components[1];
OrigComponent c2 = decoder.Components[2];
PdfJsFrameComponent c0 = decoder.Components[0];
PdfJsFrameComponent c1 = decoder.Components[1];
PdfJsFrameComponent c2 = decoder.Components[2];
var uniform1 = new Size(1, 1);
@ -126,7 +225,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
if (componentCount == 4)
{
OrigComponent c3 = decoder.Components[2];
PdfJsFrameComponent c3 = decoder.Components[2];
VerifyJpeg.VerifyComponent(c3, expectedLumaSizeInBlocks, fLuma, uniform1);
}
}

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

@ -3,7 +3,7 @@
using System.Text;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
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 Xunit;

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

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

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

@ -2,7 +2,7 @@
using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
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();
[Theory]
[Theory(Skip = "Debug only, enable manually!")]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void PdfJsDecoder_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider)
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)]
public void OriginalDecoder_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider)
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;
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
LibJpegTools.SpectralData imageSharpData)
where TPixel : struct, IPixel<TPixel>
{
var libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription);
LibJpegTools.SpectralData libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription);
bool equality = libJpegData.Equals(imageSharpData);
this.Output.WriteLine("Spectral data equality: " + equality);
@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[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>
{
if (!TestEnvironment.IsWindows)
@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return;
}
var decoder = new OrigJpegDecoderCore(Configuration.Default, new JpegDecoder());
var decoder = new GolangJpegDecoderCore(Configuration.Default, new GolangJpegDecoder());
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 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.PdfJsPort;
using Xunit;
using Xunit.Abstractions;
@ -94,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
double val = rnd.NextDouble();
val *= maxValue - minValue;
val += minValue;
result[i * 8 + j] = (float)val;
}
}
@ -111,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
internal void Print8x8Data<T>(Span<T> data)
{
StringBuilder bld = new StringBuilder();
var bld = new StringBuilder();
for (int i = 0; i < 8; i++)
{
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) =>
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);
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);
}
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;
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);
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;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
@ -6,8 +8,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
using System.Linq;
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.PdfJsPort.Components;
using SixLabors.ImageSharp.Memory;
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
return result;
}
public static ComponentData Load(OrigComponent c)
public static ComponentData Load(GolangComponent c)
{
var result = new ComponentData(
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.Linq;
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.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
@ -37,9 +40,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
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();
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.Numerics;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{
@ -66,14 +66,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
string args = $@"""{sourceFile}"" ""{destFile}""";
var process = new Process
{
StartInfo =
{
StartInfo =
{
FileName = DumpToolFullPath,
Arguments = args,
WindowStyle = ProcessWindowStyle.Hidden
}
};
};
process.Start();
process.WaitForExit();
}

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

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

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

@ -1,7 +1,7 @@
// ReSharper disable InconsistentNaming
using System;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
result.LoadFrom(temp);
return result;
}
/// <summary>
/// Performs a forward DCT on an 8x8 block of coefficients, including a level shift.
/// 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.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
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.Linq;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.PixelFormats;
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)]
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 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 BadZigZagProgressive385 = "Jpg/issues/Issue385-BadZigZag-Progressive.jpg";
public const string MultiHuffmanBaseline394 = "Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg";
public const string NoEOI517 = "Jpg/issues/Issue517-No-EOI.jpg";
public const string BadRST518 = "Jpg/issues/Issue518-Bad-RST.jpg";
public const string NoEoiProgressive517 = "Jpg/issues/Issue517-No-EOI-Progressive.jpg";
public const string BadRstProgressive518 = "Jpg/issues/Issue518-Bad-RST-Progressive.jpg";
}
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