diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs
index 57704949c..119c6f2b5 100644
--- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs
+++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs
@@ -34,6 +34,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
public IptcProfile(byte[] data)
{
this.Data = data;
+ this.Initialize();
}
private IptcProfile(IptcProfile other)
@@ -99,7 +100,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
/// Removes the value with the specified tag.
///
/// The tag of the iptc value.
- /// True when the value was fount and removed.
+ /// True when the value was found and removed.
public bool RemoveValue(IptcTag tag)
{
this.Initialize();
@@ -140,13 +141,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
{
Guard.NotNull(encoding, nameof(encoding));
- foreach (IptcValue iptcValue in this.Values)
+ if (!this.IsRepeatable(tag))
{
- if (iptcValue.Tag == tag)
+ foreach (IptcValue iptcValue in this.Values)
{
- iptcValue.Encoding = encoding;
- iptcValue.Value = value;
- return;
+ if (iptcValue.Tag == tag)
+ {
+ iptcValue.Encoding = encoding;
+ iptcValue.Value = value;
+ return;
+ }
}
}
@@ -228,5 +232,50 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
i += count;
}
}
+
+ private bool IsRepeatable(IptcTag tag)
+ {
+ switch (tag)
+ {
+ case IptcTag.RecordVersion:
+ case IptcTag.ObjectType:
+ case IptcTag.Name:
+ case IptcTag.EditStatus:
+ case IptcTag.EditorialUpdate:
+ case IptcTag.Urgency:
+ case IptcTag.Category:
+ case IptcTag.FixtureIdentifier:
+ case IptcTag.ReleaseDate:
+ case IptcTag.ReleaseTime:
+ case IptcTag.ExpirationDate:
+ case IptcTag.ExpirationTime:
+ case IptcTag.SpecialInstructions:
+ case IptcTag.ActionAdvised:
+ case IptcTag.CreatedDate:
+ case IptcTag.CreatedTime:
+ case IptcTag.DigitalCreationDate:
+ case IptcTag.DigitalCreationTime:
+ case IptcTag.OriginatingProgram:
+ case IptcTag.ProgramVersion:
+ case IptcTag.ObjectCycle:
+ case IptcTag.City:
+ case IptcTag.SubLocation:
+ case IptcTag.ProvinceState:
+ case IptcTag.CountryCode:
+ case IptcTag.Country:
+ case IptcTag.OriginalTransmissionReference:
+ case IptcTag.Headline:
+ case IptcTag.Credit:
+ case IptcTag.Source:
+ case IptcTag.CopyrightNotice:
+ case IptcTag.Caption:
+ case IptcTag.ImageType:
+ case IptcTag.ImageOrientation:
+ return false;
+
+ default:
+ return true;
+ }
+ }
}
}
diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs
index 3e6da0e09..cd0b62072 100644
--- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs
+++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs
@@ -9,242 +9,247 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
public enum IptcTag
{
///
- /// Unknown
+ /// Unknown.
///
Unknown = -1,
///
- /// Record version
+ /// Record version, not repeatable.
///
RecordVersion = 0,
///
- /// Object type
+ /// Object type, not repeatable.
///
ObjectType = 3,
///
- /// Object attribute
+ /// Object attribute.
///
ObjectAttribute = 4,
///
- /// Title
+ /// Object Name, not repeatable.
///
- Title = 5,
+ Name = 5,
///
- /// Edit status
+ /// Edit status, not repeatable.
///
EditStatus = 7,
///
- /// Editorial update
+ /// Editorial update, not repeatable.
///
EditorialUpdate = 8,
///
- /// Priority
+ /// Urgency, not repeatable.
///
- Priority = 10,
+ Urgency = 10,
///
- /// Category
+ /// Subject Reference.
+ ///
+ SubjectReference = 12,
+
+ ///
+ /// Category, not repeatable.
///
Category = 15,
///
- /// Supplemental categories
+ /// Supplemental categories.
///
SupplementalCategories = 20,
///
- /// Fixture identifier
+ /// Fixture identifier, not repeatable.
///
FixtureIdentifier = 22,
///
- /// Keyword
+ /// Keywords.
///
- Keyword = 25,
+ Keywords = 25,
///
- /// Location code
+ /// Location code.
///
LocationCode = 26,
///
- /// Location name
+ /// Location name.
///
LocationName = 27,
///
- /// Release date
+ /// Release date, not repeatable.
///
ReleaseDate = 30,
///
- /// Release time
+ /// Release time, not repeatable.
///
ReleaseTime = 35,
///
- /// Expiration date
+ /// Expiration date, not repeatable.
///
ExpirationDate = 37,
///
- /// Expiration time
+ /// Expiration time, not repeatable.
///
ExpirationTime = 38,
///
- /// Special instructions
+ /// Special instructions, not repeatable.
///
SpecialInstructions = 40,
///
- /// Action advised
+ /// Action advised, not repeatable.
///
ActionAdvised = 42,
///
- /// Reference service
+ /// Reference service.
///
ReferenceService = 45,
///
- /// Reference date
+ /// Reference date.
///
ReferenceDate = 47,
///
- /// ReferenceNumber
+ /// ReferenceNumber.
///
ReferenceNumber = 50,
///
- /// Created date
+ /// Created date, not repeatable.
///
CreatedDate = 55,
///
- /// Created time
+ /// Created time, not repeatable.
///
CreatedTime = 60,
///
- /// Digital creation date
+ /// Digital creation date, not repeatable.
///
DigitalCreationDate = 62,
///
- /// Digital creation time
+ /// Digital creation time, not repeatable.
///
DigitalCreationTime = 63,
///
- /// Originating program
+ /// Originating program, not repeatable.
///
OriginatingProgram = 65,
///
- /// Program version
+ /// Program version, not repeatable.
///
ProgramVersion = 70,
///
- /// Object cycle
+ /// Object cycle, not repeatable.
///
ObjectCycle = 75,
///
- /// Byline
+ /// Byline.
///
Byline = 80,
///
- /// Byline title
+ /// Byline title.
///
BylineTitle = 85,
///
- /// City
+ /// City, not repeatable.
///
City = 90,
///
- /// Sub location
+ /// Sub location, not repeatable.
///
SubLocation = 92,
///
- /// Province/State
+ /// Province/State, not repeatable.
///
ProvinceState = 95,
///
- /// Country code
+ /// Country code, not repeatable.
///
CountryCode = 100,
///
- /// Country
+ /// Country, not repeatable.
///
Country = 101,
///
- /// Original transmission reference
+ /// Original transmission reference, not repeatable.
///
OriginalTransmissionReference = 103,
///
- /// Headline
+ /// Headline, not repeatable.
///
Headline = 105,
///
- /// Credit
+ /// Credit, not repeatable.
///
Credit = 110,
///
- /// Source
+ /// Source, not repeatable.
///
Source = 115,
///
- /// Copyright notice
+ /// Copyright notice, not repeatable.
///
CopyrightNotice = 116,
///
- /// Contact
+ /// Contact.
///
Contact = 118,
///
- /// Caption
+ /// Caption, not repeatable.
///
Caption = 120,
///
- /// Local caption
+ /// Local caption.
///
LocalCaption = 121,
///
- /// Caption writer
+ /// Caption writer.
///
CaptionWriter = 122,
///
- /// Image type
+ /// Image type, not repeatable.
///
ImageType = 130,
///
- /// Image orientation
+ /// Image orientation, not repeatable.
///
ImageOrientation = 131,
diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs
index 914690102..f15a0992d 100644
--- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs
+++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs
@@ -32,15 +32,15 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC
ContainsIptcValue(iptcValues, IptcTag.BylineTitle, "author title");
ContainsIptcValue(iptcValues, IptcTag.Credit, "credits");
ContainsIptcValue(iptcValues, IptcTag.Source, "source");
- ContainsIptcValue(iptcValues, IptcTag.Title, "title");
+ ContainsIptcValue(iptcValues, IptcTag.Name, "title");
ContainsIptcValue(iptcValues, IptcTag.CreatedDate, "20200414");
ContainsIptcValue(iptcValues, IptcTag.City, "city");
ContainsIptcValue(iptcValues, IptcTag.SubLocation, "sublocation");
ContainsIptcValue(iptcValues, IptcTag.ProvinceState, "province-state");
ContainsIptcValue(iptcValues, IptcTag.Country, "country");
ContainsIptcValue(iptcValues, IptcTag.Category, "category");
- ContainsIptcValue(iptcValues, IptcTag.Priority, "1");
- ContainsIptcValue(iptcValues, IptcTag.Keyword, "keywords");
+ ContainsIptcValue(iptcValues, IptcTag.Urgency, "1");
+ ContainsIptcValue(iptcValues, IptcTag.Keywords, "keywords");
ContainsIptcValue(iptcValues, IptcTag.CopyrightNotice, "copyright");
}
}
@@ -132,6 +132,89 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC
ContainsIptcValue(iptcValues, IptcTag.Caption, expectedCaption);
}
+ [Theory]
+ [InlineData(IptcTag.ObjectAttribute)]
+ [InlineData(IptcTag.SubjectReference)]
+ [InlineData(IptcTag.SupplementalCategories)]
+ [InlineData(IptcTag.Keywords)]
+ [InlineData(IptcTag.LocationCode)]
+ [InlineData(IptcTag.LocationName)]
+ [InlineData(IptcTag.ReferenceService)]
+ [InlineData(IptcTag.ReferenceDate)]
+ [InlineData(IptcTag.ReferenceNumber)]
+ [InlineData(IptcTag.Byline)]
+ [InlineData(IptcTag.BylineTitle)]
+ [InlineData(IptcTag.Contact)]
+ [InlineData(IptcTag.LocalCaption)]
+ [InlineData(IptcTag.CaptionWriter)]
+ public void IptcProfile_AddRepeatable_Works(IptcTag tag)
+ {
+ // arrange
+ var profile = new IptcProfile();
+ var expectedValue1 = "test";
+ var expectedValue2 = "another one";
+ profile.SetValue(tag, expectedValue1);
+
+ // act
+ profile.SetValue(tag, expectedValue2);
+
+ // assert
+ var values = profile.Values.ToList();
+ Assert.Equal(2, values.Count);
+ ContainsIptcValue(values, tag, expectedValue1);
+ ContainsIptcValue(values, tag, expectedValue2);
+ }
+
+ [Theory]
+ [InlineData(IptcTag.RecordVersion)]
+ [InlineData(IptcTag.ObjectType)]
+ [InlineData(IptcTag.Name)]
+ [InlineData(IptcTag.EditStatus)]
+ [InlineData(IptcTag.EditorialUpdate)]
+ [InlineData(IptcTag.Urgency)]
+ [InlineData(IptcTag.Category)]
+ [InlineData(IptcTag.FixtureIdentifier)]
+ [InlineData(IptcTag.ReleaseDate)]
+ [InlineData(IptcTag.ReleaseTime)]
+ [InlineData(IptcTag.ExpirationDate)]
+ [InlineData(IptcTag.ExpirationTime)]
+ [InlineData(IptcTag.SpecialInstructions)]
+ [InlineData(IptcTag.ActionAdvised)]
+ [InlineData(IptcTag.CreatedDate)]
+ [InlineData(IptcTag.CreatedTime)]
+ [InlineData(IptcTag.DigitalCreationDate)]
+ [InlineData(IptcTag.DigitalCreationTime)]
+ [InlineData(IptcTag.OriginatingProgram)]
+ [InlineData(IptcTag.ProgramVersion)]
+ [InlineData(IptcTag.ObjectCycle)]
+ [InlineData(IptcTag.City)]
+ [InlineData(IptcTag.SubLocation)]
+ [InlineData(IptcTag.ProvinceState)]
+ [InlineData(IptcTag.CountryCode)]
+ [InlineData(IptcTag.Country)]
+ [InlineData(IptcTag.OriginalTransmissionReference)]
+ [InlineData(IptcTag.Headline)]
+ [InlineData(IptcTag.Credit)]
+ [InlineData(IptcTag.CopyrightNotice)]
+ [InlineData(IptcTag.Caption)]
+ [InlineData(IptcTag.ImageType)]
+ [InlineData(IptcTag.ImageOrientation)]
+ public void IptcProfile_AddNoneRepeatable_DoesOverrideOldValue(IptcTag tag)
+ {
+ // arrange
+ var profile = new IptcProfile();
+ var expectedValue = "another one";
+ profile.SetValue(tag, "test");
+
+ // act
+ profile.SetValue(tag, expectedValue);
+
+ // assert
+ var values = profile.Values.ToList();
+ Assert.Equal(1, values.Count);
+ ContainsIptcValue(values, tag, expectedValue);
+ }
+
private static void ContainsIptcValue(IEnumerable values, IptcTag tag, string value)
{
Assert.True(values.Any(val => val.Tag == tag), $"Missing iptc tag {tag}");