diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index 72c00302d..870c4c8ce 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -20,6 +20,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc private const uint MaxStandardDataTagSize = 0x7FFF; + /// + /// 1:90 Coded Character Set + /// + private const byte IptcEnvelopeCodedCharacterSet = 0x5A; + + /// + /// This value marks that UTF-8 encoding is used in application records + /// + private static readonly byte[] CodedCharacterSetUtf8Value = { 0x1B, 0x25, 0x47 }; + /// /// Initializes a new instance of the class. /// @@ -194,6 +204,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc this.values.Add(new IptcValue(tag, encoding, value, strict)); } + /// + /// Sets the value of the specified tag. + /// + /// The tag of the iptc value. + /// The value. + /// + /// Indicates if length restrictions from the specification should be followed strictly. + /// Defaults to true. + /// + public void SetValue(IptcTag tag, string value, bool strict = true) => this.SetValue(tag, Encoding.UTF8, value, strict); + /// /// Makes sure the datetime is formatted according to the iptc specification. /// @@ -219,17 +240,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc this.SetValue(tag, Encoding.UTF8, formattedDate); } - /// - /// Sets the value of the specified tag. - /// - /// The tag of the iptc value. - /// The value. - /// - /// Indicates if length restrictions from the specification should be followed strictly. - /// Defaults to true. - /// - public void SetValue(IptcTag tag, string value, bool strict = true) => this.SetValue(tag, Encoding.UTF8, value, strict); - /// /// Updates the data of the profile. /// @@ -241,9 +251,28 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc length += value.Length + 5; } - this.Data = new byte[length]; + bool hasValuesInUtf8 = this.HasValuesInUtf8(); + + if (hasValuesInUtf8) + { + length += 5 + CodedCharacterSetUtf8Value.Length; // additional length for UTF-8 Tag + } + this.Data = new byte[length]; int i = 0; + + if (hasValuesInUtf8) + { + // Standard DataSet Tag + this.Data[i++] = IptcTagMarkerByte; + this.Data[i++] = 1; // Envelope + this.Data[i++] = IptcEnvelopeCodedCharacterSet; + this.Data[i++] = (byte)(CodedCharacterSetUtf8Value.Length >> 8); + this.Data[i++] = (byte)CodedCharacterSetUtf8Value.Length; + Buffer.BlockCopy(CodedCharacterSetUtf8Value, 0, this.Data, i, CodedCharacterSetUtf8Value.Length); + i += CodedCharacterSetUtf8Value.Length; + } + foreach (IptcValue value in this.Values) { // Standard DataSet Tag @@ -264,7 +293,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc // | | | octet 4(most significant bit) always will be 0. | // +-----------+----------------+---------------------------------------------------------------------------------+ this.Data[i++] = IptcTagMarkerByte; - this.Data[i++] = 2; + this.Data[i++] = 2; // Application this.Data[i++] = (byte)value.Tag; this.Data[i++] = (byte)(value.Length >> 8); this.Data[i++] = (byte)value.Length; @@ -309,7 +338,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc if (isValidEntry && byteCount > 0 && (offset <= this.Data.Length - byteCount)) { - var iptcData = new byte[byteCount]; + byte[] iptcData = new byte[byteCount]; Buffer.BlockCopy(this.Data, offset, iptcData, 0, (int)byteCount); this.values.Add(new IptcValue(tag, iptcData, false)); } @@ -317,5 +346,22 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc offset += (int)byteCount; } } + + /// + /// Gets if any value has UTF-8 encoding + /// + /// true if any value has UTF-8 encoding + private bool HasValuesInUtf8() + { + foreach (IptcValue value in this.values) + { + if (value.Encoding == Encoding.UTF8) + { + return true; + } + } + + return false; + } } }