From f9570d37f7aab536e35d5444cd4df872d702721c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Mon, 8 Mar 2021 17:04:31 +0300 Subject: [PATCH] Remove TiffFrameMetadataResolutionExtensions class --- .../Common/Helpers/UnitConverter.cs | 50 +++++++++- .../Tiff/TiffEncoderEntriesCollector.cs | 78 +++++++-------- .../Formats/Tiff/TiffFrameMetadata.cs | 48 +++++---- .../TiffFrameMetadataResolutionExtensions.cs | 97 ------------------- .../Tiff/Writers/TiffBaseColorWriter.cs | 6 +- .../Formats/Tiff/Writers/TiffPaletteWriter.cs | 2 +- .../Formats/Tiff/TiffEncoderTests.cs | 1 - .../Formats/Tiff/TiffMetadataTests.cs | 2 +- 8 files changed, 118 insertions(+), 166 deletions(-) delete mode 100644 src/ImageSharp/Formats/Tiff/TiffFrameMetadataResolutionExtensions.cs diff --git a/src/ImageSharp/Common/Helpers/UnitConverter.cs b/src/ImageSharp/Common/Helpers/UnitConverter.cs index 4a6e6abcb6..efc0e0e152 100644 --- a/src/ImageSharp/Common/Helpers/UnitConverter.cs +++ b/src/ImageSharp/Common/Helpers/UnitConverter.cs @@ -30,6 +30,11 @@ namespace SixLabors.ImageSharp.Common.Helpers /// private const double InchesInMeter = 1 / 0.0254D; + /// + /// The default resolution unit value. + /// + private const PixelResolutionUnit DefaultResolutionUnit = PixelResolutionUnit.PixelsPerInch; + /// /// Scales the value from centimeters to meters. /// @@ -89,7 +94,50 @@ namespace SixLabors.ImageSharp.Common.Helpers IExifValue resolution = profile.GetValue(ExifTag.ResolutionUnit); // EXIF is 1, 2, 3 so we minus "1" off the result. - return resolution is null ? default : (PixelResolutionUnit)(byte)(resolution.Value - 1); + return resolution is null ? DefaultResolutionUnit : (PixelResolutionUnit)(byte)(resolution.Value - 1); + } + + /// + /// Sets the exif profile resolution values. + /// + /// The exif profile. + /// The resolution unit. + /// The horizontal resolution value. + /// The vertical resolution value. + [MethodImpl(InliningOptions.ShortMethod)] + public static void SetResolutionValues(ExifProfile exifProfile, PixelResolutionUnit unit, double horizontal, double vertical) + { + switch (unit) + { + case PixelResolutionUnit.AspectRatio: + case PixelResolutionUnit.PixelsPerInch: + case PixelResolutionUnit.PixelsPerCentimeter: + break; + case PixelResolutionUnit.PixelsPerMeter: + { + unit = PixelResolutionUnit.PixelsPerCentimeter; + horizontal = UnitConverter.MeterToCm(horizontal); + vertical = UnitConverter.MeterToCm(vertical); + } + + break; + default: + unit = PixelResolutionUnit.PixelsPerInch; + break; + } + + exifProfile.SetValue(ExifTag.ResolutionUnit, (ushort)(unit + 1)); + + if (unit == PixelResolutionUnit.AspectRatio) + { + exifProfile.RemoveValue(ExifTag.XResolution); + exifProfile.RemoveValue(ExifTag.YResolution); + } + else + { + exifProfile.SetValue(ExifTag.XResolution, new Rational(horizontal)); + exifProfile.SetValue(ExifTag.YResolution, new Rational(vertical)); + } } } } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs index 0707ee321a..f1d6114f8f 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; - +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -12,6 +12,8 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff { internal class TiffEncoderEntriesCollector { + private const string SoftwareValue = "ImageSharp"; + public List Entries { get; } = new List(); public void ProcessGeneral(Image image) @@ -21,18 +23,20 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff public void ProcessImageFormat(TiffEncoderCore encoder) => new ImageFormatProcessor(this).Process(encoder); - public void Add(IExifValue entry) + public void AddOrReplace(IExifValue entry) { - IExifValue exist = this.Entries.Find(t => t.Tag == entry.Tag); - if (exist != null) + int index = this.Entries.FindIndex(t => t.Tag == entry.Tag); + if (index >= 0) { - this.Entries.Remove(exist); + this.Entries[index] = entry; + } + else + { + this.Entries.Add(entry); } - - this.Entries.Add(entry); } - private void AddInternal(IExifValue entry) => this.Entries.Add(entry); + private void Add(IExifValue entry) => this.Entries.Add(entry); private class GeneralProcessor { @@ -57,12 +61,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff var software = new ExifString(ExifTagValue.Software) { - Value = "ImageSharp" + Value = SoftwareValue }; - this.collector.AddInternal(width); - this.collector.AddInternal(height); - this.collector.AddInternal(software); + this.collector.Add(width); + this.collector.Add(height); + this.collector.Add(software); this.ProcessResolution(image.Metadata, frameMetadata); @@ -70,7 +74,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff this.ProcessMetadata(frameMetadata); } - private static bool IsMetadata(ExifTag tag) + private static bool IsPureMetadata(ExifTag tag) { switch ((ExifTagValue)(ushort)tag) { @@ -107,29 +111,22 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff private void ProcessResolution(ImageMetadata imageMetadata, TiffFrameMetadata frameMetadata) { - frameMetadata.SetResolutions( + UnitConverter.SetResolutionValues( + frameMetadata.ExifProfile, imageMetadata.ResolutionUnits, imageMetadata.HorizontalResolution, imageMetadata.VerticalResolution); - var xResolution = new ExifRational(ExifTagValue.XResolution) - { - Value = frameMetadata.ExifProfile.GetValue(ExifTag.XResolution).Value - }; + this.collector.Add(frameMetadata.ExifProfile.GetValue(ExifTag.ResolutionUnit).DeepClone()); - var yResolution = new ExifRational(ExifTagValue.YResolution) - { - Value = frameMetadata.ExifProfile.GetValue(ExifTag.YResolution).Value - }; + IExifValue xResolution = frameMetadata.ExifProfile.GetValue(ExifTag.XResolution)?.DeepClone(); + IExifValue yResolution = frameMetadata.ExifProfile.GetValue(ExifTag.YResolution)?.DeepClone(); - var resolutionUnit = new ExifShort(ExifTagValue.ResolutionUnit) + if (xResolution != null && yResolution != null) { - Value = frameMetadata.ExifProfile.GetValue(ExifTag.ResolutionUnit).Value - }; - - this.collector.AddInternal(xResolution); - this.collector.AddInternal(yResolution); - this.collector.AddInternal(resolutionUnit); + this.collector.Add(xResolution); + this.collector.Add(yResolution); + } } private void ProcessMetadata(TiffFrameMetadata frameMetadata) @@ -160,7 +157,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff break; case ExifParts.IfdTags: - if (!IsMetadata(entry.Tag)) + if (!IsPureMetadata(entry.Tag)) { continue; } @@ -170,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff if (!this.collector.Entries.Exists(t => t.Tag == entry.Tag)) { - this.collector.AddInternal(entry.DeepClone()); + this.collector.AddOrReplace(entry.DeepClone()); } } } @@ -194,7 +191,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff Value = imageMetadata.IptcProfile.Data }; - this.collector.AddInternal(iptc); + this.collector.Add(iptc); } else { @@ -208,7 +205,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff Value = imageMetadata.IccProfile.ToByteArray() }; - this.collector.AddInternal(icc); + this.collector.Add(icc); } else { @@ -223,7 +220,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff Value = tiffMetadata.XmpProfile }; - this.collector.AddInternal(xmp); + this.collector.Add(xmp); } else { @@ -262,10 +259,10 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff Value = (ushort)encoder.PhotometricInterpretation }; - this.collector.Add(samplesPerPixel); - this.collector.Add(bitPerSample); - this.collector.Add(compression); - this.collector.Add(photometricInterpretation); + this.collector.AddOrReplace(samplesPerPixel); + this.collector.AddOrReplace(bitPerSample); + this.collector.AddOrReplace(compression); + this.collector.AddOrReplace(photometricInterpretation); if (encoder.UseHorizontalPredictor) { @@ -273,7 +270,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff { var predictor = new ExifShort(ExifTagValue.Predictor) { Value = (ushort)TiffPredictor.Horizontal }; - this.collector.Add(predictor); + this.collector.AddOrReplace(predictor); } } } @@ -282,12 +279,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff { switch (encoder.PhotometricInterpretation) { - case TiffPhotometricInterpretation.Rgb: - return 3; case TiffPhotometricInterpretation.PaletteColor: case TiffPhotometricInterpretation.BlackIsZero: case TiffPhotometricInterpretation.WhiteIsZero: return 1; + case TiffPhotometricInterpretation.Rgb: default: return 3; } diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index 5217650da9..242c60974a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Metadata; @@ -15,9 +16,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff /// public class TiffFrameMetadata : IDeepCloneable { - // 2 (Inch) - internal const ushort DefaultResolutionUnit = 2; - private const TiffPlanarConfiguration DefaultPlanarConfiguration = TiffPlanarConfiguration.Chunky; private const TiffPredictor DefaultPredictor = TiffPredictor.None; @@ -212,13 +210,13 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff /// Gets the resolution of the image in x- direction. /// /// The density of the image in x- direction. - public double? HorizontalResolution => this.GetResolution(ExifTag.XResolution); + public double? HorizontalResolution => this.ExifProfile.GetValue(ExifTag.XResolution)?.Value.ToDouble(); /// /// Gets the resolution of the image in y- direction. /// /// The density of the image in y- direction. - public double? VerticalResolution => this.GetResolution(ExifTag.YResolution); + public double? VerticalResolution => this.ExifProfile.GetValue(ExifTag.YResolution)?.Value.ToDouble(); /// /// Gets how the components of each pixel are stored. @@ -228,7 +226,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff /// /// Gets the unit of measurement for XResolution and YResolution. /// - public PixelResolutionUnit ResolutionUnit => this.GetResolutionUnit(); + public PixelResolutionUnit ResolutionUnit => UnitConverter.ExifProfileToResolutionUnit(this.ExifProfile); /// /// Gets a color map for palette color images. @@ -252,28 +250,16 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff public TiffSampleFormat[] SampleFormat => this.ExifProfile.GetValue(ExifTag.SampleFormat)?.Value?.Select(a => (TiffSampleFormat)a).ToArray(); /// - /// Clears the metadata. + /// Clears the pure metadata. /// public void ClearMetadata() { var tags = new List(); foreach (IExifValue entry in this.ExifProfile.Values) { - switch ((ExifTagValue)(ushort)entry.Tag) + if (IsFormatTag((ExifTagValue)(ushort)entry.Tag)) { - case ExifTagValue.ImageWidth: - case ExifTagValue.ImageLength: - case ExifTagValue.ResolutionUnit: - case ExifTagValue.XResolution: - case ExifTagValue.YResolution: - //// image format tags - case ExifTagValue.Predictor: - case ExifTagValue.PlanarConfiguration: - case ExifTagValue.PhotometricInterpretation: - case ExifTagValue.BitsPerSample: - case ExifTagValue.ColorMap: - tags.Add(entry); - break; + tags.Add(entry); } } @@ -282,5 +268,25 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff /// public IDeepCloneable DeepClone() => new TiffFrameMetadata() { ExifProfile = this.ExifProfile.DeepClone() }; + + private static bool IsFormatTag(ExifTagValue tag) + { + switch (tag) + { + case ExifTagValue.ImageWidth: + case ExifTagValue.ImageLength: + case ExifTagValue.ResolutionUnit: + case ExifTagValue.XResolution: + case ExifTagValue.YResolution: + case ExifTagValue.Predictor: + case ExifTagValue.PlanarConfiguration: + case ExifTagValue.PhotometricInterpretation: + case ExifTagValue.BitsPerSample: + case ExifTagValue.ColorMap: + return true; + } + + return false; + } } } diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadataResolutionExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadataResolutionExtensions.cs deleted file mode 100644 index 86a128ca3a..0000000000 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadataResolutionExtensions.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.Common.Helpers; -using SixLabors.ImageSharp.Metadata; -using SixLabors.ImageSharp.Metadata.Profiles.Exif; - -namespace SixLabors.ImageSharp.Formats.Experimental.Tiff -{ - internal static class TiffFrameMetadataResolutionExtensions - { - public static void SetResolutions(this TiffFrameMetadata meta, PixelResolutionUnit unit, double horizontal, double vertical) - { - switch (unit) - { - case PixelResolutionUnit.AspectRatio: - case PixelResolutionUnit.PixelsPerInch: - case PixelResolutionUnit.PixelsPerCentimeter: - break; - case PixelResolutionUnit.PixelsPerMeter: - { - unit = PixelResolutionUnit.PixelsPerCentimeter; - horizontal = UnitConverter.MeterToCm(horizontal); - vertical = UnitConverter.MeterToCm(vertical); - } - - break; - default: - unit = PixelResolutionUnit.PixelsPerInch; - break; - } - - meta.ExifProfile.SetValue(ExifTag.ResolutionUnit, (ushort)(unit + 1)); - meta.SetResolution(ExifTag.XResolution, horizontal); - meta.SetResolution(ExifTag.YResolution, vertical); - } - - public static PixelResolutionUnit GetResolutionUnit(this TiffFrameMetadata meta) - { - ushort res = meta.ExifProfile.GetValue(ExifTag.ResolutionUnit)?.Value ?? TiffFrameMetadata.DefaultResolutionUnit; - - return (PixelResolutionUnit)(res - 1); - } - - public static double? GetResolution(this TiffFrameMetadata meta, ExifTag tag) - { - IExifValue resolution = meta.ExifProfile.GetValue(tag); - if (resolution == null) - { - return null; - } - - double res = resolution.Value.ToDouble(); - switch (meta.ResolutionUnit) - { - case PixelResolutionUnit.AspectRatio: - return 0; - case PixelResolutionUnit.PixelsPerCentimeter: - return UnitConverter.CmToInch(res); - case PixelResolutionUnit.PixelsPerMeter: - return UnitConverter.MeterToInch(res); - case PixelResolutionUnit.PixelsPerInch: - default: - // DefaultResolutionUnit is Inch - return res; - } - } - - private static void SetResolution(this TiffFrameMetadata meta, ExifTag tag, double? value) - { - if (value == null) - { - meta.ExifProfile.RemoveValue(tag); - return; - } - - double res = value.Value; - switch (meta.ResolutionUnit) - { - case PixelResolutionUnit.AspectRatio: - res = 0; - break; - case PixelResolutionUnit.PixelsPerCentimeter: - res = UnitConverter.InchToCm(res); - break; - case PixelResolutionUnit.PixelsPerMeter: - res = UnitConverter.InchToMeter(res); - break; - case PixelResolutionUnit.PixelsPerInch: - default: - break; - } - - meta.ExifProfile.SetValue(tag, new Rational(res)); - } - } -} diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter.cs index 70c91fa892..32adf95c0e 100644 --- a/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter.cs +++ b/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter.cs @@ -87,17 +87,17 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Writers /// The strip byte counts. private void AddStripTags(int rowsPerStrip, uint[] stripOffsets, uint[] stripByteCounts) { - this.EntriesCollector.Add(new ExifLong(ExifTagValue.RowsPerStrip) + this.EntriesCollector.AddOrReplace(new ExifLong(ExifTagValue.RowsPerStrip) { Value = (uint)rowsPerStrip }); - this.EntriesCollector.Add(new ExifLongArray(ExifTagValue.StripOffsets) + this.EntriesCollector.AddOrReplace(new ExifLongArray(ExifTagValue.StripOffsets) { Value = stripOffsets }); - this.EntriesCollector.Add(new ExifLongArray(ExifTagValue.StripByteCounts) + this.EntriesCollector.AddOrReplace(new ExifLongArray(ExifTagValue.StripByteCounts) { Value = stripByteCounts }); diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter.cs index b094c22fc0..00f4687207 100644 --- a/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter.cs +++ b/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter.cs @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Writers Value = palette }; - this.EntriesCollector.Add(colorMap); + this.EntriesCollector.AddOrReplace(colorMap); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index ceb40d7452..ae26bf6263 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -93,7 +93,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(expectedBitsPerPixel, meta.BitsPerPixel); } - [Theory] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffEncoderCompression.CcittGroup3Fax, TiffCompression.CcittGroup3Fax)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffEncoderCompression.ModifiedHuffman, TiffCompression.Ccitt1D)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index dd5fc1a280..54b46cd3ef 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -198,10 +198,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(1, frame.SamplesPerPixel); Assert.Equal(32u, frame.RowsPerStrip); Assert.Equal(new Number[] { 297u }, frame.StripByteCounts, new NumberComparer()); + Assert.Equal(PixelResolutionUnit.PixelsPerInch, frame.ResolutionUnit); Assert.Equal(10, frame.HorizontalResolution); Assert.Equal(10, frame.VerticalResolution); Assert.Equal(TiffPlanarConfiguration.Chunky, frame.PlanarConfiguration); - Assert.Equal(PixelResolutionUnit.PixelsPerInch, frame.ResolutionUnit); Assert.Equal("IrfanView", frame.ExifProfile.GetValue(ExifTag.Software).Value); Assert.Null(frame.ExifProfile.GetValue(ExifTag.DateTime)?.Value); Assert.Equal("This is author1;Author2", frame.ExifProfile.GetValue(ExifTag.Artist).Value);