Browse Source

Add PhotometricInterpretation to the tiff metadata

pull/1570/head
Brian Popow 5 years ago
parent
commit
572f616ae3
  1. 2
      src/ImageSharp/Formats/Tiff/ITiffEncoderOptions.cs
  2. 4
      src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
  3. 5
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  4. 10
      src/ImageSharp/Formats/Tiff/TiffMetadata.cs
  5. 1
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
  6. 27
      tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs

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

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
DeflateCompressionLevel CompressionLevel { get; } DeflateCompressionLevel CompressionLevel { get; }
/// <summary> /// <summary>
/// Gets the encoding mode to use. RGB, RGB with color palette or gray. /// Gets the encoding mode to use. Possible options are RGB, RGB with a color palette, gray or BiColor.
/// If no mode is specified in the options, RGB will be used. /// If no mode is specified in the options, RGB will be used.
/// </summary> /// </summary>
TiffEncodingMode Mode { get; } TiffEncodingMode Mode { get; }

4
src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs

@ -2,10 +2,9 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Icc;
@ -43,6 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
tiffMetadata.ByteOrder = byteOrder; tiffMetadata.ByteOrder = byteOrder;
tiffMetadata.BitsPerPixel = GetBitsPerPixel(rootFrameMetadata); tiffMetadata.BitsPerPixel = GetBitsPerPixel(rootFrameMetadata);
tiffMetadata.Compression = rootFrameMetadata.Compression; tiffMetadata.Compression = rootFrameMetadata.Compression;
tiffMetadata.PhotometricInterpretation = rootFrameMetadata.PhotometricInterpretation;
if (!ignoreMetadata) if (!ignoreMetadata)
{ {

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

@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
public TiffEncoderCore(ITiffEncoderOptions options, MemoryAllocator memoryAllocator) public TiffEncoderCore(ITiffEncoderOptions options, MemoryAllocator memoryAllocator)
{ {
this.memoryAllocator = memoryAllocator; this.memoryAllocator = memoryAllocator;
this.CompressionType = options.Compression;
this.Mode = options.Mode; this.Mode = options.Mode;
this.quantizer = options.Quantizer ?? KnownQuantizers.Octree; this.quantizer = options.Quantizer ?? KnownQuantizers.Octree;
this.UseHorizontalPredictor = options.UseHorizontalPredictor; this.UseHorizontalPredictor = options.UseHorizontalPredictor;
this.CompressionType = options.Compression;
this.compressionLevel = options.CompressionLevel; this.compressionLevel = options.CompressionLevel;
this.maxStripBytes = options.MaxStripBytes; this.maxStripBytes = options.MaxStripBytes;
} }
@ -271,8 +271,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
this.Mode = TiffEncodingMode.BiColor; this.Mode = TiffEncodingMode.BiColor;
break; break;
case TiffBitsPerPixel.Pixel8: case TiffBitsPerPixel.Pixel8:
// todo: can gray or palette this.Mode = tiffMetadata.PhotometricInterpretation != TiffPhotometricInterpretation.PaletteColor ? TiffEncodingMode.Gray : TiffEncodingMode.Rgb;
this.Mode = TiffEncodingMode.Gray;
break; break;
default: default:
this.Mode = TiffEncodingMode.Rgb; this.Mode = TiffEncodingMode.Rgb;

10
src/ImageSharp/Formats/Tiff/TiffMetadata.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
@ -24,9 +25,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
private TiffMetadata(TiffMetadata other) private TiffMetadata(TiffMetadata other)
{ {
this.ByteOrder = other.ByteOrder; this.ByteOrder = other.ByteOrder;
this.XmpProfile = other.XmpProfile;
this.BitsPerPixel = other.BitsPerPixel; this.BitsPerPixel = other.BitsPerPixel;
this.Compression = other.Compression; this.Compression = other.Compression;
this.PhotometricInterpretation = other.PhotometricInterpretation;
this.XmpProfile = other.XmpProfile != null ? new byte[other.XmpProfile.Length] : null;
other.XmpProfile?.AsSpan().CopyTo(this.XmpProfile.AsSpan());
} }
/// <summary> /// <summary>
@ -44,6 +47,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// </summary> /// </summary>
public TiffCompression Compression { get; internal set; } = TiffCompression.None; public TiffCompression Compression { get; internal set; } = TiffCompression.None;
/// <summary>
/// Gets the photometric interpretation which indicates how the pixels are to be interpreted, e.g. if the image is bicolor, RGB, color paletted etc.
/// </summary>
public TiffPhotometricInterpretation PhotometricInterpretation { get; internal set; }
/// <summary> /// <summary>
/// Gets or sets the XMP profile. /// Gets or sets the XMP profile.
/// For internal use only. ImageSharp not support XMP profile. /// For internal use only. ImageSharp not support XMP profile.

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

@ -73,6 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Pixel1)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Pixel1)]
[WithFile(GrayscaleUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Pixel8)] [WithFile(GrayscaleUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Pixel8)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Pixel24)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Pixel24)]
[WithFile(Calliphora_PaletteUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Pixel24)]
public void TiffEncoder_PreserveBitsPerPixel<TPixel>(TestImageProvider<TPixel> provider, TiffBitsPerPixel expectedBitsPerPixel) public void TiffEncoder_PreserveBitsPerPixel<TPixel>(TestImageProvider<TPixel> provider, TiffBitsPerPixel expectedBitsPerPixel)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {

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

@ -36,12 +36,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Fact] [Fact]
public void CloneIsDeep() public void CloneIsDeep()
{ {
byte[] xmpData = { 1, 1, 1 };
var meta = new TiffMetadata var meta = new TiffMetadata
{ {
Compression = TiffCompression.Deflate, Compression = TiffCompression.Deflate,
BitsPerPixel = TiffBitsPerPixel.Pixel8, BitsPerPixel = TiffBitsPerPixel.Pixel8,
ByteOrder = ByteOrder.BigEndian, ByteOrder = ByteOrder.BigEndian,
XmpProfile = new byte[3] XmpProfile = xmpData,
PhotometricInterpretation = TiffPhotometricInterpretation.Rgb
}; };
var clone = (TiffMetadata)meta.DeepClone(); var clone = (TiffMetadata)meta.DeepClone();
@ -49,12 +51,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
clone.Compression = TiffCompression.None; clone.Compression = TiffCompression.None;
clone.BitsPerPixel = TiffBitsPerPixel.Pixel24; clone.BitsPerPixel = TiffBitsPerPixel.Pixel24;
clone.ByteOrder = ByteOrder.LittleEndian; clone.ByteOrder = ByteOrder.LittleEndian;
clone.XmpProfile = new byte[1]; clone.PhotometricInterpretation = TiffPhotometricInterpretation.YCbCr;
Assert.False(meta.Compression == clone.Compression); Assert.False(meta.Compression == clone.Compression);
Assert.False(meta.BitsPerPixel == clone.BitsPerPixel); Assert.False(meta.BitsPerPixel == clone.BitsPerPixel);
Assert.False(meta.ByteOrder == clone.ByteOrder); Assert.False(meta.ByteOrder == clone.ByteOrder);
Assert.False(meta.XmpProfile.SequenceEqual(clone.XmpProfile)); Assert.False(meta.PhotometricInterpretation == clone.PhotometricInterpretation);
Assert.False(meta.XmpProfile.Equals(clone.XmpProfile));
Assert.True(meta.XmpProfile.SequenceEqual(clone.XmpProfile));
} }
[Theory] [Theory]
@ -95,6 +99,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Equal(expectedCompression, tiffMetadata.Compression); Assert.Equal(expectedCompression, tiffMetadata.Compression);
} }
[Theory]
[InlineData(Calliphora_RgbUncompressed, TiffPhotometricInterpretation.Rgb)]
[InlineData(Calliphora_BiColorUncompressed, TiffPhotometricInterpretation.BlackIsZero)]
[InlineData(Calliphora_PaletteUncompressed, TiffPhotometricInterpretation.PaletteColor)]
public void Identify_DetectsCorrectPhotometricInterpretation(string imagePath, TiffPhotometricInterpretation expectedPhotometricInterpretation)
{
var testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false);
IImageInfo imageInfo = Image.Identify(this.configuration, stream);
Assert.NotNull(imageInfo);
TiffMetadata tiffMetadata = imageInfo.Metadata.GetTiffMetadata();
Assert.NotNull(tiffMetadata);
Assert.Equal(expectedPhotometricInterpretation, tiffMetadata.PhotometricInterpretation);
}
[Theory] [Theory]
[InlineData(GrayscaleUncompressed, ByteOrder.BigEndian)] [InlineData(GrayscaleUncompressed, ByteOrder.BigEndian)]
[InlineData(LittleEndianByteOrder, ByteOrder.LittleEndian)] [InlineData(LittleEndianByteOrder, ByteOrder.LittleEndian)]

Loading…
Cancel
Save