|
Hi Richard,
You are of course entitled to your opinion, but the codeproject submission guidelines outline the following points:
- What does the code do?
- How do I integrate it with my existing code or how do I use it?
- If there is a similar article on CodeProject already, then how does this one differ? Why would someone want to use your version?
- Is there some aspect of the code that is of particular interest that perhaps should be covered in the article?
- Are there any particular environments the code is restricted to? (Windows 2000 or above, .NET SP1 etc)
The idea is to give the reader a clear idea of the purpose of your code, instead of forcing them to download a project, build it and then hunt around to find out what the sample does. This means articles that are code snippets, with no explanation of what the snippet does, are insufficient.
This article clearly addresses all the points above (of course, point 4 is somewhat subjective), and for the user who wants to know more about implementation, the fully documented source is available for perusal.
Regards,
Simon
|
|
|
|
|
Simon McKenzie wrote: This article clearly addresses all the points above Really? So where exactly in the 'article' does it give the reader a clear idea of the purpose of your code, instead of forcing them to download a project, build it and then hunt around to find out what the sample does. ?
Veni, vidi, abiit domum
|
|
|
|
|
Richard,
The article clearly states the following:
ExifLib simply reads Exif tags (i.e., camera model, GPS data, date picture taken, shutter speed etc.) from JPEG files, without the overhead introduced by using the GDI+ classes located in System.Drawing.Imaging, and with less lines of code for the developer.
The code sample shows exactly how to use the code (the class only has 2 methods), so there's no need to "download a project, build it and then hunt around to find out what the sample does".
Regards,
Simon
|
|
|
|
|
There is still no detail whatsoever about how the actual library works, which is what this article is supposed to be about. Sorry, but my vote stands.
Veni, vidi, abiit domum
|
|
|
|
|
Another article has a much more detailed explanation of the EXIF format that also helped me understand using this library:
ExifLibrary for .NET[^]
|
|
|
|
|
Why are you telling me this? You should post your comment to the author of the article.
|
|
|
|
|
Do you plan to support WinRT?
I got following errors when testing my app:
◦API System.IO.FileStream в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
◦API System.IO.FileMode в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
◦API System.IO.FileAccess в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
◦API System.IO.FileShare в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
◦API System.IO.FileStream.#ctor(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare) в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
◦API System.String.Format(System.String,System.Object) в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
◦API System.IO.BinaryReader.Close в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
◦API System.IO.Stream.Close в MSCORLIB, PUBLICKEYTOKEN=B77A5C561934E089 is not supported for this kind of application. ExifLib.dll calls this API.
|
|
|
|
|
Hi,
I'll look into an update with RT support, but in the meantime, you can get the code working with the following changes:
- Remove the constructor which takes a string as input
- Replace the calls to
_reader.Close() and _stream.Close() with _reader.Dispose() and _stream.Dispose() .
Please get back to me when you've given it a go.
Cheers,
Simon
|
|
|
|
|
I've tried to use some hacks and pass System.IO.Stream but Microsoft denied publication.
Changes required for RT:
1) IRandomAccessStream is used so Position should be replaced with Seek() and so on
2) int/long sometimes should be replaced with uint/ulong
3) Due to async ref/out is not supported
4) Exceptions cannot be thrown and other mechanism to notify that image have no exif should be used
Generally this means code should be rewritten for .NET 4.5.
I tried to do it myself but assumed you as author may be interested in learning new platform. In case you are not or have no time, I can share my code with you so that you can publish on your behalf.
|
|
|
|
|
Hi,
I updated the source with RT support, but I'm not clear about the store rejection rules - if it compiles, isn't that sufficient?
Regarding exceptions, how can exceptions not be thrown? They're core to the framework, so I can't understand what's meant by this - do they mean that you need to make sure you catch any exceptions which have been thrown?
Also, regarding async , you can always wrap the library calls in your own method calls which don't use out parameters, but there's no need to change the library for that reason!
Please install the latest nuget package and tell me how it goes. Also, I may have misunderstood some of your points, so please correct me if this is the case.
S
|
|
|
|
|
I have an exception thrown by the reader constructor. The image it is crashing on is 2784x400 in dimensions. I can send you the image if you want to test it just let me know where to send it.
|
|
|
|
|
Hi,
I've sent you a PM, but if you want to just provide details of the exception here, we can probably resolve this without the image (but by all means, send it through!)
Note that the dimensions of the image don't actually matter, as the library doesn't look at the pixel data at all.
Cheers,
Simon
|
|
|
|
|
Hey there, I'm getting the same error. I'm using Windows 8.1, VS2013, Windows Phone 8.1 SDK to create a Windows Phone 8 project with exiflib 1.6. I can access image streams and use them as the source for the XAML Image class just fine (so I assume that I don't have a problem with the stream).
I launch the photo chooser task from my app, select a photo, then apply this stream as the source for a BitmapImage, and finally apply this BitmapImage instance as the source for an Image control in my XAML tree. Before setting the source I'm trying to use ExitLib to access the orientation info for the stream. I'm working exclusively with the default Windows Phone images in the images library.
As soon as I call the ExifLib constructor I see this exception:
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.BitConverter.ToUInt16(Byte[] value, Int32 startIndex)
at ExifLib.ExifReader.ToUShort(Byte[] data)
at ExifLib.ExifReader.ReadUShort()
at ExifLib.ExifReader..ctor(Stream stream, Boolean leaveOpen, Boolean internalStream)
at ExifLib.ExifReader..ctor(Stream stream, Boolean leaveOpen)
Any ideas what to do here?
|
|
|
|
|
Hi Peter,
This is a Windows Phone 8 problem - the stream returned by PhotoChooserTask reports that it's seekable, but seeking doesn't actually work.
See my other post on this issue for details and a workaround.
I have just updated the library (and nuget package) to produce a clearer error message.
Cheers,
Simon
modified 24-Jul-14 2:18am.
|
|
|
|
|
Thanks for the quick reply! I read the workaround you pointed me to but had no luck. Even with the latest update I'm being told that the images are not valid JPEG files ("File is not a valid JPEG"), even new ones I download from the web. I'm able to reproduce the problem in both the WP emulator and on my physical device.
I guess I'll sit on this bug for a while. I might look into trying to access the EXIF data myself via looking at the bytes in the stream, but if your library isn't having any luck with this I don't see why I would have any better luck.
var buffer = new byte[s.Length];
s.Read(buffer, 0, buffer.Length);
var ms = new MemoryStream(buffer);
var reader = new ExifReader(ms, false);
object orientation;
reader.GetTagValue<object>(ExifTags.Orientation, out orientation);
The stack trace:
at ExifLib.ExifReader..ctor(Stream stream, Boolean leaveOpen, Boolean internalStream)
at ExifLib.ExifReader..ctor(Stream stream, Boolean leaveOpen)
|
|
|
|
|
Does it work on your PC? Would you mind supplying a link to one of the images you're trying along with the full code you're using? I use part of this code in my own Windows Phone app, so it definitely works! The change I made was only to make the error clearer - as far as I know, there's no bug in the library.
Here's a working example for Windows Phone 8:
WebClient client = new WebClient();
client.OpenReadCompleted += (sender, args) =>
{
using (var reader = new ExifReader(args.Result))
{
string cameraMake;
Debug.WriteLine("{0}: {1}", reader.GetTagValue(ExifTags.Make, out cameraMake), cameraMake);
}
};
client.OpenReadAsync(new Uri("http://opanda.com/cn/iexif/images/gg_gps.jpg"));
Output:
True: NIKON CORPORATION
I hope this helps!
Cheers,
Simon
modified 25-Jul-14 0:17am.
|
|
|
|
|
Hi Simon,
thanks for your library.
I noticed that the reader always closes the stream, which is may not desired.
I cloned your work <a href="https://github.com/esskar/ExifLib.Net">to github</a>[<a href="https://github.com/esskar/ExifLib.Net" target="_blank" title="New Window">^</a>] and exteneded it.
Hope that helps.
Regards,
Sascha
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity.
|
|
|
|
|
Hi esskar,
You make a good point, but BinaryReader only received the new leaveOpen parameter in .NET 4.5, and I don't want to remove support for older frameworks yet, plus I also don't want to reinvent the wheel by rewriting my own binary reader.
Regards,
Simon McKenzie
|
|
|
|
|
Hi Esskar,
Just FYI, the latest update to the library adds a leaveOpen parameter to allow the user to specify whether they want the stream left open. You'll probably find a number of fixes added since you cloned the library.
Cheers,
Simon
|
|
|
|
|
thanks for your answer i added ExifLib.dll to my project but
I want to get 3 items : date and time picture taken and GPS data including longitude and latitude
in 3 variables for saving in my database.
i dont know which parts of your code should i use and how?!
Can you help me?
thanks
|
|
|
|
|
Here's an example for you. Note that GetTagValue returns a bool success flag, so you will need to handle this for images which don't contain the tag you're retrieving.
using (var reader = new ExifReader(@"d:\temp\gg_gps.jpg"))
{
double[] latitudeDMS;
reader.GetTagValue(ExifTags.GPSLatitude, out latitudeDMS);
double[] longitudeDMS;
reader.GetTagValue(ExifTags.GPSLongitude, out longitudeDMS);
string latitudeRef;
reader.GetTagValue(ExifTags.GPSLatitudeRef, out latitudeRef);
string longitudeRef;
reader.GetTagValue(ExifTags.GPSLongitudeRef, out longitudeRef);
DateTime dateTaken;
reader.GetTagValue(ExifTags.DateTimeDigitized, out dateTaken);
var latitudeDecimalDegrees = (latitudeRef == "N" ? 1 : -1)*
(latitudeDMS[0] + latitudeDMS[1]/60 + latitudeDMS[2]/3600);
var longitudeDecimalDegrees = (longitudeRef == "E" ? 1 : -1)*
(longitudeDMS[0] + longitudeDMS[1]/60 + longitudeDMS[2]/3600);
Console.WriteLine("Latitude: {0:F6}; Longitude: {1:F6}; Taken: {2}", latitudeDecimalDegrees, longitudeDecimalDegrees, dateTaken);
}
modified 16-Jan-14 15:57pm.
|
|
|
|
|
when i run the code there is an error in ExifReader.cs
ERROR: result = DateTime.ParseExact(str, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture); String was not recognized as a valid DateTime.
str "2013-01-04 20:41:59 " string
+ result {1/1/0001 12:00:00 AM} System.DateTime
in my photo metadata is dd/MM/YYYY HH:mm:ss
i dont know how should i convert the order ?
|
|
|
|
|
If your date's in a non-standard format, then you can always just retrieve it as a string and process it youself. Note however that EXIF dates should be in yyyy:MM:dd HH:mm:ss format, so your camera is definitely breaking the rules. See page 22 of the spec for more details.
To retrieve as a string, just use this instead:
string dateTaken;
reader.GetTagValue(ExifTags.DateTimeDigitized, out dateTaken);
|
|
|
|
|
thanks for your answer when i use your code i got the result as string
"2013-01-04 20:41:59"
in order to convert string format of dataTaken variable to DateTime i use this code
DateTime MyDateTime;
MyDateTime = new DateTime();
MyDateTime = DateTime.ParseExact(dateTaken, "YYYY-MM-DD HH:MM:SS", null);
but i get this error
ERROR : String was not recognized as a valid DateTime.
|
|
|
|
|
Hi,
You've made some errors in your parse string - for example, minutes are represented using a lower case M, and months are represented using an upper case M. This is what you should have used:
DateTime myDateTime = DateTime.ParseExact("2013-01-04 20:41:59", "yyyy-MM-dd HH:mm:ss", null);
Note that there's no point in initialising MyDateTime with new DateTime() , as you overwrite it immediately. Also, the c# coding guidelines stipulate camel casing for local variable names, i.e. myDateTime , not MyDateTime .
Cheers,
Simon
|
|
|
|
|