Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support BigTIFF encoded TIFF data #302

Merged
merged 5 commits into from
Aug 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions MetadataExtractor/DirectoryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,46 @@ public static bool TryGetInt64(this Directory directory, int tagType, out long v
catch
{
// ignored
}
}

value = default;
return false;
}

#endregion

#region UInt64

/// <summary>Returns a tag's value as an <see cref="ulong"/>, or throws if conversion is not possible.</summary>
/// <remarks>
/// If the value is <see cref="IConvertible"/>, then that interface is used for conversion of the value.
/// If the value is an array of <see cref="IConvertible"/> having length one, then the single item is converted.
/// </remarks>
/// <exception cref="MetadataException">No value exists for <paramref name="tagType"/>, or the value is not convertible to the requested type.</exception>
[Pure]
public static ulong GetUInt64(this Directory directory, int tagType)
{
if (directory.TryGetUInt64(tagType, out ulong value))
return value;

return ThrowValueNotPossible<ulong>(directory, tagType);
}

[Pure]
public static bool TryGetUInt64(this Directory directory, int tagType, out ulong value)
{
var convertible = GetConvertibleObject(directory, tagType);

if (convertible != null)
{
try
{
value = convertible.ToUInt64(null);
return true;
}
catch
{
// ignored
}
}
Expand Down
94 changes: 50 additions & 44 deletions MetadataExtractor/Formats/Exif/ExifTiffHandler.cs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions MetadataExtractor/Formats/Photoshop/PhotoshopTiffHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public PhotoshopTiffHandler(List<Directory> directories)
{
}

public override bool CustomProcessTag(int tagOffset, ICollection<int> processedIfdOffsets, IndexedReader reader, int tagId, int byteCount)
public override bool CustomProcessTag(int tagOffset, HashSet<int> processedIfdOffsets, IndexedReader reader, int tagId, int byteCount, bool isBigTiff)
{
switch (tagId)
{
Expand All @@ -45,7 +45,7 @@ public override bool CustomProcessTag(int tagOffset, ICollection<int> processedI
return true;
}

return base.CustomProcessTag(tagOffset, processedIfdOffsets, reader, tagId, byteCount);
return base.CustomProcessTag(tagOffset, processedIfdOffsets, reader, tagId, byteCount, isBigTiff);
}
}
}
17 changes: 12 additions & 5 deletions MetadataExtractor/Formats/QuickTime/QuickTimeTiffHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,21 @@ public QuickTimeTiffHandler(List<Directory> directories)
{
}

public override void SetTiffMarker(int marker)
public override TiffStandard ProcessTiffMarker(ushort marker)
{
const int StandardTiffMarker = 0x002A;
if (marker != StandardTiffMarker)
const ushort StandardTiffMarker = 0x002A;
const ushort BigTiffMarker = 0x002B;

var standard = marker switch
{
throw new TiffProcessingException($"Unexpected TIFF marker: 0x{marker:X}");
}
StandardTiffMarker => TiffStandard.Tiff,
BigTiffMarker => TiffStandard.BigTiff,
_ => throw new TiffProcessingException($"Unexpected TIFF marker: 0x{marker:X}")
};

PushDirectory(new T());

return standard;
}
}
}
10 changes: 7 additions & 3 deletions MetadataExtractor/Formats/Tiff/DirectoryTiffHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,21 @@ private Directory GetCurrentOrErrorDirectory()
public void SetInt32SArray(int tagId, int[] array) => CurrentDirectory!.Set(tagId, array);
public void SetInt32U(int tagId, uint int32U) => CurrentDirectory!.Set(tagId, int32U);
public void SetInt32UArray(int tagId, uint[] array) => CurrentDirectory!.Set(tagId, array);
public void SetInt64S(int tagId, long int64S) => CurrentDirectory!.Set(tagId, int64S);
public void SetInt64SArray(int tagId, long[] array) => CurrentDirectory!.Set(tagId, array);
public void SetInt64U(int tagId, ulong int64U) => CurrentDirectory!.Set(tagId, int64U);
public void SetInt64UArray(int tagId, ulong[] array) => CurrentDirectory!.Set(tagId, array);

#pragma warning restore format

public abstract bool CustomProcessTag(int tagOffset, ICollection<int> processedIfdOffsets, IndexedReader reader, int tagId, int byteCount);
public abstract bool CustomProcessTag(int tagOffset, HashSet<int> processedIfdOffsets, IndexedReader reader, int tagId, int byteCount, bool isBigTiff);

public abstract bool TryCustomProcessFormat(int tagId, TiffDataFormatCode formatCode, uint componentCount, out long byteCount);
public abstract bool TryCustomProcessFormat(int tagId, TiffDataFormatCode formatCode, ulong componentCount, out ulong byteCount);

public abstract bool HasFollowerIfd();

public abstract bool TryEnterSubIfd(int tagType);

public abstract void SetTiffMarker(int marker);
public abstract TiffStandard ProcessTiffMarker(ushort marker);
}
}
25 changes: 17 additions & 8 deletions MetadataExtractor/Formats/Tiff/ITiffHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ namespace MetadataExtractor.Formats.Tiff
/// <author>Drew Noakes https://drewnoakes.com</author>
public interface ITiffHandler
{
/// <summary>Receives the 2-byte marker found in the TIFF header.</summary>
/// <remarks>
/// <summary>
/// Receives the 2-byte marker found in the TIFF header.
/// <para />
/// </summary>
/// <remarks>
/// Implementations are not obligated to use this information for any purpose, though it may be useful for
/// validation or perhaps differentiating the type of mapping to use for observed tags and IFDs.
/// </remarks>
/// <param name="marker">the 2-byte value found at position 2 of the TIFF header</param>
/// <exception cref="TiffProcessingException"/>
void SetTiffMarker(int marker);
/// <param name="marker">The 2-byte value found at position 2 of the TIFF header.</param>
/// <returns>The TIFF standard via which to interpret the data stream.</returns>
/// <exception cref="TiffProcessingException">The value of <paramref name="marker"/> is not supported.</exception>
TiffStandard ProcessTiffMarker(ushort marker);

bool TryEnterSubIfd(int tagType);

Expand All @@ -30,9 +31,9 @@ public interface ITiffHandler
void EndingIfd();

/// <exception cref="System.IO.IOException"/>
bool CustomProcessTag(int tagOffset, ICollection<int> processedIfdOffsets, IndexedReader reader, int tagId, int byteCount);
bool CustomProcessTag(int tagOffset, HashSet<int> processedIfdOffsets, IndexedReader reader, int tagId, int byteCount, bool isBigTiff);

bool TryCustomProcessFormat(int tagId, TiffDataFormatCode formatCode, uint componentCount, out long byteCount);
bool TryCustomProcessFormat(int tagId, TiffDataFormatCode formatCode, ulong componentCount, out ulong byteCount);

void Warn(string message);

Expand Down Expand Up @@ -77,5 +78,13 @@ public interface ITiffHandler
void SetInt32U(int tagId, uint int32U);

void SetInt32UArray(int tagId, uint[] array);

void SetInt64S(int tagId, long int64S);

void SetInt64SArray(int tagId, long[] array);

void SetInt64U(int tagId, ulong int64U);

void SetInt64UArray(int tagId, ulong[] array);
}
}
25 changes: 21 additions & 4 deletions MetadataExtractor/Formats/Tiff/TiffDataFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ public enum TiffDataFormatCode : ushort
Int32S = 9,
RationalS = 10,
Single = 11,
Double = 12
Double = 12,

// From BigTIFF
Int64U = 16,
Int64S = 17,
Ifd8 = 18
}

/// <summary>An enumeration of data formats used by the TIFF specification.</summary>
Expand All @@ -37,9 +42,14 @@ public sealed class TiffDataFormat
public static readonly TiffDataFormat RationalS = new("SRATIONAL", TiffDataFormatCode.RationalS, 8);
public static readonly TiffDataFormat Single = new("SINGLE", TiffDataFormatCode.Single, 4);
public static readonly TiffDataFormat Double = new("DOUBLE", TiffDataFormatCode.Double, 8);

// From BigTIFF
public static readonly TiffDataFormat Int64U = new("ULONG8", TiffDataFormatCode.Int64U, 8);
public static readonly TiffDataFormat Int64S = new("SLONG8", TiffDataFormatCode.Int64S, 8);
public static readonly TiffDataFormat Ifd8 = new("IFD8", TiffDataFormatCode.Ifd8, 8);
#pragma warning restore format

public static TiffDataFormat? FromTiffFormatCode(TiffDataFormatCode tiffFormatCode)
public static TiffDataFormat? FromTiffFormatCode(TiffDataFormatCode tiffFormatCode, bool isBigTiff)
{
return tiffFormatCode switch
{
Expand All @@ -56,15 +66,22 @@ public sealed class TiffDataFormat
TiffDataFormatCode.Single => Single,
TiffDataFormatCode.Double => Double,

// From BigTIFF
TiffDataFormatCode.Int64U => isBigTiff ? Int64U : null,
TiffDataFormatCode.Int64S => isBigTiff ? Int64S : null,
TiffDataFormatCode.Ifd8 => isBigTiff ? Ifd8 : null,

_ => null,
};
}

public string Name { get; }
public int ComponentSizeBytes { get; }

public byte ComponentSizeBytes { get; }

public TiffDataFormatCode TiffFormatCode { get; }

private TiffDataFormat(string name, TiffDataFormatCode tiffFormatCode, int componentSizeBytes)
private TiffDataFormat(string name, TiffDataFormatCode tiffFormatCode, byte componentSizeBytes)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
TiffFormatCode = tiffFormatCode;
Expand Down
Loading