|
Updated. Tell me how you go!
|
|
|
|
|
Thanks for quick update!
I've tried updated code, but USC2 encoded data are not converted to string. They're only shown in hexademical or byte array expression.
XPTitle: 28, 200, 208, 197, 169, 186, 0, 0
XPComment: 0x4400650065006500650065007300630063006300630072006900700074007400740074000000
XPAuthor: 200, 185, 72, 197, 220, 180, 64, 199, 120, 177, 52, 198, 0, 0
XPKeywords: 0x54006100670031003B0054006100670032003B0054006100670033003B00DCD060C5F8AD34000000
XPSubject: 252, 200, 176, 198, 28, 200, 0, 0
Like this. Maybe tiffDataType category processing in value getters may need to be touched.
|
|
|
|
|
You need to declare the destination variable as a string, because these fields are actually stored as unsigned byte arrays, and the EXIF itself doesn't know that it's unicode encoded. Using a string means the reader will assume the content is unicode, and decode it accordingly:
string xpComment;
if (reader.GetTagValue(ExifTags.XPComment, out xpComment))
{
}
|
|
|
|
|
Oh, I understood. I just ran ExifLibTestApp unmodified.
I changed btnPopulate_Click in Test program from
var props = Enum.GetValues(typeof (ExifTags)).Cast<ushort>().Select(tagID =>
{
object val;
if (reader.GetTagValue(tagID, out val))
{
if (val is double)
{
int[] rational;
if (reader.GetTagValue(tagID, out rational))
val = string.Format("{0} ({1}/{2})", val, rational[0], rational[1]);
}
return string.Format("{0}: {1}", Enum.GetName(typeof (ExifTags), tagID), RenderTag(val));
}
return null;
}).Where(x => x != null).ToArray();
to
var props = Enum.GetValues(typeof (ExifTags)).Cast<ushort>().Select(tagID =>
{
object val;
if (tagID >= (ushort)ExifTags.XPTitle && tagID <= (ushort)ExifTags.XPSubject)
{
string XPExif;
if (reader.GetTagValue(tagID, out XPExif))
return string.Format("{0}: {1}", Enum.GetName(typeof(ExifTags), tagID), XPExif);
}
else if (reader.GetTagValue(tagID, out val))
{
if (val is double)
{
int[] rational;
if (reader.GetTagValue(tagID, out rational))
val = string.Format("{0} ({1}/{2})", val, rational[0], rational[1]);
}
return string.Format("{0}: {1}", Enum.GetName(typeof (ExifTags), tagID), RenderTag(val));
}
return null;
}).Where(x => x != null).ToArray();
and it worked like a charm. Thanks!
|
|
|
|
|
No worries.
Note that the test app is just for the purposes of a simple demonstration, and that I would always recommend retrieving tag values explicitly by name, rather than just trawling through all values in the enumeration.
Simon
|
|
|
|
|
Hi simon,
Is there any way to get comment tag? I am not talking about usercomment.if you open an image in software called irfanview, go to image option on top and click information,it will open a popup with comment* button on it.You click on that comment* button it will open another popup with comment TEXtarea. I want to get that textarea info. in my project they are inserting some info in that area which I need to get using C#. Please share any ideas you have.
Rgds
Avi
|
|
|
|
|
Hi Avi,
If it's not in the exif, then this library can't extract it. Can you provide a link to a file which contains one of these comments?
Cheers,
Simon
|
|
|
|
|
Hi again Avi,
I'm not sure which particular field you're looking for (there's a lot of metadata in your image, and I don't want to install IrfanView), but the image you sent me does contain embedded XMP metadata, and this is probably what you're looking for.
There are lots of libraries out there, or you can just marshal a commandline tool like exiftool, depending on your requirements.
Cheers,
Simon
|
|
|
|
|
Hi Avi,
The tag you're looking for is called XPComment , and I've just added it to ExifTags . Thanks for noticing it!
Cheers,
Simon
|
|
|
|
|
Hi Simon, Im Trying to get the value of DateTimeOriginal, but it returns the same value of DateTimeDigitized, is it correct?
Thanks
|
|
|
|
|
Hi Arthur,
The library doesn't have any awareness of specific tags, so if 2 tags return the same value, it's because they genuinely do contain the same value.
According to the exif spec, these are the definitions of your two fields:
DateTimeOriginal
Date and time of original data
DateTimeDigitized
Date and time of digital data
Since your images are probably from a digital camera, it's expected that these would be the same. These would generally only differ if you were working with scanned images.
Cheers,
Simon
|
|
|
|
|
Great library, thanks. I'm just trying to figure out how to interpret the data. For example, for one image I get:
Metering Mode: 5
Flash: 16
How do I translate the numbers into their meaning?
I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone - Bjarne Stroustrup
The world is going to laugh at you anyway, might as well crack the 1st joke!
My code has no bugs, it runs exactly as it was written.
|
|
|
|
|
After A LOT of searching, I finally found a resource. I'll post it here in case someone else needs it:
http://www.kanzaki.com/ns/exif[^]
I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone - Bjarne Stroustrup
The world is going to laugh at you anyway, might as well crack the 1st joke!
My code has no bugs, it runs exactly as it was written.
|
|
|
|
|
Thanks Alexander,
Sorry I didn't see your message - my CodeProject email subscription expired! Anyway, thanks for the link. Just to ensure we have a full reference here, my answer to a similar question explains the flash values, and, similarly, the MeteringMode is also a bitwise field composed of the following parameters:
0: Unknown
1: Average
2: CenterWeightedAverage
3: Spot
4: MultiSpot
5: Pattern
6: Partial
255: Other
The best reference for exif fields is always the EXIF spec.
Cheers,
Simon
|
|
|
|
|
If I want to walk through all of the exif tags in an image, how do I do that?
The only public methods I see on the class expect an ExifTag argument.
|
|
|
|
|
Hi,
The sample app shows a technique for viewing all tags for a given image.
Cheers,
Simon
|
|
|
|
|
IEnumerable<ExifTags> tags = Enum.GetValues(typeof(ExifTags)).Cast<ExifTags>();
using (ExifReader reader = new ExifReader(file))
{
foreach(ExifTags tag in tags)
{
Object value;
if (reader.GetTagValue<Object>(tag, out value))
{
Console.WriteLine(tag + " = " + value);
}
}
}
|
|
|
|
|
I'm using ExifLib in a Windows Store App
I processed a couple of image files cleanly, but then ran into this runtime exception:
System.InvalidCastException was unhandled by user code
HResult=-2147467262
Message=Unable to cast object of type 'System.Byte[]' to type 'System.String'.
Source=ExifLib
StackTrace:
at ExifLib.ExifReader.GetTagValue[T](Dictionary`2 tagDictionary, UInt16 tagID, T& result)
at ExifLib.ExifReader.GetTagValue[T](UInt16 tagID, T& result)
at ExifLib.ExifReader.GetTagValue[T](ExifTags tag, T& result)
at Photrax.MainPage.<convertuserselectionstomapmarkers>d__0.MoveNext()
InnerException:
...from this code:
String makerNote;
. . .
exfrdr.GetTagValue(ExifTags.MakerNote, out makerNote);
I commented out the "MakerNote" code to get past that, but then I got the same error on ExifTag.FileSource. Any ideas? Is there a way to test for these kinds of problems and bypass those vals when they are problematic?
|
|
|
|
|
Hi,
The bug is yours
If you're ever unsure about the datatype of a field, you can always read it as an object and check. MakerNote and FileSource are generally byte[] fields, as they have a datatype of UNDEFINED in the EXIF spec, which is always a good reference to use when reading EXIF data.
ExifLib uses exception-based error handling, so always use try-catch, as you can never be sure that the file you're reading is well structured.
Cheers,
Simon
|
|
|
|
|
Thanks for your quick response, Simon!
As to "read it as an object and check" have you got an example on how to do that at your keyboardtips?
As to the catch block, is there an ExifLib-specific exception class I can use, or should I just use the generic "catch (Exception ex)" ?
|
|
|
|
|
Like this:
object obj;
if (reader.GetTagValue(..., out obj))
Once you know the datatype, code appropriately. Alternatively, use the spec I mentioned in my previous message.
If you want to catch errors produced by using the wrong datatype, then you can catch InvalidCastException , but otherwise, since there's not much you can do about bad data, you may as well catch Exception . There is an ExifLibException class, but it's only thrown from the constructor.
|
|
|
|
|
Okay, this seems to work:
Object fileSource;
. . .
exfrdr.GetTagValue(ExifTags.FileSource, out fileSource);
. . .
if (null != fileSource)
{
. . .
}
With that code and a sample three image files, I got "null" for two fileSources, and "3" (?) for the other - and, look, ma! No exceptions!
|
|
|
|
|
A value of "3" is to be expected. See here for details.
You shouldn't need to check for null. Your final code should look like this:
byte fileSource;
. . .
if (exfrdr.GetTagValue(ExifTags.FileSource, out fileSource))
{
. . .
}
modified 19-Oct-14 0:12am.
|
|
|
|
|
I'll look into that "3" value, but I ended up getting what I wanted for "fileSource" from the file's Path property. So, as you can see, I want the path to the file, not what type of device was used to create the image (I was misinterpreting what "fileSource" meant - it seems to me it should have been named photoSource or something like that instead).
The thumbnail is working great, though (it's being retrieved and stored perfectly).
|
|
|
|
|
Simon,
Thanks again for this awesome library!
Looking through the code, I found some things I'm interested in grabbing, specifically:
// primary tags
ImageDescription
DateTime
Artist
// EXIF tags
DateTimeOriginal
DateTimeDigitized
SubjectDistance
SubjectArea
MakerNote
UserComment
RelatedSoundFile
SubjectLocation
FileSource
//GPS tags
GPSLatitude
GPSLongitude
GPSAltitude
GPSTimestamp
GPSSatellites
GPSDestLatitude
GPSDestLongitude
GPSDestBearing
GPSAreaInformation
GPSDateStamp
How do I determine which data type each of these are (String, DateTime, etc.)?
|
|
|
|
|