Browse Source

Merge branch 'main' into stefannikolei/nullable/metadata_profiles

pull/2330/head
James Jackson-South 4 years ago
committed by GitHub
parent
commit
753720f115
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  2. 5
      src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
  3. 2
      src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs
  4. 20
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  5. 20
      src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
  6. 9
      src/ImageSharp/Formats/Tiff/Writers/TiffColorWriterFactory.cs
  7. 22
      src/ImageSharp/Formats/Tiff/Writers/TiffGrayL16Writer{TPixel}.cs
  8. 7
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  9. 47
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
  10. 1
      tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
  11. 5
      tests/ImageSharp.Tests/TestImages.cs
  12. 3
      tests/Images/Input/Tiff/Calliphora_gray_deflate_16bit.tiff
  13. 3
      tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor_16bit.tiff
  14. 3
      tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor_16bit.tiff
  15. 3
      tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed_16bit.tiff
  16. 3
      tests/Images/Input/Tiff/grayscale_uncompressed_16bit.tiff

31
src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

@ -67,6 +67,11 @@ internal static class HorizontalPredictor
{ {
ApplyHorizontalPrediction8Bit(rows, width); ApplyHorizontalPrediction8Bit(rows, width);
} }
else if (bitsPerPixel == 16)
{
// Assume rows are L16 grayscale since that's currently the only way 16 bits is supported by encoder
ApplyHorizontalPrediction16Bit(rows, width);
}
else if (bitsPerPixel == 24) else if (bitsPerPixel == 24)
{ {
ApplyHorizontalPrediction24Bit(rows, width); ApplyHorizontalPrediction24Bit(rows, width);
@ -102,6 +107,32 @@ internal static class HorizontalPredictor
} }
} }
/// <summary>
/// Applies a horizontal predictor to the L16 row.
/// Make use of the fact that many continuous-tone images rarely vary much in pixel value from one pixel to the next.
/// In such images, if we replace the pixel values by differences between consecutive pixels, many of the differences should be 0, plus
/// or minus 1, and so on.This reduces the apparent information content and allows LZW to encode the data more compactly.
/// </summary>
/// <param name="rows">The L16 pixel rows.</param>
/// <param name="width">The width.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private static void ApplyHorizontalPrediction16Bit(Span<byte> rows, int width)
{
DebugGuard.IsTrue(rows.Length % width == 0, "Values must be equals");
int height = rows.Length / width;
for (int y = 0; y < height; y++)
{
Span<byte> rowSpan = rows.Slice(y * width, width);
Span<L16> rowL16 = MemoryMarshal.Cast<byte, L16>(rowSpan);
for (int x = rowL16.Length - 1; x >= 1; x--)
{
ushort val = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue);
rowL16[x].PackedValue = val;
}
}
}
/// <summary> /// <summary>
/// Applies a horizontal predictor to a gray pixel row. /// Applies a horizontal predictor to a gray pixel row.
/// </summary> /// </summary>

5
src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs

@ -73,6 +73,11 @@ internal static class TiffConstants
/// </summary> /// </summary>
public static readonly TiffBitsPerSample BitsPerSample8Bit = new TiffBitsPerSample(8, 0, 0); public static readonly TiffBitsPerSample BitsPerSample8Bit = new TiffBitsPerSample(8, 0, 0);
/// <summary>
/// The bits per sample for 16-bit grayscale images.
/// </summary>
public static readonly TiffBitsPerSample BitsPerSample16Bit = new TiffBitsPerSample(16, 0, 0);
/// <summary> /// <summary>
/// The bits per sample for color images with 8 bits for each color channel. /// The bits per sample for color images with 8 bits for each color channel.
/// </summary> /// </summary>

2
src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs

@ -54,7 +54,7 @@ public enum TiffBitsPerPixel
/// <summary> /// <summary>
/// 16 bits per pixel, for gray images. /// 16 bits per pixel, for gray images.
/// ///
/// Note: The TiffEncoder does not yet support 16 bits per color channel and will default to 24 bits per pixel instead. /// Note: The TiffEncoder does not yet support 16 bits per color channel and will default to 16 bits grayscale instead.
/// </summary> /// </summary>
Bit16 = 16, Bit16 = 16,

20
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs

@ -376,11 +376,14 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals
case TiffBitsPerPixel.Bit8: case TiffBitsPerPixel.Bit8:
this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor); this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor);
break; break;
case TiffBitsPerPixel.Bit16:
// Assume desire to encode as L16 grayscale
this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.BlackIsZero, compression, predictor);
break;
case TiffBitsPerPixel.Bit6: case TiffBitsPerPixel.Bit6:
case TiffBitsPerPixel.Bit10: case TiffBitsPerPixel.Bit10:
case TiffBitsPerPixel.Bit12: case TiffBitsPerPixel.Bit12:
case TiffBitsPerPixel.Bit14: case TiffBitsPerPixel.Bit14:
case TiffBitsPerPixel.Bit16:
case TiffBitsPerPixel.Bit30: case TiffBitsPerPixel.Bit30:
case TiffBitsPerPixel.Bit36: case TiffBitsPerPixel.Bit36:
case TiffBitsPerPixel.Bit42: case TiffBitsPerPixel.Bit42:
@ -413,13 +416,20 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals
return; return;
} }
// At the moment only 8 and 32 bits per pixel can be preserved by the tiff encoder. // At the moment only 8, 16 and 32 bits per pixel can be preserved by the tiff encoder.
if (inputBitsPerPixel == 8) if (inputBitsPerPixel == 8)
{ {
this.SetEncoderOptions(TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); this.SetEncoderOptions(TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.BlackIsZero, compression, predictor);
return; return;
} }
if (inputBitsPerPixel == 16)
{
// Assume desire to encode as L16 grayscale
this.SetEncoderOptions(TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, compression, predictor);
return;
}
this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, predictor); this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, predictor);
return; return;
} }
@ -434,6 +444,12 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals
return; return;
} }
if (inputBitsPerPixel == 16)
{
this.SetEncoderOptions(TiffBitsPerPixel.Bit16, photometricInterpretation, compression, predictor);
return;
}
this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor); this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor);
return; return;

20
src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs

@ -343,20 +343,20 @@ internal class TiffEncoderEntriesCollector
return TiffConstants.BitsPerSampleRgb8Bit.ToArray(); return TiffConstants.BitsPerSampleRgb8Bit.ToArray();
case TiffPhotometricInterpretation.WhiteIsZero: case TiffPhotometricInterpretation.WhiteIsZero:
if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1) return encoder.BitsPerPixel switch
{ {
return TiffConstants.BitsPerSample1Bit.ToArray(); TiffBitsPerPixel.Bit1 => TiffConstants.BitsPerSample1Bit.ToArray(),
} TiffBitsPerPixel.Bit16 => TiffConstants.BitsPerSample16Bit.ToArray(),
_ => TiffConstants.BitsPerSample8Bit.ToArray()
return TiffConstants.BitsPerSample8Bit.ToArray(); };
case TiffPhotometricInterpretation.BlackIsZero: case TiffPhotometricInterpretation.BlackIsZero:
if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1) return encoder.BitsPerPixel switch
{ {
return TiffConstants.BitsPerSample1Bit.ToArray(); TiffBitsPerPixel.Bit1 => TiffConstants.BitsPerSample1Bit.ToArray(),
} TiffBitsPerPixel.Bit16 => TiffConstants.BitsPerSample16Bit.ToArray(),
_ => TiffConstants.BitsPerSample8Bit.ToArray()
return TiffConstants.BitsPerSample8Bit.ToArray(); };
default: default:
return TiffConstants.BitsPerSampleRgb8Bit.ToArray(); return TiffConstants.BitsPerSampleRgb8Bit.ToArray();

9
src/ImageSharp/Formats/Tiff/Writers/TiffColorWriterFactory.cs

@ -27,12 +27,13 @@ internal static class TiffColorWriterFactory
return new TiffPaletteWriter<TPixel>(image, quantizer, pixelSamplingStrategy, memoryAllocator, configuration, entriesCollector, bitsPerPixel); return new TiffPaletteWriter<TPixel>(image, quantizer, pixelSamplingStrategy, memoryAllocator, configuration, entriesCollector, bitsPerPixel);
case TiffPhotometricInterpretation.BlackIsZero: case TiffPhotometricInterpretation.BlackIsZero:
case TiffPhotometricInterpretation.WhiteIsZero: case TiffPhotometricInterpretation.WhiteIsZero:
if (bitsPerPixel == 1) return bitsPerPixel switch
{ {
return new TiffBiColorWriter<TPixel>(image, memoryAllocator, configuration, entriesCollector); 1 => new TiffBiColorWriter<TPixel>(image, memoryAllocator, configuration, entriesCollector),
} 16 => new TiffGrayL16Writer<TPixel>(image, memoryAllocator, configuration, entriesCollector),
_ => new TiffGrayWriter<TPixel>(image, memoryAllocator, configuration, entriesCollector)
};
return new TiffGrayWriter<TPixel>(image, memoryAllocator, configuration, entriesCollector);
default: default:
return new TiffRgbWriter<TPixel>(image, memoryAllocator, configuration, entriesCollector); return new TiffRgbWriter<TPixel>(image, memoryAllocator, configuration, entriesCollector);
} }

22
src/ImageSharp/Formats/Tiff/Writers/TiffGrayL16Writer{TPixel}.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.Writers;
internal sealed class TiffGrayL16Writer<TPixel> : TiffCompositeColorWriter<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public TiffGrayL16Writer(ImageFrame<TPixel> image, MemoryAllocator memoryAllocator, Configuration configuration, TiffEncoderEntriesCollector entriesCollector)
: base(image, memoryAllocator, configuration, entriesCollector)
{
}
/// <inheritdoc />
public override int BitsPerPixel => 16;
/// <inheritdoc />
protected override void EncodePixels(Span<TPixel> pixels, Span<byte> buffer) => PixelOperations<TPixel>.Instance.ToL16Bytes(this.Configuration, pixels, buffer, pixels.Length);
}

7
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

@ -27,6 +27,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester
[InlineData(RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)] [InlineData(RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)]
[InlineData(SmallRgbDeflate, 24, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(SmallRgbDeflate, 24, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)]
[InlineData(Calliphora_GrayscaleUncompressed, 8, 200, 298, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Calliphora_GrayscaleUncompressed, 8, 200, 298, 96, 96, PixelResolutionUnit.PixelsPerInch)]
[InlineData(Calliphora_GrayscaleUncompressed16Bit, 16, 200, 298, 96, 96, PixelResolutionUnit.PixelsPerInch)]
[InlineData(Flower4BitPalette, 4, 73, 43, 72, 72, PixelResolutionUnit.PixelsPerInch)] [InlineData(Flower4BitPalette, 4, 73, 43, 72, 72, PixelResolutionUnit.PixelsPerInch)]
public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit)
{ {
@ -34,7 +35,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester
using MemoryStream stream = new(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
ImageInfo info = Image.Identify(stream); ImageInfo info = Image.Identify(stream);
Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); Assert.Equal(expectedPixelSize, info.PixelType.BitsPerPixel);
Assert.Equal(expectedWidth, info.Width); Assert.Equal(expectedWidth, info.Width);
Assert.Equal(expectedHeight, info.Height); Assert.Equal(expectedHeight, info.Height);
Assert.NotNull(info.Metadata); Assert.NotNull(info.Metadata);
@ -64,6 +65,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester
[Theory] [Theory]
[WithFile(RgbUncompressed, PixelTypes.Rgba32)] [WithFile(RgbUncompressed, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)]
[WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)]
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Uncompressed<TPixel>(TestImageProvider<TPixel> provider) public void TiffDecoder_CanDecode_Uncompressed<TPixel>(TestImageProvider<TPixel> provider)
@ -599,6 +601,8 @@ public class TiffDecoderTests : TiffDecoderBaseTester
[WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)] [WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleDeflate, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleDeflate, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleDeflate_Predictor, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleDeflate_Predictor, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleDeflate16Bit, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleDeflate_Predictor16Bit, PixelTypes.Rgba32)]
[WithFile(Calliphora_RgbDeflate_Predictor, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbDeflate_Predictor, PixelTypes.Rgba32)]
[WithFile(RgbDeflate, PixelTypes.Rgba32)] [WithFile(RgbDeflate, PixelTypes.Rgba32)]
[WithFile(RgbDeflatePredictor, PixelTypes.Rgba32)] [WithFile(RgbDeflatePredictor, PixelTypes.Rgba32)]
@ -615,6 +619,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester
[WithFile(Calliphora_RgbPaletteLzw_Predictor, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbPaletteLzw_Predictor, PixelTypes.Rgba32)]
[WithFile(Calliphora_RgbLzwPredictor, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbLzwPredictor, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleLzw_Predictor, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleLzw_Predictor, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleLzw_Predictor16Bit, PixelTypes.Rgba32)]
[WithFile(SmallRgbLzw, PixelTypes.Rgba32)] [WithFile(SmallRgbLzw, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_LzwCompressed<TPixel>(TestImageProvider<TPixel> provider) public void TiffDecoder_CanDecode_LzwCompressed<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider); where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);

47
tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs

@ -17,6 +17,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester
[InlineData(TiffPhotometricInterpretation.PaletteColor, TiffBitsPerPixel.Bit8)] [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffBitsPerPixel.Bit8)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffBitsPerPixel.Bit8)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffBitsPerPixel.Bit8)]
[InlineData(TiffPhotometricInterpretation.WhiteIsZero, TiffBitsPerPixel.Bit8)] [InlineData(TiffPhotometricInterpretation.WhiteIsZero, TiffBitsPerPixel.Bit8)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffBitsPerPixel.Bit16)]
//// Unsupported TiffPhotometricInterpretation should default to 24 bits //// Unsupported TiffPhotometricInterpretation should default to 24 bits
[InlineData(TiffPhotometricInterpretation.CieLab, TiffBitsPerPixel.Bit24)] [InlineData(TiffPhotometricInterpretation.CieLab, TiffBitsPerPixel.Bit24)]
[InlineData(TiffPhotometricInterpretation.ColorFilterArray, TiffBitsPerPixel.Bit24)] [InlineData(TiffPhotometricInterpretation.ColorFilterArray, TiffBitsPerPixel.Bit24)]
@ -28,7 +29,9 @@ public class TiffEncoderTests : TiffEncoderBaseTester
{ {
// arrange // arrange
var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation }; var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation };
using Image input = new Image<Rgb24>(10, 10); using Image input = expectedBitsPerPixel is TiffBitsPerPixel.Bit16
? new Image<L16>(10, 10)
: new Image<Rgb24>(10, 10);
using var memStream = new MemoryStream(); using var memStream = new MemoryStream();
// act // act
@ -44,6 +47,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester
[Theory] [Theory]
[InlineData(TiffBitsPerPixel.Bit24)] [InlineData(TiffBitsPerPixel.Bit24)]
[InlineData(TiffBitsPerPixel.Bit16)]
[InlineData(TiffBitsPerPixel.Bit8)] [InlineData(TiffBitsPerPixel.Bit8)]
[InlineData(TiffBitsPerPixel.Bit4)] [InlineData(TiffBitsPerPixel.Bit4)]
[InlineData(TiffBitsPerPixel.Bit1)] [InlineData(TiffBitsPerPixel.Bit1)]
@ -117,14 +121,17 @@ public class TiffEncoderTests : TiffEncoderBaseTester
[Theory] [Theory]
[InlineData(null, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)] [InlineData(null, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffBitsPerPixel.Bit16, TiffCompression.Deflate)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffBitsPerPixel.Bit8, TiffCompression.Deflate)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffBitsPerPixel.Bit8, TiffCompression.Deflate)]
[InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.Deflate, TiffBitsPerPixel.Bit8, TiffCompression.Deflate)] [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.Deflate, TiffBitsPerPixel.Bit8, TiffCompression.Deflate)]
[InlineData(null, TiffCompression.PackBits, TiffBitsPerPixel.Bit24, TiffCompression.PackBits)] [InlineData(null, TiffCompression.PackBits, TiffBitsPerPixel.Bit24, TiffCompression.PackBits)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.PackBits, TiffBitsPerPixel.Bit24, TiffCompression.PackBits)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.PackBits, TiffBitsPerPixel.Bit24, TiffCompression.PackBits)]
[InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.PackBits, TiffBitsPerPixel.Bit8, TiffCompression.PackBits)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits, TiffBitsPerPixel.Bit16, TiffCompression.PackBits)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits, TiffBitsPerPixel.Bit8, TiffCompression.PackBits)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits, TiffBitsPerPixel.Bit8, TiffCompression.PackBits)]
[InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.PackBits, TiffBitsPerPixel.Bit8, TiffCompression.PackBits)]
[InlineData(null, TiffCompression.Lzw, TiffBitsPerPixel.Bit24, TiffCompression.Lzw)] [InlineData(null, TiffCompression.Lzw, TiffBitsPerPixel.Bit24, TiffCompression.Lzw)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Lzw, TiffBitsPerPixel.Bit24, TiffCompression.Lzw)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Lzw, TiffBitsPerPixel.Bit24, TiffCompression.Lzw)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffBitsPerPixel.Bit16, TiffCompression.Lzw)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffBitsPerPixel.Bit8, TiffCompression.Lzw)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffBitsPerPixel.Bit8, TiffCompression.Lzw)]
[InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.Lzw, TiffBitsPerPixel.Bit8, TiffCompression.Lzw)] [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.Lzw, TiffBitsPerPixel.Bit8, TiffCompression.Lzw)]
[InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.CcittGroup3Fax, TiffBitsPerPixel.Bit1, TiffCompression.CcittGroup3Fax)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.CcittGroup3Fax, TiffBitsPerPixel.Bit1, TiffCompression.CcittGroup3Fax)]
@ -143,7 +150,9 @@ public class TiffEncoderTests : TiffEncoderBaseTester
{ {
// arrange // arrange
var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation, Compression = compression }; var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation, Compression = compression };
using Image input = new Image<Rgb24>(10, 10); using Image input = expectedBitsPerPixel is TiffBitsPerPixel.Bit16
? new Image<L16>(10, 10)
: new Image<Rgb24>(10, 10);
using var memStream = new MemoryStream(); using var memStream = new MemoryStream();
// act // act
@ -160,6 +169,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester
[Theory] [Theory]
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit1)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit1)]
[WithFile(GrayscaleUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)] [WithFile(GrayscaleUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)]
[WithFile(GrayscaleUncompressed16Bit, PixelTypes.L16, TiffBitsPerPixel.Bit16)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit24)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit24)]
[WithFile(Rgb4BitPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit4)] [WithFile(Rgb4BitPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit4)]
[WithFile(RgbPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)] [WithFile(RgbPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)]
@ -406,6 +416,36 @@ public class TiffEncoderTests : TiffEncoderBaseTester
where TPixel : unmanaged, IPixel<TPixel> => where TPixel : unmanaged, IPixel<TPixel> =>
TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.PaletteColor, TiffCompression.Lzw, TiffPredictor.Horizontal, useExactComparer: false, compareTolerance: 0.001f); TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.PaletteColor, TiffCompression.Lzw, TiffPredictor.Horizontal, useExactComparer: false, compareTolerance: 0.001f);
[Theory]
[WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray16_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero);
[Theory]
[WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray16_WithDeflateCompression_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate);
[Theory]
[WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray16_WithDeflateCompressionAndPredictor_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffPredictor.Horizontal);
[Theory]
[WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray16_WithLzwCompression_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw);
[Theory]
[WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray16_WithLzwCompressionAndPredictor_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffPredictor.Horizontal);
[Theory]
[WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray16_WithPackBitsCompression_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits);
[Theory] [Theory]
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeBiColor_BlackIsZero_Works<TPixel>(TestImageProvider<TPixel> provider) public void TiffEncoder_EncodeBiColor_BlackIsZero_Works<TPixel>(TestImageProvider<TPixel> provider)
@ -473,6 +513,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester
[Theory] [Theory]
[WithFile(GrayscaleUncompressed, PixelTypes.L8, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)] [WithFile(GrayscaleUncompressed, PixelTypes.L8, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)]
[WithFile(GrayscaleUncompressed16Bit, PixelTypes.L16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate)]
[WithFile(RgbUncompressed, PixelTypes.Rgb24, TiffPhotometricInterpretation.Rgb, TiffCompression.None)] [WithFile(RgbUncompressed, PixelTypes.Rgb24, TiffPhotometricInterpretation.Rgb, TiffCompression.None)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.None)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.None)]

1
tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs

@ -75,6 +75,7 @@ public class TiffMetadataTests
[Theory] [Theory]
[InlineData(Calliphora_BiColorUncompressed, 1)] [InlineData(Calliphora_BiColorUncompressed, 1)]
[InlineData(GrayscaleUncompressed, 8)] [InlineData(GrayscaleUncompressed, 8)]
[InlineData(GrayscaleUncompressed16Bit, 16)]
[InlineData(RgbUncompressed, 24)] [InlineData(RgbUncompressed, 24)]
public void Identify_DetectsCorrectBitPerPixel(string imagePath, int expectedBitsPerPixel) public void Identify_DetectsCorrectBitPerPixel(string imagePath, int expectedBitsPerPixel)
{ {

5
tests/ImageSharp.Tests/TestImages.cs

@ -767,6 +767,10 @@ public static class TestImages
public const string Calliphora_GrayscaleDeflate_Predictor = "Tiff/Calliphora_gray_deflate_predictor.tiff"; public const string Calliphora_GrayscaleDeflate_Predictor = "Tiff/Calliphora_gray_deflate_predictor.tiff";
public const string Calliphora_GrayscaleLzw_Predictor = "Tiff/Calliphora_gray_lzw_predictor.tiff"; public const string Calliphora_GrayscaleLzw_Predictor = "Tiff/Calliphora_gray_lzw_predictor.tiff";
public const string Calliphora_GrayscaleDeflate = "Tiff/Calliphora_gray_deflate.tiff"; public const string Calliphora_GrayscaleDeflate = "Tiff/Calliphora_gray_deflate.tiff";
public const string Calliphora_GrayscaleUncompressed16Bit = "Tiff/Calliphora_grayscale_uncompressed_16bit.tiff";
public const string Calliphora_GrayscaleDeflate_Predictor16Bit = "Tiff/Calliphora_gray_deflate_predictor_16bit.tiff";
public const string Calliphora_GrayscaleLzw_Predictor16Bit = "Tiff/Calliphora_gray_lzw_predictor_16bit.tiff";
public const string Calliphora_GrayscaleDeflate16Bit = "Tiff/Calliphora_gray_deflate_16bit.tiff";
public const string Calliphora_RgbDeflate_Predictor = "Tiff/Calliphora_rgb_deflate_predictor.tiff"; public const string Calliphora_RgbDeflate_Predictor = "Tiff/Calliphora_rgb_deflate_predictor.tiff";
public const string Calliphora_RgbJpeg = "Tiff/Calliphora_rgb_jpeg.tiff"; public const string Calliphora_RgbJpeg = "Tiff/Calliphora_rgb_jpeg.tiff";
public const string Calliphora_PaletteUncompressed = "Tiff/Calliphora_palette_uncompressed.tiff"; public const string Calliphora_PaletteUncompressed = "Tiff/Calliphora_palette_uncompressed.tiff";
@ -798,6 +802,7 @@ public static class TestImages
public const string GrayscaleDeflateMultistrip = "Tiff/grayscale_deflate_multistrip.tiff"; public const string GrayscaleDeflateMultistrip = "Tiff/grayscale_deflate_multistrip.tiff";
public const string GrayscaleUncompressed = "Tiff/grayscale_uncompressed.tiff"; public const string GrayscaleUncompressed = "Tiff/grayscale_uncompressed.tiff";
public const string GrayscaleUncompressed16Bit = "Tiff/grayscale_uncompressed_16bit.tiff";
public const string GrayscaleJpegCompressed = "Tiff/JpegCompressedGray.tiff"; public const string GrayscaleJpegCompressed = "Tiff/JpegCompressedGray.tiff";
public const string PaletteDeflateMultistrip = "Tiff/palette_grayscale_deflate_multistrip.tiff"; public const string PaletteDeflateMultistrip = "Tiff/palette_grayscale_deflate_multistrip.tiff";
public const string PaletteUncompressed = "Tiff/palette_uncompressed.tiff"; public const string PaletteUncompressed = "Tiff/palette_uncompressed.tiff";

3
tests/Images/Input/Tiff/Calliphora_gray_deflate_16bit.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4fdf62eb43c0349cb8c6ad67e5389a0f307944d8a8e760667a7f78fcc48a9ffa
size 62698

3
tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor_16bit.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8040010e7f760d09dda49145050b07f32826037c11686d976b4b7949a0c40c18
size 54086

3
tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor_16bit.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:67246d3bfc0c361fae21db04fa0251168c7e12abe3c3cc134cd1d685fb09876f
size 58392

3
tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed_16bit.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:42077e6e0d0e7e32bdc0dadb837aad03fd4ae9ceff158bdf213ea9b76dbc36f1
size 119601

3
tests/Images/Input/Tiff/grayscale_uncompressed_16bit.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:49de8d78dc22c4c7e62b0c02ae409550c0247c49ec4685162a0fe986d3280aa7
size 131294
Loading…
Cancel
Save