diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 1b3a8e27f6..7dac3c283a 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -49,6 +49,7 @@ + diff --git a/src/ImageSharp/Metadata/Profiles/Exif/DC-X008-Translation-2019-E.pdf b/src/ImageSharp/Metadata/Profiles/Exif/DC-X008-Translation-2019-E.pdf index cd7141fc8d..22a1058168 100644 Binary files a/src/ImageSharp/Metadata/Profiles/Exif/DC-X008-Translation-2019-E.pdf and b/src/ImageSharp/Metadata/Profiles/Exif/DC-X008-Translation-2019-E.pdf differ diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs index 0c81f14dd4..543e3d5c4d 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Text; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { @@ -22,5 +23,8 @@ internal static class ExifConstants 0x00, 0x2A }; + + // UTF-8 is better than ASCII, UTF-8 encodes the ASCII codes the same way + public static Encoding DefaultEncoding => Encoding.UTF8; } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifEncodedStringHelpers.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifEncodedStringHelpers.cs new file mode 100644 index 0000000000..5fd613b1f0 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifEncodedStringHelpers.cs @@ -0,0 +1,121 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers.Binary; +using System.Text; +using static SixLabors.ImageSharp.Metadata.Profiles.Exif.EncodedString; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal static class ExifEncodedStringHelpers + { + public const int CharacterCodeBytesLength = 8; + + private const ulong AsciiCode = 0x_00_00_00_49_49_43_53_41; + private const ulong JISCode = 0x_00_00_00_00_00_53_49_4A; + private const ulong UnicodeCode = 0x_45_44_4F_43_49_4E_55; + private const ulong UndefinedCode = 0x_00_00_00_00_00_00_00_00; + + private static ReadOnlySpan AsciiCodeBytes => new byte[] { 0x41, 0x53, 0x43, 0x49, 0x49, 0, 0, 0 }; + + private static ReadOnlySpan JISCodeBytes => new byte[] { 0x4A, 0x49, 0x53, 0, 0, 0, 0, 0 }; + + private static ReadOnlySpan UnicodeCodeBytes => new byte[] { 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0 }; + + private static ReadOnlySpan UndefinedCodeBytes => new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; + + // 20932 EUC-JP Japanese (JIS 0208-1990 and 0212-1990) + // https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding?view=net-6.0 + private static Encoding JIS0208Encoding => CodePagesEncodingProvider.Instance.GetEncoding(20932); + + public static bool IsEncodedString(ExifTagValue tag) => tag switch + { + ExifTagValue.UserComment or ExifTagValue.GPSProcessingMethod or ExifTagValue.GPSAreaInformation => true, + _ => false + }; + + public static ReadOnlySpan GetCodeBytes(CharacterCode code) => code switch + { + CharacterCode.ASCII => AsciiCodeBytes, + CharacterCode.JIS => JISCodeBytes, + CharacterCode.Unicode => UnicodeCodeBytes, + CharacterCode.Undefined => UndefinedCodeBytes, + _ => UndefinedCodeBytes + }; + + public static Encoding GetEncoding(CharacterCode code) => code switch + { + CharacterCode.ASCII => Encoding.ASCII, + CharacterCode.JIS => JIS0208Encoding, + CharacterCode.Unicode => Encoding.Unicode, + CharacterCode.Undefined => Encoding.UTF8, + _ => Encoding.UTF8 + }; + + public static bool TryParse(ReadOnlySpan buffer, out EncodedString encodedString) + { + if (TryDetect(buffer, out CharacterCode code)) + { + string text = GetEncoding(code).GetString(buffer.Slice(CharacterCodeBytesLength)); + encodedString = new EncodedString(code, text); + return true; + } + + encodedString = default; + return false; + } + + public static uint GetDataLength(EncodedString encodedString) => + (uint)GetEncoding(encodedString.Code).GetByteCount(encodedString.Text) + CharacterCodeBytesLength; + + public static int Write(EncodedString encodedString, Span destination) + { + GetCodeBytes(encodedString.Code).CopyTo(destination); + + string text = encodedString.Text; + int count = Write(GetEncoding(encodedString.Code), text, destination.Slice(CharacterCodeBytesLength)); + + return CharacterCodeBytesLength + count; + } + + public static unsafe int Write(Encoding encoding, string value, Span destination) + { + fixed (char* c = value) + { + fixed (byte* b = destination) + { + return encoding.GetBytes(c, value.Length, b, destination.Length); + } + } + } + + private static bool TryDetect(ReadOnlySpan buffer, out CharacterCode code) + { + if (buffer.Length >= CharacterCodeBytesLength) + { + ulong test = BinaryPrimitives.ReadUInt64LittleEndian(buffer); + switch (test) + { + case AsciiCode: + code = CharacterCode.ASCII; + return true; + case JISCode: + code = CharacterCode.JIS; + return true; + case UnicodeCode: + code = CharacterCode.Unicode; + return true; + case UndefinedCode: + code = CharacterCode.Undefined; + return true; + default: + break; + } + } + + code = default; + return false; + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 2fcd1cc07d..9b5e098c83 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -241,9 +241,7 @@ private static TDataType[] ToArray(ExifDataType dataType, ReadOnlySpa return result; } - private byte ConvertToByte(ReadOnlySpan buffer) => buffer[0]; - - private string ConvertToString(ReadOnlySpan buffer) + private static string ConvertToString(Encoding encoding, ReadOnlySpan buffer) { int nullCharIndex = buffer.IndexOf((byte)0); @@ -252,9 +250,11 @@ private string ConvertToString(ReadOnlySpan buffer) buffer = buffer.Slice(0, nullCharIndex); } - return Encoding.UTF8.GetString(buffer); + return encoding.GetString(buffer); } + private byte ConvertToByte(ReadOnlySpan buffer) => buffer[0]; + private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, bool isArray) { if (buffer.Length == 0) @@ -267,8 +267,9 @@ private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, bo case ExifDataType.Unknown: return null; case ExifDataType.Ascii: - return this.ConvertToString(buffer); + return ConvertToString(ExifConstants.DefaultEncoding, buffer); case ExifDataType.Byte: + case ExifDataType.Undefined: if (!isArray) { return this.ConvertToByte(buffer); @@ -354,13 +355,7 @@ private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, bo } return ToArray(dataType, buffer, this.ConvertToUInt64); - case ExifDataType.Undefined: - if (!isArray) - { - return this.ConvertToByte(buffer); - } - return buffer.ToArray(); default: throw new NotSupportedException($"Data type {dataType} is not supported."); } @@ -453,7 +448,7 @@ private void ReadValue64(List values, Span offsetBuffer) // Likewise, tags that point to other IFDs, like e.g. the SubIFDs tag, are now allowed to have the datatype TIFF_IFD8 in BigTIFF. // Again, the old datatypes TIFF_IFD, and the hardly recommendable TIFF_LONG, are still valid, too. // https://www.awaresystems.be/imaging/tiff/bigtiff.html - ExifValue exifValue = null; + ExifValue exifValue; switch (tag) { case ExifTagValue.StripOffsets: diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifUcs2StringHelpers.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifUcs2StringHelpers.cs new file mode 100644 index 0000000000..ccc1c80ade --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifUcs2StringHelpers.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Text; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal static class ExifUcs2StringHelpers + { + public static Encoding Ucs2Encoding => Encoding.GetEncoding("UCS-2"); + + public static bool IsUcs2Tag(ExifTagValue tag) => tag switch + { + ExifTagValue.XPAuthor or ExifTagValue.XPComment or ExifTagValue.XPKeywords or ExifTagValue.XPSubject or ExifTagValue.XPTitle => true, + _ => false, + }; + + public static int Write(string value, Span destination) => ExifEncodedStringHelpers.Write(Ucs2Encoding, value, destination); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs index e2ed569548..a14539bca2 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs @@ -4,7 +4,6 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; -using System.Text; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { @@ -274,9 +273,19 @@ internal static uint GetNumberOfComponents(IExifValue exifValue) { object value = exifValue.GetValue(); + if (ExifUcs2StringHelpers.IsUcs2Tag((ExifTagValue)(ushort)exifValue.Tag)) + { + return (uint)ExifUcs2StringHelpers.Ucs2Encoding.GetByteCount((string)value); + } + + if (value is EncodedString encodedString) + { + return ExifEncodedStringHelpers.GetDataLength(encodedString); + } + if (exifValue.DataType == ExifDataType.Ascii) { - return (uint)Encoding.UTF8.GetBytes((string)value).Length + 1; + return (uint)ExifConstants.DefaultEncoding.GetByteCount((string)value) + 1; } if (value is Array arrayValue) @@ -289,11 +298,6 @@ internal static uint GetNumberOfComponents(IExifValue exifValue) private static int WriteArray(IExifValue value, Span destination, int offset) { - if (value.DataType == ExifDataType.Ascii) - { - return WriteValue(ExifDataType.Ascii, value.GetValue(), destination, offset); - } - int newOffset = offset; foreach (object obj in (Array)value.GetValue()) { @@ -378,7 +382,7 @@ private static int WriteValue(ExifDataType dataType, object value, Span de switch (dataType) { case ExifDataType.Ascii: - offset = Write(Encoding.UTF8.GetBytes((string)value), destination, offset); + offset = Write(ExifConstants.DefaultEncoding.GetBytes((string)value), destination, offset); destination[offset] = 0; return offset + 1; case ExifDataType.Byte: @@ -425,14 +429,25 @@ private static int WriteValue(ExifDataType dataType, object value, Span de } } - internal static int WriteValue(IExifValue value, Span destination, int offset) + internal static int WriteValue(IExifValue exifValue, Span destination, int offset) { - if (value.IsArray && value.DataType != ExifDataType.Ascii) + object value = exifValue.GetValue(); + + if (ExifUcs2StringHelpers.IsUcs2Tag((ExifTagValue)(ushort)exifValue.Tag)) + { + return offset + ExifUcs2StringHelpers.Write((string)value, destination.Slice(offset)); + } + else if (value is EncodedString encodedString) + { + return offset + ExifEncodedStringHelpers.Write(encodedString, destination.Slice(offset)); + } + + if (exifValue.IsArray) { - return WriteArray(value, destination, offset); + return WriteArray(exifValue, destination, offset); } - return WriteValue(value.DataType, value.GetValue(), destination, offset); + return WriteValue(exifValue.DataType, value, destination, offset); } } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs index fdde66c513..964fb6e948 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs @@ -41,31 +41,6 @@ public abstract partial class ExifTag /// public static ExifTag TIFFEPStandardID => new ExifTag(ExifTagValue.TIFFEPStandardID); - /// - /// Gets the XPTitle exif tag. - /// - public static ExifTag XPTitle => new ExifTag(ExifTagValue.XPTitle); - - /// - /// Gets the XPComment exif tag. - /// - public static ExifTag XPComment => new ExifTag(ExifTagValue.XPComment); - - /// - /// Gets the XPAuthor exif tag. - /// - public static ExifTag XPAuthor => new ExifTag(ExifTagValue.XPAuthor); - - /// - /// Gets the XPKeywords exif tag. - /// - public static ExifTag XPKeywords => new ExifTag(ExifTagValue.XPKeywords); - - /// - /// Gets the XPSubject exif tag. - /// - public static ExifTag XPSubject => new ExifTag(ExifTagValue.XPSubject); - /// /// Gets the GPSVersionID exif tag. /// diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.EncodedString.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.EncodedString.cs new file mode 100644 index 0000000000..335098a435 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.EncodedString.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the UserComment exif tag. + /// + public static ExifTag UserComment { get; } = new ExifTag(ExifTagValue.UserComment); + + /// + /// Gets the GPSProcessingMethod exif tag. + /// + public static ExifTag GPSProcessingMethod { get; } = new ExifTag(ExifTagValue.GPSProcessingMethod); + + /// + /// Gets the GPSAreaInformation exif tag. + /// + public static ExifTag GPSAreaInformation { get; } = new ExifTag(ExifTagValue.GPSAreaInformation); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Ucs2String.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Ucs2String.cs new file mode 100644 index 0000000000..a6911d76d7 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Ucs2String.cs @@ -0,0 +1,34 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the title tag used by Windows (encoded in UCS2). + /// + public static ExifTag XPTitle => new ExifTag(ExifTagValue.XPTitle); + + /// + /// Gets the comment tag used by Windows (encoded in UCS2). + /// + public static ExifTag XPComment => new ExifTag(ExifTagValue.XPComment); + + /// + /// Gets the author tag used by Windows (encoded in UCS2). + /// + public static ExifTag XPAuthor => new ExifTag(ExifTagValue.XPAuthor); + + /// + /// Gets the keywords tag used by Windows (encoded in UCS2). + /// + public static ExifTag XPKeywords => new ExifTag(ExifTagValue.XPKeywords); + + /// + /// Gets the subject tag used by Windows (encoded in UCS2). + /// + public static ExifTag XPSubject => new ExifTag(ExifTagValue.XPSubject); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs index 1d9af6adce..58886f4036 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs @@ -31,11 +31,6 @@ public abstract partial class ExifTag /// public static ExifTag MakerNote { get; } = new ExifTag(ExifTagValue.MakerNote); - /// - /// Gets the UserComment exif tag. - /// - public static ExifTag UserComment { get; } = new ExifTag(ExifTagValue.UserComment); - /// /// Gets the FlashpixVersion exif tag. /// @@ -71,16 +66,6 @@ public abstract partial class ExifTag /// public static ExifTag ImageSourceData { get; } = new ExifTag(ExifTagValue.ImageSourceData); - /// - /// Gets the GPSProcessingMethod exif tag. - /// - public static ExifTag GPSProcessingMethod { get; } = new ExifTag(ExifTagValue.GPSProcessingMethod); - - /// - /// Gets the GPSAreaInformation exif tag. - /// - public static ExifTag GPSAreaInformation { get; } = new ExifTag(ExifTagValue.GPSAreaInformation); - /// /// Gets the FileSource exif tag. /// diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/EncodedString.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/EncodedString.cs new file mode 100644 index 0000000000..e9cd27427c --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/EncodedString.cs @@ -0,0 +1,94 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + /// The EXIF encoded string structure. + /// + public readonly struct EncodedString : IEquatable + { + /// + /// Initializes a new instance of the struct. + /// Default use Unicode character code. + /// + /// The text value. + public EncodedString(string text) + : this(CharacterCode.Unicode, text) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The character code. + /// The text value. + public EncodedString(CharacterCode code, string text) + { + this.Text = text; + this.Code = code; + } + + /// + /// The 8-byte character code enum. + /// + public enum CharacterCode + { + /// + /// The ASCII (ITU-T T.50 IA5) character code. + /// + ASCII, + + /// + /// The JIS (X208-1990) character code. + /// + JIS, + + /// + /// The Unicode character code. + /// + Unicode, + + /// + /// The undefined character code. + /// + Undefined + } + + /// + /// Gets the character ode. + /// + public CharacterCode Code { get; } + + /// + /// Gets the text. + /// + public string Text { get; } + + /// + /// Converts the specified to an instance of this type. + /// + /// The text value. + public static implicit operator EncodedString(string text) => new(text); + + /// + /// Converts the specified to a . + /// + /// The to convert. + public static explicit operator string(EncodedString encodedString) => encodedString.Text; + + /// + public override bool Equals(object obj) => obj is EncodedString other && this.Equals(other); + + /// + public bool Equals(EncodedString other) => this.Text == other.Text && this.Code == other.Code; + + /// + public override int GetHashCode() => HashCode.Combine(this.Text, this.Code); + + /// + public override string ToString() => this.Text; + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifEncodedString.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifEncodedString.cs new file mode 100644 index 0000000000..ba9fca5c8f --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifEncodedString.cs @@ -0,0 +1,55 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifEncodedString : ExifValue + { + public ExifEncodedString(ExifTag tag) + : base(tag) + { + } + + public ExifEncodedString(ExifTagValue tag) + : base(tag) + { + } + + private ExifEncodedString(ExifEncodedString value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Undefined; + + protected override string StringValue => this.Value.Text; + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + if (value is string stringValue) + { + this.Value = new EncodedString(stringValue); + return true; + } + else if (value is byte[] buffer) + { + if (ExifEncodedStringHelpers.TryParse(buffer, out EncodedString encodedString)) + { + this.Value = encodedString; + return true; + } + } + + return false; + } + + public override IExifValue DeepClone() => new ExifEncodedString(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifUcs2String.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifUcs2String.cs new file mode 100644 index 0000000000..42637925c7 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifUcs2String.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifUcs2String : ExifValue + { + public ExifUcs2String(ExifTag tag) + : base(tag) + { + } + + public ExifUcs2String(ExifTagValue tag) + : base(tag) + { + } + + private ExifUcs2String(ExifUcs2String value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Byte; + + protected override string StringValue => this.Value; + + public override object GetValue() => this.Value; + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + if (value is byte[] buffer) + { + this.Value = ExifUcs2StringHelpers.Ucs2Encoding.GetString(buffer); + return true; + } + + return false; + } + + public override IExifValue DeepClone() => new ExifUcs2String(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs index 33fb90cc04..fa5cf9b2fa 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs @@ -15,21 +15,36 @@ public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, bool isA { switch (dataType) { - case ExifDataType.Byte: return isArray ? (ExifValue)new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType); - case ExifDataType.DoubleFloat: return isArray ? (ExifValue)new ExifDoubleArray(tag) : new ExifDouble(tag); - case ExifDataType.SingleFloat: return isArray ? (ExifValue)new ExifFloatArray(tag) : new ExifFloat(tag); - case ExifDataType.Long: return isArray ? (ExifValue)new ExifLongArray(tag) : new ExifLong(tag); - case ExifDataType.Long8: return isArray ? (ExifValue)new ExifLong8Array(tag) : new ExifLong8(tag); - case ExifDataType.Rational: return isArray ? (ExifValue)new ExifRationalArray(tag) : new ExifRational(tag); - case ExifDataType.Short: return isArray ? (ExifValue)new ExifShortArray(tag) : new ExifShort(tag); - case ExifDataType.SignedByte: return isArray ? (ExifValue)new ExifSignedByteArray(tag) : new ExifSignedByte(tag); - case ExifDataType.SignedLong: return isArray ? (ExifValue)new ExifSignedLongArray(tag) : new ExifSignedLong(tag); - case ExifDataType.SignedLong8: return isArray ? (ExifValue)new ExifSignedLong8Array(tag) : new ExifSignedLong8(tag); - case ExifDataType.SignedRational: return isArray ? (ExifValue)new ExifSignedRationalArray(tag) : new ExifSignedRational(tag); - case ExifDataType.SignedShort: return isArray ? (ExifValue)new ExifSignedShortArray(tag) : new ExifSignedShort(tag); - case ExifDataType.Ascii: return new ExifString(tag); - case ExifDataType.Undefined: return isArray ? (ExifValue)new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType); - default: return null; + case ExifDataType.Byte: + return isArray ? new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType); + case ExifDataType.DoubleFloat: + return isArray ? new ExifDoubleArray(tag) : new ExifDouble(tag); + case ExifDataType.SingleFloat: + return isArray ? new ExifFloatArray(tag) : new ExifFloat(tag); + case ExifDataType.Long: + return isArray ? new ExifLongArray(tag) : new ExifLong(tag); + case ExifDataType.Long8: + return isArray ? new ExifLong8Array(tag) : new ExifLong8(tag); + case ExifDataType.Rational: + return isArray ? new ExifRationalArray(tag) : new ExifRational(tag); + case ExifDataType.Short: + return isArray ? new ExifShortArray(tag) : new ExifShort(tag); + case ExifDataType.SignedByte: + return isArray ? new ExifSignedByteArray(tag) : new ExifSignedByte(tag); + case ExifDataType.SignedLong: + return isArray ? new ExifSignedLongArray(tag) : new ExifSignedLong(tag); + case ExifDataType.SignedLong8: + return isArray ? new ExifSignedLong8Array(tag) : new ExifSignedLong8(tag); + case ExifDataType.SignedRational: + return isArray ? new ExifSignedRationalArray(tag) : new ExifSignedRational(tag); + case ExifDataType.SignedShort: + return isArray ? new ExifSignedShortArray(tag) : new ExifSignedShort(tag); + case ExifDataType.Ascii: + return new ExifString(tag); + case ExifDataType.Undefined: + return isArray ? new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType); + default: + return null; } } @@ -37,275 +52,530 @@ private static object CreateValue(ExifTagValue tag) { switch (tag) { - case ExifTagValue.FaxProfile: return new ExifByte(ExifTag.FaxProfile, ExifDataType.Byte); - case ExifTagValue.ModeNumber: return new ExifByte(ExifTag.ModeNumber, ExifDataType.Byte); - case ExifTagValue.GPSAltitudeRef: return new ExifByte(ExifTag.GPSAltitudeRef, ExifDataType.Byte); + case ExifTagValue.FaxProfile: + return new ExifByte(ExifTag.FaxProfile, ExifDataType.Byte); + case ExifTagValue.ModeNumber: + return new ExifByte(ExifTag.ModeNumber, ExifDataType.Byte); + case ExifTagValue.GPSAltitudeRef: + return new ExifByte(ExifTag.GPSAltitudeRef, ExifDataType.Byte); - case ExifTagValue.ClipPath: return new ExifByteArray(ExifTag.ClipPath, ExifDataType.Byte); - case ExifTagValue.VersionYear: return new ExifByteArray(ExifTag.VersionYear, ExifDataType.Byte); - case ExifTagValue.XMP: return new ExifByteArray(ExifTag.XMP, ExifDataType.Byte); - case ExifTagValue.CFAPattern2: return new ExifByteArray(ExifTag.CFAPattern2, ExifDataType.Byte); - case ExifTagValue.TIFFEPStandardID: return new ExifByteArray(ExifTag.TIFFEPStandardID, ExifDataType.Byte); - case ExifTagValue.XPTitle: return new ExifByteArray(ExifTag.XPTitle, ExifDataType.Byte); - case ExifTagValue.XPComment: return new ExifByteArray(ExifTag.XPComment, ExifDataType.Byte); - case ExifTagValue.XPAuthor: return new ExifByteArray(ExifTag.XPAuthor, ExifDataType.Byte); - case ExifTagValue.XPKeywords: return new ExifByteArray(ExifTag.XPKeywords, ExifDataType.Byte); - case ExifTagValue.XPSubject: return new ExifByteArray(ExifTag.XPSubject, ExifDataType.Byte); - case ExifTagValue.GPSVersionID: return new ExifByteArray(ExifTag.GPSVersionID, ExifDataType.Byte); + case ExifTagValue.ClipPath: + return new ExifByteArray(ExifTag.ClipPath, ExifDataType.Byte); + case ExifTagValue.VersionYear: + return new ExifByteArray(ExifTag.VersionYear, ExifDataType.Byte); + case ExifTagValue.XMP: + return new ExifByteArray(ExifTag.XMP, ExifDataType.Byte); + case ExifTagValue.CFAPattern2: + return new ExifByteArray(ExifTag.CFAPattern2, ExifDataType.Byte); + case ExifTagValue.TIFFEPStandardID: + return new ExifByteArray(ExifTag.TIFFEPStandardID, ExifDataType.Byte); + case ExifTagValue.GPSVersionID: + return new ExifByteArray(ExifTag.GPSVersionID, ExifDataType.Byte); - case ExifTagValue.PixelScale: return new ExifDoubleArray(ExifTag.PixelScale); - case ExifTagValue.IntergraphMatrix: return new ExifDoubleArray(ExifTag.IntergraphMatrix); - case ExifTagValue.ModelTiePoint: return new ExifDoubleArray(ExifTag.ModelTiePoint); - case ExifTagValue.ModelTransform: return new ExifDoubleArray(ExifTag.ModelTransform); + case ExifTagValue.PixelScale: + return new ExifDoubleArray(ExifTag.PixelScale); + case ExifTagValue.IntergraphMatrix: + return new ExifDoubleArray(ExifTag.IntergraphMatrix); + case ExifTagValue.ModelTiePoint: + return new ExifDoubleArray(ExifTag.ModelTiePoint); + case ExifTagValue.ModelTransform: + return new ExifDoubleArray(ExifTag.ModelTransform); - case ExifTagValue.SubfileType: return new ExifLong(ExifTag.SubfileType); - case ExifTagValue.SubIFDOffset: return new ExifLong(ExifTag.SubIFDOffset); - case ExifTagValue.GPSIFDOffset: return new ExifLong(ExifTag.GPSIFDOffset); - case ExifTagValue.T4Options: return new ExifLong(ExifTag.T4Options); - case ExifTagValue.T6Options: return new ExifLong(ExifTag.T6Options); - case ExifTagValue.XClipPathUnits: return new ExifLong(ExifTag.XClipPathUnits); - case ExifTagValue.YClipPathUnits: return new ExifLong(ExifTag.YClipPathUnits); - case ExifTagValue.ProfileType: return new ExifLong(ExifTag.ProfileType); - case ExifTagValue.CodingMethods: return new ExifLong(ExifTag.CodingMethods); - case ExifTagValue.T82ptions: return new ExifLong(ExifTag.T82ptions); - case ExifTagValue.JPEGInterchangeFormat: return new ExifLong(ExifTag.JPEGInterchangeFormat); - case ExifTagValue.JPEGInterchangeFormatLength: return new ExifLong(ExifTag.JPEGInterchangeFormatLength); - case ExifTagValue.MDFileTag: return new ExifLong(ExifTag.MDFileTag); - case ExifTagValue.StandardOutputSensitivity: return new ExifLong(ExifTag.StandardOutputSensitivity); - case ExifTagValue.RecommendedExposureIndex: return new ExifLong(ExifTag.RecommendedExposureIndex); - case ExifTagValue.ISOSpeed: return new ExifLong(ExifTag.ISOSpeed); - case ExifTagValue.ISOSpeedLatitudeyyy: return new ExifLong(ExifTag.ISOSpeedLatitudeyyy); - case ExifTagValue.ISOSpeedLatitudezzz: return new ExifLong(ExifTag.ISOSpeedLatitudezzz); - case ExifTagValue.FaxRecvParams: return new ExifLong(ExifTag.FaxRecvParams); - case ExifTagValue.FaxRecvTime: return new ExifLong(ExifTag.FaxRecvTime); - case ExifTagValue.ImageNumber: return new ExifLong(ExifTag.ImageNumber); + case ExifTagValue.SubfileType: + return new ExifLong(ExifTag.SubfileType); + case ExifTagValue.SubIFDOffset: + return new ExifLong(ExifTag.SubIFDOffset); + case ExifTagValue.GPSIFDOffset: + return new ExifLong(ExifTag.GPSIFDOffset); + case ExifTagValue.T4Options: + return new ExifLong(ExifTag.T4Options); + case ExifTagValue.T6Options: + return new ExifLong(ExifTag.T6Options); + case ExifTagValue.XClipPathUnits: + return new ExifLong(ExifTag.XClipPathUnits); + case ExifTagValue.YClipPathUnits: + return new ExifLong(ExifTag.YClipPathUnits); + case ExifTagValue.ProfileType: + return new ExifLong(ExifTag.ProfileType); + case ExifTagValue.CodingMethods: + return new ExifLong(ExifTag.CodingMethods); + case ExifTagValue.T82ptions: + return new ExifLong(ExifTag.T82ptions); + case ExifTagValue.JPEGInterchangeFormat: + return new ExifLong(ExifTag.JPEGInterchangeFormat); + case ExifTagValue.JPEGInterchangeFormatLength: + return new ExifLong(ExifTag.JPEGInterchangeFormatLength); + case ExifTagValue.MDFileTag: + return new ExifLong(ExifTag.MDFileTag); + case ExifTagValue.StandardOutputSensitivity: + return new ExifLong(ExifTag.StandardOutputSensitivity); + case ExifTagValue.RecommendedExposureIndex: + return new ExifLong(ExifTag.RecommendedExposureIndex); + case ExifTagValue.ISOSpeed: + return new ExifLong(ExifTag.ISOSpeed); + case ExifTagValue.ISOSpeedLatitudeyyy: + return new ExifLong(ExifTag.ISOSpeedLatitudeyyy); + case ExifTagValue.ISOSpeedLatitudezzz: + return new ExifLong(ExifTag.ISOSpeedLatitudezzz); + case ExifTagValue.FaxRecvParams: + return new ExifLong(ExifTag.FaxRecvParams); + case ExifTagValue.FaxRecvTime: + return new ExifLong(ExifTag.FaxRecvTime); + case ExifTagValue.ImageNumber: + return new ExifLong(ExifTag.ImageNumber); - case ExifTagValue.FreeOffsets: return new ExifLongArray(ExifTag.FreeOffsets); - case ExifTagValue.FreeByteCounts: return new ExifLongArray(ExifTag.FreeByteCounts); - case ExifTagValue.ColorResponseUnit: return new ExifLongArray(ExifTag.ColorResponseUnit); - case ExifTagValue.TileOffsets: return new ExifLongArray(ExifTag.TileOffsets); - case ExifTagValue.SMinSampleValue: return new ExifLongArray(ExifTag.SMinSampleValue); - case ExifTagValue.SMaxSampleValue: return new ExifLongArray(ExifTag.SMaxSampleValue); - case ExifTagValue.JPEGQTables: return new ExifLongArray(ExifTag.JPEGQTables); - case ExifTagValue.JPEGDCTables: return new ExifLongArray(ExifTag.JPEGDCTables); - case ExifTagValue.JPEGACTables: return new ExifLongArray(ExifTag.JPEGACTables); - case ExifTagValue.StripRowCounts: return new ExifLongArray(ExifTag.StripRowCounts); - case ExifTagValue.IntergraphRegisters: return new ExifLongArray(ExifTag.IntergraphRegisters); - case ExifTagValue.TimeZoneOffset: return new ExifLongArray(ExifTag.TimeZoneOffset); - case ExifTagValue.SubIFDs: return new ExifLongArray(ExifTag.SubIFDs); + case ExifTagValue.FreeOffsets: + return new ExifLongArray(ExifTag.FreeOffsets); + case ExifTagValue.FreeByteCounts: + return new ExifLongArray(ExifTag.FreeByteCounts); + case ExifTagValue.ColorResponseUnit: + return new ExifLongArray(ExifTag.ColorResponseUnit); + case ExifTagValue.TileOffsets: + return new ExifLongArray(ExifTag.TileOffsets); + case ExifTagValue.SMinSampleValue: + return new ExifLongArray(ExifTag.SMinSampleValue); + case ExifTagValue.SMaxSampleValue: + return new ExifLongArray(ExifTag.SMaxSampleValue); + case ExifTagValue.JPEGQTables: + return new ExifLongArray(ExifTag.JPEGQTables); + case ExifTagValue.JPEGDCTables: + return new ExifLongArray(ExifTag.JPEGDCTables); + case ExifTagValue.JPEGACTables: + return new ExifLongArray(ExifTag.JPEGACTables); + case ExifTagValue.StripRowCounts: + return new ExifLongArray(ExifTag.StripRowCounts); + case ExifTagValue.IntergraphRegisters: + return new ExifLongArray(ExifTag.IntergraphRegisters); + case ExifTagValue.TimeZoneOffset: + return new ExifLongArray(ExifTag.TimeZoneOffset); + case ExifTagValue.SubIFDs: + return new ExifLongArray(ExifTag.SubIFDs); - case ExifTagValue.ImageWidth: return new ExifNumber(ExifTag.ImageWidth); - case ExifTagValue.ImageLength: return new ExifNumber(ExifTag.ImageLength); - case ExifTagValue.RowsPerStrip: return new ExifNumber(ExifTag.RowsPerStrip); - case ExifTagValue.TileWidth: return new ExifNumber(ExifTag.TileWidth); - case ExifTagValue.TileLength: return new ExifNumber(ExifTag.TileLength); - case ExifTagValue.BadFaxLines: return new ExifNumber(ExifTag.BadFaxLines); - case ExifTagValue.ConsecutiveBadFaxLines: return new ExifNumber(ExifTag.ConsecutiveBadFaxLines); - case ExifTagValue.PixelXDimension: return new ExifNumber(ExifTag.PixelXDimension); - case ExifTagValue.PixelYDimension: return new ExifNumber(ExifTag.PixelYDimension); + case ExifTagValue.ImageWidth: + return new ExifNumber(ExifTag.ImageWidth); + case ExifTagValue.ImageLength: + return new ExifNumber(ExifTag.ImageLength); + case ExifTagValue.RowsPerStrip: + return new ExifNumber(ExifTag.RowsPerStrip); + case ExifTagValue.TileWidth: + return new ExifNumber(ExifTag.TileWidth); + case ExifTagValue.TileLength: + return new ExifNumber(ExifTag.TileLength); + case ExifTagValue.BadFaxLines: + return new ExifNumber(ExifTag.BadFaxLines); + case ExifTagValue.ConsecutiveBadFaxLines: + return new ExifNumber(ExifTag.ConsecutiveBadFaxLines); + case ExifTagValue.PixelXDimension: + return new ExifNumber(ExifTag.PixelXDimension); + case ExifTagValue.PixelYDimension: + return new ExifNumber(ExifTag.PixelYDimension); - case ExifTagValue.StripByteCounts: return new ExifNumberArray(ExifTag.StripByteCounts); - case ExifTagValue.StripOffsets: return new ExifNumberArray(ExifTag.StripOffsets); - case ExifTagValue.TileByteCounts: return new ExifNumberArray(ExifTag.TileByteCounts); - case ExifTagValue.ImageLayer: return new ExifNumberArray(ExifTag.ImageLayer); + case ExifTagValue.StripByteCounts: + return new ExifNumberArray(ExifTag.StripByteCounts); + case ExifTagValue.StripOffsets: + return new ExifNumberArray(ExifTag.StripOffsets); + case ExifTagValue.TileByteCounts: + return new ExifNumberArray(ExifTag.TileByteCounts); + case ExifTagValue.ImageLayer: + return new ExifNumberArray(ExifTag.ImageLayer); - case ExifTagValue.XPosition: return new ExifRational(ExifTag.XPosition); - case ExifTagValue.YPosition: return new ExifRational(ExifTag.YPosition); - case ExifTagValue.XResolution: return new ExifRational(ExifTag.XResolution); - case ExifTagValue.YResolution: return new ExifRational(ExifTag.YResolution); - case ExifTagValue.BatteryLevel: return new ExifRational(ExifTag.BatteryLevel); - case ExifTagValue.ExposureTime: return new ExifRational(ExifTag.ExposureTime); - case ExifTagValue.FNumber: return new ExifRational(ExifTag.FNumber); - case ExifTagValue.MDScalePixel: return new ExifRational(ExifTag.MDScalePixel); - case ExifTagValue.CompressedBitsPerPixel: return new ExifRational(ExifTag.CompressedBitsPerPixel); - case ExifTagValue.ApertureValue: return new ExifRational(ExifTag.ApertureValue); - case ExifTagValue.MaxApertureValue: return new ExifRational(ExifTag.MaxApertureValue); - case ExifTagValue.SubjectDistance: return new ExifRational(ExifTag.SubjectDistance); - case ExifTagValue.FocalLength: return new ExifRational(ExifTag.FocalLength); - case ExifTagValue.FlashEnergy2: return new ExifRational(ExifTag.FlashEnergy2); - case ExifTagValue.FocalPlaneXResolution2: return new ExifRational(ExifTag.FocalPlaneXResolution2); - case ExifTagValue.FocalPlaneYResolution2: return new ExifRational(ExifTag.FocalPlaneYResolution2); - case ExifTagValue.ExposureIndex2: return new ExifRational(ExifTag.ExposureIndex2); - case ExifTagValue.Humidity: return new ExifRational(ExifTag.Humidity); - case ExifTagValue.Pressure: return new ExifRational(ExifTag.Pressure); - case ExifTagValue.Acceleration: return new ExifRational(ExifTag.Acceleration); - case ExifTagValue.FlashEnergy: return new ExifRational(ExifTag.FlashEnergy); - case ExifTagValue.FocalPlaneXResolution: return new ExifRational(ExifTag.FocalPlaneXResolution); - case ExifTagValue.FocalPlaneYResolution: return new ExifRational(ExifTag.FocalPlaneYResolution); - case ExifTagValue.ExposureIndex: return new ExifRational(ExifTag.ExposureIndex); - case ExifTagValue.DigitalZoomRatio: return new ExifRational(ExifTag.DigitalZoomRatio); - case ExifTagValue.GPSAltitude: return new ExifRational(ExifTag.GPSAltitude); - case ExifTagValue.GPSDOP: return new ExifRational(ExifTag.GPSDOP); - case ExifTagValue.GPSSpeed: return new ExifRational(ExifTag.GPSSpeed); - case ExifTagValue.GPSTrack: return new ExifRational(ExifTag.GPSTrack); - case ExifTagValue.GPSImgDirection: return new ExifRational(ExifTag.GPSImgDirection); - case ExifTagValue.GPSDestBearing: return new ExifRational(ExifTag.GPSDestBearing); - case ExifTagValue.GPSDestDistance: return new ExifRational(ExifTag.GPSDestDistance); + case ExifTagValue.XPosition: + return new ExifRational(ExifTag.XPosition); + case ExifTagValue.YPosition: + return new ExifRational(ExifTag.YPosition); + case ExifTagValue.XResolution: + return new ExifRational(ExifTag.XResolution); + case ExifTagValue.YResolution: + return new ExifRational(ExifTag.YResolution); + case ExifTagValue.BatteryLevel: + return new ExifRational(ExifTag.BatteryLevel); + case ExifTagValue.ExposureTime: + return new ExifRational(ExifTag.ExposureTime); + case ExifTagValue.FNumber: + return new ExifRational(ExifTag.FNumber); + case ExifTagValue.MDScalePixel: + return new ExifRational(ExifTag.MDScalePixel); + case ExifTagValue.CompressedBitsPerPixel: + return new ExifRational(ExifTag.CompressedBitsPerPixel); + case ExifTagValue.ApertureValue: + return new ExifRational(ExifTag.ApertureValue); + case ExifTagValue.MaxApertureValue: + return new ExifRational(ExifTag.MaxApertureValue); + case ExifTagValue.SubjectDistance: + return new ExifRational(ExifTag.SubjectDistance); + case ExifTagValue.FocalLength: + return new ExifRational(ExifTag.FocalLength); + case ExifTagValue.FlashEnergy2: + return new ExifRational(ExifTag.FlashEnergy2); + case ExifTagValue.FocalPlaneXResolution2: + return new ExifRational(ExifTag.FocalPlaneXResolution2); + case ExifTagValue.FocalPlaneYResolution2: + return new ExifRational(ExifTag.FocalPlaneYResolution2); + case ExifTagValue.ExposureIndex2: + return new ExifRational(ExifTag.ExposureIndex2); + case ExifTagValue.Humidity: + return new ExifRational(ExifTag.Humidity); + case ExifTagValue.Pressure: + return new ExifRational(ExifTag.Pressure); + case ExifTagValue.Acceleration: + return new ExifRational(ExifTag.Acceleration); + case ExifTagValue.FlashEnergy: + return new ExifRational(ExifTag.FlashEnergy); + case ExifTagValue.FocalPlaneXResolution: + return new ExifRational(ExifTag.FocalPlaneXResolution); + case ExifTagValue.FocalPlaneYResolution: + return new ExifRational(ExifTag.FocalPlaneYResolution); + case ExifTagValue.ExposureIndex: + return new ExifRational(ExifTag.ExposureIndex); + case ExifTagValue.DigitalZoomRatio: + return new ExifRational(ExifTag.DigitalZoomRatio); + case ExifTagValue.GPSAltitude: + return new ExifRational(ExifTag.GPSAltitude); + case ExifTagValue.GPSDOP: + return new ExifRational(ExifTag.GPSDOP); + case ExifTagValue.GPSSpeed: + return new ExifRational(ExifTag.GPSSpeed); + case ExifTagValue.GPSTrack: + return new ExifRational(ExifTag.GPSTrack); + case ExifTagValue.GPSImgDirection: + return new ExifRational(ExifTag.GPSImgDirection); + case ExifTagValue.GPSDestBearing: + return new ExifRational(ExifTag.GPSDestBearing); + case ExifTagValue.GPSDestDistance: + return new ExifRational(ExifTag.GPSDestDistance); - case ExifTagValue.WhitePoint: return new ExifRationalArray(ExifTag.WhitePoint); - case ExifTagValue.PrimaryChromaticities: return new ExifRationalArray(ExifTag.PrimaryChromaticities); - case ExifTagValue.YCbCrCoefficients: return new ExifRationalArray(ExifTag.YCbCrCoefficients); - case ExifTagValue.ReferenceBlackWhite: return new ExifRationalArray(ExifTag.ReferenceBlackWhite); - case ExifTagValue.GPSLatitude: return new ExifRationalArray(ExifTag.GPSLatitude); - case ExifTagValue.GPSLongitude: return new ExifRationalArray(ExifTag.GPSLongitude); - case ExifTagValue.GPSTimestamp: return new ExifRationalArray(ExifTag.GPSTimestamp); - case ExifTagValue.GPSDestLatitude: return new ExifRationalArray(ExifTag.GPSDestLatitude); - case ExifTagValue.GPSDestLongitude: return new ExifRationalArray(ExifTag.GPSDestLongitude); - case ExifTagValue.LensSpecification: return new ExifRationalArray(ExifTag.LensSpecification); + case ExifTagValue.WhitePoint: + return new ExifRationalArray(ExifTag.WhitePoint); + case ExifTagValue.PrimaryChromaticities: + return new ExifRationalArray(ExifTag.PrimaryChromaticities); + case ExifTagValue.YCbCrCoefficients: + return new ExifRationalArray(ExifTag.YCbCrCoefficients); + case ExifTagValue.ReferenceBlackWhite: + return new ExifRationalArray(ExifTag.ReferenceBlackWhite); + case ExifTagValue.GPSLatitude: + return new ExifRationalArray(ExifTag.GPSLatitude); + case ExifTagValue.GPSLongitude: + return new ExifRationalArray(ExifTag.GPSLongitude); + case ExifTagValue.GPSTimestamp: + return new ExifRationalArray(ExifTag.GPSTimestamp); + case ExifTagValue.GPSDestLatitude: + return new ExifRationalArray(ExifTag.GPSDestLatitude); + case ExifTagValue.GPSDestLongitude: + return new ExifRationalArray(ExifTag.GPSDestLongitude); + case ExifTagValue.LensSpecification: + return new ExifRationalArray(ExifTag.LensSpecification); - case ExifTagValue.OldSubfileType: return new ExifShort(ExifTag.OldSubfileType); - case ExifTagValue.Compression: return new ExifShort(ExifTag.Compression); - case ExifTagValue.PhotometricInterpretation: return new ExifShort(ExifTag.PhotometricInterpretation); - case ExifTagValue.Thresholding: return new ExifShort(ExifTag.Thresholding); - case ExifTagValue.CellWidth: return new ExifShort(ExifTag.CellWidth); - case ExifTagValue.CellLength: return new ExifShort(ExifTag.CellLength); - case ExifTagValue.FillOrder: return new ExifShort(ExifTag.FillOrder); - case ExifTagValue.Orientation: return new ExifShort(ExifTag.Orientation); - case ExifTagValue.SamplesPerPixel: return new ExifShort(ExifTag.SamplesPerPixel); - case ExifTagValue.PlanarConfiguration: return new ExifShort(ExifTag.PlanarConfiguration); - case ExifTagValue.Predictor: return new ExifShort(ExifTag.Predictor); - case ExifTagValue.GrayResponseUnit: return new ExifShort(ExifTag.GrayResponseUnit); - case ExifTagValue.ResolutionUnit: return new ExifShort(ExifTag.ResolutionUnit); - case ExifTagValue.CleanFaxData: return new ExifShort(ExifTag.CleanFaxData); - case ExifTagValue.InkSet: return new ExifShort(ExifTag.InkSet); - case ExifTagValue.NumberOfInks: return new ExifShort(ExifTag.NumberOfInks); - case ExifTagValue.DotRange: return new ExifShort(ExifTag.DotRange); - case ExifTagValue.Indexed: return new ExifShort(ExifTag.Indexed); - case ExifTagValue.OPIProxy: return new ExifShort(ExifTag.OPIProxy); - case ExifTagValue.JPEGProc: return new ExifShort(ExifTag.JPEGProc); - case ExifTagValue.JPEGRestartInterval: return new ExifShort(ExifTag.JPEGRestartInterval); - case ExifTagValue.YCbCrPositioning: return new ExifShort(ExifTag.YCbCrPositioning); - case ExifTagValue.Rating: return new ExifShort(ExifTag.Rating); - case ExifTagValue.RatingPercent: return new ExifShort(ExifTag.RatingPercent); - case ExifTagValue.ExposureProgram: return new ExifShort(ExifTag.ExposureProgram); - case ExifTagValue.Interlace: return new ExifShort(ExifTag.Interlace); - case ExifTagValue.SelfTimerMode: return new ExifShort(ExifTag.SelfTimerMode); - case ExifTagValue.SensitivityType: return new ExifShort(ExifTag.SensitivityType); - case ExifTagValue.MeteringMode: return new ExifShort(ExifTag.MeteringMode); - case ExifTagValue.LightSource: return new ExifShort(ExifTag.LightSource); - case ExifTagValue.FocalPlaneResolutionUnit2: return new ExifShort(ExifTag.FocalPlaneResolutionUnit2); - case ExifTagValue.SensingMethod2: return new ExifShort(ExifTag.SensingMethod2); - case ExifTagValue.Flash: return new ExifShort(ExifTag.Flash); - case ExifTagValue.ColorSpace: return new ExifShort(ExifTag.ColorSpace); - case ExifTagValue.FocalPlaneResolutionUnit: return new ExifShort(ExifTag.FocalPlaneResolutionUnit); - case ExifTagValue.SensingMethod: return new ExifShort(ExifTag.SensingMethod); - case ExifTagValue.CustomRendered: return new ExifShort(ExifTag.CustomRendered); - case ExifTagValue.ExposureMode: return new ExifShort(ExifTag.ExposureMode); - case ExifTagValue.WhiteBalance: return new ExifShort(ExifTag.WhiteBalance); - case ExifTagValue.FocalLengthIn35mmFilm: return new ExifShort(ExifTag.FocalLengthIn35mmFilm); - case ExifTagValue.SceneCaptureType: return new ExifShort(ExifTag.SceneCaptureType); - case ExifTagValue.GainControl: return new ExifShort(ExifTag.GainControl); - case ExifTagValue.Contrast: return new ExifShort(ExifTag.Contrast); - case ExifTagValue.Saturation: return new ExifShort(ExifTag.Saturation); - case ExifTagValue.Sharpness: return new ExifShort(ExifTag.Sharpness); - case ExifTagValue.SubjectDistanceRange: return new ExifShort(ExifTag.SubjectDistanceRange); - case ExifTagValue.GPSDifferential: return new ExifShort(ExifTag.GPSDifferential); + case ExifTagValue.OldSubfileType: + return new ExifShort(ExifTag.OldSubfileType); + case ExifTagValue.Compression: + return new ExifShort(ExifTag.Compression); + case ExifTagValue.PhotometricInterpretation: + return new ExifShort(ExifTag.PhotometricInterpretation); + case ExifTagValue.Thresholding: + return new ExifShort(ExifTag.Thresholding); + case ExifTagValue.CellWidth: + return new ExifShort(ExifTag.CellWidth); + case ExifTagValue.CellLength: + return new ExifShort(ExifTag.CellLength); + case ExifTagValue.FillOrder: + return new ExifShort(ExifTag.FillOrder); + case ExifTagValue.Orientation: + return new ExifShort(ExifTag.Orientation); + case ExifTagValue.SamplesPerPixel: + return new ExifShort(ExifTag.SamplesPerPixel); + case ExifTagValue.PlanarConfiguration: + return new ExifShort(ExifTag.PlanarConfiguration); + case ExifTagValue.Predictor: + return new ExifShort(ExifTag.Predictor); + case ExifTagValue.GrayResponseUnit: + return new ExifShort(ExifTag.GrayResponseUnit); + case ExifTagValue.ResolutionUnit: + return new ExifShort(ExifTag.ResolutionUnit); + case ExifTagValue.CleanFaxData: + return new ExifShort(ExifTag.CleanFaxData); + case ExifTagValue.InkSet: + return new ExifShort(ExifTag.InkSet); + case ExifTagValue.NumberOfInks: + return new ExifShort(ExifTag.NumberOfInks); + case ExifTagValue.DotRange: + return new ExifShort(ExifTag.DotRange); + case ExifTagValue.Indexed: + return new ExifShort(ExifTag.Indexed); + case ExifTagValue.OPIProxy: + return new ExifShort(ExifTag.OPIProxy); + case ExifTagValue.JPEGProc: + return new ExifShort(ExifTag.JPEGProc); + case ExifTagValue.JPEGRestartInterval: + return new ExifShort(ExifTag.JPEGRestartInterval); + case ExifTagValue.YCbCrPositioning: + return new ExifShort(ExifTag.YCbCrPositioning); + case ExifTagValue.Rating: + return new ExifShort(ExifTag.Rating); + case ExifTagValue.RatingPercent: + return new ExifShort(ExifTag.RatingPercent); + case ExifTagValue.ExposureProgram: + return new ExifShort(ExifTag.ExposureProgram); + case ExifTagValue.Interlace: + return new ExifShort(ExifTag.Interlace); + case ExifTagValue.SelfTimerMode: + return new ExifShort(ExifTag.SelfTimerMode); + case ExifTagValue.SensitivityType: + return new ExifShort(ExifTag.SensitivityType); + case ExifTagValue.MeteringMode: + return new ExifShort(ExifTag.MeteringMode); + case ExifTagValue.LightSource: + return new ExifShort(ExifTag.LightSource); + case ExifTagValue.FocalPlaneResolutionUnit2: + return new ExifShort(ExifTag.FocalPlaneResolutionUnit2); + case ExifTagValue.SensingMethod2: + return new ExifShort(ExifTag.SensingMethod2); + case ExifTagValue.Flash: + return new ExifShort(ExifTag.Flash); + case ExifTagValue.ColorSpace: + return new ExifShort(ExifTag.ColorSpace); + case ExifTagValue.FocalPlaneResolutionUnit: + return new ExifShort(ExifTag.FocalPlaneResolutionUnit); + case ExifTagValue.SensingMethod: + return new ExifShort(ExifTag.SensingMethod); + case ExifTagValue.CustomRendered: + return new ExifShort(ExifTag.CustomRendered); + case ExifTagValue.ExposureMode: + return new ExifShort(ExifTag.ExposureMode); + case ExifTagValue.WhiteBalance: + return new ExifShort(ExifTag.WhiteBalance); + case ExifTagValue.FocalLengthIn35mmFilm: + return new ExifShort(ExifTag.FocalLengthIn35mmFilm); + case ExifTagValue.SceneCaptureType: + return new ExifShort(ExifTag.SceneCaptureType); + case ExifTagValue.GainControl: + return new ExifShort(ExifTag.GainControl); + case ExifTagValue.Contrast: + return new ExifShort(ExifTag.Contrast); + case ExifTagValue.Saturation: + return new ExifShort(ExifTag.Saturation); + case ExifTagValue.Sharpness: + return new ExifShort(ExifTag.Sharpness); + case ExifTagValue.SubjectDistanceRange: + return new ExifShort(ExifTag.SubjectDistanceRange); + case ExifTagValue.GPSDifferential: + return new ExifShort(ExifTag.GPSDifferential); - case ExifTagValue.BitsPerSample: return new ExifShortArray(ExifTag.BitsPerSample); - case ExifTagValue.MinSampleValue: return new ExifShortArray(ExifTag.MinSampleValue); - case ExifTagValue.MaxSampleValue: return new ExifShortArray(ExifTag.MaxSampleValue); - case ExifTagValue.GrayResponseCurve: return new ExifShortArray(ExifTag.GrayResponseCurve); - case ExifTagValue.ColorMap: return new ExifShortArray(ExifTag.ColorMap); - case ExifTagValue.ExtraSamples: return new ExifShortArray(ExifTag.ExtraSamples); - case ExifTagValue.PageNumber: return new ExifShortArray(ExifTag.PageNumber); - case ExifTagValue.TransferFunction: return new ExifShortArray(ExifTag.TransferFunction); - case ExifTagValue.HalftoneHints: return new ExifShortArray(ExifTag.HalftoneHints); - case ExifTagValue.SampleFormat: return new ExifShortArray(ExifTag.SampleFormat); - case ExifTagValue.TransferRange: return new ExifShortArray(ExifTag.TransferRange); - case ExifTagValue.DefaultImageColor: return new ExifShortArray(ExifTag.DefaultImageColor); - case ExifTagValue.JPEGLosslessPredictors: return new ExifShortArray(ExifTag.JPEGLosslessPredictors); - case ExifTagValue.JPEGPointTransforms: return new ExifShortArray(ExifTag.JPEGPointTransforms); - case ExifTagValue.YCbCrSubsampling: return new ExifShortArray(ExifTag.YCbCrSubsampling); - case ExifTagValue.CFARepeatPatternDim: return new ExifShortArray(ExifTag.CFARepeatPatternDim); - case ExifTagValue.IntergraphPacketData: return new ExifShortArray(ExifTag.IntergraphPacketData); - case ExifTagValue.ISOSpeedRatings: return new ExifShortArray(ExifTag.ISOSpeedRatings); - case ExifTagValue.SubjectArea: return new ExifShortArray(ExifTag.SubjectArea); - case ExifTagValue.SubjectLocation: return new ExifShortArray(ExifTag.SubjectLocation); + case ExifTagValue.BitsPerSample: + return new ExifShortArray(ExifTag.BitsPerSample); + case ExifTagValue.MinSampleValue: + return new ExifShortArray(ExifTag.MinSampleValue); + case ExifTagValue.MaxSampleValue: + return new ExifShortArray(ExifTag.MaxSampleValue); + case ExifTagValue.GrayResponseCurve: + return new ExifShortArray(ExifTag.GrayResponseCurve); + case ExifTagValue.ColorMap: + return new ExifShortArray(ExifTag.ColorMap); + case ExifTagValue.ExtraSamples: + return new ExifShortArray(ExifTag.ExtraSamples); + case ExifTagValue.PageNumber: + return new ExifShortArray(ExifTag.PageNumber); + case ExifTagValue.TransferFunction: + return new ExifShortArray(ExifTag.TransferFunction); + case ExifTagValue.HalftoneHints: + return new ExifShortArray(ExifTag.HalftoneHints); + case ExifTagValue.SampleFormat: + return new ExifShortArray(ExifTag.SampleFormat); + case ExifTagValue.TransferRange: + return new ExifShortArray(ExifTag.TransferRange); + case ExifTagValue.DefaultImageColor: + return new ExifShortArray(ExifTag.DefaultImageColor); + case ExifTagValue.JPEGLosslessPredictors: + return new ExifShortArray(ExifTag.JPEGLosslessPredictors); + case ExifTagValue.JPEGPointTransforms: + return new ExifShortArray(ExifTag.JPEGPointTransforms); + case ExifTagValue.YCbCrSubsampling: + return new ExifShortArray(ExifTag.YCbCrSubsampling); + case ExifTagValue.CFARepeatPatternDim: + return new ExifShortArray(ExifTag.CFARepeatPatternDim); + case ExifTagValue.IntergraphPacketData: + return new ExifShortArray(ExifTag.IntergraphPacketData); + case ExifTagValue.ISOSpeedRatings: + return new ExifShortArray(ExifTag.ISOSpeedRatings); + case ExifTagValue.SubjectArea: + return new ExifShortArray(ExifTag.SubjectArea); + case ExifTagValue.SubjectLocation: + return new ExifShortArray(ExifTag.SubjectLocation); - case ExifTagValue.ShutterSpeedValue: return new ExifSignedRational(ExifTag.ShutterSpeedValue); - case ExifTagValue.BrightnessValue: return new ExifSignedRational(ExifTag.BrightnessValue); - case ExifTagValue.ExposureBiasValue: return new ExifSignedRational(ExifTag.ExposureBiasValue); - case ExifTagValue.AmbientTemperature: return new ExifSignedRational(ExifTag.AmbientTemperature); - case ExifTagValue.WaterDepth: return new ExifSignedRational(ExifTag.WaterDepth); - case ExifTagValue.CameraElevationAngle: return new ExifSignedRational(ExifTag.CameraElevationAngle); + case ExifTagValue.ShutterSpeedValue: + return new ExifSignedRational(ExifTag.ShutterSpeedValue); + case ExifTagValue.BrightnessValue: + return new ExifSignedRational(ExifTag.BrightnessValue); + case ExifTagValue.ExposureBiasValue: + return new ExifSignedRational(ExifTag.ExposureBiasValue); + case ExifTagValue.AmbientTemperature: + return new ExifSignedRational(ExifTag.AmbientTemperature); + case ExifTagValue.WaterDepth: + return new ExifSignedRational(ExifTag.WaterDepth); + case ExifTagValue.CameraElevationAngle: + return new ExifSignedRational(ExifTag.CameraElevationAngle); - case ExifTagValue.Decode: return new ExifSignedRationalArray(ExifTag.Decode); + case ExifTagValue.Decode: + return new ExifSignedRationalArray(ExifTag.Decode); - case ExifTagValue.ImageDescription: return new ExifString(ExifTag.ImageDescription); - case ExifTagValue.Make: return new ExifString(ExifTag.Make); - case ExifTagValue.Model: return new ExifString(ExifTag.Model); - case ExifTagValue.Software: return new ExifString(ExifTag.Software); - case ExifTagValue.DateTime: return new ExifString(ExifTag.DateTime); - case ExifTagValue.Artist: return new ExifString(ExifTag.Artist); - case ExifTagValue.HostComputer: return new ExifString(ExifTag.HostComputer); - case ExifTagValue.Copyright: return new ExifString(ExifTag.Copyright); - case ExifTagValue.DocumentName: return new ExifString(ExifTag.DocumentName); - case ExifTagValue.PageName: return new ExifString(ExifTag.PageName); - case ExifTagValue.InkNames: return new ExifString(ExifTag.InkNames); - case ExifTagValue.TargetPrinter: return new ExifString(ExifTag.TargetPrinter); - case ExifTagValue.ImageID: return new ExifString(ExifTag.ImageID); - case ExifTagValue.MDLabName: return new ExifString(ExifTag.MDLabName); - case ExifTagValue.MDSampleInfo: return new ExifString(ExifTag.MDSampleInfo); - case ExifTagValue.MDPrepDate: return new ExifString(ExifTag.MDPrepDate); - case ExifTagValue.MDPrepTime: return new ExifString(ExifTag.MDPrepTime); - case ExifTagValue.MDFileUnits: return new ExifString(ExifTag.MDFileUnits); - case ExifTagValue.SEMInfo: return new ExifString(ExifTag.SEMInfo); - case ExifTagValue.SpectralSensitivity: return new ExifString(ExifTag.SpectralSensitivity); - case ExifTagValue.DateTimeOriginal: return new ExifString(ExifTag.DateTimeOriginal); - case ExifTagValue.DateTimeDigitized: return new ExifString(ExifTag.DateTimeDigitized); - case ExifTagValue.SubsecTime: return new ExifString(ExifTag.SubsecTime); - case ExifTagValue.SubsecTimeOriginal: return new ExifString(ExifTag.SubsecTimeOriginal); - case ExifTagValue.SubsecTimeDigitized: return new ExifString(ExifTag.SubsecTimeDigitized); - case ExifTagValue.RelatedSoundFile: return new ExifString(ExifTag.RelatedSoundFile); - case ExifTagValue.FaxSubaddress: return new ExifString(ExifTag.FaxSubaddress); - case ExifTagValue.OffsetTime: return new ExifString(ExifTag.OffsetTime); - case ExifTagValue.OffsetTimeOriginal: return new ExifString(ExifTag.OffsetTimeOriginal); - case ExifTagValue.OffsetTimeDigitized: return new ExifString(ExifTag.OffsetTimeDigitized); - case ExifTagValue.SecurityClassification: return new ExifString(ExifTag.SecurityClassification); - case ExifTagValue.ImageHistory: return new ExifString(ExifTag.ImageHistory); - case ExifTagValue.ImageUniqueID: return new ExifString(ExifTag.ImageUniqueID); - case ExifTagValue.OwnerName: return new ExifString(ExifTag.OwnerName); - case ExifTagValue.SerialNumber: return new ExifString(ExifTag.SerialNumber); - case ExifTagValue.LensMake: return new ExifString(ExifTag.LensMake); - case ExifTagValue.LensModel: return new ExifString(ExifTag.LensModel); - case ExifTagValue.LensSerialNumber: return new ExifString(ExifTag.LensSerialNumber); - case ExifTagValue.GDALMetadata: return new ExifString(ExifTag.GDALMetadata); - case ExifTagValue.GDALNoData: return new ExifString(ExifTag.GDALNoData); - case ExifTagValue.GPSLatitudeRef: return new ExifString(ExifTag.GPSLatitudeRef); - case ExifTagValue.GPSLongitudeRef: return new ExifString(ExifTag.GPSLongitudeRef); - case ExifTagValue.GPSSatellites: return new ExifString(ExifTag.GPSSatellites); - case ExifTagValue.GPSStatus: return new ExifString(ExifTag.GPSStatus); - case ExifTagValue.GPSMeasureMode: return new ExifString(ExifTag.GPSMeasureMode); - case ExifTagValue.GPSSpeedRef: return new ExifString(ExifTag.GPSSpeedRef); - case ExifTagValue.GPSTrackRef: return new ExifString(ExifTag.GPSTrackRef); - case ExifTagValue.GPSImgDirectionRef: return new ExifString(ExifTag.GPSImgDirectionRef); - case ExifTagValue.GPSMapDatum: return new ExifString(ExifTag.GPSMapDatum); - case ExifTagValue.GPSDestLatitudeRef: return new ExifString(ExifTag.GPSDestLatitudeRef); - case ExifTagValue.GPSDestLongitudeRef: return new ExifString(ExifTag.GPSDestLongitudeRef); - case ExifTagValue.GPSDestBearingRef: return new ExifString(ExifTag.GPSDestBearingRef); - case ExifTagValue.GPSDestDistanceRef: return new ExifString(ExifTag.GPSDestDistanceRef); - case ExifTagValue.GPSDateStamp: return new ExifString(ExifTag.GPSDateStamp); + case ExifTagValue.ImageDescription: + return new ExifString(ExifTag.ImageDescription); + case ExifTagValue.Make: + return new ExifString(ExifTag.Make); + case ExifTagValue.Model: + return new ExifString(ExifTag.Model); + case ExifTagValue.Software: + return new ExifString(ExifTag.Software); + case ExifTagValue.DateTime: + return new ExifString(ExifTag.DateTime); + case ExifTagValue.Artist: + return new ExifString(ExifTag.Artist); + case ExifTagValue.HostComputer: + return new ExifString(ExifTag.HostComputer); + case ExifTagValue.Copyright: + return new ExifString(ExifTag.Copyright); + case ExifTagValue.DocumentName: + return new ExifString(ExifTag.DocumentName); + case ExifTagValue.PageName: + return new ExifString(ExifTag.PageName); + case ExifTagValue.InkNames: + return new ExifString(ExifTag.InkNames); + case ExifTagValue.TargetPrinter: + return new ExifString(ExifTag.TargetPrinter); + case ExifTagValue.ImageID: + return new ExifString(ExifTag.ImageID); + case ExifTagValue.MDLabName: + return new ExifString(ExifTag.MDLabName); + case ExifTagValue.MDSampleInfo: + return new ExifString(ExifTag.MDSampleInfo); + case ExifTagValue.MDPrepDate: + return new ExifString(ExifTag.MDPrepDate); + case ExifTagValue.MDPrepTime: + return new ExifString(ExifTag.MDPrepTime); + case ExifTagValue.MDFileUnits: + return new ExifString(ExifTag.MDFileUnits); + case ExifTagValue.SEMInfo: + return new ExifString(ExifTag.SEMInfo); + case ExifTagValue.SpectralSensitivity: + return new ExifString(ExifTag.SpectralSensitivity); + case ExifTagValue.DateTimeOriginal: + return new ExifString(ExifTag.DateTimeOriginal); + case ExifTagValue.DateTimeDigitized: + return new ExifString(ExifTag.DateTimeDigitized); + case ExifTagValue.SubsecTime: + return new ExifString(ExifTag.SubsecTime); + case ExifTagValue.SubsecTimeOriginal: + return new ExifString(ExifTag.SubsecTimeOriginal); + case ExifTagValue.SubsecTimeDigitized: + return new ExifString(ExifTag.SubsecTimeDigitized); + case ExifTagValue.RelatedSoundFile: + return new ExifString(ExifTag.RelatedSoundFile); + case ExifTagValue.FaxSubaddress: + return new ExifString(ExifTag.FaxSubaddress); + case ExifTagValue.OffsetTime: + return new ExifString(ExifTag.OffsetTime); + case ExifTagValue.OffsetTimeOriginal: + return new ExifString(ExifTag.OffsetTimeOriginal); + case ExifTagValue.OffsetTimeDigitized: + return new ExifString(ExifTag.OffsetTimeDigitized); + case ExifTagValue.SecurityClassification: + return new ExifString(ExifTag.SecurityClassification); + case ExifTagValue.ImageHistory: + return new ExifString(ExifTag.ImageHistory); + case ExifTagValue.ImageUniqueID: + return new ExifString(ExifTag.ImageUniqueID); + case ExifTagValue.OwnerName: + return new ExifString(ExifTag.OwnerName); + case ExifTagValue.SerialNumber: + return new ExifString(ExifTag.SerialNumber); + case ExifTagValue.LensMake: + return new ExifString(ExifTag.LensMake); + case ExifTagValue.LensModel: + return new ExifString(ExifTag.LensModel); + case ExifTagValue.LensSerialNumber: + return new ExifString(ExifTag.LensSerialNumber); + case ExifTagValue.GDALMetadata: + return new ExifString(ExifTag.GDALMetadata); + case ExifTagValue.GDALNoData: + return new ExifString(ExifTag.GDALNoData); + case ExifTagValue.GPSLatitudeRef: + return new ExifString(ExifTag.GPSLatitudeRef); + case ExifTagValue.GPSLongitudeRef: + return new ExifString(ExifTag.GPSLongitudeRef); + case ExifTagValue.GPSSatellites: + return new ExifString(ExifTag.GPSSatellites); + case ExifTagValue.GPSStatus: + return new ExifString(ExifTag.GPSStatus); + case ExifTagValue.GPSMeasureMode: + return new ExifString(ExifTag.GPSMeasureMode); + case ExifTagValue.GPSSpeedRef: + return new ExifString(ExifTag.GPSSpeedRef); + case ExifTagValue.GPSTrackRef: + return new ExifString(ExifTag.GPSTrackRef); + case ExifTagValue.GPSImgDirectionRef: + return new ExifString(ExifTag.GPSImgDirectionRef); + case ExifTagValue.GPSMapDatum: + return new ExifString(ExifTag.GPSMapDatum); + case ExifTagValue.GPSDestLatitudeRef: + return new ExifString(ExifTag.GPSDestLatitudeRef); + case ExifTagValue.GPSDestLongitudeRef: + return new ExifString(ExifTag.GPSDestLongitudeRef); + case ExifTagValue.GPSDestBearingRef: + return new ExifString(ExifTag.GPSDestBearingRef); + case ExifTagValue.GPSDestDistanceRef: + return new ExifString(ExifTag.GPSDestDistanceRef); + case ExifTagValue.GPSDateStamp: + return new ExifString(ExifTag.GPSDateStamp); - case ExifTagValue.FileSource: return new ExifByte(ExifTag.FileSource, ExifDataType.Undefined); - case ExifTagValue.SceneType: return new ExifByte(ExifTag.SceneType, ExifDataType.Undefined); + case ExifTagValue.FileSource: + return new ExifByte(ExifTag.FileSource, ExifDataType.Undefined); + case ExifTagValue.SceneType: + return new ExifByte(ExifTag.SceneType, ExifDataType.Undefined); - case ExifTagValue.JPEGTables: return new ExifByteArray(ExifTag.JPEGTables, ExifDataType.Undefined); - case ExifTagValue.OECF: return new ExifByteArray(ExifTag.OECF, ExifDataType.Undefined); - case ExifTagValue.ExifVersion: return new ExifByteArray(ExifTag.ExifVersion, ExifDataType.Undefined); - case ExifTagValue.ComponentsConfiguration: return new ExifByteArray(ExifTag.ComponentsConfiguration, ExifDataType.Undefined); - case ExifTagValue.MakerNote: return new ExifByteArray(ExifTag.MakerNote, ExifDataType.Undefined); - case ExifTagValue.UserComment: return new ExifByteArray(ExifTag.UserComment, ExifDataType.Undefined); - case ExifTagValue.FlashpixVersion: return new ExifByteArray(ExifTag.FlashpixVersion, ExifDataType.Undefined); - case ExifTagValue.SpatialFrequencyResponse: return new ExifByteArray(ExifTag.SpatialFrequencyResponse, ExifDataType.Undefined); - case ExifTagValue.SpatialFrequencyResponse2: return new ExifByteArray(ExifTag.SpatialFrequencyResponse2, ExifDataType.Undefined); - case ExifTagValue.Noise: return new ExifByteArray(ExifTag.Noise, ExifDataType.Undefined); - case ExifTagValue.CFAPattern: return new ExifByteArray(ExifTag.CFAPattern, ExifDataType.Undefined); - case ExifTagValue.DeviceSettingDescription: return new ExifByteArray(ExifTag.DeviceSettingDescription, ExifDataType.Undefined); - case ExifTagValue.ImageSourceData: return new ExifByteArray(ExifTag.ImageSourceData, ExifDataType.Undefined); - case ExifTagValue.GPSProcessingMethod: return new ExifByteArray(ExifTag.GPSProcessingMethod, ExifDataType.Undefined); - case ExifTagValue.GPSAreaInformation: return new ExifByteArray(ExifTag.GPSAreaInformation, ExifDataType.Undefined); + case ExifTagValue.JPEGTables: + return new ExifByteArray(ExifTag.JPEGTables, ExifDataType.Undefined); + case ExifTagValue.OECF: + return new ExifByteArray(ExifTag.OECF, ExifDataType.Undefined); + case ExifTagValue.ExifVersion: + return new ExifByteArray(ExifTag.ExifVersion, ExifDataType.Undefined); + case ExifTagValue.ComponentsConfiguration: + return new ExifByteArray(ExifTag.ComponentsConfiguration, ExifDataType.Undefined); + case ExifTagValue.MakerNote: + return new ExifByteArray(ExifTag.MakerNote, ExifDataType.Undefined); + case ExifTagValue.FlashpixVersion: + return new ExifByteArray(ExifTag.FlashpixVersion, ExifDataType.Undefined); + case ExifTagValue.SpatialFrequencyResponse: + return new ExifByteArray(ExifTag.SpatialFrequencyResponse, ExifDataType.Undefined); + case ExifTagValue.SpatialFrequencyResponse2: + return new ExifByteArray(ExifTag.SpatialFrequencyResponse2, ExifDataType.Undefined); + case ExifTagValue.Noise: + return new ExifByteArray(ExifTag.Noise, ExifDataType.Undefined); + case ExifTagValue.CFAPattern: + return new ExifByteArray(ExifTag.CFAPattern, ExifDataType.Undefined); + case ExifTagValue.DeviceSettingDescription: + return new ExifByteArray(ExifTag.DeviceSettingDescription, ExifDataType.Undefined); + case ExifTagValue.ImageSourceData: + return new ExifByteArray(ExifTag.ImageSourceData, ExifDataType.Undefined); - default: return null; + case ExifTagValue.XPTitle: + return new ExifUcs2String(ExifTag.XPTitle); + case ExifTagValue.XPComment: + return new ExifUcs2String(ExifTag.XPComment); + case ExifTagValue.XPAuthor: + return new ExifUcs2String(ExifTag.XPAuthor); + case ExifTagValue.XPKeywords: + return new ExifUcs2String(ExifTag.XPKeywords); + case ExifTagValue.XPSubject: + return new ExifUcs2String(ExifTag.XPSubject); + + case ExifTagValue.UserComment: + return new ExifEncodedString(ExifTag.UserComment); + case ExifTagValue.GPSProcessingMethod: + return new ExifEncodedString(ExifTag.GPSProcessingMethod); + case ExifTagValue.GPSAreaInformation: + return new ExifEncodedString(ExifTag.GPSAreaInformation); + + default: + return null; } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index 53c81631de..840cc9f685 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Runtime.CompilerServices; +using System.Text; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Metadata; @@ -300,5 +301,72 @@ public void Decode_WithInvalidIptcTag_DoesNotThrowException(TestImagePro }); Assert.Null(ex); } + + [Fact] + public void EncodedStringTags_WriteAndRead() + { + using var memoryStream = new MemoryStream(); + using (var image = Image.Load(TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora))) + { + var exif = new ExifProfile(); + + exif.SetValue(ExifTag.GPSDateStamp, "2022-01-06"); + + exif.SetValue(ExifTag.XPTitle, "A bit of test metadata for image title"); + exif.SetValue(ExifTag.XPComment, "A bit of test metadata for image comment"); + exif.SetValue(ExifTag.XPAuthor, "Dan Petitt"); + exif.SetValue(ExifTag.XPKeywords, "Keyword1;Keyword2"); + exif.SetValue(ExifTag.XPSubject, "This is a subject"); + + // exif.SetValue(ExifTag.UserComment, new EncodedString(EncodedString.CharacterCode.JIS, "ビッ")); + exif.SetValue(ExifTag.UserComment, new EncodedString(EncodedString.CharacterCode.JIS, "eng comment text (JIS)")); + + exif.SetValue(ExifTag.GPSProcessingMethod, new EncodedString(EncodedString.CharacterCode.ASCII, "GPS processing method (ASCII)")); + exif.SetValue(ExifTag.GPSAreaInformation, new EncodedString(EncodedString.CharacterCode.Unicode, "GPS area info (Unicode)")); + + image.Metadata.ExifProfile = exif; + + image.Save(memoryStream, new JpegEncoder()); + } + + memoryStream.Seek(0, SeekOrigin.Begin); + using (var image = Image.Load(memoryStream)) + { + ExifProfile exif = image.Metadata.ExifProfile; + VerifyEncodedStrings(exif); + } + } + + [Fact] + public void EncodedStringTags_Read() + { + using (var image = Image.Load(TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora_EncodedStrings))) + { + ExifProfile exif = image.Metadata.ExifProfile; + VerifyEncodedStrings(exif); + } + } + + private static void VerifyEncodedStrings(ExifProfile exif) + { + Assert.NotNull(exif); + + Assert.Equal("2022-01-06", exif.GetValue(ExifTag.GPSDateStamp).Value); + + Assert.Equal("A bit of test metadata for image title", exif.GetValue(ExifTag.XPTitle).Value); + Assert.Equal("A bit of test metadata for image comment", exif.GetValue(ExifTag.XPComment).Value); + Assert.Equal("Dan Petitt", exif.GetValue(ExifTag.XPAuthor).Value); + Assert.Equal("Keyword1;Keyword2", exif.GetValue(ExifTag.XPKeywords).Value); + Assert.Equal("This is a subject", exif.GetValue(ExifTag.XPSubject).Value); + + Assert.Equal("eng comment text (JIS)", exif.GetValue(ExifTag.UserComment).Value.Text); + Assert.Equal(EncodedString.CharacterCode.JIS, exif.GetValue(ExifTag.UserComment).Value.Code); + + Assert.Equal("GPS processing method (ASCII)", exif.GetValue(ExifTag.GPSProcessingMethod).Value.Text); + Assert.Equal(EncodedString.CharacterCode.ASCII, exif.GetValue(ExifTag.GPSProcessingMethod).Value.Code); + + Assert.Equal("GPS area info (Unicode)", (string)exif.GetValue(ExifTag.GPSAreaInformation).Value); + Assert.Equal(EncodedString.CharacterCode.Unicode, exif.GetValue(ExifTag.GPSAreaInformation).Value.Code); + } } } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 7fc3ff6f19..a859852279 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -51,6 +51,9 @@ public enum TestImageWriteFormat { ExifTag.ImageDescription, "ImageDescription" }, { ExifTag.ExposureTime, new Rational(1.0 / 1600.0) }, { ExifTag.Model, "Model" }, + { ExifTag.XPAuthor, "The XPAuthor text" }, + { ExifTag.UserComment, new EncodedString(EncodedString.CharacterCode.Unicode, "The Unicode text") }, + { ExifTag.GPSAreaInformation, new EncodedString("Default constructor text (GPSAreaInformation)") }, }; [Theory] @@ -504,7 +507,7 @@ private static ExifProfile CreateExifProfile() public void IfdStructure() { var exif = new ExifProfile(); - exif.SetValue(ExifTag.XPAuthor, Encoding.GetEncoding("UCS-2").GetBytes("Dan Petitt")); + exif.SetValue(ExifTag.XPAuthor, "Dan Petitt"); Span actualBytes = exif.ToByteArray(); diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs index a5ca115d49..aaad4e2306 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Text; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using Xunit; @@ -23,11 +25,6 @@ public class ExifValuesTests { ExifTag.XMP }, { ExifTag.CFAPattern2 }, { ExifTag.TIFFEPStandardID }, - { ExifTag.XPTitle }, - { ExifTag.XPComment }, - { ExifTag.XPAuthor }, - { ExifTag.XPKeywords }, - { ExifTag.XPSubject }, { ExifTag.GPSVersionID }, }; @@ -295,7 +292,7 @@ public class ExifValuesTests { ExifTag.GPSDestLongitudeRef }, { ExifTag.GPSDestBearingRef }, { ExifTag.GPSDestDistanceRef }, - { ExifTag.GPSDateStamp } + { ExifTag.GPSDateStamp }, }; public static TheoryData UndefinedTags => new TheoryData @@ -311,7 +308,6 @@ public class ExifValuesTests { ExifTag.ExifVersion }, { ExifTag.ComponentsConfiguration }, { ExifTag.MakerNote }, - { ExifTag.UserComment }, { ExifTag.FlashpixVersion }, { ExifTag.SpatialFrequencyResponse }, { ExifTag.SpatialFrequencyResponse2 }, @@ -319,10 +315,24 @@ public class ExifValuesTests { ExifTag.CFAPattern }, { ExifTag.DeviceSettingDescription }, { ExifTag.ImageSourceData }, + }; + + public static TheoryData EncodedStringTags => new TheoryData + { + { ExifTag.UserComment }, { ExifTag.GPSProcessingMethod }, { ExifTag.GPSAreaInformation } }; + public static TheoryData Ucs2StringTags => new TheoryData + { + { ExifTag.XPTitle }, + { ExifTag.XPComment }, + { ExifTag.XPAuthor }, + { ExifTag.XPKeywords }, + { ExifTag.XPSubject }, + }; + [Theory] [MemberData(nameof(ByteTags))] public void ExifByteTests(ExifTag tag) @@ -593,5 +603,46 @@ public void ExifUndefinedArrayTests(ExifTag tag) var typed = (ExifByteArray)value; Assert.Equal(expected, typed.Value); } + + [Theory] + [MemberData(nameof(EncodedStringTags))] + public void ExifEncodedStringTests(ExifTag tag) + { + foreach (object code in Enum.GetValues(typeof(EncodedString.CharacterCode))) + { + var charCode = (EncodedString.CharacterCode)code; + + Assert.Equal(ExifEncodedStringHelpers.CharacterCodeBytesLength, ExifEncodedStringHelpers.GetCodeBytes(charCode).Length); + + const string expectedText = "test string"; + var expected = new EncodedString(charCode, expectedText); + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(123)); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifEncodedString)value; + Assert.Equal(expected, typed.Value); + Assert.Equal(expectedText, (string)typed.Value); + Assert.Equal(charCode, typed.Value.Code); + } + } + + [Theory] + [MemberData(nameof(Ucs2StringTags))] + public void ExifUcs2StringTests(ExifTag tag) + { + const string expected = "Dan Petitt"; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(123)); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifUcs2String)value; + Assert.Equal(expected, typed.Value); + + Assert.True(value.TrySetValue(Encoding.GetEncoding("UCS-2").GetBytes(expected))); + Assert.Equal(expected, typed.Value); + } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index a73d262433..5ff71ba396 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -192,6 +192,7 @@ public static class Bad public const string Exif = "Jpg/baseline/exif.jpg"; public const string Floorplan = "Jpg/baseline/Floorplan.jpg"; public const string Calliphora = "Jpg/baseline/Calliphora.jpg"; + public const string Calliphora_EncodedStrings = "Jpg/baseline/Calliphora_encoded_strings.jpg"; public const string Ycck = "Jpg/baseline/ycck.jpg"; public const string Turtle420 = "Jpg/baseline/turtle.jpg"; public const string GammaDalaiLamaGray = "Jpg/baseline/gamma_dalai_lama_gray.jpg"; diff --git a/tests/Images/Input/Jpg/baseline/Calliphora_encoded_strings.jpg b/tests/Images/Input/Jpg/baseline/Calliphora_encoded_strings.jpg new file mode 100644 index 0000000000..b652ed2e58 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/Calliphora_encoded_strings.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:59f76d2935a619d128a63d6bfcd5ce9feec492a7f5175327e47554c90b4ec242 +size 258081