Browse Source

Merge branch 'main' into js/transform-metadata

pull/2946/head
James Jackson-South 11 months ago
parent
commit
1d18df92bf
  1. 8
      src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs
  2. 20
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  3. 8
      src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs
  4. 2
      src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs
  5. 53
      src/ImageSharp/Metadata/Profiles/Exif/ExifEncodedStringHelpers.cs
  6. 18
      src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs
  7. 37
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  8. 6
      src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
  9. 8
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs
  10. 2
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs
  11. 2
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs
  12. 4
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs
  13. 7
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifEncodedString.cs
  14. 26
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs
  15. 14
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs
  16. 4
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs
  17. 2
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs
  18. 12
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs
  19. 2
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs
  20. 2
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs
  21. 8
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs
  22. 840
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs
  23. 24
      src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs
  24. 5
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  25. 19
      tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
  26. 2
      tests/ImageSharp.Tests/TestImages.cs
  27. 3
      tests/Images/Input/Tiff/Issues/ExtraSamplesUnspecified.tif
  28. 3
      tests/Images/Input/Webp/issues/Issue2906.webp

8
src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs

@ -14,7 +14,7 @@ internal class EntryReader : BaseExifReader
: base(stream, allocator) => : base(stream, allocator) =>
this.IsBigEndian = byteOrder == ByteOrder.BigEndian; this.IsBigEndian = byteOrder == ByteOrder.BigEndian;
public List<IExifValue> Values { get; } = new(); public List<IExifValue> Values { get; } = [];
public ulong NextIfdOffset { get; private set; } public ulong NextIfdOffset { get; private set; }
@ -31,8 +31,6 @@ internal class EntryReader : BaseExifReader
{ {
this.ReadValues64(this.Values, ifdOffset); this.ReadValues64(this.Values, ifdOffset);
this.NextIfdOffset = this.ReadUInt64(); this.NextIfdOffset = this.ReadUInt64();
//// this.ReadSubIfd64(this.Values);
} }
} }
@ -62,9 +60,9 @@ internal class HeaderReader : BaseExifReader
{ {
this.IsBigTiff = true; this.IsBigTiff = true;
ushort bytesize = this.ReadUInt16(); ushort byteSize = this.ReadUInt16();
ushort reserve = this.ReadUInt16(); ushort reserve = this.ReadUInt16();
if (bytesize == TiffConstants.BigTiffByteSize && reserve == 0) if (byteSize == TiffConstants.BigTiffByteSize && reserve == 0)
{ {
this.FirstIfdOffset = this.ReadUInt64(); this.FirstIfdOffset = this.ReadUInt64();
return; return;

20
src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

@ -25,20 +25,22 @@ internal static class TiffDecoderOptionsParser
/// <returns>True, if the image uses tiles. Otherwise the images has strip's.</returns> /// <returns>True, if the image uses tiles. Otherwise the images has strip's.</returns>
public static bool VerifyAndParse(this TiffDecoderCore options, ExifProfile exifProfile, TiffFrameMetadata frameMetadata) public static bool VerifyAndParse(this TiffDecoderCore options, ExifProfile exifProfile, TiffFrameMetadata frameMetadata)
{ {
IExifValue extraSamplesExifValue = exifProfile.GetValueInternal(ExifTag.ExtraSamples); if (exifProfile.TryGetValue(ExifTag.ExtraSamples, out IExifValue<ushort[]> samples))
if (extraSamplesExifValue is not null)
{ {
short[] extraSamples = (short[])extraSamplesExifValue.GetValue(); // We only support a single sample pertaining to alpha data.
if (extraSamples.Length != 1) // Other information is discarded.
TiffExtraSampleType sampleType = (TiffExtraSampleType)samples.Value[0];
if (sampleType is TiffExtraSampleType.CorelDrawUnassociatedAlphaData)
{ {
TiffThrowHelper.ThrowNotSupported("ExtraSamples is only supported with one extra sample for alpha data."); // According to libtiff, this CorelDRAW-specific value indicates unassociated alpha.
// Patch required for compatibility with malformed CorelDRAW-generated TIFFs.
// https://libtiff.gitlab.io/libtiff/releases/v3.9.0beta.html
sampleType = TiffExtraSampleType.UnassociatedAlphaData;
} }
TiffExtraSampleType extraSamplesType = (TiffExtraSampleType)extraSamples[0]; if (sampleType is (TiffExtraSampleType.UnassociatedAlphaData or TiffExtraSampleType.AssociatedAlphaData))
options.ExtraSamplesType = extraSamplesType;
if (extraSamplesType is not (TiffExtraSampleType.UnassociatedAlphaData or TiffExtraSampleType.AssociatedAlphaData))
{ {
TiffThrowHelper.ThrowNotSupported("Decoding Tiff images with ExtraSamples is not supported with UnspecifiedData."); options.ExtraSamplesType = sampleType;
} }
} }

8
src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs

@ -22,5 +22,11 @@ internal enum TiffExtraSampleType
/// The extra data is unassociated alpha data is transparency information that logically exists independent of an image; /// The extra data is unassociated alpha data is transparency information that logically exists independent of an image;
/// it is commonly called a soft matte. /// it is commonly called a soft matte.
/// </summary> /// </summary>
UnassociatedAlphaData = 2 UnassociatedAlphaData = 2,
/// <summary>
/// A CorelDRAW-specific value observed in damaged files, indicating unassociated alpha.
/// Not part of the official TIFF specification; patched in ImageSharp for compatibility.
/// </summary>
CorelDrawUnassociatedAlphaData = 999,
} }

2
src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs

@ -4,7 +4,7 @@
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif;
/// <summary> /// <summary>
/// Specifies exif data types. /// Specifies Exif data types.
/// </summary> /// </summary>
public enum ExifDataType public enum ExifDataType
{ {

53
src/ImageSharp/Metadata/Profiles/Exif/ExifEncodedStringHelpers.cs

@ -16,13 +16,13 @@ internal static class ExifEncodedStringHelpers
private const ulong UnicodeCode = 0x_45_44_4F_43_49_4E_55; 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 const ulong UndefinedCode = 0x_00_00_00_00_00_00_00_00;
private static ReadOnlySpan<byte> AsciiCodeBytes => new byte[] { 0x41, 0x53, 0x43, 0x49, 0x49, 0, 0, 0 }; private static ReadOnlySpan<byte> AsciiCodeBytes => [0x41, 0x53, 0x43, 0x49, 0x49, 0, 0, 0];
private static ReadOnlySpan<byte> JISCodeBytes => new byte[] { 0x4A, 0x49, 0x53, 0, 0, 0, 0, 0 }; private static ReadOnlySpan<byte> JISCodeBytes => [0x4A, 0x49, 0x53, 0, 0, 0, 0, 0];
private static ReadOnlySpan<byte> UnicodeCodeBytes => new byte[] { 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0 }; private static ReadOnlySpan<byte> UnicodeCodeBytes => [0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0];
private static ReadOnlySpan<byte> UndefinedCodeBytes => new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; private static ReadOnlySpan<byte> UndefinedCodeBytes => [0, 0, 0, 0, 0, 0, 0, 0];
// 20932 EUC-JP Japanese (JIS 0208-1990 and 0212-1990) // 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 // https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding?view=net-6.0
@ -50,22 +50,45 @@ internal static class ExifEncodedStringHelpers
_ => UndefinedCodeBytes _ => UndefinedCodeBytes
}; };
public static Encoding GetEncoding(CharacterCode code) => code switch public static Encoding GetEncoding(CharacterCode code, ByteOrder order) => code switch
{ {
CharacterCode.ASCII => Encoding.ASCII, CharacterCode.ASCII => Encoding.ASCII,
CharacterCode.JIS => JIS0208Encoding, CharacterCode.JIS => JIS0208Encoding,
CharacterCode.Unicode => Encoding.Unicode, CharacterCode.Unicode => order is ByteOrder.BigEndian ? Encoding.BigEndianUnicode : Encoding.Unicode,
CharacterCode.Undefined => Encoding.UTF8, CharacterCode.Undefined => Encoding.UTF8,
_ => Encoding.UTF8 _ => Encoding.UTF8
}; };
public static bool TryParse(ReadOnlySpan<byte> buffer, out EncodedString encodedString) public static bool TryParse(ReadOnlySpan<byte> buffer, ByteOrder order, out EncodedString encodedString)
{ {
if (TryDetect(buffer, out CharacterCode code)) if (TryDetect(buffer, out CharacterCode code))
{ {
string text = GetEncoding(code).GetString(buffer[CharacterCodeBytesLength..]); ReadOnlySpan<byte> textBuffer = buffer[CharacterCodeBytesLength..];
encodedString = new EncodedString(code, text); if (code == CharacterCode.Unicode && textBuffer.Length >= 2)
return true; {
// Check BOM
if (textBuffer.StartsWith((ReadOnlySpan<byte>)[0xFF, 0xFE]))
{
// Little-endian BOM
string text = Encoding.Unicode.GetString(textBuffer[2..]);
encodedString = new EncodedString(code, text);
return true;
}
if (textBuffer.StartsWith((ReadOnlySpan<byte>)[0xFE, 0xFF]))
{
// Big-endian BOM
string text = Encoding.BigEndianUnicode.GetString(textBuffer[2..]);
encodedString = new EncodedString(code, text);
return true;
}
}
{
string text = GetEncoding(code, order).GetString(textBuffer);
encodedString = new EncodedString(code, text);
return true;
}
} }
encodedString = default; encodedString = default;
@ -73,14 +96,14 @@ internal static class ExifEncodedStringHelpers
} }
public static uint GetDataLength(EncodedString encodedString) => public static uint GetDataLength(EncodedString encodedString) =>
(uint)GetEncoding(encodedString.Code).GetByteCount(encodedString.Text) + CharacterCodeBytesLength; (uint)GetEncoding(encodedString.Code, ByteOrder.LittleEndian).GetByteCount(encodedString.Text) + CharacterCodeBytesLength;
public static int Write(EncodedString encodedString, Span<byte> destination) public static int Write(EncodedString encodedString, Span<byte> destination)
{ {
GetCodeBytes(encodedString.Code).CopyTo(destination); GetCodeBytes(encodedString.Code).CopyTo(destination);
string text = encodedString.Text; string text = encodedString.Text;
int count = Write(GetEncoding(encodedString.Code), text, destination[CharacterCodeBytesLength..]); int count = Write(GetEncoding(encodedString.Code, ByteOrder.LittleEndian), text, destination[CharacterCodeBytesLength..]);
return CharacterCodeBytesLength + count; return CharacterCodeBytesLength + count;
} }
@ -92,8 +115,7 @@ internal static class ExifEncodedStringHelpers
{ {
if (buffer.Length >= CharacterCodeBytesLength) if (buffer.Length >= CharacterCodeBytesLength)
{ {
ulong test = BinaryPrimitives.ReadUInt64LittleEndian(buffer); switch (BinaryPrimitives.ReadUInt64LittleEndian(buffer))
switch (test)
{ {
case AsciiCode: case AsciiCode:
code = CharacterCode.ASCII; code = CharacterCode.ASCII;
@ -108,7 +130,8 @@ internal static class ExifEncodedStringHelpers
code = CharacterCode.Undefined; code = CharacterCode.Undefined;
return true; return true;
default: default:
break; code = default;
return false;
} }
} }

18
src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs

@ -170,7 +170,7 @@ public sealed class ExifProfile : IDeepCloneable<ExifProfile>
/// <summary> /// <summary>
/// Returns the value with the specified tag. /// Returns the value with the specified tag.
/// </summary> /// </summary>
/// <param name="tag">The tag of the exif value.</param> /// <param name="tag">The tag of the Exif value.</param>
/// <param name="exifValue">The value with the specified tag.</param> /// <param name="exifValue">The value with the specified tag.</param>
/// <returns>True when found, otherwise false</returns> /// <returns>True when found, otherwise false</returns>
/// <typeparam name="TValueType">The data type of the tag.</typeparam> /// <typeparam name="TValueType">The data type of the tag.</typeparam>
@ -214,7 +214,7 @@ public sealed class ExifProfile : IDeepCloneable<ExifProfile>
/// <summary> /// <summary>
/// Sets the value of the specified tag. /// Sets the value of the specified tag.
/// </summary> /// </summary>
/// <param name="tag">The tag of the exif value.</param> /// <param name="tag">The tag of the Exif value.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <typeparam name="TValueType">The data type of the tag.</typeparam> /// <typeparam name="TValueType">The data type of the tag.</typeparam>
public void SetValue<TValueType>(ExifTag<TValueType> tag, TValueType value) public void SetValue<TValueType>(ExifTag<TValueType> tag, TValueType value)
@ -233,7 +233,7 @@ public sealed class ExifProfile : IDeepCloneable<ExifProfile>
if (this.values.Count == 0) if (this.values.Count == 0)
{ {
return Array.Empty<byte>(); return [];
} }
ExifWriter writer = new(this.values, this.Parts); ExifWriter writer = new(this.values, this.Parts);
@ -246,7 +246,7 @@ public sealed class ExifProfile : IDeepCloneable<ExifProfile>
/// <summary> /// <summary>
/// Returns the value with the specified tag. /// Returns the value with the specified tag.
/// </summary> /// </summary>
/// <param name="tag">The tag of the exif value.</param> /// <param name="tag">The tag of the Exif value.</param>
/// <returns>The value with the specified tag.</returns> /// <returns>The value with the specified tag.</returns>
internal IExifValue? GetValueInternal(ExifTag tag) internal IExifValue? GetValueInternal(ExifTag tag)
{ {
@ -264,7 +264,7 @@ public sealed class ExifProfile : IDeepCloneable<ExifProfile>
/// <summary> /// <summary>
/// Sets the value of the specified tag. /// Sets the value of the specified tag.
/// </summary> /// </summary>
/// <param name="tag">The tag of the exif value.</param> /// <param name="tag">The tag of the Exif value.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <exception cref="NotSupportedException">The newly created value is null.</exception> /// <exception cref="NotSupportedException">The newly created value is null.</exception>
internal void SetValueInternal(ExifTag tag, object? value) internal void SetValueInternal(ExifTag tag, object? value)
@ -278,11 +278,7 @@ public sealed class ExifProfile : IDeepCloneable<ExifProfile>
} }
} }
ExifValue? newExifValue = ExifValues.Create(tag); ExifValue? newExifValue = ExifValues.Create(tag) ?? throw new NotSupportedException($"Newly created value for tag {tag} is null.");
if (newExifValue is null)
{
throw new NotSupportedException($"Newly created value for tag {tag} is null.");
}
newExifValue.TrySetValue(value); newExifValue.TrySetValue(value);
this.values.Add(newExifValue); this.values.Add(newExifValue);
@ -402,7 +398,7 @@ public sealed class ExifProfile : IDeepCloneable<ExifProfile>
if (this.data is null) if (this.data is null)
{ {
this.values = new List<IExifValue>(); this.values = [];
return; return;
} }

37
src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs

@ -34,7 +34,7 @@ internal class ExifReader : BaseExifReader
/// </returns> /// </returns>
public List<IExifValue> ReadValues() public List<IExifValue> ReadValues()
{ {
List<IExifValue> values = new(); List<IExifValue> values = [];
// II == 0x4949 // II == 0x4949
this.IsBigEndian = this.ReadUInt16() != 0x4949; this.IsBigEndian = this.ReadUInt16() != 0x4949;
@ -64,7 +64,7 @@ internal class ExifReader : BaseExifReader
return; return;
} }
List<IExifValue> values = new(); List<IExifValue> values = [];
this.ReadValues(values, offset); this.ReadValues(values, offset);
for (int i = 0; i < values.Count; i++) for (int i = 0; i < values.Count; i++)
@ -90,8 +90,8 @@ internal abstract class BaseExifReader
private readonly MemoryAllocator? allocator; private readonly MemoryAllocator? allocator;
private readonly Stream data; private readonly Stream data;
private List<ExifTag>? invalidTags; private List<ExifTag>? invalidTags;
private List<ulong>? subIfds; private List<ulong>? subIfds;
private bool isBigEndian;
protected BaseExifReader(Stream stream, MemoryAllocator? allocator) protected BaseExifReader(Stream stream, MemoryAllocator? allocator)
{ {
@ -104,7 +104,7 @@ internal abstract class BaseExifReader
/// <summary> /// <summary>
/// Gets the invalid tags. /// Gets the invalid tags.
/// </summary> /// </summary>
public IReadOnlyList<ExifTag> InvalidTags => this.invalidTags ?? (IReadOnlyList<ExifTag>)Array.Empty<ExifTag>(); public IReadOnlyList<ExifTag> InvalidTags => this.invalidTags ?? (IReadOnlyList<ExifTag>)[];
/// <summary> /// <summary>
/// Gets or sets the thumbnail length in the byte stream. /// Gets or sets the thumbnail length in the byte stream.
@ -116,9 +116,19 @@ internal abstract class BaseExifReader
/// </summary> /// </summary>
public uint ThumbnailOffset { get; protected set; } public uint ThumbnailOffset { get; protected set; }
public bool IsBigEndian { get; protected set; } public bool IsBigEndian
{
get => this.isBigEndian;
protected set
{
this.isBigEndian = value;
this.ByteOrder = value ? ByteOrder.BigEndian : ByteOrder.LittleEndian;
}
}
protected ByteOrder ByteOrder { get; private set; }
public List<(ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif)> BigValues { get; } = new(); public List<(ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif)> BigValues { get; } = [];
protected void ReadBigValues(List<IExifValue> values) protected void ReadBigValues(List<IExifValue> values)
{ {
@ -486,14 +496,21 @@ internal abstract class BaseExifReader
private void Add(IList<IExifValue> values, ExifValue exif, object? value) private void Add(IList<IExifValue> values, ExifValue exif, object? value)
{ {
if (!exif.TrySetValue(value)) if (exif is ExifEncodedString encodedString)
{
if (!encodedString.TrySetValue(value, this.ByteOrder))
{
return;
}
}
else if (!exif.TrySetValue(value))
{ {
return; return;
} }
foreach (IExifValue val in values) foreach (IExifValue val in values)
{ {
// to skip duplicates must be used Equals method, // To skip duplicates must be used Equals method,
// == operator not defined for ExifValue and IExifValue // == operator not defined for ExifValue and IExifValue
if (exif.Equals(val)) if (exif.Equals(val))
{ {
@ -517,10 +534,10 @@ internal abstract class BaseExifReader
} }
private void AddInvalidTag(ExifTag tag) private void AddInvalidTag(ExifTag tag)
=> (this.invalidTags ??= new List<ExifTag>()).Add(tag); => (this.invalidTags ??= []).Add(tag);
private void AddSubIfd(object? val) private void AddSubIfd(object? val)
=> (this.subIfds ??= new List<ulong>()).Add(Convert.ToUInt64(val, CultureInfo.InvariantCulture)); => (this.subIfds ??= []).Add(Convert.ToUInt64(val, CultureInfo.InvariantCulture));
private void Seek(ulong pos) private void Seek(ulong pos)
=> this.data.Seek((long)pos, SeekOrigin.Begin); => this.data.Seek((long)pos, SeekOrigin.Begin);

6
src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs

@ -55,7 +55,7 @@ internal sealed class ExifWriter
if (length == 0) if (length == 0)
{ {
return Array.Empty<byte>(); return [];
} }
// two bytes for the byte Order marker 'II' or 'MM', followed by the number 42 (0x2A) and a 0, making 4 bytes total // two bytes for the byte Order marker 'II' or 'MM', followed by the number 42 (0x2A) and a 0, making 4 bytes total
@ -197,7 +197,7 @@ internal sealed class ExifWriter
private List<IExifValue> GetPartValues(ExifParts part) private List<IExifValue> GetPartValues(ExifParts part)
{ {
List<IExifValue> result = new(); List<IExifValue> result = [];
if (!EnumUtils.HasFlag(this.allowedParts, part)) if (!EnumUtils.HasFlag(this.allowedParts, part))
{ {
@ -332,7 +332,7 @@ internal sealed class ExifWriter
private int WriteHeaders(List<IExifValue> values, Span<byte> destination, int offset) private int WriteHeaders(List<IExifValue> values, Span<byte> destination, int offset)
{ {
this.dataOffsets = new List<int>(); this.dataOffsets = [];
int newOffset = WriteUInt16((ushort)values.Count, destination, offset); int newOffset = WriteUInt16((ushort)values.Count, destination, offset);

8
src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs

@ -4,7 +4,7 @@
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif;
/// <summary> /// <summary>
/// Class that represents an exif tag from the Exif standard 2.31. /// Class that represents an Exif tag from the Exif standard 2.31.
/// </summary> /// </summary>
public abstract partial class ExifTag : IEquatable<ExifTag> public abstract partial class ExifTag : IEquatable<ExifTag>
{ {
@ -16,21 +16,21 @@ public abstract partial class ExifTag : IEquatable<ExifTag>
/// Converts the specified <see cref="ExifTag"/> to a <see cref="ushort"/>. /// Converts the specified <see cref="ExifTag"/> to a <see cref="ushort"/>.
/// </summary> /// </summary>
/// <param name="tag">The <see cref="ExifTag"/> to convert.</param> /// <param name="tag">The <see cref="ExifTag"/> to convert.</param>
public static explicit operator ushort(ExifTag tag) => tag?.value ?? (ushort)ExifTagValue.Unknown; public static explicit operator ushort(ExifTag? tag) => tag?.value ?? (ushort)ExifTagValue.Unknown;
/// <summary> /// <summary>
/// Determines whether the specified <see cref="ExifTag"/> instances are considered equal. /// Determines whether the specified <see cref="ExifTag"/> instances are considered equal.
/// </summary> /// </summary>
/// <param name="left">The first <see cref="ExifTag"/> to compare.</param> /// <param name="left">The first <see cref="ExifTag"/> to compare.</param>
/// <param name="right"> The second <see cref="ExifTag"/> to compare.</param> /// <param name="right"> The second <see cref="ExifTag"/> to compare.</param>
public static bool operator ==(ExifTag left, ExifTag right) => Equals(left, right); public static bool operator ==(ExifTag? left, ExifTag? right) => left?.Equals(right) == true;
/// <summary> /// <summary>
/// Determines whether the specified <see cref="ExifTag"/> instances are not considered equal. /// Determines whether the specified <see cref="ExifTag"/> instances are not considered equal.
/// </summary> /// </summary>
/// <param name="left">The first <see cref="ExifTag"/> to compare.</param> /// <param name="left">The first <see cref="ExifTag"/> to compare.</param>
/// <param name="right"> The second <see cref="ExifTag"/> to compare.</param> /// <param name="right"> The second <see cref="ExifTag"/> to compare.</param>
public static bool operator !=(ExifTag left, ExifTag right) => !Equals(left, right); public static bool operator !=(ExifTag? left, ExifTag? right) => !(left == right);
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object? obj) public override bool Equals(object? obj)

2
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs

@ -43,7 +43,7 @@ internal abstract class ExifArrayValue<TValueType> : ExifValue, IExifValue<TValu
if (type == typeof(TValueType)) if (type == typeof(TValueType))
{ {
this.Value = new TValueType[] { (TValueType)value }; this.Value = [(TValueType)value];
return true; return true;
} }

2
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs

@ -30,7 +30,7 @@ internal sealed class ExifByte : ExifValue<byte>
switch (value) switch (value)
{ {
case int intValue: case int intValue:
if (intValue >= byte.MinValue && intValue <= byte.MaxValue) if (intValue is >= byte.MinValue and <= byte.MaxValue)
{ {
this.Value = (byte)intValue; this.Value = (byte)intValue;
return true; return true;

4
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs

@ -30,9 +30,9 @@ internal sealed class ExifByteArray : ExifArrayValue<byte>
if (value is int intValue) if (value is int intValue)
{ {
if (intValue >= byte.MinValue && intValue <= byte.MaxValue) if (intValue is >= byte.MinValue and <= byte.MaxValue)
{ {
this.Value = new byte[] { (byte)intValue }; this.Value = [(byte)intValue];
} }
return true; return true;

7
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifEncodedString.cs

@ -24,7 +24,7 @@ internal sealed class ExifEncodedString : ExifValue<EncodedString>
protected override string StringValue => this.Value.Text; protected override string StringValue => this.Value.Text;
public override bool TrySetValue(object? value) public bool TrySetValue(object? value, ByteOrder order)
{ {
if (base.TrySetValue(value)) if (base.TrySetValue(value))
{ {
@ -38,7 +38,7 @@ internal sealed class ExifEncodedString : ExifValue<EncodedString>
} }
else if (value is byte[] buffer) else if (value is byte[] buffer)
{ {
if (ExifEncodedStringHelpers.TryParse(buffer, out EncodedString encodedString)) if (ExifEncodedStringHelpers.TryParse(buffer, order, out EncodedString encodedString))
{ {
this.Value = encodedString; this.Value = encodedString;
return true; return true;
@ -48,5 +48,8 @@ internal sealed class ExifEncodedString : ExifValue<EncodedString>
return false; return false;
} }
public override bool TrySetValue(object? value)
=> this.TrySetValue(value, ByteOrder.LittleEndian);
public override IExifValue DeepClone() => new ExifEncodedString(this); public override IExifValue DeepClone() => new ExifEncodedString(this);
} }

26
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs

@ -47,46 +47,40 @@ internal sealed class ExifLong8Array : ExifArrayValue<ulong>
return this.SetSingle((ulong)Numerics.Clamp(val, 0, int.MaxValue)); return this.SetSingle((ulong)Numerics.Clamp(val, 0, int.MaxValue));
case uint val: case uint val:
return this.SetSingle((ulong)val); return this.SetSingle(val);
case short val: case short val:
return this.SetSingle((ulong)Numerics.Clamp(val, 0, short.MaxValue)); return this.SetSingle((ulong)Numerics.Clamp(val, 0, short.MaxValue));
case ushort val: case ushort val:
return this.SetSingle((ulong)val); return this.SetSingle(val);
case long val: case long val:
return this.SetSingle((ulong)Numerics.Clamp(val, 0, long.MaxValue)); return this.SetSingle((ulong)Numerics.Clamp(val, 0, long.MaxValue));
case long[] array: case long[] array:
{
if (value.GetType() == typeof(ulong[])) if (value.GetType() == typeof(ulong[]))
{ {
return this.SetArray((ulong[])value); return this.SetArray((ulong[])value);
} }
return this.SetArray(array); return this.SetArray(array);
}
case int[] array: case int[] array:
{
if (value.GetType() == typeof(uint[])) if (value.GetType() == typeof(uint[]))
{ {
return this.SetArray((uint[])value); return this.SetArray((uint[])value);
} }
return this.SetArray(array); return this.SetArray(array);
}
case short[] array: case short[] array:
{
if (value.GetType() == typeof(ushort[])) if (value.GetType() == typeof(ushort[]))
{ {
return this.SetArray((ushort[])value); return this.SetArray((ushort[])value);
} }
return this.SetArray(array); return this.SetArray(array);
}
} }
return false; return false;
@ -96,13 +90,13 @@ internal sealed class ExifLong8Array : ExifArrayValue<ulong>
private bool SetSingle(ulong value) private bool SetSingle(ulong value)
{ {
this.Value = new[] { value }; this.Value = [value];
return true; return true;
} }
private bool SetArray(long[] values) private bool SetArray(long[] values)
{ {
var numbers = new ulong[values.Length]; ulong[] numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = (ulong)(values[i] < 0 ? 0 : values[i]); numbers[i] = (ulong)(values[i] < 0 ? 0 : values[i]);
@ -120,7 +114,7 @@ internal sealed class ExifLong8Array : ExifArrayValue<ulong>
private bool SetArray(int[] values) private bool SetArray(int[] values)
{ {
var numbers = new ulong[values.Length]; ulong[] numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = (ulong)Numerics.Clamp(values[i], 0, int.MaxValue); numbers[i] = (ulong)Numerics.Clamp(values[i], 0, int.MaxValue);
@ -132,10 +126,10 @@ internal sealed class ExifLong8Array : ExifArrayValue<ulong>
private bool SetArray(uint[] values) private bool SetArray(uint[] values)
{ {
var numbers = new ulong[values.Length]; ulong[] numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = (ulong)values[i]; numbers[i] = values[i];
} }
this.Value = numbers; this.Value = numbers;
@ -144,7 +138,7 @@ internal sealed class ExifLong8Array : ExifArrayValue<ulong>
private bool SetArray(short[] values) private bool SetArray(short[] values)
{ {
var numbers = new ulong[values.Length]; ulong[] numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = (ulong)Numerics.Clamp(values[i], 0, short.MaxValue); numbers[i] = (ulong)Numerics.Clamp(values[i], 0, short.MaxValue);
@ -156,10 +150,10 @@ internal sealed class ExifLong8Array : ExifArrayValue<ulong>
private bool SetArray(ushort[] values) private bool SetArray(ushort[] values)
{ {
var numbers = new ulong[values.Length]; ulong[] numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = (ulong)values[i]; numbers[i] = values[i];
} }
this.Value = numbers; this.Value = numbers;

14
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs

@ -52,7 +52,6 @@ internal sealed class ExifNumberArray : ExifArrayValue<Number>
case ushort val: case ushort val:
return this.SetSingle(val); return this.SetSingle(val);
case int[] array: case int[] array:
{
// workaround for inconsistent covariance of value-typed arrays // workaround for inconsistent covariance of value-typed arrays
if (value.GetType() == typeof(uint[])) if (value.GetType() == typeof(uint[]))
{ {
@ -60,17 +59,14 @@ internal sealed class ExifNumberArray : ExifArrayValue<Number>
} }
return this.SetArray(array); return this.SetArray(array);
}
case short[] array: case short[] array:
{
if (value.GetType() == typeof(ushort[])) if (value.GetType() == typeof(ushort[]))
{ {
return this.SetArray((ushort[])value); return this.SetArray((ushort[])value);
} }
return this.SetArray(array); return this.SetArray(array);
}
} }
return false; return false;
@ -80,13 +76,13 @@ internal sealed class ExifNumberArray : ExifArrayValue<Number>
private bool SetSingle(Number value) private bool SetSingle(Number value)
{ {
this.Value = new[] { value }; this.Value = [value];
return true; return true;
} }
private bool SetArray(int[] values) private bool SetArray(int[] values)
{ {
var numbers = new Number[values.Length]; Number[] numbers = new Number[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = values[i]; numbers[i] = values[i];
@ -98,7 +94,7 @@ internal sealed class ExifNumberArray : ExifArrayValue<Number>
private bool SetArray(uint[] values) private bool SetArray(uint[] values)
{ {
var numbers = new Number[values.Length]; Number[] numbers = new Number[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = values[i]; numbers[i] = values[i];
@ -110,7 +106,7 @@ internal sealed class ExifNumberArray : ExifArrayValue<Number>
private bool SetArray(short[] values) private bool SetArray(short[] values)
{ {
var numbers = new Number[values.Length]; Number[] numbers = new Number[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = values[i]; numbers[i] = values[i];
@ -122,7 +118,7 @@ internal sealed class ExifNumberArray : ExifArrayValue<Number>
private bool SetArray(ushort[] values) private bool SetArray(ushort[] values)
{ {
var numbers = new Number[values.Length]; Number[] numbers = new Number[values.Length];
for (int i = 0; i < values.Length; i++) for (int i = 0; i < values.Length; i++)
{ {
numbers[i] = values[i]; numbers[i] = values[i];

4
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs

@ -38,7 +38,7 @@ internal sealed class ExifRationalArray : ExifArrayValue<Rational>
{ {
if (signed.Numerator >= 0 && signed.Denominator >= 0) if (signed.Numerator >= 0 && signed.Denominator >= 0)
{ {
this.Value = new[] { new Rational((uint)signed.Numerator, (uint)signed.Denominator) }; this.Value = [new Rational((uint)signed.Numerator, (uint)signed.Denominator)];
} }
return true; return true;
@ -56,7 +56,7 @@ internal sealed class ExifRationalArray : ExifArrayValue<Rational>
return false; return false;
} }
var unsigned = new Rational[signed.Length]; Rational[] unsigned = new Rational[signed.Length];
for (int i = 0; i < signed.Length; i++) for (int i = 0; i < signed.Length; i++)
{ {
SignedRational s = signed[i]; SignedRational s = signed[i];

2
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs

@ -36,7 +36,7 @@ internal sealed class ExifShort : ExifValue<ushort>
switch (value) switch (value)
{ {
case int intValue: case int intValue:
if (intValue >= ushort.MinValue && intValue <= ushort.MaxValue) if (intValue is >= ushort.MinValue and <= ushort.MaxValue)
{ {
this.Value = (ushort)intValue; this.Value = (ushort)intValue;
return true; return true;

12
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs

@ -41,9 +41,9 @@ internal sealed class ExifShortArray : ExifArrayValue<ushort>
if (value is int signedInt) if (value is int signedInt)
{ {
if (signedInt >= ushort.MinValue && signedInt <= ushort.MaxValue) if (signedInt is >= ushort.MinValue and <= ushort.MaxValue)
{ {
this.Value = new ushort[] { (ushort)signedInt }; this.Value = [(ushort)signedInt];
} }
return true; return true;
@ -53,7 +53,7 @@ internal sealed class ExifShortArray : ExifArrayValue<ushort>
{ {
if (signedShort >= ushort.MinValue) if (signedShort >= ushort.MinValue)
{ {
this.Value = new ushort[] { (ushort)signedShort }; this.Value = [(ushort)signedShort];
} }
return true; return true;
@ -66,12 +66,12 @@ internal sealed class ExifShortArray : ExifArrayValue<ushort>
private bool TrySetSignedIntArray(int[] signed) private bool TrySetSignedIntArray(int[] signed)
{ {
if (Array.FindIndex(signed, x => x < ushort.MinValue || x > ushort.MaxValue) > -1) if (Array.FindIndex(signed, x => x is < ushort.MinValue or > ushort.MaxValue) > -1)
{ {
return false; return false;
} }
var unsigned = new ushort[signed.Length]; ushort[] unsigned = new ushort[signed.Length];
for (int i = 0; i < signed.Length; i++) for (int i = 0; i < signed.Length; i++)
{ {
int s = signed[i]; int s = signed[i];
@ -89,7 +89,7 @@ internal sealed class ExifShortArray : ExifArrayValue<ushort>
return false; return false;
} }
var unsigned = new ushort[signed.Length]; ushort[] unsigned = new ushort[signed.Length];
for (int i = 0; i < signed.Length; i++) for (int i = 0; i < signed.Length; i++)
{ {
short s = signed[i]; short s = signed[i];

2
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs

@ -31,7 +31,7 @@ internal sealed class ExifSignedByte : ExifValue<sbyte>
switch (value) switch (value)
{ {
case int intValue: case int intValue:
if (intValue >= sbyte.MinValue && intValue <= sbyte.MaxValue) if (intValue is >= sbyte.MinValue and <= sbyte.MaxValue)
{ {
this.Value = (sbyte)intValue; this.Value = (sbyte)intValue;
return true; return true;

2
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs

@ -31,7 +31,7 @@ internal sealed class ExifSignedShort : ExifValue<short>
switch (value) switch (value)
{ {
case int intValue: case int intValue:
if (intValue >= short.MinValue && intValue <= short.MaxValue) if (intValue is >= short.MinValue and <= short.MaxValue)
{ {
this.Value = (short)intValue; this.Value = (short)intValue;
return true; return true;

8
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs

@ -36,9 +36,9 @@ internal sealed class ExifSignedShortArray : ExifArrayValue<short>
if (value is int intValue) if (value is int intValue)
{ {
if (intValue >= short.MinValue && intValue <= short.MaxValue) if (intValue is >= short.MinValue and <= short.MaxValue)
{ {
this.Value = new short[] { (short)intValue }; this.Value = [(short)intValue];
} }
return true; return true;
@ -51,12 +51,12 @@ internal sealed class ExifSignedShortArray : ExifArrayValue<short>
private bool TrySetSignedArray(int[] intArray) private bool TrySetSignedArray(int[] intArray)
{ {
if (Array.FindIndex(intArray, x => x < short.MinValue || x > short.MaxValue) > -1) if (Array.FindIndex(intArray, x => x is < short.MinValue or > short.MaxValue) > -1)
{ {
return false; return false;
} }
var value = new short[intArray.Length]; short[] value = new short[intArray.Length];
for (int i = 0; i < intArray.Length; i++) for (int i = 0; i < intArray.Length; i++)
{ {
int s = intArray[i]; int s = intArray[i];

840
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs

@ -3,7 +3,7 @@
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif;
internal static partial class ExifValues internal static class ExifValues
{ {
public static ExifValue? Create(ExifTagValue tag) => (ExifValue?)CreateValue(tag); public static ExifValue? Create(ExifTagValue tag) => (ExifValue?)CreateValue(tag);
@ -12,573 +12,281 @@ internal static partial class ExifValues
public static ExifValue? Create(ExifTagValue tag, ExifDataType dataType, ulong numberOfComponents) => Create(tag, dataType, numberOfComponents != 1); public static ExifValue? Create(ExifTagValue tag, ExifDataType dataType, ulong numberOfComponents) => Create(tag, dataType, numberOfComponents != 1);
public static ExifValue? Create(ExifTagValue tag, ExifDataType dataType, bool isArray) public static ExifValue? Create(ExifTagValue tag, ExifDataType dataType, bool isArray)
{ => dataType switch
switch (dataType)
{ {
case ExifDataType.Byte: ExifDataType.Byte => isArray ? new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType),
return isArray ? new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType); ExifDataType.DoubleFloat => isArray ? new ExifDoubleArray(tag) : new ExifDouble(tag),
case ExifDataType.DoubleFloat: ExifDataType.SingleFloat => isArray ? new ExifFloatArray(tag) : new ExifFloat(tag),
return isArray ? new ExifDoubleArray(tag) : new ExifDouble(tag); ExifDataType.Long => isArray ? new ExifLongArray(tag) : new ExifLong(tag),
case ExifDataType.SingleFloat: ExifDataType.Long8 => isArray ? new ExifLong8Array(tag) : new ExifLong8(tag),
return isArray ? new ExifFloatArray(tag) : new ExifFloat(tag); ExifDataType.Rational => isArray ? new ExifRationalArray(tag) : new ExifRational(tag),
case ExifDataType.Long: ExifDataType.Short => isArray ? new ExifShortArray(tag) : new ExifShort(tag),
return isArray ? new ExifLongArray(tag) : new ExifLong(tag); ExifDataType.SignedByte => isArray ? new ExifSignedByteArray(tag) : new ExifSignedByte(tag),
case ExifDataType.Long8: ExifDataType.SignedLong => isArray ? new ExifSignedLongArray(tag) : new ExifSignedLong(tag),
return isArray ? new ExifLong8Array(tag) : new ExifLong8(tag); ExifDataType.SignedLong8 => isArray ? new ExifSignedLong8Array(tag) : new ExifSignedLong8(tag),
case ExifDataType.Rational: ExifDataType.SignedRational => isArray ? new ExifSignedRationalArray(tag) : new ExifSignedRational(tag),
return isArray ? new ExifRationalArray(tag) : new ExifRational(tag); ExifDataType.SignedShort => isArray ? new ExifSignedShortArray(tag) : new ExifSignedShort(tag),
case ExifDataType.Short: ExifDataType.Ascii => new ExifString(tag),
return isArray ? new ExifShortArray(tag) : new ExifShort(tag); ExifDataType.Undefined => isArray ? new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType),
case ExifDataType.SignedByte: _ => null,
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;
}
}
private static object? CreateValue(ExifTagValue tag) private static object? CreateValue(ExifTagValue tag)
{ => tag switch
switch (tag)
{ {
case ExifTagValue.FaxProfile: ExifTagValue.FaxProfile => new ExifByte(ExifTag.FaxProfile, ExifDataType.Byte),
return new ExifByte(ExifTag.FaxProfile, ExifDataType.Byte); ExifTagValue.ModeNumber => new ExifByte(ExifTag.ModeNumber, ExifDataType.Byte),
case ExifTagValue.ModeNumber: ExifTagValue.GPSAltitudeRef => new ExifByte(ExifTag.GPSAltitudeRef, ExifDataType.Byte),
return new ExifByte(ExifTag.ModeNumber, ExifDataType.Byte); ExifTagValue.ClipPath => new ExifByteArray(ExifTag.ClipPath, ExifDataType.Byte),
case ExifTagValue.GPSAltitudeRef: ExifTagValue.VersionYear => new ExifByteArray(ExifTag.VersionYear, ExifDataType.Byte),
return new ExifByte(ExifTag.GPSAltitudeRef, ExifDataType.Byte); ExifTagValue.XMP => new ExifByteArray(ExifTag.XMP, ExifDataType.Byte),
ExifTagValue.CFAPattern2 => new ExifByteArray(ExifTag.CFAPattern2, ExifDataType.Byte),
case ExifTagValue.ClipPath: ExifTagValue.TIFFEPStandardID => new ExifByteArray(ExifTag.TIFFEPStandardID, ExifDataType.Byte),
return new ExifByteArray(ExifTag.ClipPath, ExifDataType.Byte); ExifTagValue.GPSVersionID => new ExifByteArray(ExifTag.GPSVersionID, ExifDataType.Byte),
case ExifTagValue.VersionYear: ExifTagValue.PixelScale => new ExifDoubleArray(ExifTag.PixelScale),
return new ExifByteArray(ExifTag.VersionYear, ExifDataType.Byte); ExifTagValue.IntergraphMatrix => new ExifDoubleArray(ExifTag.IntergraphMatrix),
case ExifTagValue.XMP: ExifTagValue.ModelTiePoint => new ExifDoubleArray(ExifTag.ModelTiePoint),
return new ExifByteArray(ExifTag.XMP, ExifDataType.Byte); ExifTagValue.ModelTransform => new ExifDoubleArray(ExifTag.ModelTransform),
case ExifTagValue.CFAPattern2: ExifTagValue.SubfileType => new ExifLong(ExifTag.SubfileType),
return new ExifByteArray(ExifTag.CFAPattern2, ExifDataType.Byte); ExifTagValue.SubIFDOffset => new ExifLong(ExifTag.SubIFDOffset),
case ExifTagValue.TIFFEPStandardID: ExifTagValue.GPSIFDOffset => new ExifLong(ExifTag.GPSIFDOffset),
return new ExifByteArray(ExifTag.TIFFEPStandardID, ExifDataType.Byte); ExifTagValue.T4Options => new ExifLong(ExifTag.T4Options),
case ExifTagValue.GPSVersionID: ExifTagValue.T6Options => new ExifLong(ExifTag.T6Options),
return new ExifByteArray(ExifTag.GPSVersionID, ExifDataType.Byte); ExifTagValue.XClipPathUnits => new ExifLong(ExifTag.XClipPathUnits),
ExifTagValue.YClipPathUnits => new ExifLong(ExifTag.YClipPathUnits),
case ExifTagValue.PixelScale: ExifTagValue.ProfileType => new ExifLong(ExifTag.ProfileType),
return new ExifDoubleArray(ExifTag.PixelScale); ExifTagValue.CodingMethods => new ExifLong(ExifTag.CodingMethods),
case ExifTagValue.IntergraphMatrix: ExifTagValue.T82ptions => new ExifLong(ExifTag.T82ptions),
return new ExifDoubleArray(ExifTag.IntergraphMatrix); ExifTagValue.JPEGInterchangeFormat => new ExifLong(ExifTag.JPEGInterchangeFormat),
case ExifTagValue.ModelTiePoint: ExifTagValue.JPEGInterchangeFormatLength => new ExifLong(ExifTag.JPEGInterchangeFormatLength),
return new ExifDoubleArray(ExifTag.ModelTiePoint); ExifTagValue.MDFileTag => new ExifLong(ExifTag.MDFileTag),
case ExifTagValue.ModelTransform: ExifTagValue.StandardOutputSensitivity => new ExifLong(ExifTag.StandardOutputSensitivity),
return new ExifDoubleArray(ExifTag.ModelTransform); ExifTagValue.RecommendedExposureIndex => new ExifLong(ExifTag.RecommendedExposureIndex),
ExifTagValue.ISOSpeed => new ExifLong(ExifTag.ISOSpeed),
case ExifTagValue.SubfileType: ExifTagValue.ISOSpeedLatitudeyyy => new ExifLong(ExifTag.ISOSpeedLatitudeyyy),
return new ExifLong(ExifTag.SubfileType); ExifTagValue.ISOSpeedLatitudezzz => new ExifLong(ExifTag.ISOSpeedLatitudezzz),
case ExifTagValue.SubIFDOffset: ExifTagValue.FaxRecvParams => new ExifLong(ExifTag.FaxRecvParams),
return new ExifLong(ExifTag.SubIFDOffset); ExifTagValue.FaxRecvTime => new ExifLong(ExifTag.FaxRecvTime),
case ExifTagValue.GPSIFDOffset: ExifTagValue.ImageNumber => new ExifLong(ExifTag.ImageNumber),
return new ExifLong(ExifTag.GPSIFDOffset); ExifTagValue.FreeOffsets => new ExifLongArray(ExifTag.FreeOffsets),
case ExifTagValue.T4Options: ExifTagValue.FreeByteCounts => new ExifLongArray(ExifTag.FreeByteCounts),
return new ExifLong(ExifTag.T4Options); ExifTagValue.ColorResponseUnit => new ExifLongArray(ExifTag.ColorResponseUnit),
case ExifTagValue.T6Options: ExifTagValue.SMinSampleValue => new ExifLongArray(ExifTag.SMinSampleValue),
return new ExifLong(ExifTag.T6Options); ExifTagValue.SMaxSampleValue => new ExifLongArray(ExifTag.SMaxSampleValue),
case ExifTagValue.XClipPathUnits: ExifTagValue.JPEGQTables => new ExifLongArray(ExifTag.JPEGQTables),
return new ExifLong(ExifTag.XClipPathUnits); ExifTagValue.JPEGDCTables => new ExifLongArray(ExifTag.JPEGDCTables),
case ExifTagValue.YClipPathUnits: ExifTagValue.JPEGACTables => new ExifLongArray(ExifTag.JPEGACTables),
return new ExifLong(ExifTag.YClipPathUnits); ExifTagValue.StripRowCounts => new ExifLongArray(ExifTag.StripRowCounts),
case ExifTagValue.ProfileType: ExifTagValue.IntergraphRegisters => new ExifLongArray(ExifTag.IntergraphRegisters),
return new ExifLong(ExifTag.ProfileType); ExifTagValue.SubIFDs => new ExifLongArray(ExifTag.SubIFDs),
case ExifTagValue.CodingMethods: ExifTagValue.ImageWidth => new ExifNumber(ExifTag.ImageWidth),
return new ExifLong(ExifTag.CodingMethods); ExifTagValue.ImageLength => new ExifNumber(ExifTag.ImageLength),
case ExifTagValue.T82ptions: ExifTagValue.RowsPerStrip => new ExifNumber(ExifTag.RowsPerStrip),
return new ExifLong(ExifTag.T82ptions); ExifTagValue.TileWidth => new ExifNumber(ExifTag.TileWidth),
case ExifTagValue.JPEGInterchangeFormat: ExifTagValue.TileLength => new ExifNumber(ExifTag.TileLength),
return new ExifLong(ExifTag.JPEGInterchangeFormat); ExifTagValue.BadFaxLines => new ExifNumber(ExifTag.BadFaxLines),
case ExifTagValue.JPEGInterchangeFormatLength: ExifTagValue.ConsecutiveBadFaxLines => new ExifNumber(ExifTag.ConsecutiveBadFaxLines),
return new ExifLong(ExifTag.JPEGInterchangeFormatLength); ExifTagValue.PixelXDimension => new ExifNumber(ExifTag.PixelXDimension),
case ExifTagValue.MDFileTag: ExifTagValue.PixelYDimension => new ExifNumber(ExifTag.PixelYDimension),
return new ExifLong(ExifTag.MDFileTag); ExifTagValue.StripByteCounts => new ExifNumberArray(ExifTag.StripByteCounts),
case ExifTagValue.StandardOutputSensitivity: ExifTagValue.StripOffsets => new ExifNumberArray(ExifTag.StripOffsets),
return new ExifLong(ExifTag.StandardOutputSensitivity); ExifTagValue.TileByteCounts => new ExifNumberArray(ExifTag.TileByteCounts),
case ExifTagValue.RecommendedExposureIndex: ExifTagValue.TileOffsets => new ExifNumberArray(ExifTag.TileOffsets),
return new ExifLong(ExifTag.RecommendedExposureIndex); ExifTagValue.ImageLayer => new ExifNumberArray(ExifTag.ImageLayer),
case ExifTagValue.ISOSpeed: ExifTagValue.XPosition => new ExifRational(ExifTag.XPosition),
return new ExifLong(ExifTag.ISOSpeed); ExifTagValue.YPosition => new ExifRational(ExifTag.YPosition),
case ExifTagValue.ISOSpeedLatitudeyyy: ExifTagValue.XResolution => new ExifRational(ExifTag.XResolution),
return new ExifLong(ExifTag.ISOSpeedLatitudeyyy); ExifTagValue.YResolution => new ExifRational(ExifTag.YResolution),
case ExifTagValue.ISOSpeedLatitudezzz: ExifTagValue.BatteryLevel => new ExifRational(ExifTag.BatteryLevel),
return new ExifLong(ExifTag.ISOSpeedLatitudezzz); ExifTagValue.ExposureTime => new ExifRational(ExifTag.ExposureTime),
case ExifTagValue.FaxRecvParams: ExifTagValue.FNumber => new ExifRational(ExifTag.FNumber),
return new ExifLong(ExifTag.FaxRecvParams); ExifTagValue.MDScalePixel => new ExifRational(ExifTag.MDScalePixel),
case ExifTagValue.FaxRecvTime: ExifTagValue.CompressedBitsPerPixel => new ExifRational(ExifTag.CompressedBitsPerPixel),
return new ExifLong(ExifTag.FaxRecvTime); ExifTagValue.ApertureValue => new ExifRational(ExifTag.ApertureValue),
case ExifTagValue.ImageNumber: ExifTagValue.MaxApertureValue => new ExifRational(ExifTag.MaxApertureValue),
return new ExifLong(ExifTag.ImageNumber); ExifTagValue.SubjectDistance => new ExifRational(ExifTag.SubjectDistance),
ExifTagValue.FocalLength => new ExifRational(ExifTag.FocalLength),
case ExifTagValue.FreeOffsets: ExifTagValue.FlashEnergy2 => new ExifRational(ExifTag.FlashEnergy2),
return new ExifLongArray(ExifTag.FreeOffsets); ExifTagValue.FocalPlaneXResolution2 => new ExifRational(ExifTag.FocalPlaneXResolution2),
case ExifTagValue.FreeByteCounts: ExifTagValue.FocalPlaneYResolution2 => new ExifRational(ExifTag.FocalPlaneYResolution2),
return new ExifLongArray(ExifTag.FreeByteCounts); ExifTagValue.ExposureIndex2 => new ExifRational(ExifTag.ExposureIndex2),
case ExifTagValue.ColorResponseUnit: ExifTagValue.Humidity => new ExifRational(ExifTag.Humidity),
return new ExifLongArray(ExifTag.ColorResponseUnit); ExifTagValue.Pressure => new ExifRational(ExifTag.Pressure),
case ExifTagValue.SMinSampleValue: ExifTagValue.Acceleration => new ExifRational(ExifTag.Acceleration),
return new ExifLongArray(ExifTag.SMinSampleValue); ExifTagValue.FlashEnergy => new ExifRational(ExifTag.FlashEnergy),
case ExifTagValue.SMaxSampleValue: ExifTagValue.FocalPlaneXResolution => new ExifRational(ExifTag.FocalPlaneXResolution),
return new ExifLongArray(ExifTag.SMaxSampleValue); ExifTagValue.FocalPlaneYResolution => new ExifRational(ExifTag.FocalPlaneYResolution),
case ExifTagValue.JPEGQTables: ExifTagValue.ExposureIndex => new ExifRational(ExifTag.ExposureIndex),
return new ExifLongArray(ExifTag.JPEGQTables); ExifTagValue.DigitalZoomRatio => new ExifRational(ExifTag.DigitalZoomRatio),
case ExifTagValue.JPEGDCTables: ExifTagValue.GPSAltitude => new ExifRational(ExifTag.GPSAltitude),
return new ExifLongArray(ExifTag.JPEGDCTables); ExifTagValue.GPSDOP => new ExifRational(ExifTag.GPSDOP),
case ExifTagValue.JPEGACTables: ExifTagValue.GPSSpeed => new ExifRational(ExifTag.GPSSpeed),
return new ExifLongArray(ExifTag.JPEGACTables); ExifTagValue.GPSTrack => new ExifRational(ExifTag.GPSTrack),
case ExifTagValue.StripRowCounts: ExifTagValue.GPSImgDirection => new ExifRational(ExifTag.GPSImgDirection),
return new ExifLongArray(ExifTag.StripRowCounts); ExifTagValue.GPSDestBearing => new ExifRational(ExifTag.GPSDestBearing),
case ExifTagValue.IntergraphRegisters: ExifTagValue.GPSDestDistance => new ExifRational(ExifTag.GPSDestDistance),
return new ExifLongArray(ExifTag.IntergraphRegisters); ExifTagValue.GPSHPositioningError => new ExifRational(ExifTag.GPSHPositioningError),
case ExifTagValue.SubIFDs: ExifTagValue.WhitePoint => new ExifRationalArray(ExifTag.WhitePoint),
return new ExifLongArray(ExifTag.SubIFDs); ExifTagValue.PrimaryChromaticities => new ExifRationalArray(ExifTag.PrimaryChromaticities),
ExifTagValue.YCbCrCoefficients => new ExifRationalArray(ExifTag.YCbCrCoefficients),
case ExifTagValue.ImageWidth: ExifTagValue.ReferenceBlackWhite => new ExifRationalArray(ExifTag.ReferenceBlackWhite),
return new ExifNumber(ExifTag.ImageWidth); ExifTagValue.GPSLatitude => new ExifRationalArray(ExifTag.GPSLatitude),
case ExifTagValue.ImageLength: ExifTagValue.GPSLongitude => new ExifRationalArray(ExifTag.GPSLongitude),
return new ExifNumber(ExifTag.ImageLength); ExifTagValue.GPSTimestamp => new ExifRationalArray(ExifTag.GPSTimestamp),
case ExifTagValue.RowsPerStrip: ExifTagValue.GPSDestLatitude => new ExifRationalArray(ExifTag.GPSDestLatitude),
return new ExifNumber(ExifTag.RowsPerStrip); ExifTagValue.GPSDestLongitude => new ExifRationalArray(ExifTag.GPSDestLongitude),
case ExifTagValue.TileWidth: ExifTagValue.LensSpecification => new ExifRationalArray(ExifTag.LensSpecification),
return new ExifNumber(ExifTag.TileWidth); ExifTagValue.OldSubfileType => new ExifShort(ExifTag.OldSubfileType),
case ExifTagValue.TileLength: ExifTagValue.Compression => new ExifShort(ExifTag.Compression),
return new ExifNumber(ExifTag.TileLength); ExifTagValue.PhotometricInterpretation => new ExifShort(ExifTag.PhotometricInterpretation),
case ExifTagValue.BadFaxLines: ExifTagValue.Thresholding => new ExifShort(ExifTag.Thresholding),
return new ExifNumber(ExifTag.BadFaxLines); ExifTagValue.CellWidth => new ExifShort(ExifTag.CellWidth),
case ExifTagValue.ConsecutiveBadFaxLines: ExifTagValue.CellLength => new ExifShort(ExifTag.CellLength),
return new ExifNumber(ExifTag.ConsecutiveBadFaxLines); ExifTagValue.FillOrder => new ExifShort(ExifTag.FillOrder),
case ExifTagValue.PixelXDimension: ExifTagValue.Orientation => new ExifShort(ExifTag.Orientation),
return new ExifNumber(ExifTag.PixelXDimension); ExifTagValue.SamplesPerPixel => new ExifShort(ExifTag.SamplesPerPixel),
case ExifTagValue.PixelYDimension: ExifTagValue.PlanarConfiguration => new ExifShort(ExifTag.PlanarConfiguration),
return new ExifNumber(ExifTag.PixelYDimension); ExifTagValue.Predictor => new ExifShort(ExifTag.Predictor),
ExifTagValue.GrayResponseUnit => new ExifShort(ExifTag.GrayResponseUnit),
case ExifTagValue.StripByteCounts: ExifTagValue.ResolutionUnit => new ExifShort(ExifTag.ResolutionUnit),
return new ExifNumberArray(ExifTag.StripByteCounts); ExifTagValue.CleanFaxData => new ExifShort(ExifTag.CleanFaxData),
case ExifTagValue.StripOffsets: ExifTagValue.InkSet => new ExifShort(ExifTag.InkSet),
return new ExifNumberArray(ExifTag.StripOffsets); ExifTagValue.NumberOfInks => new ExifShort(ExifTag.NumberOfInks),
case ExifTagValue.TileByteCounts: ExifTagValue.DotRange => new ExifShort(ExifTag.DotRange),
return new ExifNumberArray(ExifTag.TileByteCounts); ExifTagValue.Indexed => new ExifShort(ExifTag.Indexed),
case ExifTagValue.TileOffsets: ExifTagValue.OPIProxy => new ExifShort(ExifTag.OPIProxy),
return new ExifNumberArray(ExifTag.TileOffsets); ExifTagValue.JPEGProc => new ExifShort(ExifTag.JPEGProc),
case ExifTagValue.ImageLayer: ExifTagValue.JPEGRestartInterval => new ExifShort(ExifTag.JPEGRestartInterval),
return new ExifNumberArray(ExifTag.ImageLayer); ExifTagValue.YCbCrPositioning => new ExifShort(ExifTag.YCbCrPositioning),
ExifTagValue.Rating => new ExifShort(ExifTag.Rating),
case ExifTagValue.XPosition: ExifTagValue.RatingPercent => new ExifShort(ExifTag.RatingPercent),
return new ExifRational(ExifTag.XPosition); ExifTagValue.ExposureProgram => new ExifShort(ExifTag.ExposureProgram),
case ExifTagValue.YPosition: ExifTagValue.Interlace => new ExifShort(ExifTag.Interlace),
return new ExifRational(ExifTag.YPosition); ExifTagValue.SelfTimerMode => new ExifShort(ExifTag.SelfTimerMode),
case ExifTagValue.XResolution: ExifTagValue.SensitivityType => new ExifShort(ExifTag.SensitivityType),
return new ExifRational(ExifTag.XResolution); ExifTagValue.MeteringMode => new ExifShort(ExifTag.MeteringMode),
case ExifTagValue.YResolution: ExifTagValue.LightSource => new ExifShort(ExifTag.LightSource),
return new ExifRational(ExifTag.YResolution); ExifTagValue.FocalPlaneResolutionUnit2 => new ExifShort(ExifTag.FocalPlaneResolutionUnit2),
case ExifTagValue.BatteryLevel: ExifTagValue.SensingMethod2 => new ExifShort(ExifTag.SensingMethod2),
return new ExifRational(ExifTag.BatteryLevel); ExifTagValue.Flash => new ExifShort(ExifTag.Flash),
case ExifTagValue.ExposureTime: ExifTagValue.ColorSpace => new ExifShort(ExifTag.ColorSpace),
return new ExifRational(ExifTag.ExposureTime); ExifTagValue.FocalPlaneResolutionUnit => new ExifShort(ExifTag.FocalPlaneResolutionUnit),
case ExifTagValue.FNumber: ExifTagValue.SensingMethod => new ExifShort(ExifTag.SensingMethod),
return new ExifRational(ExifTag.FNumber); ExifTagValue.CustomRendered => new ExifShort(ExifTag.CustomRendered),
case ExifTagValue.MDScalePixel: ExifTagValue.ExposureMode => new ExifShort(ExifTag.ExposureMode),
return new ExifRational(ExifTag.MDScalePixel); ExifTagValue.WhiteBalance => new ExifShort(ExifTag.WhiteBalance),
case ExifTagValue.CompressedBitsPerPixel: ExifTagValue.FocalLengthIn35mmFilm => new ExifShort(ExifTag.FocalLengthIn35mmFilm),
return new ExifRational(ExifTag.CompressedBitsPerPixel); ExifTagValue.SceneCaptureType => new ExifShort(ExifTag.SceneCaptureType),
case ExifTagValue.ApertureValue: ExifTagValue.GainControl => new ExifShort(ExifTag.GainControl),
return new ExifRational(ExifTag.ApertureValue); ExifTagValue.Contrast => new ExifShort(ExifTag.Contrast),
case ExifTagValue.MaxApertureValue: ExifTagValue.Saturation => new ExifShort(ExifTag.Saturation),
return new ExifRational(ExifTag.MaxApertureValue); ExifTagValue.Sharpness => new ExifShort(ExifTag.Sharpness),
case ExifTagValue.SubjectDistance: ExifTagValue.SubjectDistanceRange => new ExifShort(ExifTag.SubjectDistanceRange),
return new ExifRational(ExifTag.SubjectDistance); ExifTagValue.GPSDifferential => new ExifShort(ExifTag.GPSDifferential),
case ExifTagValue.FocalLength: ExifTagValue.BitsPerSample => new ExifShortArray(ExifTag.BitsPerSample),
return new ExifRational(ExifTag.FocalLength); ExifTagValue.MinSampleValue => new ExifShortArray(ExifTag.MinSampleValue),
case ExifTagValue.FlashEnergy2: ExifTagValue.MaxSampleValue => new ExifShortArray(ExifTag.MaxSampleValue),
return new ExifRational(ExifTag.FlashEnergy2); ExifTagValue.GrayResponseCurve => new ExifShortArray(ExifTag.GrayResponseCurve),
case ExifTagValue.FocalPlaneXResolution2: ExifTagValue.ColorMap => new ExifShortArray(ExifTag.ColorMap),
return new ExifRational(ExifTag.FocalPlaneXResolution2); ExifTagValue.ExtraSamples => new ExifShortArray(ExifTag.ExtraSamples),
case ExifTagValue.FocalPlaneYResolution2: ExifTagValue.PageNumber => new ExifShortArray(ExifTag.PageNumber),
return new ExifRational(ExifTag.FocalPlaneYResolution2); ExifTagValue.TransferFunction => new ExifShortArray(ExifTag.TransferFunction),
case ExifTagValue.ExposureIndex2: ExifTagValue.HalftoneHints => new ExifShortArray(ExifTag.HalftoneHints),
return new ExifRational(ExifTag.ExposureIndex2); ExifTagValue.SampleFormat => new ExifShortArray(ExifTag.SampleFormat),
case ExifTagValue.Humidity: ExifTagValue.TransferRange => new ExifShortArray(ExifTag.TransferRange),
return new ExifRational(ExifTag.Humidity); ExifTagValue.DefaultImageColor => new ExifShortArray(ExifTag.DefaultImageColor),
case ExifTagValue.Pressure: ExifTagValue.JPEGLosslessPredictors => new ExifShortArray(ExifTag.JPEGLosslessPredictors),
return new ExifRational(ExifTag.Pressure); ExifTagValue.JPEGPointTransforms => new ExifShortArray(ExifTag.JPEGPointTransforms),
case ExifTagValue.Acceleration: ExifTagValue.YCbCrSubsampling => new ExifShortArray(ExifTag.YCbCrSubsampling),
return new ExifRational(ExifTag.Acceleration); ExifTagValue.CFARepeatPatternDim => new ExifShortArray(ExifTag.CFARepeatPatternDim),
case ExifTagValue.FlashEnergy: ExifTagValue.IntergraphPacketData => new ExifShortArray(ExifTag.IntergraphPacketData),
return new ExifRational(ExifTag.FlashEnergy); ExifTagValue.ISOSpeedRatings => new ExifShortArray(ExifTag.ISOSpeedRatings),
case ExifTagValue.FocalPlaneXResolution: ExifTagValue.SubjectArea => new ExifShortArray(ExifTag.SubjectArea),
return new ExifRational(ExifTag.FocalPlaneXResolution); ExifTagValue.SubjectLocation => new ExifShortArray(ExifTag.SubjectLocation),
case ExifTagValue.FocalPlaneYResolution: ExifTagValue.ShutterSpeedValue => new ExifSignedRational(ExifTag.ShutterSpeedValue),
return new ExifRational(ExifTag.FocalPlaneYResolution); ExifTagValue.BrightnessValue => new ExifSignedRational(ExifTag.BrightnessValue),
case ExifTagValue.ExposureIndex: ExifTagValue.ExposureBiasValue => new ExifSignedRational(ExifTag.ExposureBiasValue),
return new ExifRational(ExifTag.ExposureIndex); ExifTagValue.AmbientTemperature => new ExifSignedRational(ExifTag.AmbientTemperature),
case ExifTagValue.DigitalZoomRatio: ExifTagValue.WaterDepth => new ExifSignedRational(ExifTag.WaterDepth),
return new ExifRational(ExifTag.DigitalZoomRatio); ExifTagValue.CameraElevationAngle => new ExifSignedRational(ExifTag.CameraElevationAngle),
case ExifTagValue.GPSAltitude: ExifTagValue.Decode => new ExifSignedRationalArray(ExifTag.Decode),
return new ExifRational(ExifTag.GPSAltitude); ExifTagValue.TimeZoneOffset => new ExifSignedShortArray(ExifTag.TimeZoneOffset),
case ExifTagValue.GPSDOP: ExifTagValue.ImageDescription => new ExifString(ExifTag.ImageDescription),
return new ExifRational(ExifTag.GPSDOP); ExifTagValue.Make => new ExifString(ExifTag.Make),
case ExifTagValue.GPSSpeed: ExifTagValue.Model => new ExifString(ExifTag.Model),
return new ExifRational(ExifTag.GPSSpeed); ExifTagValue.Software => new ExifString(ExifTag.Software),
case ExifTagValue.GPSTrack: ExifTagValue.DateTime => new ExifString(ExifTag.DateTime),
return new ExifRational(ExifTag.GPSTrack); ExifTagValue.Artist => new ExifString(ExifTag.Artist),
case ExifTagValue.GPSImgDirection: ExifTagValue.HostComputer => new ExifString(ExifTag.HostComputer),
return new ExifRational(ExifTag.GPSImgDirection); ExifTagValue.Copyright => new ExifString(ExifTag.Copyright),
case ExifTagValue.GPSDestBearing: ExifTagValue.DocumentName => new ExifString(ExifTag.DocumentName),
return new ExifRational(ExifTag.GPSDestBearing); ExifTagValue.PageName => new ExifString(ExifTag.PageName),
case ExifTagValue.GPSDestDistance: ExifTagValue.InkNames => new ExifString(ExifTag.InkNames),
return new ExifRational(ExifTag.GPSDestDistance); ExifTagValue.TargetPrinter => new ExifString(ExifTag.TargetPrinter),
case ExifTagValue.GPSHPositioningError: ExifTagValue.ImageID => new ExifString(ExifTag.ImageID),
return new ExifRational(ExifTag.GPSHPositioningError); ExifTagValue.MDLabName => new ExifString(ExifTag.MDLabName),
ExifTagValue.MDSampleInfo => new ExifString(ExifTag.MDSampleInfo),
case ExifTagValue.WhitePoint: ExifTagValue.MDPrepDate => new ExifString(ExifTag.MDPrepDate),
return new ExifRationalArray(ExifTag.WhitePoint); ExifTagValue.MDPrepTime => new ExifString(ExifTag.MDPrepTime),
case ExifTagValue.PrimaryChromaticities: ExifTagValue.MDFileUnits => new ExifString(ExifTag.MDFileUnits),
return new ExifRationalArray(ExifTag.PrimaryChromaticities); ExifTagValue.SEMInfo => new ExifString(ExifTag.SEMInfo),
case ExifTagValue.YCbCrCoefficients: ExifTagValue.SpectralSensitivity => new ExifString(ExifTag.SpectralSensitivity),
return new ExifRationalArray(ExifTag.YCbCrCoefficients); ExifTagValue.DateTimeOriginal => new ExifString(ExifTag.DateTimeOriginal),
case ExifTagValue.ReferenceBlackWhite: ExifTagValue.DateTimeDigitized => new ExifString(ExifTag.DateTimeDigitized),
return new ExifRationalArray(ExifTag.ReferenceBlackWhite); ExifTagValue.SubsecTime => new ExifString(ExifTag.SubsecTime),
case ExifTagValue.GPSLatitude: ExifTagValue.SubsecTimeOriginal => new ExifString(ExifTag.SubsecTimeOriginal),
return new ExifRationalArray(ExifTag.GPSLatitude); ExifTagValue.SubsecTimeDigitized => new ExifString(ExifTag.SubsecTimeDigitized),
case ExifTagValue.GPSLongitude: ExifTagValue.RelatedSoundFile => new ExifString(ExifTag.RelatedSoundFile),
return new ExifRationalArray(ExifTag.GPSLongitude); ExifTagValue.FaxSubaddress => new ExifString(ExifTag.FaxSubaddress),
case ExifTagValue.GPSTimestamp: ExifTagValue.OffsetTime => new ExifString(ExifTag.OffsetTime),
return new ExifRationalArray(ExifTag.GPSTimestamp); ExifTagValue.OffsetTimeOriginal => new ExifString(ExifTag.OffsetTimeOriginal),
case ExifTagValue.GPSDestLatitude: ExifTagValue.OffsetTimeDigitized => new ExifString(ExifTag.OffsetTimeDigitized),
return new ExifRationalArray(ExifTag.GPSDestLatitude); ExifTagValue.SecurityClassification => new ExifString(ExifTag.SecurityClassification),
case ExifTagValue.GPSDestLongitude: ExifTagValue.ImageHistory => new ExifString(ExifTag.ImageHistory),
return new ExifRationalArray(ExifTag.GPSDestLongitude); ExifTagValue.ImageUniqueID => new ExifString(ExifTag.ImageUniqueID),
case ExifTagValue.LensSpecification: ExifTagValue.OwnerName => new ExifString(ExifTag.OwnerName),
return new ExifRationalArray(ExifTag.LensSpecification); ExifTagValue.SerialNumber => new ExifString(ExifTag.SerialNumber),
ExifTagValue.LensMake => new ExifString(ExifTag.LensMake),
case ExifTagValue.OldSubfileType: ExifTagValue.LensModel => new ExifString(ExifTag.LensModel),
return new ExifShort(ExifTag.OldSubfileType); ExifTagValue.LensSerialNumber => new ExifString(ExifTag.LensSerialNumber),
case ExifTagValue.Compression: ExifTagValue.GDALMetadata => new ExifString(ExifTag.GDALMetadata),
return new ExifShort(ExifTag.Compression); ExifTagValue.GDALNoData => new ExifString(ExifTag.GDALNoData),
case ExifTagValue.PhotometricInterpretation: ExifTagValue.GPSLatitudeRef => new ExifString(ExifTag.GPSLatitudeRef),
return new ExifShort(ExifTag.PhotometricInterpretation); ExifTagValue.GPSLongitudeRef => new ExifString(ExifTag.GPSLongitudeRef),
case ExifTagValue.Thresholding: ExifTagValue.GPSSatellites => new ExifString(ExifTag.GPSSatellites),
return new ExifShort(ExifTag.Thresholding); ExifTagValue.GPSStatus => new ExifString(ExifTag.GPSStatus),
case ExifTagValue.CellWidth: ExifTagValue.GPSMeasureMode => new ExifString(ExifTag.GPSMeasureMode),
return new ExifShort(ExifTag.CellWidth); ExifTagValue.GPSSpeedRef => new ExifString(ExifTag.GPSSpeedRef),
case ExifTagValue.CellLength: ExifTagValue.GPSTrackRef => new ExifString(ExifTag.GPSTrackRef),
return new ExifShort(ExifTag.CellLength); ExifTagValue.GPSImgDirectionRef => new ExifString(ExifTag.GPSImgDirectionRef),
case ExifTagValue.FillOrder: ExifTagValue.GPSMapDatum => new ExifString(ExifTag.GPSMapDatum),
return new ExifShort(ExifTag.FillOrder); ExifTagValue.GPSDestLatitudeRef => new ExifString(ExifTag.GPSDestLatitudeRef),
case ExifTagValue.Orientation: ExifTagValue.GPSDestLongitudeRef => new ExifString(ExifTag.GPSDestLongitudeRef),
return new ExifShort(ExifTag.Orientation); ExifTagValue.GPSDestBearingRef => new ExifString(ExifTag.GPSDestBearingRef),
case ExifTagValue.SamplesPerPixel: ExifTagValue.GPSDestDistanceRef => new ExifString(ExifTag.GPSDestDistanceRef),
return new ExifShort(ExifTag.SamplesPerPixel); ExifTagValue.GPSDateStamp => new ExifString(ExifTag.GPSDateStamp),
case ExifTagValue.PlanarConfiguration: ExifTagValue.FileSource => new ExifByte(ExifTag.FileSource, ExifDataType.Undefined),
return new ExifShort(ExifTag.PlanarConfiguration); ExifTagValue.SceneType => new ExifByte(ExifTag.SceneType, ExifDataType.Undefined),
case ExifTagValue.Predictor: ExifTagValue.JPEGTables => new ExifByteArray(ExifTag.JPEGTables, ExifDataType.Undefined),
return new ExifShort(ExifTag.Predictor); ExifTagValue.OECF => new ExifByteArray(ExifTag.OECF, ExifDataType.Undefined),
case ExifTagValue.GrayResponseUnit: ExifTagValue.ExifVersion => new ExifByteArray(ExifTag.ExifVersion, ExifDataType.Undefined),
return new ExifShort(ExifTag.GrayResponseUnit); ExifTagValue.ComponentsConfiguration => new ExifByteArray(ExifTag.ComponentsConfiguration, ExifDataType.Undefined),
case ExifTagValue.ResolutionUnit: ExifTagValue.MakerNote => new ExifByteArray(ExifTag.MakerNote, ExifDataType.Undefined),
return new ExifShort(ExifTag.ResolutionUnit); ExifTagValue.FlashpixVersion => new ExifByteArray(ExifTag.FlashpixVersion, ExifDataType.Undefined),
case ExifTagValue.CleanFaxData: ExifTagValue.SpatialFrequencyResponse => new ExifByteArray(ExifTag.SpatialFrequencyResponse, ExifDataType.Undefined),
return new ExifShort(ExifTag.CleanFaxData); ExifTagValue.SpatialFrequencyResponse2 => new ExifByteArray(ExifTag.SpatialFrequencyResponse2, ExifDataType.Undefined),
case ExifTagValue.InkSet: ExifTagValue.Noise => new ExifByteArray(ExifTag.Noise, ExifDataType.Undefined),
return new ExifShort(ExifTag.InkSet); ExifTagValue.CFAPattern => new ExifByteArray(ExifTag.CFAPattern, ExifDataType.Undefined),
case ExifTagValue.NumberOfInks: ExifTagValue.DeviceSettingDescription => new ExifByteArray(ExifTag.DeviceSettingDescription, ExifDataType.Undefined),
return new ExifShort(ExifTag.NumberOfInks); ExifTagValue.ImageSourceData => new ExifByteArray(ExifTag.ImageSourceData, ExifDataType.Undefined),
case ExifTagValue.DotRange: ExifTagValue.XPTitle => new ExifUcs2String(ExifTag.XPTitle),
return new ExifShort(ExifTag.DotRange); ExifTagValue.XPComment => new ExifUcs2String(ExifTag.XPComment),
case ExifTagValue.Indexed: ExifTagValue.XPAuthor => new ExifUcs2String(ExifTag.XPAuthor),
return new ExifShort(ExifTag.Indexed); ExifTagValue.XPKeywords => new ExifUcs2String(ExifTag.XPKeywords),
case ExifTagValue.OPIProxy: ExifTagValue.XPSubject => new ExifUcs2String(ExifTag.XPSubject),
return new ExifShort(ExifTag.OPIProxy); ExifTagValue.UserComment => new ExifEncodedString(ExifTag.UserComment),
case ExifTagValue.JPEGProc: ExifTagValue.GPSProcessingMethod => new ExifEncodedString(ExifTag.GPSProcessingMethod),
return new ExifShort(ExifTag.JPEGProc); ExifTagValue.GPSAreaInformation => new ExifEncodedString(ExifTag.GPSAreaInformation),
case ExifTagValue.JPEGRestartInterval: _ => null,
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.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.TimeZoneOffset:
return new ExifSignedShortArray(ExifTag.TimeZoneOffset);
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.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);
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;
}
}
} }

24
src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs

@ -4,35 +4,35 @@
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif;
/// <summary> /// <summary>
/// A value of the exif profile. /// A value of the Exif profile.
/// </summary> /// </summary>
public interface IExifValue : IDeepCloneable<IExifValue> public interface IExifValue : IDeepCloneable<IExifValue>
{ {
/// <summary> /// <summary>
/// Gets the data type of the exif value. /// Gets the data type of the Exif value.
/// </summary> /// </summary>
ExifDataType DataType { get; } public ExifDataType DataType { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether the value is an array. /// Gets a value indicating whether the value is an array.
/// </summary> /// </summary>
bool IsArray { get; } public bool IsArray { get; }
/// <summary> /// <summary>
/// Gets the tag of the exif value. /// Gets the tag of the Exif value.
/// </summary> /// </summary>
ExifTag Tag { get; } public ExifTag Tag { get; }
/// <summary> /// <summary>
/// Gets the value of this exif value. /// Gets the value of this Exif value.
/// </summary> /// </summary>
/// <returns>The value of this exif value.</returns> /// <returns>The value of this Exif value.</returns>
object? GetValue(); public object? GetValue();
/// <summary> /// <summary>
/// Sets the value of this exif value. /// Sets the value of this Exif value.
/// </summary> /// </summary>
/// <param name="value">The value of this exif value.</param> /// <param name="value">The value of this Exif value.</param>
/// <returns>A value indicating whether the value could be set.</returns> /// <returns>A value indicating whether the value could be set.</returns>
bool TrySetValue(object? value); public bool TrySetValue(object? value);
} }

5
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

@ -828,4 +828,9 @@ public class TiffDecoderTests : TiffDecoderBaseTester
testOutputDetails: details, testOutputDetails: details,
appendPixelTypeToFileName: false); appendPixelTypeToFileName: false);
} }
[Theory]
[WithFile(ExtraSamplesUnspecified, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_ExtraSamplesUnspecified<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
} }

19
tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs

@ -5,6 +5,7 @@ using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
@ -559,4 +560,22 @@ public class WebpDecoderTests
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToOriginal(provider, ReferenceDecoder); image.CompareToOriginal(provider, ReferenceDecoder);
} }
[Theory]
[WithFile(Lossy.Issue2906, PixelTypes.Rgba32)]
public void WebpDecoder_CanDecode_Issue2906<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(WebpDecoder.Instance);
ExifProfile exifProfile = image.Metadata.ExifProfile;
IExifValue<EncodedString> comment = exifProfile.GetValue(ExifTag.UserComment);
Assert.NotNull(comment);
Assert.Equal(EncodedString.CharacterCode.Unicode, comment.Value.Code);
Assert.StartsWith("1girl, pariya, ", comment.Value.Text);
image.DebugSave(provider);
image.CompareToOriginal(provider, ReferenceDecoder);
}
} }

2
tests/ImageSharp.Tests/TestImages.cs

@ -875,6 +875,7 @@ public static class TestImages
public const string Issue2801 = "Webp/issues/Issue2801.webp"; public const string Issue2801 = "Webp/issues/Issue2801.webp";
public const string Issue2866 = "Webp/issues/Issue2866.webp"; public const string Issue2866 = "Webp/issues/Issue2866.webp";
public const string Issue2925 = "Webp/issues/Issue2925.webp"; public const string Issue2925 = "Webp/issues/Issue2925.webp";
public const string Issue2906 = "Webp/issues/Issue2906.webp";
} }
public const string AlphaBlend = "Webp/alpha-blend.webp"; public const string AlphaBlend = "Webp/alpha-blend.webp";
@ -1136,6 +1137,7 @@ public static class TestImages
public const string Issues2679 = "Tiff/Issues/Issue2679.tiff"; public const string Issues2679 = "Tiff/Issues/Issue2679.tiff";
public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff"; public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff";
public const string Tiled0000023664 = "Tiff/Issues/tiled-0000023664.tiff"; public const string Tiled0000023664 = "Tiff/Issues/tiled-0000023664.tiff";
public const string ExtraSamplesUnspecified = "Tiff/Issues/ExtraSamplesUnspecified.tif";
public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff"; public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff";
public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff"; public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff";

3
tests/Images/Input/Tiff/Issues/ExtraSamplesUnspecified.tif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:71d28f17d2d56481faa4d241fae882eae4f8303c70f85bc3759f6a0c2074979e
size 1426558

3
tests/Images/Input/Webp/issues/Issue2906.webp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:56fe6a91feb9545c0a15966e0f6bc560890b193073c96ae9e39bf387c7e0cbca
size 157092
Loading…
Cancel
Save