Question

I've been looking around for a decent way of reading metadata (specifically, the date taken) from JPEG files in C#, and am coming up a little short. Existing information, as far as I can see, shows code like the following;

BitmapMetadata bmd = (BitmapMetadata)frame.Metadata;
string a1 = (string)bmd.GetQuery("/app1/ifd/exif:{uint=36867}");

But in my ignorance I have no idea what bit of metadata GetQuery() will return, or what to pass it.

I want to attempt reading XMP first, falling back to EXIF if XMP does not exist. Is there a simple way of doing this?

Thanks.

Was it helpful?

Solution

The following seems to work nicely, but if there's something bad about it, I'd appreciate any comments.

    public string GetDate(FileInfo f)
    {
        using(FileStream fs = new FileStream(f.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            BitmapSource img = BitmapFrame.Create(fs);
            BitmapMetadata md = (BitmapMetadata)img.Metadata;
            string date = md.DateTaken;
            Console.WriteLine(date);
            return date;
        }
    }

OTHER TIPS

I've ported my long-time open-source Java library to .NET recently, and it supports XMP, Exif, ICC, JFIF and many more types of metadata across a range of image formats. It will definitely achieve what you're after.

https://github.com/drewnoakes/metadata-extractor-dotnet

var directories = ImageMetadataReader.ReadMetadata(imagePath);
var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
var dateTime = subIfdDirectory?.GetDescription(ExifDirectoryBase.TagDateTime);

This library also supports XMP data, via a C# port of Adobe's XmpCore library for Java.

https://github.com/drewnoakes/xmp-core-dotnet

If you're struggling with XMP jn jpeg, this works. It's not called brutal for nothing!

public class BrutalXmp
{
    public XmlDocument ExtractXmp(byte[] jpegBytes)
    {
        var asString = Encoding.UTF8.GetString(jpegBytes);
        var start = asString.IndexOf("<x:xmpmeta");
        var end = asString.IndexOf("</x:xmpmeta>") + 12;
        if (start == -1 || end == -1)
            return null;
        var justTheMeta = asString.Substring(start, end - start);
        var returnVal = new XmlDocument();
        returnVal.LoadXml(justTheMeta);
        return returnVal;
    }
}

I think what you are doing is a good solution because the System.DateTaken handler automatically apply Photo metadata policies of falling back to other namespaces to find if a value exist.

My company makes a .NET toolkit that includes XMP and EXIF parsers.

The typical process is something like this:

XmpParser parser = new XmpParser();
System.Xml.XmlDocument xml = (System.Xml.XmlDocument)parser.ParseFromImage(stream, frameIndex);

for EXIF you would do this:

ExitParser parser = new ExifParser();
ExifCollection exif = parser.ParseFromImage(stream, frameIndex);

obviously, frameIndex would be 0 for JPEG.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top