I want to extract exif data from jpg images. ExifLib seemed like a good choice to simplify this chore, and so I installed it via NuGet.
I then tried to get started using the sample code from here (commenting out the MessageBox code for now):
using (ExifReader reader = new ExifReader(@"C:\temp\testImage.jpg"))
{
// Extract the tag data using the ExifTags enumeration
DateTime datePictureTaken;
if (reader.GetTagValue<DateTime>(ExifTags.DateTimeDigitized, out datePictureTaken))
{
// Do whatever is required with the extracted information
//System.Windows.MessageBox.Show(this, string.Format("The picture was taken on {0}",
// datePictureTaken), "Image information"); //, MessageBoxButtons.OK);
}
}
but get an error:
The best overloaded method match for 'ExifLib.ExifReader.ExifReader(System.IO.Stream)' has some invalid arguments
and
Argument 1: cannot convert from 'string' to 'System.IO.Stream'
both on this line:
using (ExifReader reader = new ExifReader(@"C:\temp\testImage.jpg"))
Is this fixable, or is ExifLib not usable from a WPF / XAML app?
If ExifLib is not a viable solution for a WPF / XAML app, what alternatives exist?
Update:
With this code, from Simon McKenzie's answer:
private void btnLoadNewPhotoset_Click(object sender, RoutedEventArgs e)
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = store.OpenFile("testImage.jpg", FileMode.Open))
using (var reader = new ExifReader(stream))
{
// ...
}
}
I still get an error:
The type or namespace name 'IsolatedStorage' does not exist in the namespace 'System.IO' (are you missing an assembly reference?)
This is a Windows Store (C#) app created in Visual Studio 2013. The project's properties shows that it targets Windows 8.1, and Configuration Manager shows configuration == debug, platform = x64)
My project's displayed References are:
.NET for Windows Store apps
Bing.Maps.Xaml
ExifLib
Microsoft Visual C++ Runtime Package
Windows 8.1
What am I missing?
Update 2:
When I look in Reference Manager at Assemblies.Framework, it says, "All of the Framework assembles are already referenced..." I assume mscorlib.dll is supposed to be one of these (it doesn't list them)?
I searched my hard drive for "mscorlib.dll" and I've got a million of them, all different sizes and dates. Which one should I try to add as a reference? I've got everything from one in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5 dated 7/9/2012 with file size of 2,564,528 to one in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5.1 to...you name it.
Thinking "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5.1" seemed the best bet, I tried to reference it via the Browse button, but when I did, I got scolded with:
In the interests of full disclosure, in Reference Manager for Windows 8.1, it says, "The Windows 8.1. SDK is already referenced."
For Windows 8.1.Extensions, it shows me:
Microsoft Visual C++ 2013 Runtime Package for Windows 12.0 (unchecked)
Microsoft Visual C++ 2013 Runtime Package 11.0 (checked)
Since this seems to be the cause of one of the warnings, I reversed their checkedness (checked 2013, unchecked the other).
I also checked:
Behaviors SDK (XAML) 12.0
SQLite for Windows Runtime 3.8.6 (because I will eventually be using SQLite in this project)
Update 3:
I just found this: "Isolated storage is not available for Windows Store apps. Instead, use the application data classes in the Windows.Storage namespaces included in the Windows Runtime API to store local data and files." here.
Update 4:
I'm waiting for Simon's example, but I'm thinking it might be something like this:
using Windows.Storage;
using ExifLib;
. . .
private async void btnOpenImgFiles_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
IReadOnlyList<StorageFile> files = await openPicker.PickMultipleFilesAsync();
for (int i = 0; i < files.Count; i++)
{
using (var randomAccessStream = await files[i].OpenAsync(FileAccessMode.Read))
using (var stream = randomAccessStream.AsStream())
using (var exfrdr = new ExifReader(stream))
{
// ...exfrdr
}
}
}
The string constructor is not available in Windows Phone/Windows Store apps because they aren't allowed direct filesystem access. You will instead need to pass in a stream containing your image. Here's an example using a FileOpenPicker
. Note the use of AsStream(...)
to convert the IRandomAccessStream
into a Stream
for use with an ExifReader
.
using System;
using System.IO;
using Windows.Storage;
using Windows.Storage.Pickers;
// ...
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".jpg");
var file = await picker.PickSingleFileAsync();
using (var randomAccessStream = await file.OpenAsync(FileAccessMode.Read))
{
using (var stream = randomAccessStream.AsStream())
{
using (var reader = new ExifReader(stream))
{
string model;
if (reader.GetTagValue(ExifTags.Model, out model))
{
var dialog = new MessageDialog(model, "Camera Model");
dialog.ShowAsync();
}
}
}
}