diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index 7de838bc94..bfbaa1b31c 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -968,7 +968,7 @@ public static uint RotateRightSoftwareFallback(uint value, int offset)
/// Tells whether input value is outside of the given range.
///
/// Value.
- /// Mininum value, inclusive.
+ /// Minimum value, inclusive.
/// Maximum value, inclusive.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOutOfRange(int value, int min, int max)
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index a07db1c952..99039567ae 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -90,6 +90,11 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
///
private JFifMarker jFif;
+ ///
+ /// Whether the image has a JFIF marker. This is needed to determine, if the colorspace is YCbCr.
+ ///
+ private bool hasJFif;
+
///
/// Contains information about the Adobe marker.
///
@@ -514,17 +519,50 @@ private JpegColorSpace DeduceJpegColorSpace(byte componentCount)
if (componentCount == 3)
{
- if (!this.adobe.Equals(default) && this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
+ // 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))
{
- return JpegColorSpace.RGB;
+ 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();
+ }
+
+ if (this.hasJFif)
+ {
+ // JFIF implies 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)
{
return JpegColorSpace.RGB;
}
+ // 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;
+ }
+
// Some images are poorly encoded and contain incorrect colorspace transform metadata.
// We ignore that and always fall back to the default colorspace.
return JpegColorSpace.YCbCr;
@@ -532,9 +570,24 @@ private JpegColorSpace DeduceJpegColorSpace(byte componentCount)
if (componentCount == 4)
{
- return this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck
- ? JpegColorSpace.Ycck
- : JpegColorSpace.Cmyk;
+ // 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;
}
JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount);
@@ -701,6 +754,8 @@ private void ExtendProfile(ref byte[] profile, byte[] extension)
/// 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.
diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
index 1073ffff78..0dc412a6f9 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
@@ -51,5 +51,8 @@ internal static class JpegThrowHelper
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowNotSupportedComponentCount(int componentCount) => throw new NotSupportedException($"Images with {componentCount} components are not supported.");
+
+ [MethodImpl(InliningOptions.ColdPath)]
+ public static void ThrowNotSupportedColorSpace() => throw new NotSupportedException("Image color space could not be deduced.");
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
index 88dbcb8828..3b2c765b38 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
@@ -65,13 +65,11 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
jpegDecoder.ParseStream(stream, spectralConverterGray, CancellationToken.None);
// TODO: Should we pass through the CancellationToken from the tiff decoder?
- using var decompressedBuffer = spectralConverterGray.GetPixelBuffer(CancellationToken.None);
+ using Buffer2D decompressedBuffer = spectralConverterGray.GetPixelBuffer(CancellationToken.None);
CopyImageBytesToBuffer(buffer, decompressedBuffer);
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:
{
@@ -82,7 +80,7 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
jpegDecoder.ParseStream(stream, spectralConverter, CancellationToken.None);
// TODO: Should we pass through the CancellationToken from the tiff decoder?
- using var decompressedBuffer = spectralConverter.GetPixelBuffer(CancellationToken.None);
+ using Buffer2D decompressedBuffer = spectralConverter.GetPixelBuffer(CancellationToken.None);
CopyImageBytesToBuffer(buffer, decompressedBuffer);
break;
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrConverter.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrConverter.cs
index c6594f9084..41c3facd19 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrConverter.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrConverter.cs
@@ -19,16 +19,16 @@ internal class YCbCrConverter
private static readonly Rational[] DefaultLuma =
{
- new Rational(299, 1000),
- new Rational(587, 1000),
- new Rational(114, 1000)
+ new(299, 1000),
+ new(587, 1000),
+ new(114, 1000)
};
private static readonly Rational[] DefaultReferenceBlackWhite =
{
- new Rational(0, 1), new Rational(255, 1),
- new Rational(128, 1), new Rational(255, 1),
- new Rational(128, 1), new Rational(255, 1)
+ new(0, 1), new(255, 1),
+ new(128, 1), new(255, 1),
+ new(128, 1), new(255, 1)
};
public YCbCrConverter(Rational[] referenceBlackAndWhite, Rational[] coefficients)
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs
index 52cc1f0f17..9b37cf16a5 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs
@@ -39,8 +39,15 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
Span tmpBufferSpan = tmpBuffer.GetSpan();
ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], data, tmpBufferSpan);
ycbcrData = tmpBufferSpan;
+ this.DecodeYCbCrData(pixels, left, top, width, height, ycbcrData);
+ return;
}
+ this.DecodeYCbCrData(pixels, left, top, width, height, ycbcrData);
+ }
+
+ private void DecodeYCbCrData(Buffer2D pixels, int left, int top, int width, int height, ReadOnlySpan ycbcrData)
+ {
var color = default(TPixel);
int offset = 0;
int widthPadding = 0;
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index 1cd3d2c0c1..c595246a5b 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -228,7 +228,7 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
/// The pixel format.
/// The IFD tags.
/// The token to monitor cancellation.
- /// The tiff frame.
+ /// The tiff frame.
private ImageFrame DecodeFrame(ExifProfile tags, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index 6baf71466a..6d99fed3e1 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
@@ -459,6 +459,14 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi
case TiffCompression.Jpeg:
{
options.CompressionType = TiffDecoderCompressionType.Jpeg;
+
+ if (options.PhotometricInterpretation is TiffPhotometricInterpretation.YCbCr && options.JpegTables is null)
+ {
+ // Note: Setting PhotometricInterpretation and color type to RGB here, since the jpeg decoder will handle the conversion of the pixel data.
+ options.PhotometricInterpretation = TiffPhotometricInterpretation.Rgb;
+ options.ColorType = TiffColorType.Rgb;
+ }
+
break;
}
diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets
index 5258601897..4e1b9503e1 100644
--- a/tests/Directory.Build.targets
+++ b/tests/Directory.Build.targets
@@ -21,7 +21,7 @@
-
+
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index ceded79cc2..b9569c7a46 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -303,8 +303,6 @@ public void TiffDecoder_CanDecode_24Bit_Gray(TestImageProvider p
[Theory]
[WithFile(FlowerYCbCr888Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerYCbCr888Planar, PixelTypes.Rgba32)]
- [WithFile(RgbYCbCr888Contiguoush1v1, PixelTypes.Rgba32)]
- [WithFile(RgbYCbCr888Contiguoush2v1, PixelTypes.Rgba32)]
[WithFile(RgbYCbCr888Contiguoush2v2, PixelTypes.Rgba32)]
[WithFile(RgbYCbCr888Contiguoush4v4, PixelTypes.Rgba32)]
[WithFile(FlowerYCbCr888Contiguoush2v1, PixelTypes.Rgba32)]
@@ -317,6 +315,7 @@ public void TiffDecoder_CanDecode_YCbCr_24Bit(TestImageProvider
// converting the pixel data from Magick.NET to our format with YCbCr?
using Image image = provider.GetImage();
image.DebugSave(provider);
+ image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
[Theory]
@@ -642,10 +641,13 @@ public void CanDecodeJustOneFrame(TestImageProvider provider)
[Theory]
[WithFile(RgbJpegCompressed, PixelTypes.Rgba32)]
+ [WithFile(RgbJpegCompressed2, PixelTypes.Rgba32)]
[WithFile(RgbWithStripsJpegCompressed, PixelTypes.Rgba32)]
[WithFile(YCbCrJpegCompressed, PixelTypes.Rgba32)]
+ [WithFile(YCbCrJpegCompressed2, PixelTypes.Rgba32)]
[WithFile(RgbJpegCompressedNoJpegTable, PixelTypes.Rgba32)]
[WithFile(GrayscaleJpegCompressed, PixelTypes.Rgba32)]
+ [WithFile(Issues2123, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_JpegCompressed(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, useExactComparer: false);
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index a3ef6942f3..023efd7076 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -780,6 +780,7 @@ public static class Tiff
public const string RgbDeflatePredictor = "Tiff/rgb_deflate_predictor.tiff";
public const string RgbDeflateMultistrip = "Tiff/rgb_deflate_multistrip.tiff";
public const string RgbJpegCompressed = "Tiff/rgb_jpegcompression.tiff";
+ public const string RgbJpegCompressed2 = "Tiff/twain-rgb-jpeg-with-bogus-ycbcr-subsampling.tiff";
public const string RgbWithStripsJpegCompressed = "Tiff/rgb_jpegcompressed_stripped.tiff";
public const string RgbJpegCompressedNoJpegTable = "Tiff/rgb_jpegcompressed_nojpegtable.tiff";
public const string RgbLzwPredictor = "Tiff/rgb_lzw_predictor.tiff";
@@ -825,11 +826,10 @@ public static class Tiff
public const string FlowerYCbCr888Contiguoush2v1 = "Tiff/flower-ycbcr-contig-08_h2v1.tiff";
public const string FlowerYCbCr888Contiguoush2v2 = "Tiff/flower-ycbcr-contig-08_h2v2.tiff";
public const string FlowerYCbCr888Contiguoush4v4 = "Tiff/flower-ycbcr-contig-08_h4v4.tiff";
- public const string RgbYCbCr888Contiguoush1v1 = "Tiff/rgb-ycbcr-contig-08_h1v1.tiff";
- public const string RgbYCbCr888Contiguoush2v1 = "Tiff/rgb-ycbcr-contig-08_h2v1.tiff";
public const string RgbYCbCr888Contiguoush2v2 = "Tiff/rgb-ycbcr-contig-08_h2v2.tiff";
public const string RgbYCbCr888Contiguoush4v4 = "Tiff/rgb-ycbcr-contig-08_h4v4.tiff";
public const string YCbCrJpegCompressed = "Tiff/ycbcr_jpegcompressed.tiff";
+ public const string YCbCrJpegCompressed2 = "Tiff/ycbcr_jpegcompressed2.tiff";
public const string FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff";
public const string FlowerRgb444Planar = "Tiff/flower-rgb-planar-04.tiff";
public const string FlowerRgb222Contiguous = "Tiff/flower-rgb-contig-02.tiff";
@@ -912,6 +912,7 @@ public static class Tiff
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
public const string Issues1891 = "Tiff/Issues/Issue1891.tiff";
+ public const string Issues2123 = "Tiff/Issues/Issue2123.tiff";
public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff";
public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff";
diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h1v1.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h1v1.png
new file mode 100644
index 0000000000..3c9cbce8f6
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h1v1.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4f43aec94a8febc4174d1c3b0637b9e613781acccc1dc988cb62f521e26c4038
+size 9775
diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h2v1.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h2v1.png
new file mode 100644
index 0000000000..9edccbed24
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h2v1.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f874b0a5172d494a8c8e9760fe87e02d138d78e15de637506ff46334ad7d0629
+size 9792
diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h2v2.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h2v2.png
new file mode 100644
index 0000000000..d8fa6791a7
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h2v2.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fa07f9f6a85a87e145224a6e2d42c7ecc26b9128d01eee3f45fc4333f05d560c
+size 9808
diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h4v4.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h4v4.png
new file mode 100644
index 0000000000..78fba45962
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-contig-08_h4v4.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c34d570b0e6d7d9fe830e4696c6acb279929b86e6f4b9f572d4b379fee383315
+size 9504
diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-planar-08_h1v1.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-planar-08_h1v1.png
new file mode 100644
index 0000000000..3c9cbce8f6
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_flower-ycbcr-planar-08_h1v1.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4f43aec94a8febc4174d1c3b0637b9e613781acccc1dc988cb62f521e26c4038
+size 9775
diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_rgb-ycbcr-contig-08_h2v2.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_rgb-ycbcr-contig-08_h2v2.png
new file mode 100644
index 0000000000..a1d71cbaff
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_rgb-ycbcr-contig-08_h2v2.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:77a101bcc2059d8ca98ac7b1c4fe67a286c33f0d9fa7d37bb4a5073377f70c62
+size 91016
diff --git a/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_rgb-ycbcr-contig-08_h4v4.png b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_rgb-ycbcr-contig-08_h4v4.png
new file mode 100644
index 0000000000..cb1f0ea692
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_YCbCr_24Bit_Rgba32_rgb-ycbcr-contig-08_h4v4.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cbe7c1ab6862e2f6ad5ad5f0a02634a2a3e99fbf1a404168b1fbcd7aafb27884
+size 84732
diff --git a/tests/Images/Input/Tiff/Issues/Issue2123.tiff b/tests/Images/Input/Tiff/Issues/Issue2123.tiff
new file mode 100644
index 0000000000..a21bffca12
--- /dev/null
+++ b/tests/Images/Input/Tiff/Issues/Issue2123.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5663288720203035c454c61c529222c2170df21dcde1a89f1f30e3b668020d6f
+size 3805
diff --git a/tests/Images/Input/Tiff/rgb-ycbcr-contig-08_h2v1.tiff b/tests/Images/Input/Tiff/rgb-ycbcr-contig-08_h2v1.tiff
deleted file mode 100644
index 82350e5b29..0000000000
--- a/tests/Images/Input/Tiff/rgb-ycbcr-contig-08_h2v1.tiff
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:95b1ba4ff48ea2263041eca4ada44d009277297bb3b3a185d48580bdf3f7caaf
-size 81382
diff --git a/tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff b/tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff
index b97ab8830d..a10b0dfa55 100644
--- a/tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff
+++ b/tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6b81013d7b0a29ed1ac9c33e175e0c0e69494b93b2b65b692f16d9ea042b9d5d
-size 7759
+oid sha256:3e889209fc31702aaa7c966c1b5370cc0904cbfbcfd17718977045049cc1bfd9
+size 5904
diff --git a/tests/Images/Input/Tiff/twain-rgb-jpeg-with-bogus-ycbcr-subsampling.tiff b/tests/Images/Input/Tiff/twain-rgb-jpeg-with-bogus-ycbcr-subsampling.tiff
new file mode 100644
index 0000000000..67c5bcf9a6
--- /dev/null
+++ b/tests/Images/Input/Tiff/twain-rgb-jpeg-with-bogus-ycbcr-subsampling.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d7a559d36e3852265ab4f82e43d28cc0bfc310813a5ced08e51c1366d8e323f9
+size 146853
diff --git a/tests/Images/Input/Tiff/ycbcr_jpegcompressed2.tiff b/tests/Images/Input/Tiff/ycbcr_jpegcompressed2.tiff
new file mode 100644
index 0000000000..26495d577d
--- /dev/null
+++ b/tests/Images/Input/Tiff/ycbcr_jpegcompressed2.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:533f92b6a45c2de4dc0f3cdb8debf45dcfe84790cfa652404b2f44e15f06e44f
+size 38816