Browse Source

Rework setting tiff encoder parameters according to review

pull/1553/head
Brian Popow 5 years ago
parent
commit
ccc3f9b881
  1. 12
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  2. 172
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  3. 70
      src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
  4. 30
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
  5. 10
      tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs

12
src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

@ -62,19 +62,19 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowNotSupported("Variable-sized strips are not supported."); TiffThrowHelper.ThrowNotSupported("Variable-sized strips are not supported.");
} }
VerifyRequiredFieldsArePresent(exifProfile); VerifyRequiredFieldsArePresent(exifProfile, frameMetadata);
options.PlanarConfiguration = (TiffPlanarConfiguration?)exifProfile.GetValue(ExifTag.PlanarConfiguration)?.Value ?? DefaultPlanarConfiguration; options.PlanarConfiguration = (TiffPlanarConfiguration?)exifProfile.GetValue(ExifTag.PlanarConfiguration)?.Value ?? DefaultPlanarConfiguration;
options.Predictor = frameMetadata.Predictor ?? TiffFrameMetadata.DefaultPredictor; options.Predictor = frameMetadata.Predictor ?? TiffPredictor.None;
options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffFrameMetadata.DefaultPhotometricInterpretation; options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb;
options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffFrameMetadata.DefaultBitsPerPixel; options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24;
options.BitsPerSample = GetBitsPerSample(frameMetadata.BitsPerPixel); options.BitsPerSample = GetBitsPerSample(frameMetadata.BitsPerPixel);
options.ParseColorType(exifProfile); options.ParseColorType(exifProfile);
options.ParseCompression(frameMetadata.Compression, exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile);
} }
private static void VerifyRequiredFieldsArePresent(ExifProfile exifProfile) private static void VerifyRequiredFieldsArePresent(ExifProfile exifProfile, TiffFrameMetadata frameMetadata)
{ {
if (exifProfile.GetValue(ExifTag.StripOffsets) == null) if (exifProfile.GetValue(ExifTag.StripOffsets) == null)
{ {
@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowImageFormatException("StripByteCounts are missing and are required for decoding the TIFF image!"); TiffThrowHelper.ThrowImageFormatException("StripByteCounts are missing and are required for decoding the TIFF image!");
} }
if (exifProfile.GetValue(ExifTag.BitsPerSample) == null) if (frameMetadata.BitsPerPixel == null)
{ {
TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!"); TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!");
} }

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

@ -54,6 +54,26 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary> /// </summary>
private readonly DeflateCompressionLevel compressionLevel; private readonly DeflateCompressionLevel compressionLevel;
/// <summary>
/// The default predictor is None.
/// </summary>
private const TiffPredictor DefaultPredictor = TiffPredictor.None;
/// <summary>
/// The default bits per pixel is Bit24.
/// </summary>
private const TiffBitsPerPixel DefaultBitsPerPixel = TiffBitsPerPixel.Bit24;
/// <summary>
/// The default compression is None.
/// </summary>
private const TiffCompression DefaultCompression = TiffCompression.None;
/// <summary>
/// The default photometric interpretation is Rgb.
/// </summary>
private const TiffPhotometricInterpretation DefaultPhotometricInterpretation = TiffPhotometricInterpretation.Rgb;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TiffEncoderCore"/> class. /// Initializes a new instance of the <see cref="TiffEncoderCore"/> class.
/// </summary> /// </summary>
@ -105,21 +125,33 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.configuration = image.GetConfiguration(); this.configuration = image.GetConfiguration();
TiffPhotometricInterpretation rootFramePhotometricInterpretation = GetRootFramePhotometricInterpretation(image);
TiffPhotometricInterpretation photometricInterpretation = this.PhotometricInterpretation == TiffPhotometricInterpretation.PaletteColor
? TiffPhotometricInterpretation.PaletteColor
: rootFramePhotometricInterpretation;
ImageFrameMetadata rootFrameMetaData = image.Frames.RootFrame.Metadata; ImageFrameMetadata rootFrameMetaData = image.Frames.RootFrame.Metadata;
TiffFrameMetadata rootFrameTiffMetaData = rootFrameMetaData.GetTiffMetadata(); TiffFrameMetadata rootFrameTiffMetaData = rootFrameMetaData.GetTiffMetadata();
TiffBitsPerPixel? rootFrameBitsPerPixel = rootFrameTiffMetaData.BitsPerPixel;
// If the user has not chosen a predictor or compression, set the values from the decoded image, if present. // Determine the correct values to encode with.
this.HorizontalPredictor ??= rootFrameTiffMetaData.Predictor; // EncoderOptions > Metadata > Default.
this.CompressionType ??= rootFrameTiffMetaData.Compression; TiffBitsPerPixel? bitsPerPixel = this.BitsPerPixel ?? rootFrameTiffMetaData.BitsPerPixel;
TiffPhotometricInterpretation? photometricInterpretation = this.PhotometricInterpretation ?? rootFrameTiffMetaData.PhotometricInterpretation;
TiffPredictor predictor =
this.HorizontalPredictor
?? rootFrameTiffMetaData.Predictor
?? DefaultPredictor;
this.SetBitsPerPixel(rootFrameBitsPerPixel, image.PixelType.BitsPerPixel, photometricInterpretation); TiffCompression compression =
this.SetPhotometricInterpretation(photometricInterpretation); this.CompressionType
?? rootFrameTiffMetaData.Compression
?? DefaultCompression;
// Make sure, the bits per pixel and PhotometricInterpretation have values which makes sense in combination with the other chosen values.
bitsPerPixel = this.SanitizeBitsPerPixel(bitsPerPixel, image.PixelType.BitsPerPixel, photometricInterpretation, compression);
photometricInterpretation = this.SanitizePhotometricInterpretation(photometricInterpretation, bitsPerPixel, compression);
this.BitsPerPixel = bitsPerPixel;
this.PhotometricInterpretation = photometricInterpretation;
this.CompressionType = compression;
this.HorizontalPredictor = predictor;
using (var writer = new TiffStreamWriter(stream)) using (var writer = new TiffStreamWriter(stream))
{ {
@ -270,98 +302,65 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return nextIfdMarker; return nextIfdMarker;
} }
private void SetPhotometricInterpretation(TiffPhotometricInterpretation? photometricInterpretation) private TiffPhotometricInterpretation SanitizePhotometricInterpretation(TiffPhotometricInterpretation? photometricInterpretation, TiffBitsPerPixel? bitsPerPixel, TiffCompression compression)
{ {
// Make sure, that the fax compressions are only used together with the WhiteIsZero. // Make sure, that the fax compressions are only used together with the WhiteIsZero.
if (this.CompressionType == TiffCompression.CcittGroup3Fax || this.CompressionType == TiffCompression.Ccitt1D) if (compression == TiffCompression.CcittGroup3Fax || compression == TiffCompression.Ccitt1D)
{ {
// The user has not specified a preferred photometric interpretation. // The “normal” PhotometricInterpretation for bilevel CCITT compressed data is WhiteIsZero.
if (this.PhotometricInterpretation == null) return TiffPhotometricInterpretation.WhiteIsZero;
{
this.PhotometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero;
this.BitsPerPixel = TiffBitsPerPixel.Bit1;
return;
}
if (this.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && this.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero)
{
TiffThrowHelper.ThrowImageFormatException(
$"The {this.CompressionType} compression and {this.PhotometricInterpretation} aren't compatible. Please use {this.CompressionType} only with {TiffPhotometricInterpretation.BlackIsZero} or {TiffPhotometricInterpretation.WhiteIsZero}.");
}
else
{
// The “normal” PhotometricInterpretation for bilevel CCITT compressed data is WhiteIsZero.
this.PhotometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero;
}
return;
}
switch (this.PhotometricInterpretation)
{
// The currently supported values by the encoder for photometric interpretation:
case TiffPhotometricInterpretation.PaletteColor:
case TiffPhotometricInterpretation.BlackIsZero:
case TiffPhotometricInterpretation.WhiteIsZero:
break;
default:
this.PhotometricInterpretation = TiffPhotometricInterpretation.Rgb;
break;
} }
// Use the bits per pixel to determine the photometric interpretation. // Use the bits per pixel to determine the photometric interpretation.
this.SetPhotometricInterpretationWithBitsPerPixel(this.BitsPerPixel, photometricInterpretation);
}
private void SetPhotometricInterpretationWithBitsPerPixel(TiffBitsPerPixel? bitsPerPixel, TiffPhotometricInterpretation? photometricInterpretation)
{
switch (bitsPerPixel) switch (bitsPerPixel)
{ {
case TiffBitsPerPixel.Bit1: case TiffBitsPerPixel.Bit1:
this.PhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero; return TiffPhotometricInterpretation.BlackIsZero;
break;
case TiffBitsPerPixel.Bit4: case TiffBitsPerPixel.Bit4:
this.PhotometricInterpretation = TiffPhotometricInterpretation.PaletteColor; return TiffPhotometricInterpretation.PaletteColor;
break;
case TiffBitsPerPixel.Bit8: case TiffBitsPerPixel.Bit8:
this.PhotometricInterpretation = photometricInterpretation == TiffPhotometricInterpretation.PaletteColor return photometricInterpretation == TiffPhotometricInterpretation.PaletteColor
? TiffPhotometricInterpretation.PaletteColor ? TiffPhotometricInterpretation.PaletteColor
: TiffPhotometricInterpretation.BlackIsZero; : TiffPhotometricInterpretation.BlackIsZero;
}
break; if (photometricInterpretation.HasValue)
default: {
this.PhotometricInterpretation = TiffPhotometricInterpretation.Rgb; return photometricInterpretation.Value;
break;
} }
return DefaultPhotometricInterpretation;
} }
private void SetBitsPerPixel(TiffBitsPerPixel? rootFrameBitsPerPixel, int inputBitsPerPixel, TiffPhotometricInterpretation photometricInterpretation) private TiffBitsPerPixel SanitizeBitsPerPixel(TiffBitsPerPixel? bitsPerPixel, int inputBitsPerPixel, TiffPhotometricInterpretation? photometricInterpretation, TiffCompression compression)
{ {
this.BitsPerPixel ??= rootFrameBitsPerPixel; // Make sure Palette color is only used with 4 and 8 bit per pixel.
if (photometricInterpretation == TiffPhotometricInterpretation.PaletteColor) if (photometricInterpretation == TiffPhotometricInterpretation.PaletteColor)
{ {
if (this.BitsPerPixel != TiffBitsPerPixel.Bit8 && this.BitsPerPixel != TiffBitsPerPixel.Bit4) if (bitsPerPixel != TiffBitsPerPixel.Bit8 && bitsPerPixel != TiffBitsPerPixel.Bit4)
{ {
this.BitsPerPixel = TiffBitsPerPixel.Bit8; return TiffBitsPerPixel.Bit8;
} }
}
return; if (compression == TiffCompression.Ccitt1D || compression == TiffCompression.CcittGroup3Fax)
{
return TiffBitsPerPixel.Bit1;
} }
if (this.BitsPerPixel.HasValue) if (bitsPerPixel.HasValue)
{ {
return; return bitsPerPixel.Value;
} }
if (this.PhotometricInterpretation == null && inputBitsPerPixel == 8) // If no photometric interpretation was chosen, the input image bit per pixel should be preserved.
if (photometricInterpretation == null)
{ {
this.BitsPerPixel = TiffBitsPerPixel.Bit8; // At the moment only 8 and 32 bits per pixel can be preserved by the tiff encoder.
return; return inputBitsPerPixel == 8 ? TiffBitsPerPixel.Bit8 : DefaultBitsPerPixel;
} }
switch (this.PhotometricInterpretation) switch (photometricInterpretation)
{ {
case TiffPhotometricInterpretation.BlackIsZero: case TiffPhotometricInterpretation.BlackIsZero:
case TiffPhotometricInterpretation.WhiteIsZero: case TiffPhotometricInterpretation.WhiteIsZero:
@ -369,37 +368,28 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.CompressionType == TiffCompression.CcittGroup3Fax || this.CompressionType == TiffCompression.CcittGroup3Fax ||
this.CompressionType == TiffCompression.CcittGroup4Fax) this.CompressionType == TiffCompression.CcittGroup4Fax)
{ {
this.BitsPerPixel = TiffBitsPerPixel.Bit1; return TiffBitsPerPixel.Bit1;
} }
else else
{ {
this.BitsPerPixel = TiffBitsPerPixel.Bit8; return TiffBitsPerPixel.Bit8;
} }
break;
case TiffPhotometricInterpretation.PaletteColor: case TiffPhotometricInterpretation.PaletteColor:
if (this.BitsPerPixel != TiffBitsPerPixel.Bit8 && this.BitsPerPixel != TiffBitsPerPixel.Bit4) if (bitsPerPixel != TiffBitsPerPixel.Bit8 && bitsPerPixel != TiffBitsPerPixel.Bit4)
{ {
this.BitsPerPixel = TiffBitsPerPixel.Bit8; return TiffBitsPerPixel.Bit8;
}
else
{
return bitsPerPixel.Value;
} }
break;
case TiffPhotometricInterpretation.Rgb: case TiffPhotometricInterpretation.Rgb:
this.BitsPerPixel = TiffBitsPerPixel.Bit24; return TiffBitsPerPixel.Bit24;
break;
default:
this.PhotometricInterpretation = TiffPhotometricInterpretation.Rgb;
this.BitsPerPixel = TiffBitsPerPixel.Bit24;
break;
} }
}
private static TiffPhotometricInterpretation GetRootFramePhotometricInterpretation(Image image) return DefaultBitsPerPixel;
{
ExifProfile exifProfile = image.Frames.RootFrame.Metadata.ExifProfile;
return exifProfile?.GetValue(ExifTag.PhotometricInterpretation) != null
? (TiffPhotometricInterpretation)exifProfile?.GetValue(ExifTag.PhotometricInterpretation).Value
: TiffPhotometricInterpretation.BlackIsZero;
} }
} }
} }

70
src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs

@ -11,26 +11,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary> /// </summary>
public class TiffFrameMetadata : IDeepCloneable public class TiffFrameMetadata : IDeepCloneable
{ {
/// <summary>
/// The default predictor is None.
/// </summary>
public const TiffPredictor DefaultPredictor = TiffPredictor.None;
/// <summary>
/// The default bits per pixel is Bit24.
/// </summary>
public const TiffBitsPerPixel DefaultBitsPerPixel = TiffBitsPerPixel.Bit24;
/// <summary>
/// The default compression is None.
/// </summary>
public const TiffCompression DefaultCompression = TiffCompression.None;
/// <summary>
/// The default photometric interpretation is BlackIsZero.
/// </summary>
public const TiffPhotometricInterpretation DefaultPhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class. /// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class.
/// </summary> /// </summary>
@ -42,7 +22,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class. /// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class.
/// </summary> /// </summary>
/// <param name="other">The other tiff frame metadata.</param> /// <param name="other">The other tiff frame metadata.</param>
private TiffFrameMetadata(TiffFrameMetadata other) => this.BitsPerPixel = other.BitsPerPixel; private TiffFrameMetadata(TiffFrameMetadata other)
{
this.BitsPerPixel = other.BitsPerPixel;
this.Compression = other.Compression;
this.PhotometricInterpretation = other.PhotometricInterpretation;
this.Predictor = other.Predictor;
}
/// <summary> /// <summary>
/// Gets or sets the bits per pixel. /// Gets or sets the bits per pixel.
@ -84,17 +70,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="profile">The Exif profile containing tiff frame directory tags.</param> /// <param name="profile">The Exif profile containing tiff frame directory tags.</param>
internal static void Parse(TiffFrameMetadata meta, ExifProfile profile) internal static void Parse(TiffFrameMetadata meta, ExifProfile profile)
{ {
profile ??= new ExifProfile(); if (profile != null)
{
ushort[] bitsPerSample = profile.GetValue(ExifTag.BitsPerSample)?.Value; ushort[] bitsPerSample = profile.GetValue(ExifTag.BitsPerSample)?.Value;
meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(bitsPerSample); meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(bitsPerSample);
meta.Compression = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value ?? DefaultCompression; meta.Compression = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value;
meta.PhotometricInterpretation = (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value ?? DefaultPhotometricInterpretation; meta.PhotometricInterpretation =
meta.Predictor = (TiffPredictor?)profile.GetValue(ExifTag.Predictor)?.Value ?? DefaultPredictor; (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value;
meta.Predictor = (TiffPredictor?)profile.GetValue(ExifTag.Predictor)?.Value;
profile.RemoveValue(ExifTag.Compression);
profile.RemoveValue(ExifTag.PhotometricInterpretation); profile.RemoveValue(ExifTag.BitsPerSample);
profile.RemoveValue(ExifTag.Predictor); profile.RemoveValue(ExifTag.Compression);
profile.RemoveValue(ExifTag.PhotometricInterpretation);
profile.RemoveValue(ExifTag.Predictor);
}
} }
/// <summary> /// <summary>
@ -102,11 +91,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary> /// </summary>
/// <param name="bitsPerSample">The tiff bits per sample.</param> /// <param name="bitsPerSample">The tiff bits per sample.</param>
/// <returns>Bits per pixel.</returns> /// <returns>Bits per pixel.</returns>
private static TiffBitsPerPixel BitsPerPixelFromBitsPerSample(ushort[] bitsPerSample) private static TiffBitsPerPixel? BitsPerPixelFromBitsPerSample(ushort[] bitsPerSample)
{ {
if (bitsPerSample == null) if (bitsPerSample == null)
{ {
return DefaultBitsPerPixel; return null;
} }
int bitsPerPixel = 0; int bitsPerPixel = 0;
@ -119,17 +108,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
} }
/// <inheritdoc/> /// <inheritdoc/>
public IDeepCloneable DeepClone() public IDeepCloneable DeepClone() => new TiffFrameMetadata(this);
{
var clone = new TiffFrameMetadata
{
BitsPerPixel = this.BitsPerPixel,
Compression = this.Compression,
PhotometricInterpretation = this.PhotometricInterpretation,
Predictor = this.Predictor
};
return clone;
}
} }
} }

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

@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory] [Theory]
[InlineData(TiffBitsPerPixel.Bit24)] [InlineData(TiffBitsPerPixel.Bit24)]
[InlineData(TiffBitsPerPixel.Bit8)] [InlineData(TiffBitsPerPixel.Bit8)]
[InlineData(TiffBitsPerPixel.Bit4)] [InlineData(TiffBitsPerPixel.Bit4)]
[InlineData(TiffBitsPerPixel.Bit1)] [InlineData(TiffBitsPerPixel.Bit1)]
public void EncoderOptions_SetBitPerPixel_Works(TiffBitsPerPixel bitsPerPixel) public void EncoderOptions_SetBitPerPixel_Works(TiffBitsPerPixel bitsPerPixel)
@ -136,8 +136,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
// assert // assert
memStream.Position = 0; memStream.Position = 0;
using var output = Image.Load<Rgba32>(Configuration, memStream); using var output = Image.Load<Rgba32>(Configuration, memStream);
ExifProfile exifProfile = output.Frames.RootFrame.Metadata.ExifProfile; TiffFrameMetadata frameMetaData = output.Frames.RootFrame.Metadata.GetTiffMetadata();
var frameMetaData = TiffFrameMetadata.Parse(exifProfile);
Assert.Equal(expectedBitsPerPixel, frameMetaData.BitsPerPixel); Assert.Equal(expectedBitsPerPixel, frameMetaData.BitsPerPixel);
} }
@ -156,8 +155,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
// assert // assert
memStream.Position = 0; memStream.Position = 0;
using var output = Image.Load<Rgba32>(Configuration, memStream); using var output = Image.Load<Rgba32>(Configuration, memStream);
ExifProfile exifProfile = output.Frames.RootFrame.Metadata.ExifProfile; var frameMetaData = output.Frames.RootFrame.Metadata.GetTiffMetadata();
var frameMetaData = TiffFrameMetadata.Parse(exifProfile);
Assert.Equal(expectedBitsPerPixel, frameMetaData.BitsPerPixel); Assert.Equal(expectedBitsPerPixel, frameMetaData.BitsPerPixel);
} }
@ -184,11 +182,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
} }
[Theory] [Theory]
[WithFile(RgbLzwNoPredictor, PixelTypes.Rgba32, TiffPredictor.None)] [WithFile(RgbLzwNoPredictor, PixelTypes.Rgba32, null)]
[WithFile(RgbLzwPredictor, PixelTypes.Rgba32, TiffPredictor.Horizontal)] [WithFile(RgbLzwPredictor, PixelTypes.Rgba32, TiffPredictor.Horizontal)]
[WithFile(RgbDeflate, PixelTypes.Rgba32, TiffPredictor.None)] [WithFile(RgbDeflate, PixelTypes.Rgba32, null)]
[WithFile(RgbDeflatePredictor, PixelTypes.Rgba32, TiffPredictor.Horizontal)] [WithFile(RgbDeflatePredictor, PixelTypes.Rgba32, TiffPredictor.Horizontal)]
public void TiffEncoder_PreservesPredictor<TPixel>(TestImageProvider<TPixel> provider, TiffPredictor expectedPredictor) public void TiffEncoder_PreservesPredictor<TPixel>(TestImageProvider<TPixel> provider, TiffPredictor? expectedPredictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// arrange // arrange
@ -230,20 +228,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Equal(expectedCompression, frameMetaData.Compression); Assert.Equal(expectedCompression, frameMetaData.Compression);
} }
[Theory]
[InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.CcittGroup3Fax)]
[InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.Ccitt1D)]
public void TiffEncoder_IncompatibilityOptions_ThrowsImageFormatException(TiffPhotometricInterpretation photometricInterpretation, TiffCompression compression)
{
// arrange
using var input = new Image<Rgb24>(10, 10);
var encoder = new TiffEncoder() { PhotometricInterpretation = photometricInterpretation, Compression = compression };
using var memStream = new MemoryStream();
// act
Assert.Throws<ImageFormatException>(() => input.Save(memStream, encoder));
}
[Theory] [Theory]
[WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeRgb_Works<TPixel>(TestImageProvider<TPixel> provider) public void TiffEncoder_EncodeRgb_Works<TPixel>(TestImageProvider<TPixel> provider)
@ -350,7 +334,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory] [Theory]
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeBiColor_Works<TPixel>(TestImageProvider<TPixel> provider) public void TiffEncoder_EncodeBiColor_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.BlackIsZero); where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit1, TiffPhotometricInterpretation.BlackIsZero);
[Theory] [Theory]
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)]

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

@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.NotNull(rootFrameMetaData.XmpProfile); Assert.NotNull(rootFrameMetaData.XmpProfile);
Assert.NotNull(rootFrameMetaData.ExifProfile); Assert.NotNull(rootFrameMetaData.ExifProfile);
Assert.Equal(2599, rootFrameMetaData.XmpProfile.Length); Assert.Equal(2599, rootFrameMetaData.XmpProfile.Length);
Assert.Equal(27, rootFrameMetaData.ExifProfile.Values.Count); Assert.Equal(26, rootFrameMetaData.ExifProfile.Values.Count);
} }
} }
} }
@ -170,9 +170,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
TiffFrameMetadata tiffFrameMetadata = rootFrame.Metadata.GetTiffMetadata(); TiffFrameMetadata tiffFrameMetadata = rootFrame.Metadata.GetTiffMetadata();
Assert.NotNull(exifProfile); Assert.NotNull(exifProfile);
// The original exifProfile has 30 values, but 3 of those values will be stored in the TiffFrameMetaData // The original exifProfile has 30 values, but 4 of those values will be stored in the TiffFrameMetaData
// and removed from the profile on decode. // and removed from the profile on decode.
Assert.Equal(27, exifProfile.Values.Count); Assert.Equal(26, exifProfile.Values.Count);
Assert.Equal(TiffBitsPerPixel.Bit4, tiffFrameMetadata.BitsPerPixel);
Assert.Equal(TiffCompression.Lzw, tiffFrameMetadata.Compression); Assert.Equal(TiffCompression.Lzw, tiffFrameMetadata.Compression);
Assert.Equal("This is Название", exifProfile.GetValue(ExifTag.ImageDescription).Value); Assert.Equal("This is Название", exifProfile.GetValue(ExifTag.ImageDescription).Value);
Assert.Equal("This is Изготовитель камеры", exifProfile.GetValue(ExifTag.Make).Value); Assert.Equal("This is Изготовитель камеры", exifProfile.GetValue(ExifTag.Make).Value);
@ -213,9 +214,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
TiffMetadata tiffMetaData = image.Metadata.GetTiffMetadata(); TiffMetadata tiffMetaData = image.Metadata.GetTiffMetadata();
Assert.NotNull(tiffMetaData); Assert.NotNull(tiffMetaData);
Assert.Equal(ByteOrder.LittleEndian, tiffMetaData.ByteOrder); Assert.Equal(ByteOrder.LittleEndian, tiffMetaData.ByteOrder);
var frameMetaData = TiffFrameMetadata.Parse(exifProfile);
Assert.Equal(TiffBitsPerPixel.Bit4, frameMetaData.BitsPerPixel);
} }
} }

Loading…
Cancel
Save