Here I am again. I haven’t written anything smart for a while now because I’ve been working on my next Windows Phone application called Photo Light. It should be out in less than 10 days, and it will be a small, light and free photo editor. One of the things it does is display EXIF data of the loaded photo. In this article, I’ll describe how to read the EXIF data for a photo and display it in a page. Let’s get started.
First of all, to get the EXIF of a photo, we need to get a photo. To do that, we use a PhotoChooserTask object which returns us the chosen photo. Then we need a way to read the EXIF data from the returned stream. What’s the problem here? Well, the problem is how to get that data. There is a cute little library that does the job. It’s called ExifLib and it’s available on Code Project under Code Project Open License. But don’t go downloading it yet! The version that’s on Code Project won’t do the job, because we’re not working strictly with files and file names, which the library requests, but with the stream of data given back from the PhotoChooserTask. In order to get it to work with Windows Phone, go to the blog post of Tim Heuer who did a slight modification of the library to work with WP7. Download his project and get the library from Libs folder! Add it to your newly created Windows Phone project. When the application launches, launch the PhotoChooserTask. It will return you the chosen photo, which you can then use to create JpegInfo object and get all the info for the selected JPEG. Here’s how it looks in the end:
You’ll notice that a lot of information is missing, but it will work better once you try it on the phone with a photo you’ve taken with the camera!
Here’s the layout XAML from MainPage.xaml:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="EXIF READER" Style="{StaticResource PhoneTextNormalStyle}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Margin="12,0,12,0" Grid.Row="1"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <Image Name="loadedImg" MaxHeight="300" HorizontalAlignment="Center" Grid.Row="0"/> <ScrollViewer Margin="12" Grid.Row="1"> <StackPanel Margin="12"> <TextBlock Name="artist" Margin="12,0"/> <TextBlock Name="copyright" Margin="12,0"/> <TextBlock Name="datetime" Margin="12,0"/> <TextBlock Name="description" Margin="12,0"/> <TextBlock Name="exposure" Margin="12,0"/> <TextBlock Name="filename" Margin="12,0"/> <TextBlock Name="filesize" Margin="12,0"/> <TextBlock Name="flash" Margin="12,0"/> <TextBlock Name="fnumber" Margin="12,0"/> <TextBlock Name="gpslatitude" Margin="12,0"/> <TextBlock Name="gpslatituderef" Margin="12,0"/> <TextBlock Name="gpslongitude" Margin="12,0"/> <TextBlock Name="gpslongituderef" Margin="12,0"/> <TextBlock Name="height" Margin="12,0"/> <TextBlock Name="iscolor" Margin="12,0"/> <TextBlock Name="isvalid" Margin="12,0"/> <TextBlock Name="loadtime" Margin="12,0"/> <TextBlock Name="make" Margin="12,0"/> <TextBlock Name="orientation" Margin="12,0"/> <TextBlock Name="resolutionunit" Margin="12,0"/> <TextBlock Name="software" Margin="12,0"/> <TextBlock Name="thumbdata" Margin="12,0"/> <TextBlock Name="thumboffset" Margin="12,0"/> <TextBlock Name="thumbsize" Margin="12,0"/> <TextBlock Name="usercomment" Margin="12,0"/> <TextBlock Name="width" Margin="12,0"/> <TextBlock Name="xresolution" Margin="12,0"/> <TextBlock Name="yresolution" Margin="12,0"/> </StackPanel> </ScrollViewer> </Grid> </Grid> |
And here’s the MainPage.xaml.cs, the code behind:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
public partial class MainPage : PhoneApplicationPage { // Constructor bool photoLoaded = false; public MainPage() { this.Loaded += new RoutedEventHandler(MainPage_Loaded); InitializeComponent(); } void MainPage_Loaded(object sender, RoutedEventArgs e) { if (!photoLoaded) { PhotoChooserTask task = new PhotoChooserTask(); task.Completed += new EventHandler<PhotoResult>(task_Completed); task.Show(); } } void task_Completed(object sender, PhotoResult e) { if (e.TaskResult == TaskResult.OK) { photoLoaded = true; JpegInfo info = ExifLib.ExifReader.ReadJpeg(e.ChosenPhoto, e.OriginalFileName); var img = new BitmapImage(); img.SetSource(e.ChosenPhoto); loadedImg.Source = img; ReadExif(info); } } private void ReadExif(JpegInfo info) { artist.Text = "Artist: " + info.Artist; copyright.Text = "Copyright: " + info.Copyright; datetime.Text = "Datetime: " + info.DateTime; description.Text = "Description: " + info.Description; exposure.Text = "Exposure: " + info.ExposureTime; filename.Text = "File name: " + info.FileName; filesize.Text = "File size: " + info.FileSize; flash.Text = "Flash: " + info.Flash; fnumber.Text = "F number: " + info.FNumber; gpslatitude.Text = "GPS Latitude: " + info.GpsLatitude; gpslatituderef.Text = "GPS Latitude ref: " + info.GpsLatitudeRef; gpslongitude.Text = "GPS Longitude: " + info.GpsLongitude; gpslongituderef.Text = "GPS Longitude ref: " + info.GpsLongitudeRef; height.Text = "Height: " + info.Height; iscolor.Text = "Is color: " + info.IsColor; isvalid.Text = "Is valid: " + info.IsValid; loadtime.Text = "Load time: " + info.LoadTime; make.Text = "Make: " + info.Make; orientation.Text = "Orientation: " + info.Orientation; resolutionunit.Text = "Resolution unit: " + info.ResolutionUnit; software.Text = "Software: " + info.Software; thumbdata.Text = "Thumbnail data: " + info.ThumbnailData; thumboffset.Text = "Thumbnail offset: " + info.ThumbnailOffset; thumbsize.Text = "Thumbnail size: " + info.ThumbnailSize; usercomment.Text = "User comment: " + info.UserComment; width.Text = "Width: " + info.Width; xresolution.Text = "X resolution: " + info.XResolution; yresolution.Text = "Y resolution: " + info.YResolution; photoLoaded = true; } } |
So, now you know how to get the EXIF data for the pictures on your phone. I hope this was helpful. You will be able to find EXIF data reader in my Photo Light application that will be published and available in less than 10 days. I will make sure you know about it when it gets published, just follow my blog. :)
Hey..Thanks a lot for this post! It helped a lot. Can you confirm if you are able to get the values on an actual phone? I tried it on the emulator and got values very similar to you. Also, is there any way that I can read the ISO number of the image?
Hi
I can confirm that I get more values on the phone, but some still stay either empty or unformatted because they either don’t exist or are written in a different format.
Good question about the ISO number – you cannot get it from the info structure that is used in the article, but I am looking into it, and if I find a solution, I’ll share it in my next blog article.
If you liked the article, share it on social networks :)
Regards,
Igor
Would be prettier if all ReadExif does is: DataContext=info; and the rest is binding in xaml.
Thank you for your comment.
You are right, that might have been prettier, but I would still have to have a bunch of textboxes to display what’s the data that I’m displaying.
Still, the idea wasn’t to be pretty but to show what properties are available to you ;)
Hey there,
first of all, thanks for the great article, implemented it in my own project :)
I want to use the library to primarily read GpsLongitude and GpsLatitude but it seems to always stay on zero-values, also on a real device.
Is there any other way to read that EXIF-Data out of a JPEG-File in a Windows Phone Application?
Thanks in advance and keep up the good work :)
hi there
thank your for your comment and question! :)
This may be a stupid question, but have you turned on the “save location” option in pictures+camera settings on your phone?
You could probably write your own library for extracting the exif data, but you would need to look deep in the documentation to see how and where exactly is the exif data placed in a jpeg file. I know only about this library…
Regards
Igor
Thanks for your replay,
yeah, the settings for location-data are set – if i take a normal picture with the camera-application it contains all exif data, but when the picture is taken within my own application and i take “JpegInfo info = ExifLib.ExifReader.ReadJpeg(e.ChosenPhoto, e.OriginalFileName)”, all the exif data is missing (like in your picture, nothing is shown). So the exif-data doesn’t seem to be written into the ChosenPhoto, for some reason… is there any workaround for that? Any way i can write all the exif data into the file so it can be read properly and not only if taken in the stock camera app?
If you take the photo using the Camera Chooser Task, the data should be there… GPS is missing, for example, but most of the other is there!
Hey there,
first of all, thanks for the great article, implemented it in my own project :)
I want to use the library to primarily read GpsLongitude and GpsLatitude but it seems to always stay on zero-values, also on a real device.
Is there any other way to read that EXIF-Data out of a JPEG-File in a Windows Phone Application?
Thanks in advance and keep up the good work :)
hi there
thank your for your comment and question! :)
This may be a stupid question, but have you turned on the “save location” option in pictures+camera settings on your phone?
You could probably write your own library for extracting the exif data, but you would need to look deep in the documentation to see how and where exactly is the exif data placed in a jpeg file. I know only about this library…
Regards
Igor
Thanks for your replay,
yeah, the settings for location-data are set – if i take a normal picture with the camera-application it contains all exif data, but when the picture is taken within my own application and i take “JpegInfo info = ExifLib.ExifReader.ReadJpeg(e.ChosenPhoto, e.OriginalFileName)”, all the exif data is missing (like in your picture, nothing is shown). So the exif-data doesn’t seem to be written into the ChosenPhoto, for some reason… is there any workaround for that? Any way i can write all the exif data into the file so it can be read properly and not only if taken in the stock camera app?
If you take the photo using the Camera Chooser Task, the data should be there… GPS is missing, for example, but most of the other is there!
For some reason, using ExifLib.dll on Lumia 900 does has a problem on display Datetime (info.DateTime;). It works perfectly fine on my previous Samsung Focus.
Thanks for mentioning it here.
Do you get some specific error or?
There is no error at all. I see latitude and longitude and others info. However, datetime is null, on all of my photos on Lumia 900, when I use VS2010 to read photo from device. On my Samsung device, there is no problem at all.
For some reason, using ExifLib.dll on Lumia 900 does has a problem on display Datetime (info.DateTime;). It works perfectly fine on my previous Samsung Focus.
Thanks for mentioning it here.
Do you get some specific error or?
There is no error at all. I see latitude and longitude and others info. However, datetime is null, on all of my photos on Lumia 900, when I use VS2010 to read photo from device. On my Samsung device, there is no problem at all.
igrali, any thoughts?
Do you have that information in the photo if you try to read EXIF data from it on your computer?
igrali, any thoughts?
Do you have that information in the photo if you try to read EXIF data from it on your computer?
Yes, I do. Exif Viewer does display datetime. I downloaded your app Photo light, It does not display datetime neither.
I’m sorry, I can’t think of a reason why it won’t work…
Yes, I do. Exif Viewer does display datetime. I downloaded your app Photo light, It does not display datetime neither.
I’m sorry, I can’t think of a reason why it won’t work…
If you have a chance, try your app on Lumia 900, and you will see what I meant. Thanks
I tried it on Lumia 800 and it happens there, too. DateTime isn’t there when you use this EXIF library…
Hey igrali,
I have a Nokia Lumia 900, and I have tested the ExifLib on the pics taken from the phone. I have the same problem as you did. Did you ever get to solve the problem ?
I’m pretty sure that the datetime is there, but nothing (null) is the value of the info.datetime. I can see all GPS data fine but only that field is missing…
If you have found an alternative library to do this, could you please share ? I cannot use the PropertyLists thing because it is not supported by silverlight application.
Thanks alot !
A CS student.
Hi
Unfortunately, I haven’t found a solution for this. I know that the date value is there because if you check it out in Windows, it’s there, but with this library it’s not. It could be that the library reads something differently… You could try writing your own library for these purposes – you would need a EXIF documentation and read it directly from the image stream. If you figure something out, share it with the rest of us ;)
Perhaps a bit late, but I found a solution for the missing DateTime problem on Nokia. I checked it on my Nokia Lumia 710 and my solution works on that one. The problem is that the EXIF data for the DateTime on Nokia is stored under a different ExifId.
What do you have to do: update the source code of the ExifLib. Download the source code and make changes to two files:
- ExifIds.cs, add an extra enum field to the Enum ExifId: DateTime2 = 0×9003,
- ExifTag.cs: add an extra case statement to the switch in Populate:
– case ExifId.DateTime2: info.DateTime = GetStringValue(); break;
That should work.
Very cool solution, thanks for sharing it here!
If you have a chance, try your app on Lumia 900, and you will see what I meant. Thanks
I tried it on Lumia 800 and it happens there, too. DateTime isn’t there when you use this EXIF library…
Hey igrali,
I have a Nokia Lumia 900, and I have tested the ExifLib on the pics taken from the phone. I have the same problem as you did. Did you ever get to solve the problem ?
I’m pretty sure that the datetime is there, but nothing (null) is the value of the info.datetime. I can see all GPS data fine but only that field is missing…
If you have found an alternative library to do this, could you please share ? I cannot use the PropertyLists thing because it is not supported by silverlight application.
Thanks alot !
A CS student.
Hi
Unfortunately, I haven’t found a solution for this. I know that the date value is there because if you check it out in Windows, it’s there, but with this library it’s not. It could be that the library reads something differently… You could try writing your own library for these purposes – you would need a EXIF documentation and read it directly from the image stream. If you figure something out, share it with the rest of us ;)
Perhaps a bit late, but I found a solution for the missing DateTime problem on Nokia. I checked it on my Nokia Lumia 710 and my solution works on that one. The problem is that the EXIF data for the DateTime on Nokia is stored under a different ExifId.
What do you have to do: update the source code of the ExifLib. Download the source code and make changes to two files:
- ExifIds.cs, add an extra enum field to the Enum ExifId: DateTime2 = 0×9003,
- ExifTag.cs: add an extra case statement to the switch in Populate:
– case ExifId.DateTime2: info.DateTime = GetStringValue(); break;
That should work.
Very cool solution, thanks for sharing it here!
Zdravo Igore
Sjajan blog u cjelini zaista, svaka čast :)
Hello Igor, great great blog, well done.
I have one question regarding using ExifLib by Mr. Heuer in conjustion with Picture Viewer Extension.
Namely, If we use PhotoChooserTask to take the picture from Picture Hub then ExifReader.ReadJpeg work with OriginalFileName (e.g. “\Applications\Data\A5504C32-FC1B-43ED-9C40-575D57D2703F\Data\PlatformData\PhotoChooser-4c555317-4828-43d4-8b42-a6292dfe98e6.jpg.jpg”).
But what if we want to use ExifReader.ReadJpeg in app where we use Picture Viewer Extension (using apps.. link. in Picture hub on specific image). In that case we get image by provided token to app as follows:
MediaLibrary library = new MediaLibrary();
Picture picture = library.GetPictureFromToken(queryStrings["token"]);
I can get picture name from “picture.Name” but in that case value is “WP_001284.jpg”.
Hot to get full OriginalFileName to work with ExifReader.ReadJpeg (second parameter)?
Best regards
Pozdrav Spaso
Hvala puno na komentaru. :)
Regarding the question about EXIF of a picture that you get from token: the name doesn’t really matter. Once you have the picture object, just do:
var info = ExifLib.ExifReader.ReadJpeg(picture.GetImage(), picture.Name);
This works great in one of my apps!
Thanks Igor for your answer.
I tried your code earlier but it didn’t work at the time when I try it. Obvious, I made some mistake.
Now it’s everything OK.
Best regards and hope to see you on KulenDayz or Mobility Day soon :)
Yap, see you there (I hope!) :)
Zdravo Igore
Sjajan blog u cjelini zaista, svaka čast :)
Hello Igor, great great blog, well done.
I have one question regarding using ExifLib by Mr. Heuer in conjustion with Picture Viewer Extension.
Namely, If we use PhotoChooserTask to take the picture from Picture Hub then ExifReader.ReadJpeg work with OriginalFileName (e.g. “\Applications\Data\A5504C32-FC1B-43ED-9C40-575D57D2703F\Data\PlatformData\PhotoChooser-4c555317-4828-43d4-8b42-a6292dfe98e6.jpg.jpg”).
But what if we want to use ExifReader.ReadJpeg in app where we use Picture Viewer Extension (using apps.. link. in Picture hub on specific image). In that case we get image by provided token to app as follows:
MediaLibrary library = new MediaLibrary();
Picture picture = library.GetPictureFromToken(queryStrings["token"]);
I can get picture name from “picture.Name” but in that case value is “WP_001284.jpg”.
Hot to get full OriginalFileName to work with ExifReader.ReadJpeg (second parameter)?
Best regards
Pozdrav Spaso
Hvala puno na komentaru. :)
Regarding the question about EXIF of a picture that you get from token: the name doesn’t really matter. Once you have the picture object, just do:
var info = ExifLib.ExifReader.ReadJpeg(picture.GetImage(), picture.Name);
This works great in one of my apps!
Thanks Igor for your answer.
I tried your code earlier but it didn’t work at the time when I try it. Obvious, I made some mistake.
Now it’s everything OK.
Best regards and hope to see you on KulenDayz or Mobility Day soon :)
Yap, see you there (I hope!) :)
Hello Igor, your post is awesome and helpful!
However, I’m working on a Windows Phone app where it requires the JPEG EXIF Metadata to be edited. How to accomplish this? Your post shows how to read the EXIF data, now how to write the EXIF of JPEG image in Windows Phone?
Thanks!
This library doesn’t have the ability to edit EXIF. To accomplish that, you’ll need to write your own code according to the specification.
Hello Igor, your post is awesome and helpful!
However, I’m working on a Windows Phone app where it requires the JPEG EXIF Metadata to be edited. How to accomplish this? Your post shows how to read the EXIF data, now how to write the EXIF of JPEG image in Windows Phone?
Thanks!
This library doesn’t have the ability to edit EXIF. To accomplish that, you’ll need to write your own code according to the specification.