diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
index 7f97303ed..9a495ad31 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
@@ -57,9 +56,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
+ if (coreMetadata.ExifProfile == null)
+ {
+ coreMetadata.ExifProfile = frame?.ExifProfile.DeepClone();
+ }
+
if (coreMetadata.IptcProfile == null)
{
- if (TryGetIptc(frame.ExifProfile.Values, out var iptcBytes))
+ if (TryGetIptc(frame.ExifProfile.Values, out byte[] iptcBytes))
{
coreMetadata.IptcProfile = new IptcProfile(iptcBytes);
}
@@ -95,7 +99,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
// Some Encoders write the data type of IPTC as long.
if (iptc.DataType == ExifDataType.Long)
{
- var iptcValues = (uint[])iptc.GetValue();
+ uint[] iptcValues = (uint[])iptc.GetValue();
iptcBytes = new byte[iptcValues.Length * 4];
Buffer.BlockCopy(iptcValues, 0, iptcBytes, 0, iptcValues.Length * 4);
if (iptcBytes[0] == 0x1c)
diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
index c0ad474b2..4916a9804 100644
--- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
@@ -66,12 +66,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.collector.Add(width);
this.collector.Add(height);
- this.collector.Add(software);
this.ProcessResolution(image.Metadata, frameMetadata);
-
this.ProcessProfiles(image.Metadata, frameMetadata);
this.ProcessMetadata(frameMetadata);
+
+ if (!this.collector.Entries.Exists(t => t.Tag == ExifTag.Software))
+ {
+ this.collector.Add(software);
+ }
}
private static bool IsPureMetadata(ExifTag tag)
@@ -174,9 +177,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff
private void ProcessProfiles(ImageMetadata imageMetadata, TiffFrameMetadata tiffFrameMetadata)
{
- if (imageMetadata.ExifProfile != null)
+ if (imageMetadata.ExifProfile != null && imageMetadata.ExifProfile.Parts != ExifParts.None)
{
- // todo: implement processing exif profile
+ imageMetadata.SyncProfiles();
+ foreach (IExifValue entry in imageMetadata.ExifProfile.Values)
+ {
+ if (!this.collector.Entries.Exists(t => t.Tag == entry.Tag) && entry.GetValue() != null)
+ {
+ ExifParts entryPart = ExifTags.GetPart(entry.Tag);
+ if (entryPart != ExifParts.None && imageMetadata.ExifProfile.Parts.HasFlag(entryPart))
+ {
+ this.collector.AddOrReplace(entry.DeepClone());
+ }
+ }
+ }
}
else
{
diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs
index dc12f3819..0a9c879ce 100644
--- a/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs
+++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs
@@ -24,12 +24,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
///
/// ExifTags
///
- ExifTags = 4,
+ ExifTags = 2,
///
/// GPSTags
///
- GpsTags = 8,
+ GpsTags = 4,
///
/// All
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index ae1de1734..bffb60302 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -42,9 +42,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder));
[Theory]
- [InlineData(TestImages.Tiff.RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)]
- [InlineData(TestImages.Tiff.SmallRgbDeflate, 24, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)]
- [InlineData(TestImages.Tiff.Calliphora_GrayscaleUncompressed, 8, 804, 1198, 96, 96, PixelResolutionUnit.PixelsPerInch)]
+ [InlineData(RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)]
+ [InlineData(SmallRgbDeflate, 24, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)]
+ [InlineData(Calliphora_GrayscaleUncompressed, 8, 804, 1198, 96, 96, PixelResolutionUnit.PixelsPerInch)]
public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit)
{
var testFile = TestFile.Create(imagePath);
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
index 5763b0e8a..f501299fd 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
@@ -292,8 +292,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Equal(frameMeta.HorizontalResolution, frameMetaOut.HorizontalResolution);
Assert.Equal(frameMeta.VerticalResolution, frameMetaOut.VerticalResolution);
- Assert.Equal("ImageSharp", frameMetaOut.ExifProfile.GetValue(ExifTag.Software).Value);
-
if (preserveMetadata)
{
Assert.Equal(tiffMeta.XmpProfile, tiffMetaOut.XmpProfile);
@@ -311,6 +309,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
Assert.Null(tiffMetaOut.XmpProfile);
+ Assert.Equal("ImageSharp", frameMetaOut.ExifProfile.GetValue(ExifTag.Software).Value);
Assert.Null(frameMeta.ExifProfile.GetValue(ExifTag.Software)?.Value);
Assert.Null(frameMeta.ExifProfile.GetValue(ExifTag.ImageDescription)?.Value);
Assert.Null(frameMeta.ExifProfile.GetValue(ExifTag.Make)?.Value);
diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs
index 10f6ff9bf..1f4bbaea9 100644
--- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs
+++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs
@@ -6,7 +6,7 @@ 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;
@@ -28,7 +28,12 @@ namespace SixLabors.ImageSharp.Tests
///
/// Writes a png file.
///
- Png
+ Png,
+
+ ///
+ /// Writes a tiff file.
+ ///
+ Tiff,
}
private static readonly Dictionary TestProfileValues = new Dictionary
@@ -69,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void ConstructorEmpty()
{
- new ExifProfile((byte[])null);
+ new ExifProfile(null);
new ExifProfile(new byte[] { });
}
@@ -92,6 +97,7 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
+ [InlineData(TestImageWriteFormat.Tiff)]
public void WriteFraction(TestImageWriteFormat imageFormat)
{
using (var memStream = new MemoryStream())
@@ -135,6 +141,7 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
+ [InlineData(TestImageWriteFormat.Tiff)]
public void ReadWriteInfinity(TestImageWriteFormat imageFormat)
{
Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();
@@ -161,9 +168,17 @@ namespace SixLabors.ImageSharp.Tests
}
[Theory]
- [InlineData(TestImageWriteFormat.Jpeg)]
- [InlineData(TestImageWriteFormat.Png)]
- public void SetValue(TestImageWriteFormat imageFormat)
+ /* The original exif profile has 19 values, the written profile should be 3 less.
+ 1 x due to setting of null "ReferenceBlackWhite" value.
+ 2 x due to use of non-standard padding tag 0xEA1C listed in EXIF Tool. We can read those values but adhere
+ strictly to the 2.3.1 specification when writing. (TODO: Support 2.3.2)
+ https://exiftool.org/TagNames/EXIF.html */
+ [InlineData(TestImageWriteFormat.Jpeg, 16)]
+ [InlineData(TestImageWriteFormat.Png, 16)]
+ /* Note: The tiff format has 24 expected profile values, because some tiff specific exif
+ values will be written in addition to the original profile. */
+ [InlineData(TestImageWriteFormat.Tiff, 24)]
+ public void SetValue(TestImageWriteFormat imageFormat, int expectedProfileValueCount)
{
Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();
image.Metadata.ExifProfile.SetValue(ExifTag.Software, "ImageSharp");
@@ -206,18 +221,12 @@ namespace SixLabors.ImageSharp.Tests
// todo: duplicate tags
Assert.Equal(2, image.Metadata.ExifProfile.Values.Count(v => (ushort)v.Tag == 59932));
- int profileCount = image.Metadata.ExifProfile.Values.Count;
image = WriteAndRead(image, imageFormat);
Assert.NotNull(image.Metadata.ExifProfile);
Assert.Equal(0, image.Metadata.ExifProfile.Values.Count(v => (ushort)v.Tag == 59932));
- // Should be 3 less.
- // 1 x due to setting of null "ReferenceBlackWhite" value.
- // 2 x due to use of non-standard padding tag 0xEA1C listed in EXIF Tool. We can read those values but adhere
- // strictly to the 2.3.1 specification when writing. (TODO: Support 2.3.2)
- // https://exiftool.org/TagNames/EXIF.html
- Assert.Equal(profileCount - 3, image.Metadata.ExifProfile.Values.Count);
+ Assert.Equal(expectedProfileValueCount, image.Metadata.ExifProfile.Values.Count);
software = image.Metadata.ExifProfile.GetValue(ExifTag.Software);
Assert.Equal("15", software.Value);
@@ -233,20 +242,42 @@ namespace SixLabors.ImageSharp.Tests
latitude = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude);
Assert.Equal(expectedLatitude, latitude.Value);
+ }
+ [Theory]
+ [InlineData(TestImageWriteFormat.Jpeg)]
+ [InlineData(TestImageWriteFormat.Png)]
+ public void WriteOnlyExifTags_Works(TestImageWriteFormat imageFormat)
+ {
+ // Arrange
+ Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();
image.Metadata.ExifProfile.Parts = ExifParts.ExifTags;
+ // Act
image = WriteAndRead(image, imageFormat);
+ // Assert
Assert.NotNull(image.Metadata.ExifProfile);
- Assert.Equal(8, image.Metadata.ExifProfile.Values.Count);
+ Assert.Equal(7, image.Metadata.ExifProfile.Values.Count);
+ foreach (IExifValue exifProfileValue in image.Metadata.ExifProfile.Values)
+ {
+ Assert.True(ExifTags.GetPart(exifProfileValue.Tag) == ExifParts.ExifTags);
+ }
+ }
+
+ [Fact]
+ public void RemoveEntry_Works()
+ {
+ // Arrange
+ Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();
+ int profileCount = image.Metadata.ExifProfile.Values.Count;
+ // Assert
Assert.NotNull(image.Metadata.ExifProfile.GetValue(ExifTag.ColorSpace));
Assert.True(image.Metadata.ExifProfile.RemoveValue(ExifTag.ColorSpace));
Assert.False(image.Metadata.ExifProfile.RemoveValue(ExifTag.ColorSpace));
Assert.Null(image.Metadata.ExifProfile.GetValue(ExifTag.ColorSpace));
-
- Assert.Equal(7, image.Metadata.ExifProfile.Values.Count);
+ Assert.Equal(profileCount - 1, image.Metadata.ExifProfile.Values.Count);
}
[Fact]
@@ -382,6 +413,7 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
+ [InlineData(TestImageWriteFormat.Tiff)]
public void WritingImagePreservesExifProfile(TestImageWriteFormat imageFormat)
{
// Arrange
@@ -456,8 +488,10 @@ namespace SixLabors.ImageSharp.Tests
return WriteAndReadJpeg(image);
case TestImageWriteFormat.Png:
return WriteAndReadPng(image);
+ case TestImageWriteFormat.Tiff:
+ return WriteAndReadTiff(image);
default:
- throw new ArgumentException("Unexpected test image format, only Jpeg and Png are allowed");
+ throw new ArgumentException("Unexpected test image format, only Jpeg, Png and Tiff are allowed");
}
}
@@ -485,6 +519,18 @@ namespace SixLabors.ImageSharp.Tests
}
}
+ private static Image WriteAndReadTiff(Image image)
+ {
+ using (var memStream = new MemoryStream())
+ {
+ image.SaveAsTiff(memStream, new TiffEncoder());
+ image.Dispose();
+
+ memStream.Position = 0;
+ return Image.Load(memStream, new TiffDecoder());
+ }
+ }
+
private static void TestProfile(ExifProfile profile)
{
Assert.NotNull(profile);