diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 4be75f2a1..30af0b4e2 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -86,14 +86,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private byte[] xmpData;
///
- /// Contains information about the JFIF marker.
+ /// Whether the image has a APP14 adobe marker. This is needed to determine image encoded colorspace.
///
- private JFifMarker jFif;
+ private bool hasAdobeMarker;
///
- /// Whether the image has a JFIF marker. This is needed to determine, if the colorspace is YCbCr.
+ /// Contains information about the JFIF marker.
///
- private bool hasJFif;
+ private JFifMarker jFif;
///
/// Contains information about the Adobe marker.
@@ -507,11 +507,12 @@ 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
- private JpegColorSpace DeduceJpegColorSpace(byte componentCount)
+ internal static JpegColorSpace DeduceJpegColorSpace(byte componentCount, ref AdobeMarker adobeMarker)
{
if (componentCount == 1)
{
@@ -520,80 +521,47 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (componentCount == 3)
{
- // We prioritize adobe marker over jfif marker, if somebody really encoded this image with redundant adobe marker,
- // then it's most likely an adobe jfif image.
- if (!this.adobe.Equals(default))
+ if (adobeMarker.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
- {
- return JpegColorSpace.YCbCr;
- }
-
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
- {
- return JpegColorSpace.RGB;
- }
-
- // Fallback to the id color deduction: If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr.
- if (this.Components[2].Id == 3 && this.Components[1].Id == 2 && this.Components[0].Id == 1)
- {
- return JpegColorSpace.YCbCr;
- }
-
- JpegThrowHelper.ThrowNotSupportedColorSpace();
+ return JpegColorSpace.RGB;
}
- if (this.hasJFif)
- {
- // JFIF implies YCbCr.
- return JpegColorSpace.YCbCr;
- }
+ return JpegColorSpace.YCbCr;
+ }
- // Fallback to the id color deduction.
- // If the component Id's are R, G, B in ASCII the colorspace is RGB and not YCbCr.
- // See: https://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#color
- if (this.Components[2].Id == 66 && this.Components[1].Id == 71 && this.Components[0].Id == 82)
+ if (componentCount == 4)
+ {
+ if (adobeMarker.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
{
- return JpegColorSpace.RGB;
+ return JpegColorSpace.Ycck;
}
- // If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr.
- if (this.Components[2].Id == 3 && this.Components[1].Id == 2 && this.Components[0].Id == 1)
- {
- return JpegColorSpace.YCbCr;
- }
+ return JpegColorSpace.Cmyk;
+ }
- // 3-channel non-subsampled images are assumed to be RGB.
- if (this.Components[2].VerticalSamplingFactor == 1 && this.Components[1].VerticalSamplingFactor == 1 && this.Components[0].VerticalSamplingFactor == 1 &&
- this.Components[2].HorizontalSamplingFactor == 1 && this.Components[1].HorizontalSamplingFactor == 1 && this.Components[0].HorizontalSamplingFactor == 1)
- {
- return JpegColorSpace.RGB;
- }
+ JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount);
+ return default;
+ }
+
+ ///
+ /// Returns encoded colorspace based on the component count.
+ ///
+ /// Number of components.
+ /// The
+ internal static JpegColorSpace DeduceJpegColorSpace(byte componentCount)
+ {
+ if (componentCount == 1)
+ {
+ return JpegColorSpace.Grayscale;
+ }
- // Some images are poorly encoded and contain incorrect colorspace transform metadata.
- // We ignore that and always fall back to the default colorspace.
+ if (componentCount == 3)
+ {
return JpegColorSpace.YCbCr;
}
if (componentCount == 4)
{
- // jfif images doesn't not support 4 component images, so we only check adobe.
- if (!this.adobe.Equals(default))
- {
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
- {
- return JpegColorSpace.Ycck;
- }
-
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
- {
- return JpegColorSpace.Cmyk;
- }
-
- JpegThrowHelper.ThrowNotSupportedColorSpace();
- }
-
- // Fallback to cmyk as neither of cmyk nor ycck have 'special' component ids.
return JpegColorSpace.Cmyk;
}
@@ -761,8 +729,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// The remaining bytes in the segment block.
private void ProcessApplicationHeaderMarker(BufferedReadStream stream, int remaining)
{
- this.hasJFif = true;
-
// We can only decode JFif identifiers.
// Some images contain multiple JFIF markers (Issue 1932) so we check to see
// if it's already been read.
@@ -1065,7 +1031,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
stream.Read(this.temp, 0, MarkerLength);
remaining -= MarkerLength;
- AdobeMarker.TryParse(this.temp, out this.adobe);
+ if (AdobeMarker.TryParse(this.temp, out this.adobe))
+ {
+ this.hasAdobeMarker = true;
+ }
if (remaining > 0)
{
@@ -1258,7 +1227,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];
@@ -1309,7 +1278,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
index += componentBytes;
}
- this.ColorSpace = this.DeduceJpegColorSpace(componentCount);
+ this.ColorSpace = this.hasAdobeMarker
+ ? DeduceJpegColorSpace(componentCount, ref this.adobe)
+ : DeduceJpegColorSpace(componentCount);
this.Metadata.GetJpegMetadata().ColorType = this.DeduceJpegColorType();
if (!metadataOnly)
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
index 50698d64d..babcb4516 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
@@ -73,10 +73,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
case TiffPhotometricInterpretation.YCbCr:
case TiffPhotometricInterpretation.Rgb:
{
- using SpectralConverter spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr
- ? new RgbJpegSpectralConverter(this.options.GeneralOptions.Configuration)
- : new SpectralConverter(this.options.GeneralOptions.Configuration);
-
+ using SpectralConverter spectralConverter =
+ new TiffJpegSpectralConverter(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 f8cf3e2a9..000000000
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-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 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 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 000000000..ced6b9027
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/TiffJpegSpectralConverter{TPixel}.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+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/src/ImageSharp/Formats/Tiff/Compression/Decompressors/WebpTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/WebpTiffCompression.cs
new file mode 100644
index 000000000..0d63382ff
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/WebpTiffCompression.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using System;
+using System.Runtime.InteropServices;
+using SixLabors.ImageSharp.Formats.Tiff.Constants;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
+{
+ ///
+ /// Class to handle cases where TIFF image data is compressed as a webp stream.
+ ///
+ internal class WebpTiffCompression : TiffBaseDecompressor
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator.
+ /// The width of the image.
+ /// The bits per pixel.
+ /// The predictor.
+ public WebpTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffPredictor predictor = TiffPredictor.None)
+ : base(memoryAllocator, width, bitsPerPixel, predictor)
+ {
+ }
+
+ ///
+ protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span buffer)
+ {
+ using var image = Image.Load(stream, new WebpDecoder());
+ CopyImageBytesToBuffer(buffer, image.Frames.RootFrame.PixelBuffer);
+ }
+
+ 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/TiffDecoderCompressionType.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs
index 44caba5b0..3188b9e9a 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs
@@ -47,5 +47,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
/// The image data is compressed as a JPEG stream.
///
Jpeg = 7,
+
+ ///
+ /// The image data is compressed as a WEBP stream.
+ ///
+ Webp = 8,
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
index 086db4b0a..2b121f4de 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
@@ -60,6 +60,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
return new JpegTiffCompression(new() { GeneralOptions = options }, allocator, width, bitsPerPixel, jpegTables, photometricInterpretation);
+ case TiffDecoderCompressionType.Webp:
+ DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
+ return new WebpTiffCompression(allocator, width, bitsPerPixel);
+
default:
throw TiffThrowHelper.NotSupportedDecompressor(nameof(method));
}
diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
index e8eecf2e4..fdb1d6aa1 100644
--- a/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
@@ -103,5 +103,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
/// if this is chosen.
///
OldDeflate = 32946,
+
+ ///
+ /// Pixel data is compressed with webp encoder.
+ ///
+ /// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
+ /// if this is chosen.
+ ///
+ Webp = 50001,
}
}
diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md
index 865b2f9c2..00d46c415 100644
--- a/src/ImageSharp/Formats/Tiff/README.md
+++ b/src/ImageSharp/Formats/Tiff/README.md
@@ -37,11 +37,12 @@
|PackBits | Y | Y | |
|CcittGroup3Fax | Y | Y | |
|CcittGroup4Fax | Y | Y | |
-|Lzw | Y | Y | Based on ImageSharp GIF LZW implementation - this code could be modified to be (i) shared, or (ii) optimised for each case |
-|Old Jpeg | | | We should not even try to support this |
+|Lzw | Y | Y | Based on ImageSharp GIF LZW implementation - this code could be modified to be (i) shared, or (ii) optimised for each case. |
+|Old Jpeg | | | We should not even try to support this. |
|Jpeg (Technote 2) | Y | Y | |
|Deflate (Technote 2) | Y | Y | Based on PNG Deflate. |
|Old Deflate (Technote 2) | | Y | |
+|Webp | | Y | |
### Photometric Interpretation Formats
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index 2e53acec8..d3686852d 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
@@ -488,6 +488,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
break;
}
+ case TiffCompression.Webp:
+ {
+ options.CompressionType = TiffDecoderCompressionType.Webp;
+ break;
+ }
+
default:
{
TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format '{compression}' is not supported");
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs
new file mode 100644
index 000000000..6bf7ae88f
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs
@@ -0,0 +1,71 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
+using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
+using SixLabors.ImageSharp.Tests.TestUtilities;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
+using Xunit;
+using Xunit.Abstractions;
+
+// ReSharper disable InconsistentNaming
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ [Trait("Format", "Jpg")]
+ public partial class JpegDecoderTests
+ {
+ [Theory]
+ [InlineData(1, 0, JpegColorSpace.Grayscale)]
+ [InlineData(3, JpegConstants.Adobe.ColorTransformUnknown, JpegColorSpace.RGB)]
+ [InlineData(3, JpegConstants.Adobe.ColorTransformYCbCr, JpegColorSpace.YCbCr)]
+ [InlineData(4, JpegConstants.Adobe.ColorTransformUnknown, JpegColorSpace.Cmyk)]
+ [InlineData(4, JpegConstants.Adobe.ColorTransformYcck, JpegColorSpace.Ycck)]
+ internal void DeduceJpegColorSpaceAdobeMarker_ShouldReturnValidColorSpace(byte componentCount, byte adobeFlag, JpegColorSpace expectedColorSpace)
+ {
+ 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);
+ }
+
+ [Theory]
+ [InlineData(2)]
+ [InlineData(5)]
+ public void DeduceJpegColorSpaceAdobeMarker_ShouldThrowOnUnsupportedComponentCount(byte componentCount)
+ {
+ AdobeMarker adobeMarker = default;
+
+ Assert.Throws(() => JpegDecoderCore.DeduceJpegColorSpace(componentCount, ref adobeMarker));
+ }
+
+ [Theory]
+ [InlineData(1, JpegColorSpace.Grayscale)]
+ [InlineData(3, JpegColorSpace.YCbCr)]
+ [InlineData(4, JpegColorSpace.Cmyk)]
+ internal void DeduceJpegColorSpace_ShouldReturnValidColorSpace(byte componentCount, JpegColorSpace expectedColorSpace)
+ {
+ JpegColorSpace actualColorSpace = JpegDecoderCore.DeduceJpegColorSpace(componentCount);
+
+ Assert.Equal(expectedColorSpace, actualColorSpace);
+ }
+
+ [Theory]
+ [InlineData(2)]
+ [InlineData(5)]
+ public void DeduceJpegColorSpace_ShouldThrowOnUnsupportedComponentCount(byte componentCount)
+ => Assert.Throws(() => JpegDecoderCore.DeduceJpegColorSpace(componentCount));
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index 0bfe3993a..6aaeafdda 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -667,6 +667,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_JpegCompressed(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, useExactComparer: false);
+ [Theory]
+ [WithFile(WebpCompressed, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_WebpCompressed(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ if (TestEnvironment.IsWindows)
+ {
+ TestTiffDecoder(provider, useExactComparer: false);
+ }
+ }
+
// https://github.com/SixLabors/ImageSharp/issues/1891
[Theory]
[WithFile(Issues1891, PixelTypes.Rgba32)]
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index b364b1d2c..3efb528a8 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -763,8 +763,8 @@ namespace SixLabors.ImageSharp.Tests
public const string Fax4Compressed = "Tiff/basi3p02_fax4.tiff";
public const string Fax4Compressed2 = "Tiff/CCITTGroup4.tiff";
public const string Fax4CompressedLowerOrderBitsFirst = "Tiff/basi3p02_fax4_lowerOrderBitsFirst.tiff";
+ public const string WebpCompressed = "Tiff/webp_compressed.tiff";
public const string Fax4CompressedMinIsBlack = "Tiff/CCITTGroup4_minisblack.tiff";
-
public const string CcittFax3AllTermCodes = "Tiff/ccitt_fax3_all_terminating_codes.tiff";
public const string CcittFax3AllMakeupCodes = "Tiff/ccitt_fax3_all_makeup_codes.tiff";
public const string HuffmanRleAllTermCodes = "Tiff/huffman_rle_all_terminating_codes.tiff";
diff --git a/tests/Images/Input/Tiff/webp_compressed.tiff b/tests/Images/Input/Tiff/webp_compressed.tiff
new file mode 100644
index 000000000..71248e521
--- /dev/null
+++ b/tests/Images/Input/Tiff/webp_compressed.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:72fd7fa941aa6201faa5368349764b4c17b582bee9be65861bad6308a8c5e4fe
+size 4898