diff --git a/MetadataExtractor/ImageMetadataReader.cs b/MetadataExtractor/ImageMetadataReader.cs
index c2995fae3..40ee0cff7 100644
--- a/MetadataExtractor/ImageMetadataReader.cs
+++ b/MetadataExtractor/ImageMetadataReader.cs
@@ -57,12 +57,13 @@ public static class ImageMetadataReader
{
/// Reads metadata from an .
/// A stream from which the file data may be read. The stream must be positioned at the beginning of the file's data.
+ /// The file name, if available. May contain path information if that's more convenient. The method will only inspect the extension of the path (i.e. EndsWith).
/// A list of instances containing the various types of metadata found within the file's data.
/// The file type is unknown, or processing errors occurred.
///
- public static IReadOnlyList ReadMetadata(Stream stream)
+ public static IReadOnlyList ReadMetadata(Stream stream, string? fileName = null)
{
- var fileType = FileTypeDetector.DetectFileType(stream);
+ var fileType = FileTypeDetector.DetectFileType(stream, fileName);
var directories = new List();
@@ -76,23 +77,29 @@ public static IReadOnlyList ReadMetadata(Stream stream)
FileType.Bmp => BmpMetadataReader.ReadMetadata(stream),
FileType.Crx => QuickTimeMetadataReader.ReadMetadata(stream),
FileType.Cr2 => TiffMetadataReader.ReadMetadata(stream),
+ FileType.Dng => TiffMetadataReader.ReadMetadata(stream),
FileType.Eps => EpsMetadataReader.ReadMetadata(stream),
FileType.Gif => GifMetadataReader.ReadMetadata(stream),
+ FileType.GoPro => TiffMetadataReader.ReadMetadata(stream),
FileType.Heif => HeifMetadataReader.ReadMetadata(stream),
FileType.Ico => IcoMetadataReader.ReadMetadata(stream),
FileType.Jpeg => JpegMetadataReader.ReadMetadata(stream),
+ FileType.Kdc => TiffMetadataReader.ReadMetadata(stream),
FileType.Mp3 => Mp3MetadataReader.ReadMetadata(stream),
FileType.Mp4 => QuickTimeMetadataReader.ReadMetadata(stream),
FileType.Nef => TiffMetadataReader.ReadMetadata(stream),
FileType.Netpbm => [NetpbmMetadataReader.ReadMetadata(stream)],
FileType.Orf => TiffMetadataReader.ReadMetadata(stream),
+ FileType.Pef => TiffMetadataReader.ReadMetadata(stream),
FileType.Pcx => [PcxMetadataReader.ReadMetadata(stream)],
FileType.Png => PngMetadataReader.ReadMetadata(stream),
FileType.Psd => PsdMetadataReader.ReadMetadata(stream),
FileType.QuickTime => QuickTimeMetadataReader.ReadMetadata(stream),
FileType.Raf => RafMetadataReader.ReadMetadata(stream),
FileType.Rw2 => TiffMetadataReader.ReadMetadata(stream),
+ FileType.Srw => TiffMetadataReader.ReadMetadata(stream),
FileType.Tga => TgaMetadataReader.ReadMetadata(stream),
+ FileType.ThreeFR => TiffMetadataReader.ReadMetadata(stream),
FileType.Tiff => TiffMetadataReader.ReadMetadata(stream),
FileType.Wav => WavMetadataReader.ReadMetadata(stream),
FileType.WebP => WebPMetadataReader.ReadMetadata(stream),
@@ -109,7 +116,7 @@ public static IReadOnlyList ReadMetadata(Stream stream)
}
/// Reads metadata from a file.
- /// Unlike , this overload includes a in the output.
+ /// Unlike , this overload includes a in the output.
/// Location of a file from which data should be read.
/// A list of instances containing the various types of metadata found within the file's data.
/// The file type is unknown, or processing errors occurred.
@@ -119,7 +126,7 @@ public static IReadOnlyList ReadMetadata(string filePath)
var directories = new List();
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
- directories.AddRange(ReadMetadata(stream));
+ directories.AddRange(ReadMetadata(stream, filePath));
directories.Add(new FileMetadataReader().Read(filePath));
diff --git a/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt b/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt
index 5ef4916ef..5c0e5ea5e 100644
--- a/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt
+++ b/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt
@@ -4378,13 +4378,13 @@ static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSeconds(double value
static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSecondsString(double value) -> string!
static MetadataExtractor.GeoLocation.DegreesMinutesSecondsToDecimal(MetadataExtractor.Rational degs, MetadataExtractor.Rational mins, MetadataExtractor.Rational secs, bool isNegative) -> double?
static MetadataExtractor.ImageMetadataReader.ReadMetadata(string! filePath) -> System.Collections.Generic.IReadOnlyList!
-static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream) -> System.Collections.Generic.IReadOnlyList!
+static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream, string? fileName = null) -> System.Collections.Generic.IReadOnlyList!
static MetadataExtractor.Rational.operator !=(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.Rational.operator ==(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.TagDescriptor.ConvertBytesToVersionString(int[]? components, int majorDigits) -> string?
static MetadataExtractor.TagDescriptor.GetFocalLengthDescription(double mm) -> string!
static MetadataExtractor.TagDescriptor.GetFStopDescription(double fStop) -> string!
-static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream) -> MetadataExtractor.Util.FileType
+static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream, string? fileName = null) -> MetadataExtractor.Util.FileType
static MetadataExtractor.Util.FileTypeExtensions.GetAllExtensions(this MetadataExtractor.Util.FileType fileType) -> System.Collections.Generic.IEnumerable?
static MetadataExtractor.Util.FileTypeExtensions.GetCommonExtension(this MetadataExtractor.Util.FileType fileType) -> string?
static MetadataExtractor.Util.FileTypeExtensions.GetLongName(this MetadataExtractor.Util.FileType fileType) -> string!
diff --git a/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt b/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt
index dbb92d0cb..4ae22099b 100644
--- a/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt
+++ b/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt
@@ -115,6 +115,12 @@ MetadataExtractor.IO.IndexedCapturingReader.Dispose() -> void
MetadataExtractor.IO.IndexedReader.GetByte(int index) -> byte
MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]!
MetadataExtractor.Util.FileType.Avif = 28 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Dng = 29 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.GoPro = 30 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Kdc = 31 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.ThreeFR = 32 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Pef = 33 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Srw = 34 -> MetadataExtractor.Util.FileType
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDescriptor.GetDescription(int tagType) -> string?
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.Name.get -> string!
override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Descriptor.GetDescription(int tagType) -> string?
diff --git a/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Shipped.txt b/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Shipped.txt
index 4bd137ed8..21349b45b 100644
--- a/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Shipped.txt
+++ b/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Shipped.txt
@@ -4366,13 +4366,13 @@ static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSeconds(double value
static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSecondsString(double value) -> string!
static MetadataExtractor.GeoLocation.DegreesMinutesSecondsToDecimal(MetadataExtractor.Rational degs, MetadataExtractor.Rational mins, MetadataExtractor.Rational secs, bool isNegative) -> double?
static MetadataExtractor.ImageMetadataReader.ReadMetadata(string! filePath) -> System.Collections.Generic.IReadOnlyList!
-static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream) -> System.Collections.Generic.IReadOnlyList!
+static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream, string? fileName = null) -> System.Collections.Generic.IReadOnlyList!
static MetadataExtractor.Rational.operator !=(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.Rational.operator ==(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.TagDescriptor.ConvertBytesToVersionString(int[]? components, int majorDigits) -> string?
static MetadataExtractor.TagDescriptor.GetFocalLengthDescription(double mm) -> string!
static MetadataExtractor.TagDescriptor.GetFStopDescription(double fStop) -> string!
-static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream) -> MetadataExtractor.Util.FileType
+static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream, string? fileName = null) -> MetadataExtractor.Util.FileType
static MetadataExtractor.Util.FileTypeExtensions.GetAllExtensions(this MetadataExtractor.Util.FileType fileType) -> System.Collections.Generic.IEnumerable?
static MetadataExtractor.Util.FileTypeExtensions.GetCommonExtension(this MetadataExtractor.Util.FileType fileType) -> string?
static MetadataExtractor.Util.FileTypeExtensions.GetLongName(this MetadataExtractor.Util.FileType fileType) -> string!
diff --git a/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Unshipped.txt
index 2cc02a266..ce84c159f 100644
--- a/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Unshipped.txt
+++ b/MetadataExtractor/PublicAPI/net8.0/PublicAPI.Unshipped.txt
@@ -114,6 +114,12 @@ MetadataExtractor.IO.IndexedCapturingReader.Dispose() -> void
MetadataExtractor.IO.IndexedReader.GetByte(int index) -> byte
MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]!
MetadataExtractor.Util.FileType.Avif = 28 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Dng = 29 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.GoPro = 30 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Kdc = 31 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.ThreeFR = 32 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Pef = 33 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Srw = 34 -> MetadataExtractor.Util.FileType
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDescriptor.GetDescription(int tagType) -> string?
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.Name.get -> string!
override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Descriptor.GetDescription(int tagType) -> string?
diff --git a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt
index ce0feab30..8885de685 100644
--- a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt
+++ b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt
@@ -4371,13 +4371,13 @@ static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSeconds(double value
static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSecondsString(double value) -> string!
static MetadataExtractor.GeoLocation.DegreesMinutesSecondsToDecimal(MetadataExtractor.Rational degs, MetadataExtractor.Rational mins, MetadataExtractor.Rational secs, bool isNegative) -> double?
static MetadataExtractor.ImageMetadataReader.ReadMetadata(string! filePath) -> System.Collections.Generic.IReadOnlyList!
-static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream) -> System.Collections.Generic.IReadOnlyList!
+static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream, string? fileName = null) -> System.Collections.Generic.IReadOnlyList!
static MetadataExtractor.Rational.operator !=(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.Rational.operator ==(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.TagDescriptor.ConvertBytesToVersionString(int[]? components, int majorDigits) -> string?
static MetadataExtractor.TagDescriptor.GetFocalLengthDescription(double mm) -> string!
static MetadataExtractor.TagDescriptor.GetFStopDescription(double fStop) -> string!
-static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream) -> MetadataExtractor.Util.FileType
+static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream, string? fileName = null) -> MetadataExtractor.Util.FileType
static MetadataExtractor.Util.FileTypeExtensions.GetAllExtensions(this MetadataExtractor.Util.FileType fileType) -> System.Collections.Generic.IEnumerable?
static MetadataExtractor.Util.FileTypeExtensions.GetCommonExtension(this MetadataExtractor.Util.FileType fileType) -> string?
static MetadataExtractor.Util.FileTypeExtensions.GetLongName(this MetadataExtractor.Util.FileType fileType) -> string!
diff --git a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt
index dbb92d0cb..4ae22099b 100644
--- a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt
+++ b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt
@@ -115,6 +115,12 @@ MetadataExtractor.IO.IndexedCapturingReader.Dispose() -> void
MetadataExtractor.IO.IndexedReader.GetByte(int index) -> byte
MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]!
MetadataExtractor.Util.FileType.Avif = 28 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Dng = 29 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.GoPro = 30 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Kdc = 31 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.ThreeFR = 32 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Pef = 33 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Srw = 34 -> MetadataExtractor.Util.FileType
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDescriptor.GetDescription(int tagType) -> string?
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.Name.get -> string!
override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Descriptor.GetDescription(int tagType) -> string?
diff --git a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt
index ca94a00fa..3b8af8019 100644
--- a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt
+++ b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt
@@ -4373,13 +4373,13 @@ static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSeconds(double value
static MetadataExtractor.GeoLocation.DecimalToDegreesMinutesSecondsString(double value) -> string!
static MetadataExtractor.GeoLocation.DegreesMinutesSecondsToDecimal(MetadataExtractor.Rational degs, MetadataExtractor.Rational mins, MetadataExtractor.Rational secs, bool isNegative) -> double?
static MetadataExtractor.ImageMetadataReader.ReadMetadata(string! filePath) -> System.Collections.Generic.IReadOnlyList!
-static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream) -> System.Collections.Generic.IReadOnlyList!
+static MetadataExtractor.ImageMetadataReader.ReadMetadata(System.IO.Stream! stream, string? fileName = null) -> System.Collections.Generic.IReadOnlyList!
static MetadataExtractor.Rational.operator !=(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.Rational.operator ==(MetadataExtractor.Rational a, MetadataExtractor.Rational b) -> bool
static MetadataExtractor.TagDescriptor.ConvertBytesToVersionString(int[]? components, int majorDigits) -> string?
static MetadataExtractor.TagDescriptor.GetFocalLengthDescription(double mm) -> string!
static MetadataExtractor.TagDescriptor.GetFStopDescription(double fStop) -> string!
-static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream) -> MetadataExtractor.Util.FileType
+static MetadataExtractor.Util.FileTypeDetector.DetectFileType(System.IO.Stream! stream, string? fileName = null) -> MetadataExtractor.Util.FileType
static MetadataExtractor.Util.FileTypeExtensions.GetAllExtensions(this MetadataExtractor.Util.FileType fileType) -> System.Collections.Generic.IEnumerable?
static MetadataExtractor.Util.FileTypeExtensions.GetCommonExtension(this MetadataExtractor.Util.FileType fileType) -> string?
static MetadataExtractor.Util.FileTypeExtensions.GetLongName(this MetadataExtractor.Util.FileType fileType) -> string!
diff --git a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt
index 2cc02a266..ce84c159f 100644
--- a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt
+++ b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt
@@ -114,6 +114,12 @@ MetadataExtractor.IO.IndexedCapturingReader.Dispose() -> void
MetadataExtractor.IO.IndexedReader.GetByte(int index) -> byte
MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]!
MetadataExtractor.Util.FileType.Avif = 28 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Dng = 29 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.GoPro = 30 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Kdc = 31 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.ThreeFR = 32 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Pef = 33 -> MetadataExtractor.Util.FileType
+MetadataExtractor.Util.FileType.Srw = 34 -> MetadataExtractor.Util.FileType
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDescriptor.GetDescription(int tagType) -> string?
override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.Name.get -> string!
override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Descriptor.GetDescription(int tagType) -> string?
diff --git a/MetadataExtractor/Util/FileType.cs b/MetadataExtractor/Util/FileType.cs
index c9d58a768..78bf5d850 100644
--- a/MetadataExtractor/Util/FileType.cs
+++ b/MetadataExtractor/Util/FileType.cs
@@ -78,7 +78,7 @@ public enum FileType
/// Encapsulated PostScript.
Eps = 23,
- /// Truevision graphics.
+ /// Truevision graphics (Targa).
Tga = 24,
/// MPEG-1 / MPEG-2 Audio Layer III.
@@ -91,7 +91,25 @@ public enum FileType
Mp4 = 27,
/// AV1 Image File Format.
- Avif = 28
+ Avif = 28,
+
+ /// DNG Image File Format.
+ Dng = 29,
+
+ /// GPR (GoPro) Image File Format.
+ GoPro = 30,
+
+ /// KDC (Kodak) Image File Format.
+ Kdc = 31,
+
+ /// 3FR (Hasselblad) Image File Format.
+ ThreeFR = 32,
+
+ /// PEF (Pentax) Image File Format.
+ Pef = 33,
+
+ /// SRW (Samsung) Image File Format.
+ Srw = 34,
}
public static class FileTypeExtensions
@@ -126,7 +144,13 @@ public static class FileTypeExtensions
"MP3",
"HEIF",
"MP4",
- "AVIF"
+ "AVIF",
+ "DNG",
+ "GPR",
+ "KDC",
+ "3FR",
+ "PEF",
+ "SRW",
];
private static readonly string[] _longNames =
@@ -160,6 +184,12 @@ public static class FileTypeExtensions
"High Efficiency Image File Format",
"MPEG-4 Part 14",
"AV1 Image File Format",
+ "Digital Negative",
+ "GoPro Raw",
+ "Kodak Raw",
+ "Hasselblad Raw",
+ "Pentax Raw",
+ "Samsung Raw",
];
private static readonly string?[] _mimeTypes =
@@ -177,12 +207,12 @@ public static class FileTypeExtensions
"audio/vnd.wave",
"video/vnd.avi",
"image/webp",
- null, // Sony RAW
- null,
- null,
- null,
- null,
- null,
+ "image/x-sony-arw", // https://stackoverflow.com/a/47612661/24874
+ "image/x-canon-crw",
+ "image/x-canon-cr2",
+ "image/x-nikon-nef",
+ "image/x-olympus-orf",
+ "image/x-fuji-raf",
null,
"video/quicktime",
"image/x-portable-graymap",
@@ -192,7 +222,13 @@ public static class FileTypeExtensions
"audio/mpeg",
"image/heic",
"video/mp4",
- "image/avif"
+ "image/avif",
+ "image/x-adobe-dng",
+ "image/x-gopro-gpr",
+ "image/x-kodak-kdc",
+ "image/x-hasselblad-3fr",
+ "image/x-pentax-pef",
+ "image/x-samsung-srw",
];
private static readonly string[]?[] _extensions =
@@ -225,7 +261,13 @@ public static class FileTypeExtensions
["mp3"],
["heic", "heif", "avci"],
["mp4", "m4a", "m4p", "m4b", "m4r", "m4v"],
- ["avif"]
+ ["avif"],
+ ["dng"],
+ ["gpr"],
+ ["kdc"],
+ ["3fr"],
+ ["pef"],
+ ["srw"],
];
public static string GetName(this FileType fileType)
diff --git a/MetadataExtractor/Util/FileTypeDetector.cs b/MetadataExtractor/Util/FileTypeDetector.cs
index fc76042e1..224145b03 100644
--- a/MetadataExtractor/Util/FileTypeDetector.cs
+++ b/MetadataExtractor/Util/FileTypeDetector.cs
@@ -47,7 +47,8 @@ public static class FileTypeDetector
{ FileType.Pcx, [0x0A, 0x05, 0x01] },
{ FileType.Eps, "%!PS"u8 },
{ FileType.Eps, [0xC5, 0xD0, 0xD3, 0xC6] },
- { FileType.Arw, "II"u8.ToArray(), [0x2a, 0x00, 0x08, 0x00] },
+ // NOTE several file types match this, which we handle in TryDisambiguate: DNG, GPR (GoPro), KDC (Kodak), 3FR (Hasselblad)
+ //{ FileType.Arw, "II"u8.ToArray(), [0x2a, 0x00, 0x08, 0x00] },
{ FileType.Crw, "II"u8.ToArray(), [0x1a, 0x00, 0x00, 0x00], "HEAPCCDR"u8.ToArray() },
{ FileType.Cr2, "II"u8.ToArray(), [0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x52] },
// NOTE this doesn't work for NEF as it incorrectly flags many other TIFF files as being NEF
@@ -59,22 +60,77 @@ public static class FileTypeDetector
{ FileType.Rw2, "II"u8.ToArray(), [0x55, 0x00] },
};
- private static readonly IEnumerable _fixedCheckers = new ITypeChecker[]
+ private static FileType TryDisambiguate(FileType detectedFileType, string fileName)
{
+ if (detectedFileType == FileType.Tiff)
+ {
+ var extension = GetExtension();
+
+ if (MemoryExtensions.Equals(extension, ".arw".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.Arw;
+ }
+ else if (MemoryExtensions.Equals(extension, ".dng".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.Dng;
+ }
+ else if (MemoryExtensions.Equals(extension, ".gpr".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.GoPro;
+ }
+ else if (MemoryExtensions.Equals(extension, ".kdc".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.Kdc;
+ }
+ else if (MemoryExtensions.Equals(extension, ".nef".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.Nef;
+ }
+ else if (MemoryExtensions.Equals(extension, ".3fr".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.ThreeFR;
+ }
+ else if (MemoryExtensions.Equals(extension, ".pef".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.Pef;
+ }
+ else if (MemoryExtensions.Equals(extension, ".srw".AsSpan(), StringComparison.OrdinalIgnoreCase))
+ {
+ return FileType.Srw;
+ }
+ }
+
+ return detectedFileType;
+
+ ReadOnlySpan GetExtension()
+ {
+ int index = fileName.LastIndexOf('.');
+
+ if (index == -1)
+ {
+ return [];
+ }
+
+ return fileName.AsSpan(index);
+ }
+ }
+
+ private static readonly IReadOnlyList _checkers =
+ [
new QuickTimeTypeChecker(),
new RiffTypeChecker(),
new TgaTypeChecker(),
new MpegAudioTypeChecker()
- };
+ ];
private static readonly int _bytesNeeded = Math.Max(
- _root.MaxDepth,
- _fixedCheckers.Max(checker => checker.ByteCount));
+ _root.MaxDepth,
+ _checkers.Max(checker => checker.ByteCount));
/// Examines the file's first bytes and estimates the file's type.
/// Stream does not support seeking.
/// An IO error occurred, or the input stream ended unexpectedly.
- public static FileType DetectFileType(Stream stream)
+ public static FileType DetectFileType(Stream stream, string? fileName = null)
{
if (!stream.CanSeek)
throw new ArgumentException("Must support seek", nameof(stream));
@@ -83,30 +139,41 @@ public static FileType DetectFileType(Stream stream)
try
{
- var bytesRead = stream.Read(bytes, 0, bytes.Length);
+ var bytesRead = stream.Read(bytes, 0, _bytesNeeded);
if (bytesRead == 0)
+ {
+ // Stream was empty
return FileType.Unknown;
+ }
+ // Rewind the stream to where we started. We are only peeking at the data.
stream.Seek(-bytesRead, SeekOrigin.Current);
+ // Use the prefix trie to match bytes.
var fileType = _root.Find(bytes);
- if (fileType == FileType.Unknown)
+ if (fileType != FileType.Unknown)
{
- foreach (var fixedChecker in _fixedCheckers)
+ // Found
+ return fileName is null ? fileType : TryDisambiguate(fileType, fileName);
+ }
+
+ foreach (var checker in _checkers)
+ {
+ if (bytesRead >= checker.ByteCount)
{
- if (bytesRead >= fixedChecker.ByteCount)
- {
- fileType = fixedChecker.CheckType(bytes);
+ fileType = checker.CheckType(bytes);
- if (fileType != FileType.Unknown)
- return fileType;
+ if (fileType != FileType.Unknown)
+ {
+ // Found
+ return fileType;
}
}
}
- return fileType;
+ return FileType.Unknown;
}
finally
{