From 04b6f3ffcfe4a714b7491fcfa8827ae8764f5ebe Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 14 May 2021 11:43:41 +0200 Subject: [PATCH] Remove ExifProfile from TiffFrameMetadata, Add ExifProfile and XmpProfile to ImageFrameMetaData --- .../Formats/Tiff/Ifd/DirectoryReader.cs | 7 + .../Formats/Tiff/TiffDecoderCore.cs | 52 ++-- .../Tiff/TiffDecoderMetadataCreator.cs | 82 +++++-- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 14 +- .../Tiff/TiffEncoderEntriesCollector.cs | 39 +-- .../Formats/Tiff/TiffFrameMetadata.cs | 230 ++++++++++++------ src/ImageSharp/Formats/Tiff/TiffMetadata.cs | 10 - src/ImageSharp/Metadata/ImageFrameMetadata.cs | 20 +- .../Formats/Tiff/TiffEncoderTests.cs | 2 +- .../Formats/Tiff/TiffMetadataTests.cs | 94 +++---- .../Metadata/ImageFrameMetadataTests.cs | 28 ++- .../Profiles/Exif/ExifProfileTests.cs | 5 +- 12 files changed, 359 insertions(+), 224 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index ea090c92b..8b2c6bd3a 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -24,8 +24,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff public DirectoryReader(Stream stream) => this.stream = stream; + /// + /// Gets the byte order. + /// public ByteOrder ByteOrder { get; private set; } + /// + /// Reads image file directories. + /// + /// Image file directories. public IEnumerable Read() { this.ByteOrder = ReadByteOrder(this.stream); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index d67ffc069..da0d73832 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/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 directories = reader.Read(); var frames = new List>(); - var framesMetadata = new List(); + var tiffFramesMataData = new List(); foreach (ExifProfile ifd in directories) { ImageFrame frame = this.DecodeFrame(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 /// /// The pixel format. /// The IFD tags. - /// The frame metadata. + /// The tiff frame metadata. /// /// The tiff frame. /// - private ImageFrame DecodeFrame(ExifProfile tags, out TiffFrameMetadata frameMetaData) + private ImageFrame DecodeFrame(ExifProfile tags, out TiffFrameMetadata tiffFrameMetaData) where TPixel : unmanaged, IPixel { - 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(this.Configuration, width, height, coreMetadata); + int width = GetImageWidth(tags); + int height = GetImageHeight(tags); + var frame = new ImageFrame(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 /// /// Gets the width of the image frame. /// - /// The image frame. + /// The image frame exif profile. /// The image width. - private static int GetImageWidth(TiffFrameMetadata frame) + private static int GetImageWidth(ExifProfile exifProfile) { - IExifValue width = frame.ExifProfile.GetValue(ExifTag.ImageWidth); + IExifValue 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 /// /// Gets the height of the image frame. /// - /// The image frame. + /// The image frame exif profile. /// The image height. - private static int GetImageHeight(TiffFrameMetadata frame) + private static int GetImageHeight(ExifProfile exifProfile) { - IExifValue height = frame.ExifProfile.GetValue(ExifTag.ImageLength); + IExifValue height = exifProfile.GetValue(ExifTag.ImageLength); if (height == null) { TiffThrowHelper.ThrowImageFormatException("The TIFF image frame is missing the ImageLength"); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs index 5b67c363a..77d3d041c 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs +++ b/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 /// internal static class TiffDecoderMetadataCreator { - public static ImageMetadata Create(List frames, bool ignoreMetadata, ByteOrder byteOrder) + public static ImageMetadata Create(List> frames, List framesMetaData, bool ignoreMetadata, ByteOrder byteOrder) + where TPixel : unmanaged, IPixel { - 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 frame = frames[i]; + ImageFrameMetadata frameMetaData = frame.Metadata; + if (frameMetaData.XmpProfile == null) { - IExifValue val = frame.ExifProfile.GetValue(ExifTag.XMP); + IExifValue 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 val = frame.ExifProfile.GetValue(ExifTag.IccProfile); + IExifValue 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 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 exifValues, out byte[] iptcBytes) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index b9f30a3ef..45a55b274 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/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; } } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs index f20395221..391f7d541 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs @@ -47,7 +47,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff public void Process(Image image) where TPixel : unmanaged, IPixel { - TiffFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetTiffMetadata(); + ImageFrame 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); } } } diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index d98b3ac94..f237ed329 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/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 /// /// Initializes a new instance of the class. /// - public TiffFrameMetadata() => this.Initialize(new ExifProfile()); + public TiffFrameMetadata() + { + } /// /// Initializes a new instance of the class. @@ -29,83 +33,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The Tiff frame directory tags. public TiffFrameMetadata(ExifProfile frameTags) => this.Initialize(frameTags); - /// - /// Initializes a new instance of the class with a given ExifProfile. - /// - /// The Tiff frame directory tags. - 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(); - } - - /// - /// Verifies that the required fields for decoding an image are present. - /// If not, a ImageFormatException will be thrown. - /// - 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!"); - } - } - - /// - /// Gets the Tiff directory tags. - /// - public ExifProfile ExifProfile { get; internal set; } - /// /// Gets or sets a general indication of the kind of data contained in this subfile. /// @@ -129,9 +56,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// /// Gets or sets the compression scheme used on the image data. /// - /// The compression scheme used on the image data. public TiffCompression Compression { get; set; } + /// + /// Gets or sets the fax compression options. + /// + public FaxCompressionOptions FaxCompressionOptions { get; set; } + /// /// Gets or sets the color space of the image data. /// @@ -212,7 +143,146 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// public TiffSampleFormat[] SampleFormat { get; set; } + /// + /// Initializes a new instance of the class with a given ExifProfile. + /// + /// The Tiff frame directory tags. + 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(); + } + + /// + /// Verifies that the required fields for decoding an image are present. + /// If not, a ImageFormatException will be thrown. + /// + 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!"); + } + } + /// - 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; + } } } diff --git a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs index 5923e831a..9d36d6613 100644 --- a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs +++ b/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 { /// @@ -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()); } /// @@ -39,12 +35,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// public TiffBitsPerPixel? BitsPerPixel { get; set; } - /// - /// Gets or sets the XMP profile. - /// For internal use only. ImageSharp not support XMP profile. - /// - internal byte[] XmpProfile { get; set; } - /// public IDeepCloneable DeepClone() => new TiffMetadata(this); } diff --git a/src/ImageSharp/Metadata/ImageFrameMetadata.cs b/src/ImageSharp/Metadata/ImageFrameMetadata.cs index 2021f1249..761cce1c1 100644 --- a/src/ImageSharp/Metadata/ImageFrameMetadata.cs +++ b/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()); } + /// + /// Gets or sets the Exif profile. + /// + public ExifProfile ExifProfile { get; set; } + + /// + /// Gets or sets the XMP profile. + /// + public byte[] XmpProfile { get; set; } + /// public ImageFrameMetadata DeepClone() => new ImageFrameMetadata(this); @@ -63,4 +79,4 @@ namespace SixLabors.ImageSharp.Metadata return newMeta; } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 77098c42c..f24ce0c64 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/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(TestImageProvider provider) where TPixel : unmanaged, IPixel => - // 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] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index 45b53eae8..66a90418b 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/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 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 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 frameRootInput = image.Frames.RootFrame; + ImageFrame 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(this.configuration, ms); ImageMetadata encodedImageMetaData = encodedImage.Metadata; - TiffMetadata tiffMetaDataEncodedImage = encodedImage.Metadata.GetTiffMetadata(); - TiffFrameMetadata tiffMetaDataEncodedRootFrame = encodedImage.Frames.RootFrame.Metadata.GetTiffMetadata(); + TiffMetadata tiffMetaDataEncodedImage = encodedImageMetaData.GetTiffMetadata(); ImageFrame 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); } } } diff --git a/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs index 3f8904904..cf63db39b 100644 --- a/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs +++ b/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 { /// /// Tests the 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())); } } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index fef890a65..cac46fd60 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/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()); } [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(100, 100);