diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs
index b86f6dff2..cd3c8eb93 100644
--- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs
+++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs
@@ -174,6 +174,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
public void SetValue(IptcTag tag, Encoding encoding, string value, bool strict = true)
{
Guard.NotNull(encoding, nameof(encoding));
+ Guard.NotNull(value, nameof(value));
if (!tag.IsRepeatable())
{
@@ -192,6 +193,27 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
this.values.Add(new IptcValue(tag, encoding, value, strict));
}
+ ///
+ /// Makes sure the datetime is formatted according to the iptc specification.
+ /// A date will be formatted as CCYYMMDD.
+ /// A time value will be formatted as HHMMSS±HHMM.
+ ///
+ /// The tag of the iptc value.
+ /// The datetime.
+ public void SetDateTimeValue(IptcTag tag, DateTime dateTime)
+ {
+ if (!tag.IsDate() && !tag.IsTime())
+ {
+ throw new ArgumentException("iptc tag is not a time or date type");
+ }
+
+ var formattedDate = tag.IsDate()
+ ? dateTime.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture)
+ : dateTime.ToString("HHmmsszzzz", System.Globalization.CultureInfo.InvariantCulture).Replace(":", string.Empty);
+
+ this.SetValue(tag, Encoding.UTF8, formattedDate);
+ }
+
///
/// Sets the value of the specified tag.
///
diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs
index 135c41e51..62f74386e 100644
--- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs
+++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs
@@ -86,30 +86,28 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
///
/// Release date. Format should be CCYYMMDD,
- /// e.g. "19890317" indicates data for release on 17 March 1989.
+ /// e.g. "19890317" for the 17 March 1989.
/// Not repeatable, max length is 8.
///
ReleaseDate = 30,
///
/// Release time. Format should be HHMMSS±HHMM,
- /// e.g. "090000-0500" indicates object for use after 0900 in
- /// New York (five hours behind UTC)
+ /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC).
/// Not repeatable, max length is 11.
///
ReleaseTime = 35,
///
/// Expiration date. Format should be CCYYMMDD,
- /// e.g. "19890317" indicates data for release on 17 March 1989.
+ /// e.g. "19890317" for the 17 March 1989.
/// Not repeatable, max length is 8.
///
ExpirationDate = 37,
///
/// Expiration time. Format should be HHMMSS±HHMM,
- /// e.g. "090000-0500" indicates object for use after 0900 in
- /// New York (five hours behind UTC)
+ /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC).
/// Not repeatable, max length is 11.
///
ExpirationTime = 38,
@@ -131,7 +129,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
///
/// Reference date. Format should be CCYYMMDD,
- /// e.g. "19890317" indicates data for release on 17 March 1989.
+ /// e.g. "19890317" for the 17 March 1989.
/// Not repeatable, max length is 8.
///
ReferenceDate = 47,
@@ -143,30 +141,28 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
///
/// Created date. Format should be CCYYMMDD,
- /// e.g. "19890317" indicates data for release on 17 March 1989.
+ /// e.g. "19890317" for the 17 March 1989.
/// Not repeatable, max length is 8.
///
CreatedDate = 55,
///
/// Created time. Format should be HHMMSS±HHMM,
- /// e.g. "090000-0500" indicates object for use after 0900 in
- /// New York (five hours behind UTC)
+ /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC).
/// Not repeatable, max length is 11.
///
CreatedTime = 60,
///
/// Digital creation date. Format should be CCYYMMDD,
- /// e.g. "19890317" indicates data for release on 17 March 1989.
+ /// e.g. "19890317" for the 17 March 1989.
/// Not repeatable, max length is 8.
///
DigitalCreationDate = 62,
///
/// Digital creation time. Format should be HHMMSS±HHMM,
- /// e.g. "090000-0500" indicates object for use after 0900 in
- /// New York (five hours behind UTC)
+ /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC).
/// Not repeatable, max length is 11.
///
DigitalCreationTime = 63,
diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs
index 88d463767..6b39769a7 100644
--- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs
+++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
@@ -117,5 +117,46 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
return true;
}
}
+
+ ///
+ /// Determines if the tag is a datetime tag which needs to be formatted as CCYYMMDD.
+ ///
+ /// The tag to check.
+ /// True, if its a datetime tag.
+ public static bool IsDate(this IptcTag tag)
+ {
+ switch (tag)
+ {
+ case IptcTag.CreatedDate:
+ case IptcTag.DigitalCreationDate:
+ case IptcTag.ExpirationDate:
+ case IptcTag.ReferenceDate:
+ case IptcTag.ReleaseDate:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ ///
+ /// Determines if the tag is a time tag which need to be formatted as HHMMSS±HHMM.
+ ///
+ /// The tag to check.
+ /// True, if its a time tag.
+ public static bool IsTime(this IptcTag tag)
+ {
+ switch (tag)
+ {
+ case IptcTag.CreatedTime:
+ case IptcTag.DigitalCreationTime:
+ case IptcTag.ExpirationTime:
+ case IptcTag.ReleaseTime:
+ return true;
+
+ default:
+ return false;
+ }
+ }
}
}
diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs
index 2c2cf5995..8e804353c 100644
--- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs
+++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs
@@ -103,6 +103,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
{
var cappedValue = value.Substring(0, maxLength);
valueBytes = this.encoding.GetBytes(cappedValue);
+
+ // It is still possible that the bytes of the string exceed the limit.
+ if (valueBytes.Length > maxLength)
+ {
+ throw new ArgumentException($"The iptc value exceeds the limit of {maxLength} bytes for the tag {this.Tag}");
+ }
}
else
{
diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs
index 321c7fe5c..9d5db439a 100644
--- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs
+++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs
@@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC
{
private static JpegDecoder JpegDecoder => new JpegDecoder() { IgnoreMetadata = false };
- public static IEnumerable