diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index 306924e62c..f123e62d5f 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -228,6 +228,10 @@ public void SetDateTimeValue(IptcTag tag, DateTimeOffset dateTimeOffset) /// /// Updates the data of the profile. /// + /// + /// When any value uses UTF-8 encoding, which is the default encoding of a value, the data starts with the + /// 1:90 Coded Character Set dataset declaring UTF-8, also when the text is ASCII only. + /// public void UpdateData() { int length = 0; @@ -337,7 +341,9 @@ private bool HasValuesInUtf8() { foreach (IptcValue value in this.values) { - if (value.Encoding == Encoding.UTF8) + // Compare the code page rather than the instance. Cloned values hold a copy of their encoding, + // and callers can pass their own UTF8Encoding, but both still write UTF-8 bytes. + if (value.Encoding.CodePage == Encoding.UTF8.CodePage) { return true; } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 37f99517c7..4ae475c653 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -34,6 +34,57 @@ public void IptcProfile_WithUtf8Data_WritesEnvelopeRecord_Works() Assert.True(profileBytes.AsSpan(0, 8).SequenceEqual(expectedEnvelopeData)); } + [Fact] + public void IptcProfile_DeepClone_WithUtf8Data_WritesEnvelopeRecord_Works() + { + // arrange + IptcProfile profile = new(); + profile.SetValue(IptcTag.City, "ESPAÑA"); + IptcProfile clone = profile.DeepClone(); + byte[] expectedEnvelopeData = [28, 1, 90, 0, 3, 27, 37, 71]; + + // act + clone.UpdateData(); + + // assert + Assert.True(clone.Data.AsSpan(0, 8).SequenceEqual(expectedEnvelopeData)); + } + + [Fact] + public void IptcProfile_WithUtf8EncodingInstance_WritesEnvelopeRecord_Works() + { + // arrange + IptcProfile profile = new(); + profile.SetValue(IptcTag.City, new System.Text.UTF8Encoding(false), "ESPAÑA"); + byte[] expectedEnvelopeData = [28, 1, 90, 0, 3, 27, 37, 71]; + + // act + profile.UpdateData(); + + // assert + Assert.True(profile.Data.AsSpan(0, 8).SequenceEqual(expectedEnvelopeData)); + } + + [Fact] + public void WritingClonedImage_WithUtf8Data_WritesEnvelopeRecordOnce() + { + // arrange + using Image image = new(1, 1); + image.Metadata.IptcProfile = new IptcProfile(); + image.Metadata.IptcProfile.SetValue(IptcTag.Caption, "ESPAÑA"); + byte[] expectedData = [28, 1, 90, 0, 3, 27, 37, 71, 28, 2, 120, 0, 7, 69, 83, 80, 65, 195, 145, 65]; + + // act + using Image once = WriteAndReadJpeg(image.Clone()); + using Image twice = WriteAndReadJpeg(once.Clone()); + + // assert + IptcProfile actual = twice.Metadata.IptcProfile; + Assert.Equal(expectedData, actual.Data); + IptcValue value = Assert.Single(actual.Values); + Assert.Equal("ESPAÑA", value.Value); + } + [Theory] [MemberData(nameof(AllIptcTags))] public void IptcProfile_SetValue_WithStrictEnabled_Works(IptcTag tag)