/*
* Geeqie
* (C) 2006 John Ellis
- * Copyright (C) 2008 The Geeqie Team
+ * Copyright (C) 2008 - 2012 The Geeqie Team
*
* Authors:
* Support for Exif file format, originally written by Eric Swalens.
* 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?)
+ * Add support for marker tag 0x0000
*
This program is free software; you can redistribute it and/or modify
#include <math.h>
#include <glib.h>
+#include <glib/gprintf.h>
#include "intl.h"
#include "main.h"
#include "exif-int.h"
+#include "jpeg_parser.h"
#include "format_raw.h"
#include "ui_fileops.h"
/* tags that are special, or need special treatment */
#define TAG_EXIFOFFSET 0x8769
#define TAG_EXIFMAKERNOTE 0x927c
+#define TAG_GPSOFFSET 0x8825
/*
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 },
item->tag = tag;
item->marker = marker;
item->elements = elements;
- item->data = NULL;
- item->data_len = 0;
switch (format)
{
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;
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;
item->data_len = sizeof(float) * elements;
break;
case EXIF_FORMAT_DOUBLE:
- item->data_len = sizeof(double) * elements;
+ item->data_len = sizeof(gdouble) * elements;
break;
}
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);
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;
}
-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;
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);
}
{
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;
/* 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;
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;
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;
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;
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);
/* 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;
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:
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)
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;
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;
}
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)
*-------------------------------------------------------------------
*/
-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;
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;
*/
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);
}
static gint exif_jpeg_parse(ExifData *exif,
- unsigned char *data, guint size,
+ guchar *data, guint size,
ExifMarker *list)
{
guint seg_offset = 0;
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))
{
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;
}
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;
*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);
return 0;
}
-static gint unmap_file(void *mapping, int size)
+static gint unmap_file(gpointer mapping, gint size)
{
if (munmap(mapping, size) == -1)
{
return 0;
}
+ExifData *exif_get_original(ExifData *processed)
+{
+ return processed;
+}
+
void exif_free(ExifData *exif)
{
GList *work;
}
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;
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)
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);
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;
}
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;
}
work = exif->items;
while (work)
- {
+ {
ExifItem *item;
item = work->data;
#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;
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);
}
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;
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:
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:
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:
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:
for (i = 0; i < ne; i++)
{
g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "",
- ((double *)data)[i]);
+ ((gdouble *)data)[i]);
}
break;
}
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)
{
}
-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;
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;
}
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);
}
{
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)
{
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++;
}
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: */