diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md
index d668ed449..c2527b008 100644
--- a/src/ImageSharp/Formats/Tiff/README.md
+++ b/src/ImageSharp/Formats/Tiff/README.md
@@ -79,9 +79,9 @@
|CellWidth | | | |
|CellLength | | | |
|FillOrder | | | |
-|ImageDescription | | | |
-|Make | | | |
-|Model | | | |
+|ImageDescription | | Y | |
+|Make | | Y | |
+|Model | | Y | |
|StripOffsets | | Y | |
|Orientation | | | |
|SamplesPerPixel | | | Currently ignored, as can be inferred from count of BitsPerSample |
@@ -97,13 +97,13 @@
|GrayResponseUnit | | | |
|GrayResponseCurve | | | |
|ResolutionUnit | | Y | |
-|Software | | | |
-|DateTime | | | |
-|Artist | | | |
-|HostComputer | | | |
+|Software | | Y | |
+|DateTime | | Y | |
+|Artist | | Y | |
+|HostComputer | | Y | |
|ColorMap | | Y | |
|ExtraSamples | | | |
-|Copyright | | | |
+|Copyright | | Y | |
### Extension TIFF Tags
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index 806d56334..d2446bb76 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -224,6 +224,12 @@ namespace ImageSharp.Formats
return image;
}
+ ///
+ /// Reads the image metadata from a specified IFD.
+ ///
+ /// The pixel format.
+ /// The IFD to read the image from.
+ /// The image to write the metadata to.
public void ReadMetadata(TiffIfd ifd, Image image)
where TPixel : struct, IPixel
{
@@ -245,6 +251,49 @@ namespace ImageSharp.Formats
image.MetaData.VerticalResolution = yResolution.ToDouble() * resolutionUnitFactor;
}
}
+
+ if (!this.options.IgnoreMetadata)
+ {
+ if (ifd.TryGetIfdEntry(TiffTags.Artist, out TiffIfdEntry artistEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.Artist, this.ReadString(ref artistEntry)));
+ }
+
+ if (ifd.TryGetIfdEntry(TiffTags.Copyright, out TiffIfdEntry copyrightEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.Copyright, this.ReadString(ref copyrightEntry)));
+ }
+
+ if (ifd.TryGetIfdEntry(TiffTags.DateTime, out TiffIfdEntry dateTimeEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.DateTime, this.ReadString(ref dateTimeEntry)));
+ }
+
+ if (ifd.TryGetIfdEntry(TiffTags.HostComputer, out TiffIfdEntry hostComputerEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.HostComputer, this.ReadString(ref hostComputerEntry)));
+ }
+
+ if (ifd.TryGetIfdEntry(TiffTags.ImageDescription, out TiffIfdEntry imageDescriptionEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.ImageDescription, this.ReadString(ref imageDescriptionEntry)));
+ }
+
+ if (ifd.TryGetIfdEntry(TiffTags.Make, out TiffIfdEntry makeEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.Make, this.ReadString(ref makeEntry)));
+ }
+
+ if (ifd.TryGetIfdEntry(TiffTags.Model, out TiffIfdEntry modelEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.Model, this.ReadString(ref modelEntry)));
+ }
+
+ if (ifd.TryGetIfdEntry(TiffTags.Software, out TiffIfdEntry softwareEntry))
+ {
+ image.MetaData.Properties.Add(new ImageProperty(TiffMetadataNames.Software, this.ReadString(ref softwareEntry)));
+ }
+ }
}
///
diff --git a/src/ImageSharp/Formats/Tiff/TiffMetadataNames.cs b/src/ImageSharp/Formats/Tiff/TiffMetadataNames.cs
new file mode 100644
index 000000000..4591986b0
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/TiffMetadataNames.cs
@@ -0,0 +1,53 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ ///
+ /// Defines constants for each of the supported TIFF metadata types.
+ ///
+ public static class TiffMetadataNames
+ {
+ ///
+ /// Person who created the image.
+ ///
+ public const string Artist = "Artist";
+
+ ///
+ /// Copyright notice.
+ ///
+ public const string Copyright = "Copyright";
+
+ ///
+ /// Date and time of image creation.
+ ///
+ public const string DateTime = "DateTime";
+
+ ///
+ /// The computer and/or operating system in use at the time of image creation.
+ ///
+ public const string HostComputer = "HostComputer";
+
+ ///
+ /// A string that describes the subject of the image.
+ ///
+ public const string ImageDescription = "ImageDescription";
+
+ ///
+ /// The scanner/camera manufacturer.
+ ///
+ public const string Make = "Make";
+
+ ///
+ /// The scanner/camera model name or number.
+ ///
+ public const string Model = "Model";
+
+ ///
+ /// Name and version number of the software package(s) used to create the image.
+ ///
+ public const string Software = "Software";
+ }
+}
diff --git a/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderMetadataTests.cs b/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderMetadataTests.cs
index b3dd30f5e..e418d0d67 100644
--- a/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderMetadataTests.cs
+++ b/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderMetadataTests.cs
@@ -7,6 +7,7 @@ namespace ImageSharp.Tests
{
using System;
using System.IO;
+ using System.Linq;
using Xunit;
using ImageSharp.Formats;
@@ -14,8 +15,22 @@ namespace ImageSharp.Tests
public class TiffDecoderMetadataTests
{
- public static object[][] IsLittleEndianValues = new[] { new object[] { false },
- new object[] { true } };
+ public static object[][] BaselineMetadataValues = new[] { new object[] { false, TiffTags.Artist, TiffMetadataNames.Artist, "My Artist Name" },
+ new object[] { false, TiffTags.Copyright, TiffMetadataNames.Copyright, "My Copyright Statement" },
+ new object[] { false, TiffTags.DateTime, TiffMetadataNames.DateTime, "My DateTime Value" },
+ new object[] { false, TiffTags.HostComputer, TiffMetadataNames.HostComputer, "My Host Computer Name" },
+ new object[] { false, TiffTags.ImageDescription, TiffMetadataNames.ImageDescription, "My Image Description" },
+ new object[] { false, TiffTags.Make, TiffMetadataNames.Make, "My Camera Make" },
+ new object[] { false, TiffTags.Model, TiffMetadataNames.Model, "My Camera Model" },
+ new object[] { false, TiffTags.Software, TiffMetadataNames.Software, "My Imaging Software" },
+ new object[] { true, TiffTags.Artist, TiffMetadataNames.Artist, "My Artist Name" },
+ new object[] { true, TiffTags.Copyright, TiffMetadataNames.Copyright, "My Copyright Statement" },
+ new object[] { true, TiffTags.DateTime, TiffMetadataNames.DateTime, "My DateTime Value" },
+ new object[] { true, TiffTags.HostComputer, TiffMetadataNames.HostComputer, "My Host Computer Name" },
+ new object[] { true, TiffTags.ImageDescription, TiffMetadataNames.ImageDescription, "My Image Description" },
+ new object[] { true, TiffTags.Make, TiffMetadataNames.Make, "My Camera Make" },
+ new object[] { true, TiffTags.Model, TiffMetadataNames.Model, "My Camera Model" },
+ new object[] { true, TiffTags.Software, TiffMetadataNames.Software, "My Imaging Software" }};
[Theory]
[InlineData(false, 150u, 1u, 200u, 1u, 2u /* Inch */, 150.0, 200.0)]
@@ -34,7 +49,7 @@ namespace ImageSharp.Tests
[InlineData(true, null, null, null, null, null /* Inch */, 96.0, 96.0)]
[InlineData(true, 150u, 1u, null, null, 2u /* Inch */, 150.0, 96.0)]
[InlineData(true, null, null, 200u, 1u, 2u /* Inch */, 96.0, 200.0)]
- public void DecodeImage_SetsImageResolution(bool isLittleEndian, uint? xResolutionNumerator, uint? xResolutionDenominator,
+ public void ReadMetadata_SetsImageResolution(bool isLittleEndian, uint? xResolutionNumerator, uint? xResolutionDenominator,
uint? yResolutionNumerator, uint? yResolutionDenominator, uint? resolutionUnit,
double expectedHorizonalResolution, double expectedVerticalResolution)
{
@@ -66,5 +81,58 @@ namespace ImageSharp.Tests
Assert.Equal(expectedHorizonalResolution, image.MetaData.HorizontalResolution, 10);
Assert.Equal(expectedVerticalResolution, image.MetaData.VerticalResolution, 10);
}
+
+ [Theory]
+ [MemberData(nameof(BaselineMetadataValues))]
+ public void ReadMetadata_SetsAsciiMetadata(bool isLittleEndian, ushort tag, string metadataName, string metadataValue)
+ {
+ Stream stream = new TiffGenIfd()
+ {
+ Entries =
+ {
+ TiffGenEntry.Integer(TiffTags.ImageWidth, TiffType.Long, 150),
+ TiffGenEntry.Integer(TiffTags.ImageLength, TiffType.Long, 210),
+ TiffGenEntry.Ascii(tag, metadataValue),
+ TiffGenEntry.Integer(TiffTags.Orientation, TiffType.Short, 1)
+ }
+ }
+ .ToStream(isLittleEndian);
+
+ TiffDecoderCore decoder = new TiffDecoderCore(stream, isLittleEndian, null, null);
+ TiffIfd ifd = decoder.ReadIfd(0);
+ Image image = new Image(null, 20, 20);
+
+ decoder.ReadMetadata(ifd, image);
+ var metadata = image.MetaData.Properties.FirstOrDefault(m => m.Name == metadataName)?.Value;
+
+ Assert.Equal(metadataValue, metadata);
+ }
+
+ [Theory]
+ [MemberData(nameof(BaselineMetadataValues))]
+ public void ReadMetadata_DoesntSetMetadataIfIgnoring(bool isLittleEndian, ushort tag, string metadataName, string metadataValue)
+ {
+ Stream stream = new TiffGenIfd()
+ {
+ Entries =
+ {
+ TiffGenEntry.Integer(TiffTags.ImageWidth, TiffType.Long, 150),
+ TiffGenEntry.Integer(TiffTags.ImageLength, TiffType.Long, 210),
+ TiffGenEntry.Ascii(tag, metadataValue),
+ TiffGenEntry.Integer(TiffTags.Orientation, TiffType.Short, 1)
+ }
+ }
+ .ToStream(isLittleEndian);
+
+ DecoderOptions options = new DecoderOptions() { IgnoreMetadata = true };
+ TiffDecoderCore decoder = new TiffDecoderCore(stream, isLittleEndian, options, null);
+ TiffIfd ifd = decoder.ReadIfd(0);
+ Image image = new Image(null, 20, 20);
+
+ decoder.ReadMetadata(ifd, image);
+ var metadata = image.MetaData.Properties.FirstOrDefault(m => m.Name == metadataName)?.Value;
+
+ Assert.Equal(null, metadata);
+ }
}
}
\ No newline at end of file