Browse Source

Fix IPTC tags written on jpg files that contains non-English characters can't be correctly displayed on external apps #2212

pull/2213/head
Luis Miguel Merino 4 years ago
parent
commit
9c7ba12ee2
  1. 74
      src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs

74
src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs

@ -20,6 +20,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
private const uint MaxStandardDataTagSize = 0x7FFF;
/// <summary>
/// 1:90 Coded Character Set
/// </summary>
private const byte IptcEnvelopeCodedCharacterSet = 0x5A;
/// <summary>
/// This value marks that UTF-8 encoding is used in application records
/// </summary>
private static readonly byte[] CodedCharacterSetUtf8Value = { 0x1B, 0x25, 0x47 };
/// <summary>
/// Initializes a new instance of the <see cref="IptcProfile"/> class.
/// </summary>
@ -194,6 +204,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
this.values.Add(new IptcValue(tag, encoding, value, strict));
}
/// <summary>
/// Sets the value of the specified tag.
/// </summary>
/// <param name="tag">The tag of the iptc value.</param>
/// <param name="value">The value.</param>
/// <param name="strict">
/// Indicates if length restrictions from the specification should be followed strictly.
/// Defaults to true.
/// </param>
public void SetValue(IptcTag tag, string value, bool strict = true) => this.SetValue(tag, Encoding.UTF8, value, strict);
/// <summary>
/// Makes sure the datetime is formatted according to the iptc specification.
/// <example>
@ -219,17 +240,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc
this.SetValue(tag, Encoding.UTF8, formattedDate);
}
/// <summary>
/// Sets the value of the specified tag.
/// </summary>
/// <param name="tag">The tag of the iptc value.</param>
/// <param name="value">The value.</param>
/// <param name="strict">
/// Indicates if length restrictions from the specification should be followed strictly.
/// Defaults to true.
/// </param>
public void SetValue(IptcTag tag, string value, bool strict = true) => this.SetValue(tag, Encoding.UTF8, value, strict);
/// <summary>
/// Updates the data of the profile.
/// </summary>
@ -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;
}
}
/// <summary>
/// Gets if any value has UTF-8 encoding
/// </summary>
/// <returns>true if any value has UTF-8 encoding</returns>
private bool HasValuesInUtf8()
{
foreach (IptcValue value in this.values)
{
if (value.Encoding == Encoding.UTF8)
{
return true;
}
}
return false;
}
}
}

Loading…
Cancel
Save