diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/GrayJpegSpectralConverter.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/GrayJpegSpectralConverter.cs
new file mode 100644
index 000000000..5b793c35d
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/GrayJpegSpectralConverter.cs
@@ -0,0 +1,29 @@
+// 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 gray TIFF's which use the JPEG compression.
+ ///
+ /// The type of the pixel.
+ internal sealed class GrayJpegSpectralConverter : SpectralConverter
+ where TPixel : unmanaged, IPixel
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The configuration.
+ public GrayJpegSpectralConverter(Configuration configuration)
+ : base(configuration)
+ {
+ }
+
+ ///
+ protected override JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverterBase.GetConverter(JpegColorSpace.Grayscale, frame.Precision);
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
index ce7820ccf..f73fe508c 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
@@ -9,7 +9,6 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
-using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
@@ -55,17 +54,43 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
using var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder());
- // If the PhotometricInterpretation is YCbCr we explicitly assume the JPEG data is in RGB color space.
- // There seems no other way to determine that the JPEG data is RGB colorspace (no APP14 marker, componentId's are not RGB).
- using SpectralConverter spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr ?
- new RgbJpegSpectralConverter(this.configuration) : new SpectralConverter(this.configuration);
- var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None);
- jpegDecoder.LoadTables(this.jpegTables, scanDecoder);
- scanDecoder.ResetInterval = 0;
- jpegDecoder.ParseStream(stream, scanDecoder, CancellationToken.None);
+ switch (this.photometricInterpretation)
+ {
+ case TiffPhotometricInterpretation.BlackIsZero:
+ case TiffPhotometricInterpretation.WhiteIsZero:
+ {
+ using SpectralConverter spectralConverterGray = new GrayJpegSpectralConverter(this.configuration);
+ var scanDecoderGray = new HuffmanScanDecoder(stream, spectralConverterGray, CancellationToken.None);
+ jpegDecoder.LoadTables(this.jpegTables, scanDecoderGray);
+ scanDecoderGray.ResetInterval = 0;
+ jpegDecoder.ParseStream(stream, scanDecoderGray, CancellationToken.None);
- // TODO: Should we pass through the CancellationToken from the tiff decoder?
- CopyImageBytesToBuffer(buffer, spectralConverter.GetPixelBuffer(CancellationToken.None));
+ // TODO: Should we pass through the CancellationToken from the tiff decoder?
+ CopyImageBytesToBuffer(buffer, spectralConverterGray.GetPixelBuffer(CancellationToken.None));
+ break;
+ }
+
+ // If the PhotometricInterpretation is YCbCr we explicitly assume the JPEG data is in RGB color space.
+ // There seems no other way to determine that the JPEG data is RGB colorspace (no APP14 marker, componentId's are not RGB).
+ case TiffPhotometricInterpretation.YCbCr:
+ case TiffPhotometricInterpretation.Rgb:
+ {
+ using SpectralConverter spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr ?
+ new RgbJpegSpectralConverter(this.configuration) : new SpectralConverter(this.configuration);
+ var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None);
+ jpegDecoder.LoadTables(this.jpegTables, scanDecoder);
+ scanDecoder.ResetInterval = 0;
+ jpegDecoder.ParseStream(stream, scanDecoder, CancellationToken.None);
+
+ // TODO: Should we pass through the CancellationToken from the tiff decoder?
+ CopyImageBytesToBuffer(buffer, spectralConverter.GetPixelBuffer(CancellationToken.None));
+ break;
+ }
+
+ default:
+ TiffThrowHelper.ThrowNotSupported($"Jpeg compressed tiff with photometric interpretation {this.photometricInterpretation} is not supported");
+ break;
+ }
}
else
{
@@ -86,6 +111,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
}
}
+ private static void CopyImageBytesToBuffer(Span buffer, Buffer2D pixelBuffer)
+ {
+ int offset = 0;
+ for (int y = 0; y < pixelBuffer.Height; y++)
+ {
+ Span pixelRowSpan = pixelBuffer.DangerousGetRowSpan(y);
+ Span rgbBytes = MemoryMarshal.AsBytes(pixelRowSpan);
+ rgbBytes.CopyTo(buffer.Slice(offset));
+ offset += rgbBytes.Length;
+ }
+ }
+
///
protected override void Dispose(bool disposing)
{
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs
index 001480542..a83518064 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs
@@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System.Threading;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
using SixLabors.ImageSharp.PixelFormats;