From: Torsten C. <tc...@va...> - 2008-11-06 17:54:16
|
Hey folks, Need some help with the API. Goal is to add/modify the GPS bit in the exif information. But for now I just wanted to see what exif headers are set. So I am iterating: unsigned int i; unsigned int t; const char *name; char value[128]; const char *v; for (i = 0; i < EXIF_IFD_COUNT; i++) { ExifContent *ifd = ed->ifd[i]; const char *ifd_name = exif_ifd_get_name(i); if (!ifd_name) { continue; } NSLog(@"idf: %s", ifd_name); for (t = 0; t < 0xffff; t++) { name = exif_tag_get_title(t); if (!name) { continue; } ExifEntry *entry = exif_content_get_entry(ifd, t); if (!entry) { continue; } v = exif_entry_get_value(entry, value, sizeof(value)); if (!v) { continue; } NSLog(@"%s = %s", name, value); } } But it seems like I am not getting all information idf: GPS GPS tag version = 0x02, 0x02, 0x00, 0x00 InteroperabilityIndex = N InteroperabilityVersion = 30.00, 13.00, 53.58 East or West Longitude = W Longitude = 89.00, 40.00, 11.16 For one the Longitude format is awkward. But more importantly - the Latitude is missing. Using exiv2 on the file I get 0x0000 GPSInfo GPSVersionID Byte 4 2 2 0 0 0x0001 GPSInfo GPSLatitudeRef Ascii 2 N 0x0002 GPSInfo GPSLatitude Rational 3 30/1 13/1 133941/2500 0x0003 GPSInfo GPSLongitudeRef Ascii 2 W 0x0004 GPSInfo GPSLongitude Rational 3 89/1 40/1 6978/625 What am I doing wrong? Oh btw: I came across this as well Unknown tag 0x882a (entry 9 in '0'). Please report this tag to <lib...@li...>. cheers -- Torsten |
From: Stanislav B. <sb...@su...> - 2008-11-06 18:35:57
|
Torsten Curdt wrote: > for (t = 0; t < 0xffff; t++) { > name = exif_tag_get_title(t); > if (!name) { > continue; > } This is broken and can never work, as tags are unique only per IFD, not per EXIF. Use exif_tag_get_title_in_ifd. This bad assumption causes failure of GPS Latitude in most applications based on libexif (eog, libexif-gtk,...) libexif API is very confusing here. ExifTag is enum, something that is expected to be unique. But arguments of type ExifTag are not unique! To be able to implement such an ugly hack without compiler complains, half of these tags are defined in enum, the other half by #define. And there is not a better way to "list all tags currently known to libexif" than querying all 65536x5 possible tag/ifd combinations. There is another ugly hack to make this query with only 65538 steps: http://sourceforge.net/tracker/download.php?group_id=12272&atid=312272&file_id=284116&aid=2014281 > But it seems like I am not getting all information > > idf: GPS > GPS tag version = 0x02, 0x02, 0x00, 0x00 > InteroperabilityIndex = N > InteroperabilityVersion = 30.00, 13.00, 53.58 > East or West Longitude = W > Longitude = 89.00, 40.00, 11.16 -- Best Regards / S pozdravem, Stanislav Brabec software developer --------------------------------------------------------------------- SUSE LINUX, s. r. o. e-mail: sb...@su... Lihovarská 1060/12 tel: +420 284 028 966, +49 911 740538747 190 00 Praha 9 fax: +420 284 028 951 Czech Republic http://www.suse.cz/ |
From: Torsten C. <tc...@va...> - 2008-11-06 20:41:30
|
Hey Stanislav, Thanks for the quick feedback. > This is broken and can never work, as tags are unique only per IFD, not > per EXIF. Use exif_tag_get_title_in_ifd. I see ... makes sense Actually I was after the GPS information anyway. So I ended up with ExifEntry *entry_lat = exif_data_get_entry(ed, EXIF_TAG_GPS_LATITUDE); if (exif_entry_get_value(entry_lat, value, sizeof(value))) { NSLog(@"lat = %s", value); } ExifEntry *entry_latref = exif_data_get_entry(ed, EXIF_TAG_GPS_LATITUDE_REF); if (exif_entry_get_value(entry_latref, value, sizeof(value))) { NSLog(@"latref = %s", value); } ExifEntry *entry_lon = exif_data_get_entry(ed, EXIF_TAG_GPS_LONGITUDE); if (exif_entry_get_value(entry_lon, value, sizeof(value))) { NSLog(@"lon = %s", value); } ExifEntry *entry_lonref = exif_data_get_entry(ed, EXIF_TAG_GPS_LONGITUDE_REF); if (exif_entry_get_value(entry_lonref, value, sizeof(value))) { NSLog(@"lonref = %s", value); } Which seems to work just fine. Now how do I update or add exif information if not available? I assume I would have to create a new exif entry with exif_entry_new() Not sure how to fill it properly though. For example there is no exif_entry_set_value(). Will I have to modify the struct directly? Any pointers? cheers -- Torsten |
From: Jan P. <pa...@pi...> - 2008-11-06 21:20:50
|
Hi, > Now how do I update or add exif information if not available? > I assume I would have to create a new exif entry with exif_entry_new() > Not sure how to fill it properly though. > For example there is no exif_entry_set_value(). Will I have to modify > the struct directly? When the entry doesn't exist yet, you should do something like this: 1) e = exif_entry_new() 2) do something similar that exif_entry_initialize does for e.g. EXIF_TAG_EXIF_VERSION. Here you will have to set the correct value(s) using something like exif_set_short(e->data, exif_data_get_byte_order(e->parent->parent), val); 3) exif_content_add_entry(ifd, e); 4) exif_entry_unref(e); Hope this helps. -- Jan |
From: Jan P. <pa...@pi...> - 2008-11-06 21:22:26
|
> Longitude = 89.00, 40.00, 11.16 > > For one the Longitude format is awkward. > Using exiv2 on the file I get > 0x0004 GPSInfo GPSLongitude Rational 3 89/1 > 40/1 6978/625 Which format would you like libexif to use? The same format as exiv2 uses, i.e. the exact fractions? -- Jan |
From: Torsten C. <tc...@va...> - 2008-11-07 00:19:27
|
On Thu, Nov 6, 2008 at 10:22 PM, Jan Patera <pa...@pi...> wrote: >> Longitude = 89.00, 40.00, 11.16 >> >> For one the Longitude format is awkward. >> Using exiv2 on the file I get >> 0x0004 GPSInfo GPSLongitude Rational 3 89/1 >> 40/1 6978/625 > > Which format would you like libexif to use? The same format as exiv2 uses, > i.e. the exact fractions? Actually - never mind. Just had a look at the spec and found the exif_set_rational/exif_get_rational ... so that's just the textual representation. And doesn't really matter that much. (I would have expected a simple double printed though) What I haven't worked out yet is how to set 3 rationals. entry_lon = exif_entry_new(); exif_entry_initialize(entry_lon, EXIF_TAG_GPS_LONGITUDE); ExifRational value; value.numerator = 54 value.denominator = 1; exif_set_rational(entry_lon->data, exif_data_get_byte_order(ed), value); exif_content_add_entry(ed->ifd[EXIF_IFD_GPS], entry_lon); exif_entry_unref(entry_lon); According to the spec there are 3 rationals. But I have no idea how to do that with the API. May I ask for another pointer? :) cheers -- Torsten |
From: Jan P. <pa...@pi...> - 2008-11-07 06:30:48
|
> On Thu, Nov 6, 2008 at 10:22 PM, Jan Patera <pa...@pi...> wrote: >>> Longitude = 89.00, 40.00, 11.16 >>> > (I would have expected a simple double printed though) Well, this is what libexif does: it simply prints 3 doubles because there are 3 values. > What I haven't worked out yet is how to set 3 rationals. > > entry_lon = exif_entry_new(); > exif_entry_initialize(entry_lon, EXIF_TAG_GPS_LONGITUDE); > > ExifRational value; > value.numerator = 54 > value.denominator = 1; > > exif_set_rational(entry_lon->data, exif_data_get_byte_order(ed), > value); > > exif_content_add_entry(ed->ifd[EXIF_IFD_GPS], entry_lon); > > exif_entry_unref(entry_lon); > > According to the spec there are 3 rationals. But I have no idea how to > do that with the API. > > May I ask for another pointer? :) Hmm, did you read my second mail? Check what exif_entry_initialize does for e.g. EXIF_TAG_EXIF_VERSION. You should either 1) adapt exif_entry_initialize so that it suports also GPS tags (currently it does not) 2) copy-past-adapt the code from exif_entry_initialize to your code: e->components = 3; // Use the correct number e->format = EXIF_FORMAT_xxxx; // Use correct format. RATIONAL? e->size = exif_format_get_size (e->format) * e->components; e->data = exif_entry_alloc (e, e->size); if (!e->data) fail; exif_set_rational(e->data, o, value1); exif_set_rational(e->data+sizeof(ExifRational), o, value2); exif_set_rational(e->data+2*sizeof(ExifRational), o, value3); -- Jan |
From: Torsten C. <tc...@va...> - 2008-11-07 19:19:15
|
>> (I would have expected a simple double printed though) > > Well, this is what libexif does: it simply prints 3 doubles because > there are 3 values. True ... I meant as a single double. http://www.flickr.com/geoformats.gne But anyway > Hmm, did you read my second mail? Sorry, thought you meant use - not change or copy. > Check what exif_entry_initialize does > for e.g. EXIF_TAG_EXIF_VERSION. You should either > 1) adapt exif_entry_initialize so that it suports also GPS tags > (currently it does not) > 2) copy-past-adapt the code from exif_entry_initialize to your code: For now I just want to get the POC working. But I will provide a patch once it's there. So for now I went with 2) static void set_value(ExifEntry *entry, ExifTag tag, ExifByteOrder order, double value) { entry->tag = tag; entry->components = 3; entry->format = EXIF_FORMAT_RATIONAL; entry->size = exif_format_get_size(entry->format) * entry->components; entry->data = exif_entry_alloc(entry, entry->size); if (!entry->data) return; // dd/1,mm/1,ss/1 dd/1,mmmm/100,0/1 ExifRational value1; value1.numerator = 1; value1.denominator = 1; ExifRational value2; value2.numerator = 1; value2.denominator = 1; ExifRational value3; value3.numerator = 1; value3.denominator = 1; exif_set_rational(entry->data, order, value1); exif_set_rational(entry->data+sizeof(ExifRational), order, value2); exif_set_rational(entry->data+2*sizeof(ExifRational), order, value3); } Still needs the double -> rationals conversion though. Would be nice if libexif would support some of that a little better. Especially with exif_entry_alloc not being available outside. cheers -- Torsten |