mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
20 changed files with 337 additions and 107 deletions
@ -0,0 +1,33 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors; |
|||
|
|||
internal static class JpegCompressionUtils |
|||
{ |
|||
public static void CopyImageBytesToBuffer(Configuration configuration, Span<byte> buffer, Buffer2D<Rgb24> pixelBuffer) |
|||
{ |
|||
int offset = 0; |
|||
for (int y = 0; y < pixelBuffer.Height; y++) |
|||
{ |
|||
Span<Rgb24> pixelRowSpan = pixelBuffer.DangerousGetRowSpan(y); |
|||
PixelOperations<Rgb24>.Instance.ToRgb24Bytes(configuration, pixelRowSpan, buffer[offset..], pixelRowSpan.Length); |
|||
offset += Unsafe.SizeOf<Rgb24>() * pixelRowSpan.Length; |
|||
} |
|||
} |
|||
|
|||
public static void CopyImageBytesToBuffer(Configuration configuration, Span<byte> buffer, Buffer2D<L8> pixelBuffer) |
|||
{ |
|||
int offset = 0; |
|||
for (int y = 0; y < pixelBuffer.Height; y++) |
|||
{ |
|||
Span<L8> pixelRowSpan = pixelBuffer.DangerousGetRowSpan(y); |
|||
PixelOperations<L8>.Instance.ToL8Bytes(configuration, pixelRowSpan, buffer[offset..], pixelRowSpan.Length); |
|||
offset += Unsafe.SizeOf<L8>() * pixelRowSpan.Length; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.Jpeg; |
|||
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Constants; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors; |
|||
|
|||
internal sealed class OldJpegTiffCompression : TiffBaseDecompressor |
|||
{ |
|||
private readonly JpegDecoderOptions options; |
|||
|
|||
private readonly uint startOfImageMarker; |
|||
|
|||
private readonly TiffPhotometricInterpretation photometricInterpretation; |
|||
|
|||
public OldJpegTiffCompression( |
|||
JpegDecoderOptions options, |
|||
MemoryAllocator memoryAllocator, |
|||
int width, |
|||
int bitsPerPixel, |
|||
uint startOfImageMarker, |
|||
TiffPhotometricInterpretation photometricInterpretation) |
|||
: base(memoryAllocator, width, bitsPerPixel) |
|||
{ |
|||
this.options = options; |
|||
this.startOfImageMarker = startOfImageMarker; |
|||
this.photometricInterpretation = photometricInterpretation; |
|||
} |
|||
|
|||
protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span<byte> buffer, CancellationToken cancellationToken) |
|||
{ |
|||
long stripOffset = stream.Position; |
|||
stream.Position = this.startOfImageMarker; |
|||
|
|||
this.DecodeJpegData(stream, buffer, cancellationToken); |
|||
|
|||
// Setting the stream position to the expected position.
|
|||
// This is a workaround for some images having set the stripBytesCount not equal to the compressed jpeg data.
|
|||
stream.Position = stripOffset + byteCount; |
|||
} |
|||
|
|||
private void DecodeJpegData(BufferedReadStream stream, Span<byte> buffer, CancellationToken cancellationToken) |
|||
{ |
|||
using JpegDecoderCore jpegDecoder = new(this.options); |
|||
Configuration configuration = this.options.GeneralOptions.Configuration; |
|||
switch (this.photometricInterpretation) |
|||
{ |
|||
case TiffPhotometricInterpretation.BlackIsZero: |
|||
case TiffPhotometricInterpretation.WhiteIsZero: |
|||
{ |
|||
using SpectralConverter<L8> spectralConverterGray = new GrayJpegSpectralConverter<L8>(configuration); |
|||
|
|||
jpegDecoder.ParseStream(stream, spectralConverterGray, cancellationToken); |
|||
|
|||
using Buffer2D<L8> decompressedBuffer = spectralConverterGray.GetPixelBuffer(cancellationToken); |
|||
JpegCompressionUtils.CopyImageBytesToBuffer(spectralConverterGray.Configuration, buffer, decompressedBuffer); |
|||
break; |
|||
} |
|||
|
|||
case TiffPhotometricInterpretation.YCbCr: |
|||
case TiffPhotometricInterpretation.Rgb: |
|||
{ |
|||
using SpectralConverter<Rgb24> spectralConverter = new TiffOldJpegSpectralConverter<Rgb24>(configuration, this.photometricInterpretation); |
|||
|
|||
jpegDecoder.ParseStream(stream, spectralConverter, cancellationToken); |
|||
|
|||
using Buffer2D<Rgb24> decompressedBuffer = spectralConverter.GetPixelBuffer(cancellationToken); |
|||
JpegCompressionUtils.CopyImageBytesToBuffer(spectralConverter.Configuration, buffer, decompressedBuffer); |
|||
break; |
|||
} |
|||
|
|||
default: |
|||
TiffThrowHelper.ThrowNotSupported($"Jpeg compressed tiff with photometric interpretation {this.photometricInterpretation} is not supported"); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Dispose(bool disposing) |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.Jpeg.Components; |
|||
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Constants; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors; |
|||
|
|||
/// <summary>
|
|||
/// Spectral converter for YCbCr TIFF's which use the OldJPEG compression.
|
|||
/// The jpeg data should be always treated as YCbCr color space.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
|
|||
internal sealed class TiffOldJpegSpectralConverter<TPixel> : SpectralConverter<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
private readonly TiffPhotometricInterpretation photometricInterpretation; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TiffOldJpegSpectralConverter{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The configuration.</param>
|
|||
/// <param name="photometricInterpretation">Tiff photometric interpretation.</param>
|
|||
public TiffOldJpegSpectralConverter(Configuration configuration, TiffPhotometricInterpretation photometricInterpretation) |
|||
: base(configuration) |
|||
=> this.photometricInterpretation = photometricInterpretation; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) |
|||
{ |
|||
JpegColorSpace colorSpace = GetJpegColorSpaceFromPhotometricInterpretation(this.photometricInterpretation); |
|||
return JpegColorConverterBase.GetConverter(colorSpace, frame.Precision); |
|||
} |
|||
|
|||
private static JpegColorSpace GetJpegColorSpaceFromPhotometricInterpretation(TiffPhotometricInterpretation interpretation) |
|||
=> interpretation switch |
|||
{ |
|||
// Like libtiff: Always treat the pixel data as YCbCr when the data is compressed with old jpeg compression.
|
|||
TiffPhotometricInterpretation.Rgb => JpegColorSpace.YCbCr, |
|||
TiffPhotometricInterpretation.YCbCr => JpegColorSpace.YCbCr, |
|||
_ => throw new InvalidImageContentException($"Invalid tiff photometric interpretation for jpeg encoding: {interpretation}"), |
|||
}; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:0a5a02fb888a47ed51aa6d72122f9d1996311e943be62bef4829bc1aa9f457e8 |
|||
size 214023 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:e8f722bc322b9a7621d1d858bec36ea78d31b85221f314a2b9872d3af91d600a |
|||
size 5052 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:4b2b73290a40c49a4a29e51ad53dadea65c1ceafc6a5384430f7092d613830db |
|||
size 1390339 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:790662b0fc48d5604e80a9689eb28cfa231be3eadc33f34c9bf43c211cce5c16 |
|||
size 440613 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:b6527e69a3cce3e6d425c35695319711ad36d939f934902faa47f6ee1f1c7e08 |
|||
size 10076700 |
|||
Loading…
Reference in new issue