Browse Source

Some IPTC tags can now be added multiple times, some are restricted from doing so

pull/1174/head
Brian Popow 6 years ago
parent
commit
9822c3a7eb
  1. 61
      src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs
  2. 107
      src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs
  3. 89
      tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs

61
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.
/// </summary>
/// <param name="tag">The tag of the iptc value.</param>
/// <returns>True when the value was fount and removed.</returns>
/// <returns>True when the value was found and removed.</returns>
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;
}
}
}
}

107
src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs

@ -9,242 +9,247 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
public enum IptcTag
{
/// <summary>
/// Unknown
/// Unknown.
/// </summary>
Unknown = -1,
/// <summary>
/// Record version
/// Record version, not repeatable.
/// </summary>
RecordVersion = 0,
/// <summary>
/// Object type
/// Object type, not repeatable.
/// </summary>
ObjectType = 3,
/// <summary>
/// Object attribute
/// Object attribute.
/// </summary>
ObjectAttribute = 4,
/// <summary>
/// Title
/// Object Name, not repeatable.
/// </summary>
Title = 5,
Name = 5,
/// <summary>
/// Edit status
/// Edit status, not repeatable.
/// </summary>
EditStatus = 7,
/// <summary>
/// Editorial update
/// Editorial update, not repeatable.
/// </summary>
EditorialUpdate = 8,
/// <summary>
/// Priority
/// Urgency, not repeatable.
/// </summary>
Priority = 10,
Urgency = 10,
/// <summary>
/// Category
/// Subject Reference.
/// </summary>
SubjectReference = 12,
/// <summary>
/// Category, not repeatable.
/// </summary>
Category = 15,
/// <summary>
/// Supplemental categories
/// Supplemental categories.
/// </summary>
SupplementalCategories = 20,
/// <summary>
/// Fixture identifier
/// Fixture identifier, not repeatable.
/// </summary>
FixtureIdentifier = 22,
/// <summary>
/// Keyword
/// Keywords.
/// </summary>
Keyword = 25,
Keywords = 25,
/// <summary>
/// Location code
/// Location code.
/// </summary>
LocationCode = 26,
/// <summary>
/// Location name
/// Location name.
/// </summary>
LocationName = 27,
/// <summary>
/// Release date
/// Release date, not repeatable.
/// </summary>
ReleaseDate = 30,
/// <summary>
/// Release time
/// Release time, not repeatable.
/// </summary>
ReleaseTime = 35,
/// <summary>
/// Expiration date
/// Expiration date, not repeatable.
/// </summary>
ExpirationDate = 37,
/// <summary>
/// Expiration time
/// Expiration time, not repeatable.
/// </summary>
ExpirationTime = 38,
/// <summary>
/// Special instructions
/// Special instructions, not repeatable.
/// </summary>
SpecialInstructions = 40,
/// <summary>
/// Action advised
/// Action advised, not repeatable.
/// </summary>
ActionAdvised = 42,
/// <summary>
/// Reference service
/// Reference service.
/// </summary>
ReferenceService = 45,
/// <summary>
/// Reference date
/// Reference date.
/// </summary>
ReferenceDate = 47,
/// <summary>
/// ReferenceNumber
/// ReferenceNumber.
/// </summary>
ReferenceNumber = 50,
/// <summary>
/// Created date
/// Created date, not repeatable.
/// </summary>
CreatedDate = 55,
/// <summary>
/// Created time
/// Created time, not repeatable.
/// </summary>
CreatedTime = 60,
/// <summary>
/// Digital creation date
/// Digital creation date, not repeatable.
/// </summary>
DigitalCreationDate = 62,
/// <summary>
/// Digital creation time
/// Digital creation time, not repeatable.
/// </summary>
DigitalCreationTime = 63,
/// <summary>
/// Originating program
/// Originating program, not repeatable.
/// </summary>
OriginatingProgram = 65,
/// <summary>
/// Program version
/// Program version, not repeatable.
/// </summary>
ProgramVersion = 70,
/// <summary>
/// Object cycle
/// Object cycle, not repeatable.
/// </summary>
ObjectCycle = 75,
/// <summary>
/// Byline
/// Byline.
/// </summary>
Byline = 80,
/// <summary>
/// Byline title
/// Byline title.
/// </summary>
BylineTitle = 85,
/// <summary>
/// City
/// City, not repeatable.
/// </summary>
City = 90,
/// <summary>
/// Sub location
/// Sub location, not repeatable.
/// </summary>
SubLocation = 92,
/// <summary>
/// Province/State
/// Province/State, not repeatable.
/// </summary>
ProvinceState = 95,
/// <summary>
/// Country code
/// Country code, not repeatable.
/// </summary>
CountryCode = 100,
/// <summary>
/// Country
/// Country, not repeatable.
/// </summary>
Country = 101,
/// <summary>
/// Original transmission reference
/// Original transmission reference, not repeatable.
/// </summary>
OriginalTransmissionReference = 103,
/// <summary>
/// Headline
/// Headline, not repeatable.
/// </summary>
Headline = 105,
/// <summary>
/// Credit
/// Credit, not repeatable.
/// </summary>
Credit = 110,
/// <summary>
/// Source
/// Source, not repeatable.
/// </summary>
Source = 115,
/// <summary>
/// Copyright notice
/// Copyright notice, not repeatable.
/// </summary>
CopyrightNotice = 116,
/// <summary>
/// Contact
/// Contact.
/// </summary>
Contact = 118,
/// <summary>
/// Caption
/// Caption, not repeatable.
/// </summary>
Caption = 120,
/// <summary>
/// Local caption
/// Local caption.
/// </summary>
LocalCaption = 121,
/// <summary>
/// Caption writer
/// Caption writer.
/// </summary>
CaptionWriter = 122,
/// <summary>
/// Image type
/// Image type, not repeatable.
/// </summary>
ImageType = 130,
/// <summary>
/// Image orientation
/// Image orientation, not repeatable.
/// </summary>
ImageOrientation = 131,

89
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<IptcValue> values, IptcTag tag, string value)
{
Assert.True(values.Any(val => val.Tag == tag), $"Missing iptc tag {tag}");

Loading…
Cancel
Save