Browse Source

Add support for decoding gray tiff with jpeg compression

pull/2031/head
Brian Popow 4 years ago
parent
commit
3f9331856e
  1. 29
      src/ImageSharp/Formats/Tiff/Compression/Decompressors/GrayJpegSpectralConverter.cs
  2. 59
      src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
  3. 1
      src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs

29
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
{
/// <summary>
/// Spectral converter for gray TIFF's which use the JPEG compression.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
internal sealed class GrayJpegSpectralConverter<TPixel> : SpectralConverter<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="GrayJpegSpectralConverter{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
public GrayJpegSpectralConverter(Configuration configuration)
: base(configuration)
{
}
/// <inheritdoc/>
protected override JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverterBase.GetConverter(JpegColorSpace.Grayscale, frame.Precision);
}
}

59
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<Rgb24> spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr ?
new RgbJpegSpectralConverter<Rgb24>(this.configuration) : new SpectralConverter<Rgb24>(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<L8> spectralConverterGray = new GrayJpegSpectralConverter<L8>(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<Rgb24> spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr ?
new RgbJpegSpectralConverter<Rgb24>(this.configuration) : new SpectralConverter<Rgb24>(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<byte> buffer, Buffer2D<L8> pixelBuffer)
{
int offset = 0;
for (int y = 0; y < pixelBuffer.Height; y++)
{
Span<L8> pixelRowSpan = pixelBuffer.DangerousGetRowSpan(y);
Span<byte> rgbBytes = MemoryMarshal.AsBytes(pixelRowSpan);
rgbBytes.CopyTo(buffer.Slice(offset));
offset += rgbBytes.Length;
}
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{

1
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;

Loading…
Cancel
Save