Browse Source

Remove ExifProfile from TiffFrameMetadata, Add ExifProfile and XmpProfile to ImageFrameMetaData

pull/1553/head
Brian Popow 5 years ago
parent
commit
04b6f3ffcf
  1. 7
      src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs
  2. 52
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  3. 82
      src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
  4. 14
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  5. 39
      src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
  6. 230
      src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
  7. 10
      src/ImageSharp/Formats/Tiff/TiffMetadata.cs
  8. 20
      src/ImageSharp/Metadata/ImageFrameMetadata.cs
  9. 2
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
  10. 94
      tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
  11. 28
      tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs
  12. 5
      tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs

7
src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs

@ -24,8 +24,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public DirectoryReader(Stream stream) => this.stream = stream;
/// <summary>
/// Gets the byte order.
/// </summary>
public ByteOrder ByteOrder { get; private set; }
/// <summary>
/// Reads image file directories.
/// </summary>
/// <returns>Image file directories.</returns>
public IEnumerable<ExifProfile> Read()
{
this.ByteOrder = ReadByteOrder(this.stream);

52
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
@ -109,15 +110,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff
IEnumerable<ExifProfile> directories = reader.Read();
var frames = new List<ImageFrame<TPixel>>();
var framesMetadata = new List<TiffFrameMetadata>();
var tiffFramesMataData = new List<TiffFrameMetadata>();
foreach (ExifProfile ifd in directories)
{
ImageFrame<TPixel> frame = this.DecodeFrame<TPixel>(ifd, out TiffFrameMetadata frameMetadata);
frames.Add(frame);
framesMetadata.Add(frameMetadata);
tiffFramesMataData.Add(frameMetadata);
}
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(framesMetadata, this.ignoreMetadata, reader.ByteOrder);
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(frames, tiffFramesMataData, this.ignoreMetadata, reader.ByteOrder);
// todo: tiff frames can have different sizes
{
@ -153,11 +154,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
framesMetadata.Add(meta);
}
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(framesMetadata, this.ignoreMetadata, reader.ByteOrder);
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(framesMetadata, reader.ByteOrder);
TiffFrameMetadata root = framesMetadata[0];
int width = GetImageWidth(root);
int height = GetImageHeight(root);
ExifProfile rootFrameExifProfile = directories.First();
int width = GetImageWidth(rootFrameExifProfile);
int height = GetImageHeight(rootFrameExifProfile);
return new ImageInfo(new PixelTypeInfo(root.BitsPerPixel), width, height, metadata);
}
@ -167,26 +169,28 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="tags">The IFD tags.</param>
/// <param name="frameMetaData">The frame metadata.</param>
/// <param name="tiffFrameMetaData">The tiff frame metadata.</param>
/// <returns>
/// The tiff frame.
/// </returns>
private ImageFrame<TPixel> DecodeFrame<TPixel>(ExifProfile tags, out TiffFrameMetadata frameMetaData)
private ImageFrame<TPixel> DecodeFrame<TPixel>(ExifProfile tags, out TiffFrameMetadata tiffFrameMetaData)
where TPixel : unmanaged, IPixel<TPixel>
{
var coreMetadata = new ImageFrameMetadata();
frameMetaData = coreMetadata.GetTiffMetadata();
frameMetaData.Initialize(tags);
ImageFrameMetadata imageFrameMetaData = this.ignoreMetadata ?
new ImageFrameMetadata() :
new ImageFrameMetadata { ExifProfile = tags, XmpProfile = tags.GetValue(ExifTag.XMP)?.Value };
tiffFrameMetaData = imageFrameMetaData.GetTiffMetadata();
tiffFrameMetaData.Initialize(tags);
this.VerifyAndParse(frameMetaData);
this.VerifyAndParse(tiffFrameMetaData);
int width = GetImageWidth(frameMetaData);
int height = GetImageHeight(frameMetaData);
var frame = new ImageFrame<TPixel>(this.Configuration, width, height, coreMetadata);
int width = GetImageWidth(tags);
int height = GetImageHeight(tags);
var frame = new ImageFrame<TPixel>(this.Configuration, width, height, imageFrameMetaData);
int rowsPerStrip = (int)frameMetaData.RowsPerStrip;
Number[] stripOffsets = frameMetaData.StripOffsets;
Number[] stripByteCounts = frameMetaData.StripByteCounts;
int rowsPerStrip = (int)tiffFrameMetaData.RowsPerStrip;
Number[] stripOffsets = tiffFrameMetaData.StripOffsets;
Number[] stripByteCounts = tiffFrameMetaData.StripByteCounts;
if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar)
{
@ -320,11 +324,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <summary>
/// Gets the width of the image frame.
/// </summary>
/// <param name="frame">The image frame.</param>
/// <param name="exifProfile">The image frame exif profile.</param>
/// <returns>The image width.</returns>
private static int GetImageWidth(TiffFrameMetadata frame)
private static int GetImageWidth(ExifProfile exifProfile)
{
IExifValue<Number> width = frame.ExifProfile.GetValue(ExifTag.ImageWidth);
IExifValue<Number> width = exifProfile.GetValue(ExifTag.ImageWidth);
if (width == null)
{
TiffThrowHelper.ThrowImageFormatException("The TIFF image frame is missing the ImageWidth");
@ -336,11 +340,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <summary>
/// Gets the height of the image frame.
/// </summary>
/// <param name="frame">The image frame.</param>
/// <param name="exifProfile">The image frame exif profile.</param>
/// <returns>The image height.</returns>
private static int GetImageHeight(TiffFrameMetadata frame)
private static int GetImageHeight(ExifProfile exifProfile)
{
IExifValue<Number> height = frame.ExifProfile.GetValue(ExifTag.ImageLength);
IExifValue<Number> height = exifProfile.GetValue(ExifTag.ImageLength);
if (height == null)
{
TiffThrowHelper.ThrowImageFormatException("The TIFF image frame is missing the ImageLength");

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

@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
{
@ -16,64 +17,91 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
internal static class TiffDecoderMetadataCreator
{
public static ImageMetadata Create(List<TiffFrameMetadata> frames, bool ignoreMetadata, ByteOrder byteOrder)
public static ImageMetadata Create<TPixel>(List<ImageFrame<TPixel>> frames, List<TiffFrameMetadata> framesMetaData, bool ignoreMetadata, ByteOrder byteOrder)
where TPixel : unmanaged, IPixel<TPixel>
{
if (frames.Count < 1)
DebugGuard.IsTrue(frames.Count() == framesMetaData.Count, nameof(frames), "Image frames and frames metdadata should be the same size.");
if (framesMetaData.Count < 1)
{
TiffThrowHelper.ThrowImageFormatException("Expected at least one frame.");
}
var coreMetadata = new ImageMetadata();
TiffFrameMetadata rootFrameMetadata = frames[0];
coreMetadata.ResolutionUnits = rootFrameMetadata.ResolutionUnit;
if (rootFrameMetadata.HorizontalResolution != null)
{
coreMetadata.HorizontalResolution = rootFrameMetadata.HorizontalResolution.Value;
}
var imageMetaData = new ImageMetadata();
TiffFrameMetadata rootFrameMetadata = framesMetaData[0];
SetResolution(imageMetaData, rootFrameMetadata);
if (rootFrameMetadata.VerticalResolution != null)
{
coreMetadata.VerticalResolution = rootFrameMetadata.VerticalResolution.Value;
}
TiffMetadata tiffMetadata = coreMetadata.GetTiffMetadata();
TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata();
tiffMetadata.ByteOrder = byteOrder;
tiffMetadata.BitsPerPixel = GetBitsPerPixel(rootFrameMetadata);
if (!ignoreMetadata)
{
foreach (TiffFrameMetadata frame in frames)
for (int i = 0; i < frames.Count; i++)
{
if (tiffMetadata.XmpProfile == null)
ImageFrame<TPixel> frame = frames[i];
ImageFrameMetadata frameMetaData = frame.Metadata;
if (frameMetaData.XmpProfile == null)
{
IExifValue<byte[]> val = frame.ExifProfile.GetValue(ExifTag.XMP);
IExifValue<byte[]> val = frameMetaData.ExifProfile.GetValue(ExifTag.XMP);
if (val != null)
{
tiffMetadata.XmpProfile = val.Value;
frameMetaData.XmpProfile = val.Value;
}
}
if (coreMetadata.IptcProfile == null)
if (imageMetaData.IptcProfile == null)
{
if (TryGetIptc(frame.ExifProfile.Values, out byte[] iptcBytes))
if (TryGetIptc(frameMetaData.ExifProfile.Values, out byte[] iptcBytes))
{
coreMetadata.IptcProfile = new IptcProfile(iptcBytes);
imageMetaData.IptcProfile = new IptcProfile(iptcBytes);
}
}
if (coreMetadata.IccProfile == null)
if (imageMetaData.IccProfile == null)
{
IExifValue<byte[]> val = frame.ExifProfile.GetValue(ExifTag.IccProfile);
IExifValue<byte[]> val = frameMetaData.ExifProfile.GetValue(ExifTag.IccProfile);
if (val != null)
{
coreMetadata.IccProfile = new IccProfile(val.Value);
imageMetaData.IccProfile = new IccProfile(val.Value);
}
}
}
}
return coreMetadata;
return imageMetaData;
}
public static ImageMetadata Create(List<TiffFrameMetadata> framesMetaData, ByteOrder byteOrder)
{
if (framesMetaData.Count < 1)
{
TiffThrowHelper.ThrowImageFormatException("Expected at least one frame.");
}
var imageMetaData = new ImageMetadata();
TiffFrameMetadata rootFrameMetadata = framesMetaData[0];
SetResolution(imageMetaData, rootFrameMetadata);
TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata();
tiffMetadata.ByteOrder = byteOrder;
tiffMetadata.BitsPerPixel = GetBitsPerPixel(rootFrameMetadata);
return imageMetaData;
}
private static void SetResolution(ImageMetadata imageMetaData, TiffFrameMetadata rootFrameMetadata)
{
imageMetaData.ResolutionUnits = rootFrameMetadata.ResolutionUnit;
if (rootFrameMetadata.HorizontalResolution != null)
{
imageMetaData.HorizontalResolution = rootFrameMetadata.HorizontalResolution.Value;
}
if (rootFrameMetadata.VerticalResolution != null)
{
imageMetaData.VerticalResolution = rootFrameMetadata.VerticalResolution.Value;
}
}
private static bool TryGetIptc(IReadOnlyList<IExifValue> exifValues, out byte[] iptcBytes)

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

@ -4,7 +4,6 @@
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Formats.Tiff
{
@ -194,9 +193,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
private static void ParseCompression(this TiffDecoderCore options, TiffFrameMetadata entries)
private static void ParseCompression(this TiffDecoderCore options, TiffFrameMetadata tiffFrameMetaData)
{
TiffCompression compression = entries.Compression;
TiffCompression compression = tiffFrameMetaData.Compression;
switch (compression)
{
case TiffCompression.None:
@ -227,12 +226,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffCompression.CcittGroup3Fax:
{
options.CompressionType = TiffDecoderCompressionType.T4;
IExifValue t4options = entries.ExifProfile.GetValue(ExifTag.T4Options);
if (t4options != null)
{
var t4OptionValue = (FaxCompressionOptions)t4options.GetValue();
options.FaxCompressionOptions = t4OptionValue;
}
options.FaxCompressionOptions = tiffFrameMetaData.FaxCompressionOptions;
break;
}
@ -245,7 +239,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
default:
{
TiffThrowHelper.ThrowNotSupported("The specified TIFF compression format is not supported: " + compression);
TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format {compression} is not supported");
break;
}
}

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

@ -47,7 +47,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public void Process<TPixel>(Image<TPixel> image)
where TPixel : unmanaged, IPixel<TPixel>
{
TiffFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetTiffMetadata();
ImageFrame<TPixel> rootFrame = image.Frames.RootFrame;
ExifProfile rootFrameExifProfile = rootFrame.Metadata.ExifProfile ?? new ExifProfile();
byte[] rootFrameXmpBytes = rootFrame.Metadata.XmpProfile;
var width = new ExifLong(ExifTagValue.ImageWidth)
{
@ -67,9 +69,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.collector.Add(width);
this.collector.Add(height);
this.ProcessResolution(image.Metadata, frameMetadata);
this.ProcessProfiles(image.Metadata, frameMetadata);
this.ProcessMetadata(frameMetadata);
this.ProcessResolution(image.Metadata, rootFrameExifProfile);
this.ProcessProfiles(image.Metadata, rootFrameExifProfile, rootFrameXmpBytes);
this.ProcessMetadata(rootFrameExifProfile);
if (!this.collector.Entries.Exists(t => t.Tag == ExifTag.Software))
{
@ -112,18 +114,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
private void ProcessResolution(ImageMetadata imageMetadata, TiffFrameMetadata frameMetadata)
private void ProcessResolution(ImageMetadata imageMetadata, ExifProfile exifProfile)
{
UnitConverter.SetResolutionValues(
frameMetadata.ExifProfile,
exifProfile,
imageMetadata.ResolutionUnits,
imageMetadata.HorizontalResolution,
imageMetadata.VerticalResolution);
this.collector.Add(frameMetadata.ExifProfile.GetValue(ExifTag.ResolutionUnit).DeepClone());
this.collector.Add(exifProfile.GetValue(ExifTag.ResolutionUnit).DeepClone());
IExifValue xResolution = frameMetadata.ExifProfile.GetValue(ExifTag.XResolution)?.DeepClone();
IExifValue yResolution = frameMetadata.ExifProfile.GetValue(ExifTag.YResolution)?.DeepClone();
IExifValue xResolution = exifProfile.GetValue(ExifTag.XResolution)?.DeepClone();
IExifValue yResolution = exifProfile.GetValue(ExifTag.YResolution)?.DeepClone();
if (xResolution != null && yResolution != null)
{
@ -132,9 +134,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
private void ProcessMetadata(TiffFrameMetadata frameMetadata)
private void ProcessMetadata(ExifProfile exifProfile)
{
foreach (IExifValue entry in frameMetadata.ExifProfile.Values)
foreach (IExifValue entry in exifProfile.Values)
{
// todo: skip subIfd
if (entry.DataType == ExifDataType.Ifd)
@ -175,9 +177,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
private void ProcessProfiles(ImageMetadata imageMetadata, TiffFrameMetadata tiffFrameMetadata)
private void ProcessProfiles(ImageMetadata imageMetadata, ExifProfile exifProfile, byte[] xmpProfile)
{
ExifProfile exifProfile = tiffFrameMetadata.ExifProfile;
if (exifProfile != null && exifProfile.Parts != ExifParts.None)
{
foreach (IExifValue entry in exifProfile.Values)
@ -194,7 +195,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
else
{
tiffFrameMetadata.ExifProfile.RemoveValue(ExifTag.SubIFDOffset);
exifProfile.RemoveValue(ExifTag.SubIFDOffset);
}
if (imageMetadata.IptcProfile != null)
@ -209,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
else
{
tiffFrameMetadata.ExifProfile.RemoveValue(ExifTag.IPTC);
exifProfile.RemoveValue(ExifTag.IPTC);
}
if (imageMetadata.IccProfile != null)
@ -223,22 +224,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
else
{
tiffFrameMetadata.ExifProfile.RemoveValue(ExifTag.IccProfile);
exifProfile.RemoveValue(ExifTag.IccProfile);
}
TiffMetadata tiffMetadata = imageMetadata.GetTiffMetadata();
if (tiffMetadata.XmpProfile != null)
if (xmpProfile != null)
{
var xmp = new ExifByteArray(ExifTagValue.XMP, ExifDataType.Byte)
{
Value = tiffMetadata.XmpProfile
Value = xmpProfile
};
this.collector.Add(xmp);
}
else
{
tiffFrameMetadata.ExifProfile.RemoveValue(ExifTag.XMP);
exifProfile.RemoveValue(ExifTag.XMP);
}
}
}

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

@ -1,8 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Linq;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@ -21,7 +23,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <summary>
/// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class.
/// </summary>
public TiffFrameMetadata() => this.Initialize(new ExifProfile());
public TiffFrameMetadata()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class.
@ -29,83 +33,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="frameTags">The Tiff frame directory tags.</param>
public TiffFrameMetadata(ExifProfile frameTags) => this.Initialize(frameTags);
/// <summary>
/// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class with a given ExifProfile.
/// </summary>
/// <param name="frameTags">The Tiff frame directory tags.</param>
public void Initialize(ExifProfile frameTags)
{
this.ExifProfile = frameTags;
this.FillOrder = (TiffFillOrder?)this.ExifProfile.GetValue(ExifTag.FillOrder)?.Value ?? TiffFillOrder.MostSignificantBitFirst;
this.Compression = this.ExifProfile.GetValue(ExifTag.Compression) != null ? (TiffCompression)this.ExifProfile.GetValue(ExifTag.Compression).Value : TiffCompression.None;
this.SubfileType = (TiffNewSubfileType?)this.ExifProfile.GetValue(ExifTag.SubfileType)?.Value ?? TiffNewSubfileType.FullImage;
this.OldSubfileType = (TiffSubfileType?)this.ExifProfile.GetValue(ExifTag.OldSubfileType)?.Value;
this.HorizontalResolution = this.ExifProfile.GetValue(ExifTag.XResolution)?.Value.ToDouble();
this.VerticalResolution = this.ExifProfile.GetValue(ExifTag.YResolution)?.Value.ToDouble();
this.PlanarConfiguration = (TiffPlanarConfiguration?)this.ExifProfile.GetValue(ExifTag.PlanarConfiguration)?.Value ?? DefaultPlanarConfiguration;
this.ResolutionUnit = UnitConverter.ExifProfileToResolutionUnit(this.ExifProfile);
this.ColorMap = this.ExifProfile.GetValue(ExifTag.ColorMap)?.Value;
this.ExtraSamples = this.ExifProfile.GetValue(ExifTag.ExtraSamples)?.Value;
this.Predictor = (TiffPredictor?)this.ExifProfile.GetValue(ExifTag.Predictor)?.Value ?? DefaultPredictor;
this.SampleFormat = this.ExifProfile.GetValue(ExifTag.SampleFormat)?.Value?.Select(a => (TiffSampleFormat)a).ToArray();
this.SamplesPerPixel = this.ExifProfile.GetValue(ExifTag.SamplesPerPixel)?.Value;
this.StripRowCounts = this.ExifProfile.GetValue(ExifTag.StripRowCounts)?.Value;
this.RowsPerStrip = this.ExifProfile.GetValue(ExifTag.RowsPerStrip) != null ? this.ExifProfile.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;
this.TileOffsets = this.ExifProfile.GetValue(ExifTag.TileOffsets)?.Value;
this.PhotometricInterpretation = this.ExifProfile.GetValue(ExifTag.PhotometricInterpretation) != null ?
(TiffPhotometricInterpretation)this.ExifProfile.GetValue(ExifTag.PhotometricInterpretation).Value : TiffPhotometricInterpretation.WhiteIsZero;
// Required Fields for decoding the image.
this.StripOffsets = this.ExifProfile.GetValue(ExifTag.StripOffsets)?.Value;
this.StripByteCounts = this.ExifProfile.GetValue(ExifTag.StripByteCounts)?.Value;
ushort[] bits = this.ExifProfile.GetValue(ExifTag.BitsPerSample)?.Value;
if (bits == null)
{
if (this.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero || this.PhotometricInterpretation == TiffPhotometricInterpretation.BlackIsZero)
{
this.BitsPerSample = TiffBitsPerSample.Bit1;
}
this.BitsPerSample = null;
}
else
{
this.BitsPerSample = bits.GetBitsPerSample();
}
this.BitsPerPixel = this.BitsPerSample.GetValueOrDefault().BitsPerPixel();
}
/// <summary>
/// Verifies that the required fields for decoding an image are present.
/// If not, a ImageFormatException will be thrown.
/// </summary>
public void VerifyRequiredFieldsArePresent()
{
if (this.StripOffsets == null)
{
TiffThrowHelper.ThrowImageFormatException("StripOffsets are missing and are required for decoding the TIFF image!");
}
if (this.StripByteCounts == null)
{
TiffThrowHelper.ThrowImageFormatException("StripByteCounts are missing and are required for decoding the TIFF image!");
}
if (this.BitsPerSample == null)
{
TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!");
}
}
/// <summary>
/// Gets the Tiff directory tags.
/// </summary>
public ExifProfile ExifProfile { get; internal set; }
/// <summary>
/// Gets or sets a general indication of the kind of data contained in this subfile.
/// </summary>
@ -129,9 +56,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <summary>
/// Gets or sets the compression scheme used on the image data.
/// </summary>
/// <value>The compression scheme used on the image data.</value>
public TiffCompression Compression { get; set; }
/// <summary>
/// Gets or sets the fax compression options.
/// </summary>
public FaxCompressionOptions FaxCompressionOptions { get; set; }
/// <summary>
/// Gets or sets the color space of the image data.
/// </summary>
@ -212,7 +143,146 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
public TiffSampleFormat[] SampleFormat { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="TiffFrameMetadata"/> class with a given ExifProfile.
/// </summary>
/// <param name="frameTags">The Tiff frame directory tags.</param>
public void Initialize(ExifProfile frameTags)
{
this.FillOrder = (TiffFillOrder?)frameTags.GetValue(ExifTag.FillOrder)?.Value ?? TiffFillOrder.MostSignificantBitFirst;
this.Compression = frameTags.GetValue(ExifTag.Compression) != null ? (TiffCompression)frameTags.GetValue(ExifTag.Compression).Value : TiffCompression.None;
this.FaxCompressionOptions = frameTags.GetValue(ExifTag.T4Options) != null ? (FaxCompressionOptions)frameTags.GetValue(ExifTag.T4Options).Value : FaxCompressionOptions.None;
this.SubfileType = (TiffNewSubfileType?)frameTags.GetValue(ExifTag.SubfileType)?.Value ?? TiffNewSubfileType.FullImage;
this.OldSubfileType = (TiffSubfileType?)frameTags.GetValue(ExifTag.OldSubfileType)?.Value;
this.HorizontalResolution = frameTags.GetValue(ExifTag.XResolution)?.Value.ToDouble();
this.VerticalResolution = frameTags.GetValue(ExifTag.YResolution)?.Value.ToDouble();
this.ResolutionUnit = UnitConverter.ExifProfileToResolutionUnit(frameTags);
this.PlanarConfiguration = (TiffPlanarConfiguration?)frameTags.GetValue(ExifTag.PlanarConfiguration)?.Value ?? DefaultPlanarConfiguration;
this.ColorMap = frameTags.GetValue(ExifTag.ColorMap)?.Value;
this.ExtraSamples = frameTags.GetValue(ExifTag.ExtraSamples)?.Value;
this.Predictor = (TiffPredictor?)frameTags.GetValue(ExifTag.Predictor)?.Value ?? DefaultPredictor;
this.SampleFormat = frameTags.GetValue(ExifTag.SampleFormat)?.Value?.Select(a => (TiffSampleFormat)a).ToArray();
this.SamplesPerPixel = frameTags.GetValue(ExifTag.SamplesPerPixel)?.Value;
this.StripRowCounts = frameTags.GetValue(ExifTag.StripRowCounts)?.Value;
this.RowsPerStrip = frameTags.GetValue(ExifTag.RowsPerStrip) != null ? frameTags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;
this.TileOffsets = frameTags.GetValue(ExifTag.TileOffsets)?.Value;
this.PhotometricInterpretation = frameTags.GetValue(ExifTag.PhotometricInterpretation) != null ?
(TiffPhotometricInterpretation)frameTags.GetValue(ExifTag.PhotometricInterpretation).Value : TiffPhotometricInterpretation.WhiteIsZero;
// Required Fields for decoding the image.
this.StripOffsets = frameTags.GetValue(ExifTag.StripOffsets)?.Value;
this.StripByteCounts = frameTags.GetValue(ExifTag.StripByteCounts)?.Value;
ushort[] bits = frameTags.GetValue(ExifTag.BitsPerSample)?.Value;
if (bits == null)
{
if (this.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero || this.PhotometricInterpretation == TiffPhotometricInterpretation.BlackIsZero)
{
this.BitsPerSample = TiffBitsPerSample.Bit1;
}
this.BitsPerSample = null;
}
else
{
this.BitsPerSample = bits.GetBitsPerSample();
}
this.BitsPerPixel = this.BitsPerSample.GetValueOrDefault().BitsPerPixel();
}
/// <summary>
/// Verifies that the required fields for decoding an image are present.
/// If not, a ImageFormatException will be thrown.
/// </summary>
public void VerifyRequiredFieldsArePresent()
{
if (this.StripOffsets == null)
{
TiffThrowHelper.ThrowImageFormatException("StripOffsets are missing and are required for decoding the TIFF image!");
}
if (this.StripByteCounts == null)
{
TiffThrowHelper.ThrowImageFormatException("StripByteCounts are missing and are required for decoding the TIFF image!");
}
if (this.BitsPerSample == null)
{
TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!");
}
}
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new TiffFrameMetadata(this.ExifProfile.DeepClone());
public IDeepCloneable DeepClone()
{
var clone = new TiffFrameMetadata();
clone.FillOrder = this.FillOrder;
clone.Compression = this.Compression;
clone.FaxCompressionOptions = this.FaxCompressionOptions;
clone.SubfileType = this.SubfileType ?? TiffNewSubfileType.FullImage;
clone.OldSubfileType = this.OldSubfileType ?? TiffSubfileType.FullImage;
clone.HorizontalResolution = this.HorizontalResolution ?? ImageMetadata.DefaultHorizontalResolution;
clone.VerticalResolution = this.VerticalResolution ?? ImageMetadata.DefaultVerticalResolution;
clone.ResolutionUnit = this.ResolutionUnit;
clone.PlanarConfiguration = this.PlanarConfiguration;
if (this.ColorMap != null)
{
clone.ColorMap = new ushort[this.ColorMap.Length];
this.ColorMap.AsSpan().CopyTo(clone.ColorMap);
}
if (this.ExtraSamples != null)
{
clone.ExtraSamples = new ushort[this.ExtraSamples.Length];
this.ExtraSamples.AsSpan().CopyTo(clone.ExtraSamples);
}
clone.Predictor = this.Predictor;
if (this.SampleFormat != null)
{
clone.SampleFormat = new TiffSampleFormat[this.SampleFormat.Length];
this.SampleFormat.AsSpan().CopyTo(clone.SampleFormat);
}
clone.SamplesPerPixel = this.SamplesPerPixel;
if (this.StripRowCounts != null)
{
clone.StripRowCounts = new uint[this.StripRowCounts.Length];
this.StripRowCounts.AsSpan().CopyTo(clone.StripRowCounts);
}
clone.RowsPerStrip = this.RowsPerStrip;
if (this.TileOffsets != null)
{
clone.TileOffsets = new uint[this.TileOffsets.Length];
this.TileOffsets.AsSpan().CopyTo(clone.TileOffsets);
}
clone.PhotometricInterpretation = this.PhotometricInterpretation;
if (this.StripOffsets != null)
{
clone.StripOffsets = new Number[this.StripOffsets.Length];
this.StripOffsets.AsSpan().CopyTo(clone.StripOffsets);
}
if (this.StripByteCounts != null)
{
clone.StripByteCounts = new Number[this.StripByteCounts.Length];
this.StripByteCounts.AsSpan().CopyTo(clone.StripByteCounts);
}
clone.BitsPerSample = this.BitsPerSample;
clone.BitsPerPixel = this.BitsPerPixel;
return clone;
}
}
}

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

@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.Tiff
{
/// <summary>
@ -25,8 +23,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
this.ByteOrder = other.ByteOrder;
this.BitsPerPixel = other.BitsPerPixel;
this.XmpProfile = other.XmpProfile != null ? new byte[other.XmpProfile.Length] : null;
other.XmpProfile?.AsSpan().CopyTo(this.XmpProfile.AsSpan());
}
/// <summary>
@ -39,12 +35,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
public TiffBitsPerPixel? BitsPerPixel { get; set; }
/// <summary>
/// Gets or sets the XMP profile.
/// For internal use only. ImageSharp not support XMP profile.
/// </summary>
internal byte[] XmpProfile { get; set; }
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new TiffMetadata(this);
}

20
src/ImageSharp/Metadata/ImageFrameMetadata.cs

@ -1,8 +1,10 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Metadata
{
@ -35,8 +37,22 @@ namespace SixLabors.ImageSharp.Metadata
{
this.formatMetadata.Add(meta.Key, meta.Value.DeepClone());
}
this.ExifProfile = other.ExifProfile?.DeepClone();
this.XmpProfile = other.XmpProfile != null ? new byte[other.XmpProfile.Length] : null;
other.XmpProfile?.AsSpan().CopyTo(this.XmpProfile.AsSpan());
}
/// <summary>
/// Gets or sets the Exif profile.
/// </summary>
public ExifProfile ExifProfile { get; set; }
/// <summary>
/// Gets or sets the XMP profile.
/// </summary>
public byte[] XmpProfile { get; set; }
/// <inheritdoc/>
public ImageFrameMetadata DeepClone() => new ImageFrameMetadata(this);
@ -63,4 +79,4 @@ namespace SixLabors.ImageSharp.Metadata
return newMeta;
}
}
}
}

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

@ -254,7 +254,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[WithFile(Rgb4BitPalette, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeColorPalette_With4Bit_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> =>
// Note: The magick reference decoder does not support 4 bit tiff's, so we use our TIFF decoder instead.
//// Note: The magick reference decoder does not support 4 bit tiff's, so we use our TIFF decoder instead.
TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit4, TiffEncodingMode.ColorPalette, useExactComparer: false, compareTolerance: 0.001f, imageDecoder: new TiffDecoder());
[Theory]

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

@ -1,9 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -11,7 +8,6 @@ using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SixLabors.ImageSharp.PixelFormats;
@ -37,12 +33,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Fact]
public void TiffMetadata_CloneIsDeep()
{
byte[] xmpData = { 1, 1, 1 };
var meta = new TiffMetadata
{
BitsPerPixel = TiffBitsPerPixel.Bit8,
ByteOrder = ByteOrder.BigEndian,
XmpProfile = xmpData
};
var clone = (TiffMetadata)meta.DeepClone();
@ -52,8 +46,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.False(meta.BitsPerPixel == clone.BitsPerPixel);
Assert.False(meta.ByteOrder == clone.ByteOrder);
Assert.False(meta.XmpProfile.Equals(clone.XmpProfile));
Assert.True(meta.XmpProfile.SequenceEqual(clone.XmpProfile));
}
[Theory]
@ -65,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
TiffFrameMetadata meta = image.Frames.RootFrame.Metadata.GetTiffMetadata();
var cloneSameAsSampleMetaData = (TiffFrameMetadata)meta.DeepClone();
VerifyExpectedFrameMetaDataIsPresent(cloneSameAsSampleMetaData);
VerifyExpectedTiffFrameMetaDataIsPresent(cloneSameAsSampleMetaData);
var clone = (TiffFrameMetadata)meta.DeepClone();
@ -119,15 +111,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
using (Image<TPixel> image = provider.GetImage(new TiffDecoder() { IgnoreMetadata = ignoreMetadata }))
{
TiffMetadata meta = image.Metadata.GetTiffMetadata();
ImageFrameMetadata rootFrameMetaData = image.Frames.RootFrame.Metadata;
Assert.NotNull(meta);
if (ignoreMetadata)
{
Assert.Null(meta.XmpProfile);
Assert.Null(rootFrameMetaData.XmpProfile);
Assert.Null(rootFrameMetaData.ExifProfile);
}
else
{
Assert.NotNull(meta.XmpProfile);
Assert.Equal(2599, meta.XmpProfile.Length);
Assert.NotNull(rootFrameMetaData.XmpProfile);
Assert.NotNull(rootFrameMetaData.ExifProfile);
Assert.Equal(2599, rootFrameMetaData.XmpProfile.Length);
Assert.Equal(30, rootFrameMetaData.ExifProfile.Values.Count);
}
}
}
@ -155,9 +151,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
ImageFrame<TPixel> rootFrame = image.Frames.RootFrame;
Assert.Equal(32, rootFrame.Width);
Assert.Equal(32, rootFrame.Height);
TiffFrameMetadata frameMetaData = rootFrame.Metadata.GetTiffMetadata();
Assert.NotNull(frameMetaData);
Assert.NotNull(rootFrame.Metadata.XmpProfile);
Assert.Equal(2599, rootFrame.Metadata.XmpProfile.Length);
ExifProfile exifProfile = rootFrame.Metadata.ExifProfile;
Assert.NotNull(exifProfile);
Assert.Equal(30, exifProfile.Values.Count);
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.Model).Value);
Assert.Equal("IrfanView", exifProfile.GetValue(ExifTag.Software).Value);
Assert.Null(exifProfile.GetValue(ExifTag.DateTime)?.Value);
Assert.Equal("This is author1;Author2", exifProfile.GetValue(ExifTag.Artist).Value);
Assert.Null(exifProfile.GetValue(ExifTag.HostComputer)?.Value);
Assert.Equal("This is Авторские права", exifProfile.GetValue(ExifTag.Copyright).Value);
Assert.Equal(4, exifProfile.GetValue(ExifTag.Rating).Value);
Assert.Equal(75, exifProfile.GetValue(ExifTag.RatingPercent).Value);
TiffFrameMetadata tiffFrameMetadata = rootFrame.Metadata.GetTiffMetadata();
Assert.NotNull(tiffFrameMetadata);
ImageMetadata imageMetaData = image.Metadata;
Assert.NotNull(imageMetaData);
@ -170,31 +182,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Equal(ByteOrder.LittleEndian, tiffMetaData.ByteOrder);
Assert.Equal(TiffBitsPerPixel.Bit4, tiffMetaData.BitsPerPixel);
VerifyExpectedFrameMetaDataIsPresent(frameMetaData);
VerifyExpectedTiffFrameMetaDataIsPresent(tiffFrameMetadata);
}
}
private static void VerifyExpectedFrameMetaDataIsPresent(TiffFrameMetadata frameMetaData)
private static void VerifyExpectedTiffFrameMetaDataIsPresent(TiffFrameMetadata frameMetaData)
{
Assert.Equal(30, frameMetaData.ExifProfile.Values.Count);
Assert.Equal(TiffBitsPerSample.Bit4, frameMetaData.BitsPerSample);
Assert.Equal(TiffCompression.Lzw, frameMetaData.Compression);
Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frameMetaData.PhotometricInterpretation);
Assert.Equal("This is Название", frameMetaData.ExifProfile.GetValue(ExifTag.ImageDescription).Value);
Assert.Equal("This is Изготовитель камеры", frameMetaData.ExifProfile.GetValue(ExifTag.Make).Value);
Assert.Equal("This is Модель камеры", frameMetaData.ExifProfile.GetValue(ExifTag.Model).Value);
Assert.Equal(new Number[] {8u}, frameMetaData.StripOffsets, new NumberComparer());
Assert.Equal(new Number[] { 8u }, frameMetaData.StripOffsets, new NumberComparer());
Assert.Equal(1, frameMetaData.SamplesPerPixel.GetValueOrDefault());
Assert.Equal(32u, frameMetaData.RowsPerStrip);
Assert.Equal(new Number[] {297u}, frameMetaData.StripByteCounts, new NumberComparer());
Assert.Equal(new Number[] { 297u }, frameMetaData.StripByteCounts, new NumberComparer());
Assert.Equal(PixelResolutionUnit.PixelsPerInch, frameMetaData.ResolutionUnit);
Assert.Equal(10, frameMetaData.HorizontalResolution);
Assert.Equal(10, frameMetaData.VerticalResolution);
Assert.Equal(TiffPlanarConfiguration.Chunky, frameMetaData.PlanarConfiguration);
Assert.Equal("IrfanView", frameMetaData.ExifProfile.GetValue(ExifTag.Software).Value);
Assert.Null(frameMetaData.ExifProfile.GetValue(ExifTag.DateTime)?.Value);
Assert.Equal("This is author1;Author2", frameMetaData.ExifProfile.GetValue(ExifTag.Artist).Value);
Assert.Null(frameMetaData.ExifProfile.GetValue(ExifTag.HostComputer)?.Value);
Assert.Equal(48, frameMetaData.ColorMap.Length);
Assert.Equal(10537, frameMetaData.ColorMap[0]);
Assert.Equal(14392, frameMetaData.ColorMap[1]);
@ -204,9 +208,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Null(frameMetaData.ExtraSamples);
Assert.Equal(TiffPredictor.None, frameMetaData.Predictor);
Assert.Null(frameMetaData.SampleFormat);
Assert.Equal("This is Авторские права", frameMetaData.ExifProfile.GetValue(ExifTag.Copyright).Value);
Assert.Equal(4, frameMetaData.ExifProfile.GetValue(ExifTag.Rating).Value);
Assert.Equal(75, frameMetaData.ExifProfile.GetValue(ExifTag.RatingPercent).Value);
}
[Theory]
@ -223,13 +224,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
TiffFrameMetadata frame0MetaData = image.Frames[0].Metadata.GetTiffMetadata();
Assert.Equal(TiffNewSubfileType.FullImage, frame0MetaData.SubfileType);
Assert.Null(frame0MetaData.OldSubfileType);
Assert.Equal(255, image.Frames[0].Width);
Assert.Equal(255, image.Frames[0].Height);
TiffFrameMetadata frame1MetaData = image.Frames[1].Metadata.GetTiffMetadata();
Assert.Equal(TiffNewSubfileType.Preview, frame1MetaData.SubfileType);
Assert.Null(frame1MetaData.OldSubfileType);
Assert.Equal(255, image.Frames[1].Width);
Assert.Equal(255, image.Frames[1].Height);
}
@ -246,7 +245,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
ImageMetadata inputMetaData = image.Metadata;
TiffMetadata tiffMetaInput = image.Metadata.GetTiffMetadata();
TiffFrameMetadata frameMetaInput = image.Frames.RootFrame.Metadata.GetTiffMetadata();
ImageFrame<TPixel> frameRootInput = image.Frames.RootFrame;
ImageFrame<TPixel> rootFrameInput = image.Frames.RootFrame;
byte[] xmpProfileInput = rootFrameInput.Metadata.XmpProfile;
ExifProfile rootFrameExifProfileInput = rootFrameInput.Metadata.ExifProfile;
Assert.Equal(TiffCompression.Lzw, frameMetaInput.Compression);
Assert.Equal(TiffBitsPerPixel.Bit4, tiffMetaInput.BitsPerPixel);
@ -261,9 +262,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
using var encodedImage = Image.Load<Rgba32>(this.configuration, ms);
ImageMetadata encodedImageMetaData = encodedImage.Metadata;
TiffMetadata tiffMetaDataEncodedImage = encodedImage.Metadata.GetTiffMetadata();
TiffFrameMetadata tiffMetaDataEncodedRootFrame = encodedImage.Frames.RootFrame.Metadata.GetTiffMetadata();
TiffMetadata tiffMetaDataEncodedImage = encodedImageMetaData.GetTiffMetadata();
ImageFrame<Rgba32> rootFrameEncodedImage = encodedImage.Frames.RootFrame;
TiffFrameMetadata tiffMetaDataEncodedRootFrame = rootFrameEncodedImage.Metadata.GetTiffMetadata();
ExifProfile encodedImageExifProfile = rootFrameEncodedImage.Metadata.ExifProfile;
byte[] encodedImageXmpProfile = rootFrameEncodedImage.Metadata.XmpProfile;
Assert.Equal(TiffBitsPerPixel.Bit24, tiffMetaDataEncodedImage.BitsPerPixel);
Assert.Equal(TiffCompression.None, tiffMetaDataEncodedRootFrame.Compression);
@ -272,22 +275,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Equal(inputMetaData.VerticalResolution, encodedImageMetaData.VerticalResolution);
Assert.Equal(inputMetaData.ResolutionUnits, encodedImageMetaData.ResolutionUnits);
Assert.Equal(frameRootInput.Width, rootFrameEncodedImage.Width);
Assert.Equal(frameRootInput.Height, rootFrameEncodedImage.Height);
Assert.Equal(rootFrameInput.Width, rootFrameEncodedImage.Width);
Assert.Equal(rootFrameInput.Height, rootFrameEncodedImage.Height);
Assert.Equal(frameMetaInput.ResolutionUnit, tiffMetaDataEncodedRootFrame.ResolutionUnit);
Assert.Equal(frameMetaInput.HorizontalResolution, tiffMetaDataEncodedRootFrame.HorizontalResolution);
Assert.Equal(frameMetaInput.VerticalResolution, tiffMetaDataEncodedRootFrame.VerticalResolution);
Assert.Equal(tiffMetaInput.XmpProfile, tiffMetaDataEncodedImage.XmpProfile);
Assert.Equal(xmpProfileInput, encodedImageXmpProfile);
Assert.Equal("IrfanView", frameMetaInput.ExifProfile.GetValue(ExifTag.Software).Value);
Assert.Equal("This is Название", frameMetaInput.ExifProfile.GetValue(ExifTag.ImageDescription).Value);
Assert.Equal("This is Изготовитель камеры", frameMetaInput.ExifProfile.GetValue(ExifTag.Make).Value);
Assert.Equal("This is Авторские права", frameMetaInput.ExifProfile.GetValue(ExifTag.Copyright).Value);
Assert.Equal("IrfanView", rootFrameExifProfileInput.GetValue(ExifTag.Software).Value);
Assert.Equal("This is Название", rootFrameExifProfileInput.GetValue(ExifTag.ImageDescription).Value);
Assert.Equal("This is Изготовитель камеры", rootFrameExifProfileInput.GetValue(ExifTag.Make).Value);
Assert.Equal("This is Авторские права", rootFrameExifProfileInput.GetValue(ExifTag.Copyright).Value);
Assert.Equal(frameMetaInput.ExifProfile.GetValue(ExifTag.ImageDescription).Value, tiffMetaDataEncodedRootFrame.ExifProfile.GetValue(ExifTag.ImageDescription).Value);
Assert.Equal(frameMetaInput.ExifProfile.GetValue(ExifTag.Make).Value, tiffMetaDataEncodedRootFrame.ExifProfile.GetValue(ExifTag.Make).Value);
Assert.Equal(frameMetaInput.ExifProfile.GetValue(ExifTag.Copyright).Value, tiffMetaDataEncodedRootFrame.ExifProfile.GetValue(ExifTag.Copyright).Value);
Assert.Equal(rootFrameExifProfileInput.Values.Count, encodedImageExifProfile.Values.Count);
Assert.Equal(rootFrameExifProfileInput.GetValue(ExifTag.ImageDescription).Value, encodedImageExifProfile.GetValue(ExifTag.ImageDescription).Value);
Assert.Equal(rootFrameExifProfileInput.GetValue(ExifTag.Make).Value, encodedImageExifProfile.GetValue(ExifTag.Make).Value);
Assert.Equal(rootFrameExifProfileInput.GetValue(ExifTag.Copyright).Value, encodedImageExifProfile.GetValue(ExifTag.Copyright).Value);
}
}
}

28
tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs

@ -1,11 +1,13 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Linq;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using Xunit;
namespace SixLabors.ImageSharp.Tests
namespace SixLabors.ImageSharp.Tests.Metadata
{
/// <summary>
/// Tests the <see cref="ImageFrameMetadataTests"/> class.
@ -36,8 +38,28 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void CloneIsDeep()
{
var metaData = new ImageFrameMetadata();
// arrange
byte[] xmpProfile = { 1, 2, 3 };
var exifProfile = new ExifProfile();
exifProfile.SetValue(ExifTag.Software, "UnitTest");
exifProfile.SetValue(ExifTag.Artist, "UnitTest");
var metaData = new ImageFrameMetadata()
{
XmpProfile = xmpProfile,
ExifProfile = exifProfile
};
// act
ImageFrameMetadata clone = metaData.DeepClone();
// assert
Assert.NotNull(clone);
Assert.NotNull(clone.ExifProfile);
Assert.NotNull(clone.XmpProfile);
Assert.False(metaData.ExifProfile.Equals(clone.ExifProfile));
Assert.True(metaData.ExifProfile.Values.Count == clone.ExifProfile.Values.Count);
Assert.False(metaData.XmpProfile.Equals(clone.XmpProfile));
Assert.True(metaData.XmpProfile.SequenceEqual(clone.XmpProfile));
Assert.False(metaData.GetGifMetadata().Equals(clone.GetGifMetadata()));
}
}

5
tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
@ -70,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests
public void ConstructorEmpty()
{
new ExifProfile(null);
new ExifProfile(new byte[] { });
new ExifProfile(Array.Empty<byte>());
}
[Fact]
@ -328,7 +327,7 @@ namespace SixLabors.ImageSharp.Tests
var junk = new StringBuilder();
for (int i = 0; i < 65600; i++)
{
junk.Append("a");
junk.Append('a');
}
var image = new Image<Rgba32>(100, 100);

Loading…
Cancel
Save