diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 5104f606d4..f75525ab98 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -503,9 +503,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
///
- /// Returns the correct colorspace based on the image component count and the jpeg frame component id's.
+ /// Returns encoded colorspace based on the adobe APP14 marker.
///
- /// The number of components.
+ /// Number of components.
/// Parsed adobe APP14 marker.
/// The
internal static JpegColorSpace DeduceJpegColorSpace(byte componentCount, ref AdobeMarker adobeMarker)
@@ -534,6 +534,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return default;
}
+ ///
+ /// Returns encoded colorspace based on the component count and component ids.
+ ///
+ ///
+ /// Must take into account atleast RGB component identifiers i.e. [82, 71, 66]
+ /// as TIFF images with jpeg encoding don't have APP14 marker.
+ ///
+ /// Number of components.
+ /// The
internal static JpegColorSpace DeduceJpegColorSpace(byte componentCount)
{
if (componentCount == 1)
@@ -1216,7 +1225,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
int maxH = 0;
int maxV = 0;
int index = 0;
- for (int i = 0; i < componentCount; i++)
+ for (int i = 0; i < this.Frame.Components.Length; i++)
{
// 1 byte: component identifier
byte componentId = this.temp[index];
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
index 3c0ebbb6fd..e3df4b565b 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
@@ -59,7 +59,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
case TiffPhotometricInterpretation.BlackIsZero:
case TiffPhotometricInterpretation.WhiteIsZero:
{
- using SpectralConverter spectralConverterGray = new GrayJpegSpectralConverter(this.configuration);
+ using SpectralConverter spectralConverterGray =
+ new GrayJpegSpectralConverter(this.configuration);
var scanDecoderGray = new HuffmanScanDecoder(stream, spectralConverterGray, CancellationToken.None);
jpegDecoder.LoadTables(this.jpegTables, scanDecoderGray);
jpegDecoder.ParseStream(stream, spectralConverterGray, CancellationToken.None);
@@ -73,9 +74,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
case TiffPhotometricInterpretation.YCbCr:
case TiffPhotometricInterpretation.Rgb:
{
- // The jpeg data should treated as RGB color space. If the PhotometricInterpretation is YCbCr,
- // the conversion to RGB will be handled in the next step by the YCbCr color decoder.
- using SpectralConverter spectralConverter = new RgbJpegSpectralConverter(this.configuration);
+ using SpectralConverter spectralConverter =
+ new TiffJpegSpectralConverter(this.configuration, this.photometricInterpretation);
var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None);
jpegDecoder.LoadTables(this.jpegTables, scanDecoder);
jpegDecoder.ParseStream(stream, spectralConverter, CancellationToken.None);
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs
deleted file mode 100644
index fa7d0ffc9f..0000000000
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
-using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
-using SixLabors.ImageSharp.PixelFormats;
-
-namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
-{
- ///
- /// Spectral converter for TIFF's which use the JPEG compression.
- /// The compressed jpeg data should be always treated as RGB color space.
- /// If PhotometricInterpretation indicates the data is YCbCr, the color decoder will handle the conversion.
- ///
- /// The type of the pixel.
- internal sealed class RgbJpegSpectralConverter : SpectralConverter
- where TPixel : unmanaged, IPixel
- {
- ///
- /// Initializes a new instance of the class.
- /// This Spectral converter will always convert the pixel data to RGB color.
- ///
- /// The configuration.
- public RgbJpegSpectralConverter(Configuration configuration)
- : base(configuration)
- {
- }
-
- ///
- protected override JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverterBase.GetConverter(JpegColorSpace.RGB, frame.Precision);
- }
-}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/TiffJpegSpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/TiffJpegSpectralConverter{TPixel}.cs
new file mode 100644
index 0000000000..ea550b1261
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/TiffJpegSpectralConverter{TPixel}.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
+using SixLabors.ImageSharp.Formats.Tiff.Constants;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
+{
+ ///
+ /// Spectral converter for YCbCr TIFF's which use the JPEG compression.
+ /// The jpeg data should be always treated as RGB color space.
+ ///
+ /// The type of the pixel.
+ internal sealed class TiffJpegSpectralConverter : SpectralConverter
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly TiffPhotometricInterpretation photometricInterpretation;
+
+ ///
+ /// Initializes a new instance of the class.
+ /// This Spectral converter will always convert the pixel data to RGB color.
+ ///
+ /// The configuration.
+ /// Tiff photometric interpretation.
+ public TiffJpegSpectralConverter(Configuration configuration, TiffPhotometricInterpretation photometricInterpretation)
+ : base(configuration)
+ => this.photometricInterpretation = photometricInterpretation;
+
+ ///
+ protected override JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData)
+ {
+ JpegColorSpace colorSpace = GetJpegColorSpaceFromPhotometricInterpretation(this.photometricInterpretation);
+ return JpegColorConverterBase.GetConverter(colorSpace, frame.Precision);
+ }
+
+ ///
+ /// This converter must be used only for RGB and YCbCr color spaces for performance reasons.
+ /// For grayscale images must be used.
+ ///
+ private static JpegColorSpace GetJpegColorSpaceFromPhotometricInterpretation(TiffPhotometricInterpretation interpretation)
+ => interpretation switch
+ {
+ TiffPhotometricInterpretation.Rgb => JpegColorSpace.RGB,
+ TiffPhotometricInterpretation.YCbCr => JpegColorSpace.RGB,
+ _ => throw new InvalidImageContentException($"Invalid tiff photometric interpretation for jpeg encoding: {interpretation}"),
+ };
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs
index 71951cfef4..e4e59cdd9f 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs
@@ -33,8 +33,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
byte[] adobeMarkerPayload = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, adobeFlag };
ProfileResolver.AdobeMarker.CopyTo(adobeMarkerPayload);
-
_ = AdobeMarker.TryParse(adobeMarkerPayload, out AdobeMarker adobeMarker);
+
JpegColorSpace actualColorSpace = JpegDecoderCore.DeduceJpegColorSpace(componentCount, ref adobeMarker);
Assert.Equal(expectedColorSpace, actualColorSpace);
@@ -46,6 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void DeduceJpegColorSpaceAdobeMarker_ShouldThrowOnUnsupportedComponentCount(byte componentCount)
{
AdobeMarker adobeMarker = default;
+
Assert.Throws(() => JpegDecoderCore.DeduceJpegColorSpace(componentCount, ref adobeMarker));
}