Reading data metadata from JPEG, XMP or EXIF in C#
Solution 1
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;
}
}
Solution 2
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
Solution 3
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;
}
}
Solution 4
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.
tsvallender
A full-stack developer with an emphasis on the backend and Ruby on Rails.
Updated on July 09, 2022Comments
-
tsvallender almost 2 years
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.
-
tsvallender over 14 yearsThank you, but this isn't a project I can afford to spend money on I'm afraid.
-
springy76 over 9 yearsWhoever at Microsoft implemented
BitmapMetaData.DateTaken
is an PERFECT IDIOT! 1. Why is itstring
at all? Last line inget
isDateTime.ToString()
and first line inset
isConvert.ToDateTime()
. and 2.:get
returns culture specific string andset
expects culture insensitive string. IS THERE ANY QUALITY MANAGEMENT AT MICROSOFT AT ALL??? -
Drew Noakes almost 9 years@springy76, actually you're being a bit unfair. In Exif data, dates are represented as strings. Some cameras use different formats to others, so there's no guarantee that MS's could ever write code to successfully parse any date string it encounters. At least it passes the raw string along to you so you can debug what's going on.
-
Drew Noakes almost 9 years@Lijo, I don't know if
BitmapMetadata
provides GPS data, but you can easily use my library to do so if you like. -
Drew Noakes almost 9 years@tsvallender, you should dispose the
FileStream
object. -
springy76 almost 9 years@DrewNoakes no I'm not: Use Reflector/ILSpy/JustDecompile/DotPeek and look at
BitmapMetaData.DateTaken
yourself: WIC already provides a binary datetime value for this (a System.Runtime.InteropServices.ComTypes.FILETIME struct counting the number of 100-nanosecond intervals since January 1, 1601), but this property is f*cking it all up (please just reread what I already wrote). -
Andi AR over 7 yearsHi how to read xmp pano tags like mentioned here stackoverflow.com/questions/39066046/…
-
Drew Noakes over 7 yearsThere are free and open source alternatives.
-
modeeb about 6 yearsIf you need the original capture date, the last line should be
string dateTime = subIfdDirectory?.GetDescription(ExifDirectoryBase.TagDateTimeOriginal);
Or you can use this to get it in DateTime? objectDateTime? dateTime = subIfdDirectory?.GetDateTime(ExifDirectoryBase.TagDateTimeOriginal);
-
twobob almost 6 years@drew-noakes can that thing handle Picassa Region/Face data drew? I can confirm that his library does indeed work nicely for the basics you are requesting here.
-
Drew Noakes almost 6 years@twobob it's been a while since I used Picasa, but I believe it stores its metadata in its own database or in sidecar files. MetadatExtractor doesn't yet have any support for sidecar files, though I would accept a pull request if the implementation was decent.
-
twobob almost 6 yearsHi drew. I used a variation of the brutalXmp below and just ripped it out wholesale. (one can store the data inside the jpgs optionally, it's in options, and write previously externally stored data into the files - also in options) I shoved up the results for your perusal (and the next poor soul who spends days working it out how to do this, with no library support. Yup, Unity3d) REFERENCE: gist.github.com/twobob/ea6cb3b7c7d83c1b62513bcd67c0d39c
-
twobob almost 6 yearsThis is perfect for cases where support is very limiting. Many many thanks for this. with just the application of a
GetElementsByTagName("rdf:Description")
and some care one can extract Picassa3 face Region data with this. Top job. -
twobob almost 6 yearsActually , this question stackoverflow.com/questions/23595560/… is also of use should one wish to go down the meta extractor route I now realise
-
Daniel Möller over 4 yearsSometimes I wonder why in heavens don't the usual frameworks provide simple stuff like this. Any hints on doing similar things without reading the full stream?
-
Daniel Möller over 4 yearsIn order to get all metadata (not only xmp), this option works: codeproject.com/Articles/66328/…