X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=blobdiff_plain;f=src%2Fexif.c;h=872b9ccd65e54979ccc108845eb952b1af2975e1;hp=dd58bb0ad79112f481f6e52a8a87cebc1e2d7d17;hb=50f5ef3cedbeaa251a1e838bf5045a9dc7dda1ee;hpb=8c7decff43cd66410be772b6c1a3204efe7a7e00 diff --git a/src/exif.c b/src/exif.c index dd58bb0a..872b9ccd 100644 --- a/src/exif.c +++ b/src/exif.c @@ -1,13 +1,22 @@ /* - * Geeqie - * (C) 2006 John Ellis - * Copyright (C) 2008 The Geeqie Team + * Copyright (C) 2003, 2006 John Ellis + * Copyright (C) 2008 - 2016 The Geeqie Team * - * Authors: - * Support for Exif file format, originally written by Eric Swalens. - * Modified by Quy Tonthat + * Authors: Eric Swalens, Quy Tonthat * - * Reimplemented with generic data storage by John Ellis (Nov 2003) + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * The tags were added with information from the FREE document: * http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html @@ -28,28 +37,13 @@ * Unsupported at this time: * IFD1 (thumbnail) * MakerNote - * GPSInfo * * TODO: * Convert data to useable form in the ??_as_text function for: * ComponentsConfiguration * UserComment (convert this to UTF-8?) - * - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * Add support for marker tag 0x0000 + */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -67,11 +61,13 @@ #include #include +#include #include "intl.h" #include "main.h" #include "exif-int.h" +#include "jpeg_parser.h" #include "format_raw.h" #include "ui_fileops.h" @@ -103,6 +99,7 @@ ExifFormatAttrib ExifFormatList[] = { /* tags that are special, or need special treatment */ #define TAG_EXIFOFFSET 0x8769 #define TAG_EXIFMAKERNOTE 0x927c +#define TAG_GPSOFFSET 0x8825 /* @@ -437,6 +434,44 @@ ExifMarker ExifKnownMarkersList[] = { EXIF_MARKER_LIST_END }; +ExifMarker ExifKnownGPSInfoMarkersList[] = { + /* The following do not work at the moment as the tag value 0x0000 has a + * special meaning. */ + /* { 0x0000, EXIF_FORMAT_BYTE, -1, "Exif.GPSInfo.GPSVersionID", NULL, NULL }, */ + { 0x0001, EXIF_FORMAT_STRING, 2, "Exif.GPSInfo.GPSLatitudeRef", NULL, NULL }, + { 0x0002, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSLatitude", NULL, NULL }, + { 0x0003, EXIF_FORMAT_STRING, 2, "Exif.GPSInfo.GPSLongitudeRef", NULL, NULL }, + { 0x0004, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSLongitude", NULL, NULL }, + { 0x0005, EXIF_FORMAT_BYTE_UNSIGNED, 1, "Exif.GPSInfo.GPSAltitudeRef", NULL, NULL }, + { 0x0006, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.GPSInfo.GPSAltitude", NULL, NULL }, + { 0x0007, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSTimeStamp", NULL, NULL }, + { 0x0008, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSSatellites", NULL, NULL }, + { 0x0009, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSStatus", NULL, NULL }, + { 0x000a, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSMeasureMode", NULL, NULL }, + { 0x000b, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDOP", NULL, NULL }, + { 0x000c, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSSpeedRef", NULL, NULL }, + { 0x000d, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSSpeed", NULL, NULL }, + { 0x000e, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSTrackRef", NULL, NULL }, + { 0x000f, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSTrack", NULL, NULL }, + { 0x0010, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSImgDirectionRef", NULL, NULL }, + { 0x0011, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSImgDirection", NULL, NULL }, + { 0x0012, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSMapDatum", NULL, NULL }, + { 0x0013, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestLatitudeRef", NULL, NULL }, + { 0x0014, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestLatitude", NULL, NULL }, + { 0x0015, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestLongitudeRef", NULL, NULL }, + { 0x0016, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestLongitude", NULL, NULL }, + { 0x0017, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestBearingRef", NULL, NULL }, + { 0x0018, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestBearing", NULL, NULL }, + { 0x0019, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestDistanceRef", NULL, NULL }, + { 0x001a, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestDistance", NULL, NULL }, + { 0x001b, EXIF_FORMAT_UNDEFINED, -1, "Exif.GPSInfo.GPSProcessingMethod", NULL, NULL }, + { 0x001c, EXIF_FORMAT_UNDEFINED, -1, "Exif.GPSInfo.GPSAreaInformation", NULL, NULL }, + { 0x001d, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSDateStamp", NULL, NULL }, + { 0x001e, EXIF_FORMAT_SHORT, -1, "Exif.GPSInfo.GPSDifferential", NULL, NULL }, + + EXIF_MARKER_LIST_END +}; + ExifMarker ExifUnknownMarkersList[] = { { 0x0000, EXIF_FORMAT_UNKNOWN, 0, "unknown", NULL, NULL }, { 0x0000, EXIF_FORMAT_BYTE_UNSIGNED, -1, "unknown", NULL, NULL }, @@ -471,8 +506,6 @@ ExifItem *exif_item_new(ExifFormatType format, guint tag, item->tag = tag; item->marker = marker; item->elements = elements; - item->data = NULL; - item->data_len = 0; switch (format) { @@ -481,10 +514,10 @@ ExifItem *exif_item_new(ExifFormatType format, guint tag, return item; break; case EXIF_FORMAT_BYTE_UNSIGNED: - item->data_len = sizeof(char) * elements; + item->data_len = sizeof(gchar) * elements; break; case EXIF_FORMAT_STRING: - item->data_len = sizeof(char) * elements; + item->data_len = sizeof(gchar) * elements; break; case EXIF_FORMAT_SHORT_UNSIGNED: item->data_len = sizeof(guint16) * elements; @@ -496,10 +529,10 @@ ExifItem *exif_item_new(ExifFormatType format, guint tag, item->data_len = sizeof(ExifRational) * elements; break; case EXIF_FORMAT_BYTE: - item->data_len = sizeof(char) * elements; + item->data_len = sizeof(gchar) * elements; break; case EXIF_FORMAT_UNDEFINED: - item->data_len = sizeof(char) * elements; + item->data_len = sizeof(gchar) * elements; break; case EXIF_FORMAT_SHORT: item->data_len = sizeof(gint16) * elements; @@ -514,7 +547,7 @@ ExifItem *exif_item_new(ExifFormatType format, guint tag, item->data_len = sizeof(float) * elements; break; case EXIF_FORMAT_DOUBLE: - item->data_len = sizeof(double) * elements; + item->data_len = sizeof(gdouble) * elements; break; } @@ -531,7 +564,7 @@ static void exif_item_free(ExifItem *item) g_free(item); } -char *exif_item_get_tag_name(ExifItem *item) +gchar *exif_item_get_tag_name(ExifItem *item) { if (!item || !item->marker) return NULL; return g_strdup(item->marker->key); @@ -549,7 +582,7 @@ guint exif_item_get_elements(ExifItem *item) return item->elements; } -char *exif_item_get_data(ExifItem *item, guint *data_len) +gchar *exif_item_get_data(ExifItem *item, guint *data_len) { if (data_len) *data_len = item->data_len; @@ -563,13 +596,13 @@ guint exif_item_get_format_id(ExifItem *item) } -char *exif_item_get_description(ExifItem *item) +gchar *exif_item_get_description(ExifItem *item) { if (!item || !item->marker) return NULL; return g_strdup(_(item->marker->description)); } -const char *exif_item_get_format_name(ExifItem *item, gint brief) +const gchar *exif_item_get_format_name(ExifItem *item, gboolean brief) { if (!item || !item->marker) return NULL; return (brief) ? ExifFormatList[item->format].short_name : ExifFormatList[item->format].description; @@ -581,7 +614,7 @@ static GString *string_append_raw_bytes(GString *string, gpointer data, gint ne) for (i = 0 ; i < ne; i++) { - unsigned char c = ((char *)data)[i]; + guchar c = ((gchar *)data)[i]; if (c < 32 || c > 127) c = '.'; g_string_append_printf(string, "%c", c); } @@ -604,7 +637,7 @@ static GString *string_append_raw_bytes(GString *string, gpointer data, gint ne) { spacer = ""; } - g_string_append_printf(string, "%s%02x", spacer, ((char *)data)[i]); + g_string_append_printf(string, "%s%02x", spacer, ((gchar *)data)[i]); } return string; @@ -636,7 +669,7 @@ gchar *exif_text_list_find_value(ExifTextList *list, guint value) /* note: the align_buf is used to avoid alignment issues (on sparc) */ -guint16 exif_byte_get_int16(unsigned char *f, ExifByteOrder bo) +guint16 exif_byte_get_int16(guchar *f, ExifByteOrder bo) { guint16 align_buf; @@ -648,7 +681,7 @@ guint16 exif_byte_get_int16(unsigned char *f, ExifByteOrder bo) return GUINT16_FROM_BE(align_buf); } -guint32 exif_byte_get_int32(unsigned char *f, ExifByteOrder bo) +guint32 exif_byte_get_int32(guchar *f, ExifByteOrder bo) { guint32 align_buf; @@ -660,7 +693,7 @@ guint32 exif_byte_get_int32(unsigned char *f, ExifByteOrder bo) return GUINT32_FROM_BE(align_buf); } -void exif_byte_put_int16(unsigned char *f, guint16 n, ExifByteOrder bo) +void exif_byte_put_int16(guchar *f, guint16 n, ExifByteOrder bo) { guint16 align_buf; @@ -676,7 +709,7 @@ void exif_byte_put_int16(unsigned char *f, guint16 n, ExifByteOrder bo) memcpy(f, &align_buf, sizeof(guint16)); } -void exif_byte_put_int32(unsigned char *f, guint32 n, ExifByteOrder bo) +void exif_byte_put_int32(guchar *f, guint32 n, ExifByteOrder bo) { guint32 align_buf; @@ -713,7 +746,7 @@ static const ExifMarker *exif_marker_from_tag(guint16 tag, const ExifMarker *lis return (list[i].tag == 0 ? NULL : &list[i]); } -static void rational_from_data(ExifRational *r, void *src, ExifByteOrder bo) +static void rational_from_data(ExifRational *r, gpointer src, ExifByteOrder bo) { r->num = exif_byte_get_int32(src, bo); r->den = exif_byte_get_int32(src + sizeof(guint32), bo); @@ -722,7 +755,7 @@ static void rational_from_data(ExifRational *r, void *src, ExifByteOrder bo) /* src_format and item->format must be compatible * and not overrun src or item->data. */ -void exif_item_copy_data(ExifItem *item, void *src, guint len, +void exif_item_copy_data(ExifItem *item, gpointer src, guint len, ExifFormatType src_format, ExifByteOrder bo) { gint bs; @@ -755,7 +788,7 @@ void exif_item_copy_data(ExifItem *item, void *src, guint len, case EXIF_FORMAT_STRING: memcpy(dest, src, len); /* string is NULL terminated, make sure this is true */ - if (((char *)dest)[len - 1] != '\0') ((char *)dest)[len - 1] = '\0'; + if (((gchar *)dest)[len - 1] != '\0') ((gchar *)dest)[len - 1] = '\0'; break; case EXIF_FORMAT_SHORT_UNSIGNED: case EXIF_FORMAT_SHORT: @@ -807,13 +840,13 @@ void exif_item_copy_data(ExifItem *item, void *src, guint len, ExifRational r; rational_from_data(&r, src + i * bs, bo); - if (r.den) ((double *)dest)[i] = (double)r.num / r.den; + if (r.den) ((gdouble *)dest)[i] = (gdouble)r.num / r.den; } break; } } -static gint exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, guint offset, +static gint exif_parse_IFD_entry(ExifData *exif, guchar *tiff, guint offset, guint size, ExifByteOrder bo, gint level, const ExifMarker *list) @@ -889,7 +922,7 @@ static gint exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, guint offs if (data_length > 4) { data_offset = data_val; - if (size < data_offset + data_length) + if (size < data_offset || size < data_offset + data_length) { log_printf("warning: exif tag %s data will overrun end of file, ignored.\n", marker->key); return -1; @@ -911,6 +944,9 @@ static gint exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, guint offs case TAG_EXIFOFFSET: exif_parse_IFD_table(exif, tiff, data_val, size, bo, level + 1, list); break; + case TAG_GPSOFFSET: + exif_parse_IFD_table(exif, tiff, data_val, size, bo, level + 1, ExifKnownGPSInfoMarkersList); + break; case TAG_EXIFMAKERNOTE: format_exif_makernote_parse(exif, tiff, data_val, size, bo); break; @@ -921,7 +957,7 @@ static gint exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, guint offs } gint exif_parse_IFD_table(ExifData *exif, - unsigned char *tiff, guint offset, + guchar *tiff, guint offset, guint size, ExifByteOrder bo, gint level, const ExifMarker *list) @@ -955,7 +991,7 @@ gint exif_parse_IFD_table(ExifData *exif, *------------------------------------------------------------------- */ -gint exif_tiff_directory_offset(unsigned char *data, const guint len, +gint exif_tiff_directory_offset(guchar *data, const guint len, guint *offset, ExifByteOrder *bo) { if (len < 8) return FALSE; @@ -983,7 +1019,7 @@ gint exif_tiff_directory_offset(unsigned char *data, const guint len, return (*offset < len); } -gint exif_tiff_parse(ExifData *exif, unsigned char *tiff, guint size, ExifMarker *list) +gint exif_tiff_parse(ExifData *exif, guchar *tiff, guint size, ExifMarker *list) { ExifByteOrder bo; guint offset; @@ -1019,7 +1055,7 @@ gint exif_tiff_parse(ExifData *exif, unsigned char *tiff, guint size, ExifMarker */ static ExifMarker jpeg_color_marker = { 0x8773, EXIF_FORMAT_UNDEFINED, -1, "Exif.Image.InterColorProfile", NULL, NULL }; -void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length) +void exif_add_jpeg_color_profile(ExifData *exif, guchar *cp_data, guint cp_length) { ExifItem *item = exif_item_new(jpeg_color_marker.format, jpeg_color_marker.tag, 1, &jpeg_color_marker); @@ -1032,7 +1068,7 @@ void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint c } static gint exif_jpeg_parse(ExifData *exif, - unsigned char *data, guint size, + guchar *data, guint size, ExifMarker *list) { guint seg_offset = 0; @@ -1045,7 +1081,7 @@ static gint exif_jpeg_parse(ExifData *exif, return -2; } - if (exif_jpeg_segment_find(data, size, JPEG_MARKER_APP1, + if (jpeg_segment_find(data, size, JPEG_MARKER_APP1, "Exif\x00\x00", 6, &seg_offset, &seg_length)) { @@ -1060,15 +1096,27 @@ static gint exif_jpeg_parse(ExifData *exif, return res; } -unsigned char *exif_get_color_profile(ExifData *exif, guint *data_len) +guchar *exif_get_color_profile(ExifData *exif, guint *data_len) { ExifItem *prof_item = exif_get_item(exif, "Exif.Image.InterColorProfile"); if (prof_item && exif_item_get_format_id(prof_item) == EXIF_FORMAT_UNDEFINED) - return (unsigned char*) exif_item_get_data(prof_item, data_len); + return (guchar *) exif_item_get_data(prof_item, data_len); return NULL; } +gchar* exif_get_image_comment(FileData* fd) +{ + log_printf("%s", _("Can't get image comment: not compiled with Exiv2.\n")); + return g_strdup(""); +} + +void exif_set_image_comment(FileData* fd, const gchar* comment) +{ + log_printf("%s", _("Can't set image comment: not compiled with Exiv2.\n")); +} + + /* *------------------------------------------------------------------- * misc @@ -1099,12 +1147,13 @@ ExifItem *exif_get_next_item(ExifData *exif) return NULL; } -static gint map_file(const gchar *path, void **mapping, int *size) +static gint map_file(const gchar *path, void **mapping, gint *size) { - int fd; + gint fd; struct stat fs; - if ((fd = open(path, O_RDONLY)) == -1) + fd = open(path, O_RDONLY); + if (fd == -1) { perror(path); return -1; @@ -1119,7 +1168,8 @@ static gint map_file(const gchar *path, void **mapping, int *size) *size = fs.st_size; - if ((*mapping = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED) + *mapping = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (*mapping == MAP_FAILED) { perror(path); close(fd); @@ -1130,7 +1180,7 @@ static gint map_file(const gchar *path, void **mapping, int *size) return 0; } -static gint unmap_file(void *mapping, int size) +static gint unmap_file(gpointer mapping, gint size) { if (munmap(mapping, size) == -1) { @@ -1141,6 +1191,11 @@ static gint unmap_file(void *mapping, int size) return 0; } +ExifData *exif_get_original(ExifData *processed) +{ + return processed; +} + void exif_free(ExifData *exif) { GList *work; @@ -1156,14 +1211,15 @@ void exif_free(ExifData *exif) } g_list_free(exif->items); + g_free(exif->path); g_free(exif); } -ExifData *exif_read(gchar *path, gchar *sidecar_path) +ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp) { ExifData *exif; - void *f; - int size, res; + gpointer f; + gint size, res; gchar *pathl; if (!path) return NULL; @@ -1177,13 +1233,12 @@ ExifData *exif_read(gchar *path, gchar *sidecar_path) g_free(pathl); exif = g_new0(ExifData, 1); - exif->items = NULL; - exif->current = NULL; + exif->path = g_strdup(path); - if ((res = exif_jpeg_parse(exif, (unsigned char *)f, size, - ExifKnownMarkersList)) == -2) + res = exif_jpeg_parse(exif, (guchar *)f, size, ExifKnownMarkersList); + if (res == -2) { - res = exif_tiff_parse(exif, (unsigned char *)f, size, ExifKnownMarkersList); + res = exif_tiff_parse(exif, (guchar *)f, size, ExifKnownMarkersList); } if (res != 0) @@ -1199,16 +1254,16 @@ ExifData *exif_read(gchar *path, gchar *sidecar_path) default: break; case FORMAT_RAW_EXIF_TIFF: - res = exif_tiff_parse(exif, (unsigned char*)f + offset, size - offset, + res = exif_tiff_parse(exif, (guchar *)f + offset, size - offset, ExifKnownMarkersList); break; case FORMAT_RAW_EXIF_JPEG: - res = exif_jpeg_parse(exif, (unsigned char*)f + offset, size - offset, + res = exif_jpeg_parse(exif, (guchar *)f + offset, size - offset, ExifKnownMarkersList); break; case FORMAT_RAW_EXIF_IFD_II: case FORMAT_RAW_EXIF_IFD_MM: - res = exif_parse_IFD_table(exif, (unsigned char*)f, offset, size - offset, + res = exif_parse_IFD_table(exif, (guchar *)f, offset, size - offset, (exif_type == FORMAT_RAW_EXIF_IFD_II) ? EXIF_BYTE_ORDER_INTEL : EXIF_BYTE_ORDER_MOTOROLA, 0, ExifKnownMarkersList); @@ -1216,7 +1271,7 @@ ExifData *exif_read(gchar *path, gchar *sidecar_path) case FORMAT_RAW_EXIF_PROPRIETARY: if (exif_parse_func) { - res = exif_parse_func((unsigned char*)f + offset, size - offset, exif); + res = exif_parse_func((guchar *)f + offset, size - offset, exif); } break; } @@ -1232,11 +1287,6 @@ ExifData *exif_read(gchar *path, gchar *sidecar_path) if (exif) exif->items = g_list_reverse(exif->items); -#if 0 - exif_write_data_list(exif, stdout, TRUE); - exif_write_data_list(exif, stdout, FALSE); -#endif - return exif; } @@ -1248,7 +1298,7 @@ ExifItem *exif_get_item(ExifData *exif, const gchar *key) work = exif->items; while (work) - { + { ExifItem *item; item = work->data; @@ -1260,13 +1310,8 @@ ExifItem *exif_get_item(ExifData *exif, const gchar *key) #define EXIF_DATA_AS_TEXT_MAX_COUNT 16 -gchar *exif_item_get_string(ExifItem *item, int idx) -{ - return exif_item_get_data_as_text(item); -} - -gchar *exif_item_get_data_as_text(ExifItem *item) +static gchar *exif_item_get_data_as_text_full(ExifItem *item, MetadataFormat format) { const ExifMarker *marker; gpointer data; @@ -1291,19 +1336,19 @@ gchar *exif_item_get_data_as_text(ExifItem *item) case EXIF_FORMAT_BYTE_UNSIGNED: case EXIF_FORMAT_BYTE: case EXIF_FORMAT_UNDEFINED: - if (ne == 1 && marker->list) + if (ne == 1 && marker->list && format == METADATA_FORMATTED) { gchar *result; - unsigned char val; + guchar val; if (item->format == EXIF_FORMAT_BYTE_UNSIGNED || item->format == EXIF_FORMAT_UNDEFINED) { - val = ((unsigned char *)data)[0]; + val = ((guchar *)data)[0]; } else { - val = (unsigned char)(((signed char *)data)[0]); + val = (guchar)(((gchar *)data)[0]); } result = exif_text_list_find_value(marker->list, (guint)val); @@ -1316,10 +1361,10 @@ gchar *exif_item_get_data_as_text(ExifItem *item) } break; case EXIF_FORMAT_STRING: - string = g_string_append(string, (gchar *)(item->data)); + if (item->data) string = g_string_append(string, (gchar *)(item->data)); break; case EXIF_FORMAT_SHORT_UNSIGNED: - if (ne == 1 && marker->list) + if (ne == 1 && marker->list && format == METADATA_FORMATTED) { gchar *result; @@ -1337,7 +1382,7 @@ gchar *exif_item_get_data_as_text(ExifItem *item) for (i = 0; i < ne; i++) { g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "", - (unsigned long int)((guint32 *)data)[i]); + (gulong)((guint32 *)data)[i]); } break; case EXIF_FORMAT_RATIONAL_UNSIGNED: @@ -1347,7 +1392,7 @@ gchar *exif_item_get_data_as_text(ExifItem *item) r = &((ExifRational *)data)[i]; g_string_append_printf(string, "%s%ld/%ld", (i > 0) ? ", " : "", - (unsigned long)r->num, (unsigned long)r->den); + (gulong)r->num, (gulong)r->den); } break; case EXIF_FORMAT_SHORT: @@ -1361,7 +1406,7 @@ gchar *exif_item_get_data_as_text(ExifItem *item) for (i = 0; i < ne; i++) { g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "", - (long int)((gint32 *)data)[i]); + (glong)((gint32 *)data)[i]); } break; case EXIF_FORMAT_RATIONAL: @@ -1371,7 +1416,7 @@ gchar *exif_item_get_data_as_text(ExifItem *item) r = &((ExifRational *)data)[i]; g_string_append_printf(string, "%s%ld/%ld", (i > 0) ? ", " : "", - (long)r->num, (long)r->den); + (glong)r->num, (glong)r->den); } break; case EXIF_FORMAT_FLOAT: @@ -1385,7 +1430,7 @@ gchar *exif_item_get_data_as_text(ExifItem *item) for (i = 0; i < ne; i++) { g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "", - ((double *)data)[i]); + ((gdouble *)data)[i]); } break; } @@ -1402,9 +1447,20 @@ gchar *exif_item_get_data_as_text(ExifItem *item) return text; } +gchar *exif_item_get_string(ExifItem *item, gint idx) +{ + return exif_item_get_data_as_text_full(item, METADATA_PLAIN); +} + +gchar *exif_item_get_data_as_text(ExifItem *item) +{ + return exif_item_get_data_as_text_full(item, METADATA_FORMATTED); +} + gint exif_item_get_integer(ExifItem *item, gint *value) { if (!item) return FALSE; + if (!item->elements) return FALSE; switch (item->format) { @@ -1432,21 +1488,22 @@ gint exif_item_get_integer(ExifItem *item, gint *value) } -ExifRational *exif_item_get_rational(ExifItem *item, gint *sign) +ExifRational *exif_item_get_rational(ExifItem *item, gint *sign, guint n) { if (!item) return NULL; + if (n >= item->elements) return NULL; if (item->format == EXIF_FORMAT_RATIONAL || item->format == EXIF_FORMAT_RATIONAL_UNSIGNED) { if (sign) *sign = (item->format == EXIF_FORMAT_RATIONAL); - return &((ExifRational *)(item->data))[0]; + return &((ExifRational *)(item->data))[n]; } return NULL; } -const gchar *exif_get_tag_description_by_key(const gchar *key) +gchar *exif_get_tag_description_by_key(const gchar *key) { gint i; @@ -1455,10 +1512,17 @@ const gchar *exif_get_tag_description_by_key(const gchar *key) i = 0; while (ExifKnownMarkersList[i].tag > 0) { - if (strcmp(key, ExifKnownMarkersList[i].key) == 0) return _(ExifKnownMarkersList[i].description); + if (strcmp(key, ExifKnownMarkersList[i].key) == 0) return g_strdup(_(ExifKnownMarkersList[i].description)); i++; } + i = 0; + while (ExifKnownGPSInfoMarkersList[i].tag > 0) + { + if (strcmp(key, ExifKnownGPSInfoMarkersList[i].key) == 0) return g_strdup(_(ExifKnownGPSInfoMarkersList[i].description)); + i++; + } + return NULL; } @@ -1470,7 +1534,7 @@ static void exif_write_item(FILE *f, ExifItem *item) if (text) { gchar *tag = exif_item_get_tag_name(item); - fprintf(f, "%4x %9s %30s %s\n", item->tag, ExifFormatList[item->format].short_name, + g_fprintf(f, "%4x %9s %30s %s\n", item->tag, ExifFormatList[item->format].short_name, tag, text); g_free(tag); } @@ -1481,8 +1545,8 @@ void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list) { if (!f || !exif) return; - fprintf(f, " tag format key value\n"); - fprintf(f, "----------------------------------------------------\n"); + g_fprintf(f, " tag format key value\n"); + g_fprintf(f, "----------------------------------------------------\n"); if (human_readable_list) { @@ -1496,7 +1560,7 @@ void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list) text = exif_get_formatted_by_key(exif, ExifFormattedList[i].key, NULL); if (text) { - fprintf(f, " %9s %30s %s\n", "string", ExifFormattedList[i].key, text); + g_fprintf(f, " %9s %30s %s\n", "string", ExifFormattedList[i].key, text); } i++; } @@ -1516,31 +1580,142 @@ void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list) exif_write_item(f, item); } } - fprintf(f, "----------------------------------------------------\n"); + g_fprintf(f, "----------------------------------------------------\n"); } -int exif_write(ExifData *exif) +gboolean exif_write(ExifData *exif) { - log_printf("Not compiled with EXIF write support"); - return 0; + log_printf("Not compiled with EXIF write support\n"); + return FALSE; } -ExifItem *exif_add_item(ExifData *exif, const gchar *key) +gboolean exif_write_sidecar(ExifData *exif, gchar *path) { - return NULL; + log_printf("Not compiled with EXIF write support\n"); + return FALSE; } -int exif_item_delete(ExifData *exif, ExifItem *item) + +gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values) { return 0; } -int exif_item_set_string(ExifItem *item, const char *str) +GList *exif_get_metadata(ExifData *exif, const gchar *key, MetadataFormat format) { - return 0; + gchar *str; + ExifItem *item; + + if (!key) return NULL; + + /* convert xmp key to exif key */ + if (strcmp(key, "Xmp.tiff.Orientation") == 0) key = "Exif.Image.Orientation"; + + if (format == METADATA_FORMATTED) + { + gchar *text; + gint key_valid; + text = exif_get_formatted_by_key(exif, key, &key_valid); + if (key_valid) return g_list_append(NULL, text); + } + + item = exif_get_item(exif, key); + if (!item) return NULL; + + str = exif_item_get_data_as_text_full(item, format); + + if (!str) return NULL; + + return g_list_append(NULL, str); +} + +typedef struct _UnmapData UnmapData; +struct _UnmapData +{ + guchar *ptr; + guchar *map_data; + size_t map_len; +}; + +static GList *exif_unmap_list = 0; + +guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width, gint requested_height) +{ + guint offset; + const gchar* path; + struct stat st; + guchar *map_data; + size_t map_len; + int fd; + + if (!exif) return NULL; + path = exif->path; + + fd = open(path, O_RDONLY); + + + if (fd == -1) + { + return 0; + } + + if (fstat(fd, &st) == -1) + { + close(fd); + return 0; + } + map_len = st.st_size; + map_data = (guchar *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + + if (map_data == MAP_FAILED) + { + return 0; + } + + if (format_raw_img_exif_offsets(map_data, map_len, &offset, NULL) && offset) + { + UnmapData *ud; + + DEBUG_1("%s: offset %u", path, offset); + + *data_len = map_len - offset; + ud = g_new(UnmapData, 1); + ud->ptr = map_data + offset; + ud->map_data = map_data; + ud->map_len = map_len; + + exif_unmap_list = g_list_prepend(exif_unmap_list, ud); + return ud->ptr; + } + + munmap(map_data, map_len); + return NULL; + } +void exif_free_preview(guchar *buf) +{ + GList *work = exif_unmap_list; + + while (work) + { + UnmapData *ud = (UnmapData *)work->data; + if (ud->ptr == buf) + { + exif_unmap_list = g_list_remove_link(exif_unmap_list, work); + g_free(ud); + return; + } + work = work->next; + } + g_assert_not_reached(); +} +void exif_init(void) +{ +} #endif /* not HAVE_EXIV2 */ +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */