more exiv2 fixes
[geeqie.git] / src / exif-common.c
1 /*
2  *  GQView
3  *  (C) 2006 John Ellis
4  *
5 */
6
7 #ifdef HAVE_CONFIG_H
8 #  include "config.h"
9 #endif
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/mman.h>
18 #include <math.h>
19  
20 #include <glib.h>
21
22 #include "intl.h"
23
24 #include "gqview.h"
25 #include "exif.h"
26
27 #include "format_raw.h"
28 #include "ui_fileops.h"
29
30
31 /* human readable key list */
32
33 ExifFormattedText ExifFormattedList[] = {
34         { "fCamera",            N_("Camera") },
35         { "fDateTime",          N_("Date") },
36         { "fShutterSpeed",      N_("Shutter speed") },
37         { "fAperture",          N_("Aperture") },
38         { "fExposureBias",      N_("Exposure bias") },
39         { "fISOSpeedRating",    N_("ISO sensitivity") },
40         { "fFocalLength",       N_("Focal length") },
41         { "fSubjectDistance",   N_("Subject distance") },
42         { "fFlash",             N_("Flash") },
43         { "fResolution",        N_("Resolution") },
44         { NULL, NULL }
45 };
46
47 static ExifTextList ExifFlashList[] = {
48         { 0,    N_("no") },
49         { 1,    N_("yes") },
50         { 5,    N_("yes, not detected by strobe") },
51         { 7,    N_("yes, detected by strobe") },
52         EXIF_TEXT_LIST_END
53 };
54
55
56 double exif_rational_to_double(ExifRational *r, gint sign)
57 {
58         if (!r || r->den == 0.0) return 0.0;
59
60         if (sign) return (double)((int)r->num) / (double)((int)r->den);
61         return (double)r->num / r->den;
62 }
63
64 double exif_get_rational_as_double(ExifData *exif, const gchar *key)
65 {
66         ExifRational *r;
67         gint sign;
68
69         r = exif_get_rational(exif, key, &sign);
70         return exif_rational_to_double(r, sign);
71 }
72
73 static GString *append_comma_text(GString *string, const gchar *text)
74 {
75         string = g_string_append(string, ", ");
76         string = g_string_append(string, text);
77
78         return string;
79 }
80
81
82 gchar *exif_get_formatted_by_key(ExifData *exif, const gchar *key, gint *key_valid)
83 {
84         /* must begin with f, else not formatted */
85         if (key[0] != 'f')
86                 {
87                 if (key_valid) *key_valid = FALSE;
88                 return NULL;
89                 }
90
91         if (key_valid) *key_valid = TRUE;
92
93         if (strcmp(key, "fCamera") == 0)
94                 {
95                 gchar *text;
96                 gchar *make = exif_get_data_as_text(exif, "Exif.Image.Make");
97                 gchar *model = exif_get_data_as_text(exif, "Exif.Image.Model");
98                 gchar *software = exif_get_data_as_text(exif, "Exif.Image.Software");
99
100                 text = g_strdup_printf("%s%s%s%s%s%s", (make) ? make : "", ((make) && (model)) ? " " : "",
101                                                        (model) ? model : "",
102                                                        (software) ? " (" : "",
103                                                        (software) ? software : "",
104                                                        (software) ? ")" : "");
105
106                 g_free(make);
107                 g_free(model);
108                 g_free(software);
109                 return text;
110                 }
111         if (strcmp(key, "fDateTime") == 0)
112                 {
113                 gchar *text = exif_get_data_as_text(exif, "Exif.Photo.DateTimeOriginal");
114                 gchar *subsec = NULL;
115                 if (text) subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTimeOriginal");
116                 if (!text)
117                         {
118                         text = exif_get_data_as_text(exif, "Exif.Image.DateTime");
119                         if (text) subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTime");
120                         }
121                 if (subsec)
122                         {
123                         gchar *tmp = text;
124                         text = g_strconcat(tmp, ".", subsec, NULL);
125                         g_free(tmp);
126                         g_free(subsec);
127                         }
128                 return text;
129                 }
130         if (strcmp(key, "fShutterSpeed") == 0)
131                 {
132                 ExifRational *r;
133
134                 r = exif_get_rational(exif, "Exif.Photo.ExposureTime", NULL);
135                 if (r && r->num && r->den)
136                         {
137                         double n = (double)r->den / (double)r->num;
138                         return g_strdup_printf("%s%.0fs", n > 1.0 ? "1/" : "",
139                                                           n > 1.0 ? n : 1.0 / n);
140                         }
141                 r = exif_get_rational(exif, "Exif.Photo.ShutterSpeedValue", NULL);
142                 if (r && r->num  && r->den)
143                         {
144                         double n = pow(2.0, exif_rational_to_double(r, TRUE));
145
146                         /* Correct exposure time to avoid values like 1/91s (seen on Minolta DImage 7) */
147                         if (n > 1.0 && (int)n - ((int)(n/10))*10 == 1) n--;
148
149                         return g_strdup_printf("%s%.0fs", n > 1.0 ? "1/" : "",
150                                                           n > 1.0 ? floor(n) : 1.0 / n);        
151                         }
152                 return NULL;
153                 }
154         if (strcmp(key, "fAperture") == 0)
155                 {
156                 double n;
157
158                 n = exif_get_rational_as_double(exif, "Exif.Photo.FNumber");
159                 if (n == 0.0) n = exif_get_rational_as_double(exif, "Exif.Photo.ApertureValue");
160                 if (n == 0.0) return NULL;
161
162                 return g_strdup_printf("f/%.1f", n);
163                 }
164         if (strcmp(key, "fExposureBias") == 0)
165                 {
166                 ExifRational *r;
167                 gint sign;
168                 double n;
169
170                 r = exif_get_rational(exif, "Exif.Photo.ExposureBiasValue", &sign);
171                 if (!r) return NULL;
172
173                 n = exif_rational_to_double(r, sign);
174                 return g_strdup_printf("%+.1f", n);
175                 }
176         if (strcmp(key, "fFocalLength") == 0)
177                 {
178                 double n;
179
180                 n = exif_get_rational_as_double(exif, "Exif.Photo.FocalLength");
181                 if (n == 0.0) return NULL;
182                 return g_strdup_printf("%.2f mm", n);
183                 }
184         if (strcmp(key, "fISOSpeedRating") == 0)
185                 {
186                 gchar *text;
187
188                 text = exif_get_data_as_text(exif, "Exif.Photo.ISOSpeedRatings");
189                 /* kodak may set this instead */
190                 if (!text) text = exif_get_data_as_text(exif, "Exif.Photo.ExposureIndex");
191                 return text;
192                 }
193         if (strcmp(key, "fSubjectDistance") == 0)
194                 {
195                 ExifRational *r;
196                 gint sign;
197                 double n;
198
199                 r = exif_get_rational(exif, "Exif.Photo.SubjectDistance", &sign);
200                 if (!r) return NULL;
201
202                 if ((long)r->num == 0xffffffff) return g_strdup(_("infinity"));
203                 if ((long)r->num == 0) return g_strdup(_("unknown"));
204
205                 n = exif_rational_to_double(r, sign);
206                 if (n == 0.0) return _("unknown");
207                 return g_strdup_printf("%.3f m", n);
208                 }
209         if (strcmp(key, "fFlash") == 0)
210                 {
211                 /* grr, flash is a bitmask... */
212                 GString *string;
213                 gchar *text;
214                 gint n;
215                 gint v;
216
217                 if (!exif_get_integer(exif, "Exif.Photo.Flash", &n)) return NULL;
218
219                 /* Exif 2.1 only defines first 3 bits */
220                 if (n <= 0x07) return exif_get_data_as_text(exif, "Exif.Photo.Flash");
221
222                 /* must be Exif 2.2 */
223                 string = g_string_new("");
224
225                 /* flash fired (bit 0) */
226                 string = g_string_append(string, (n & 0x01) ? _("yes") : _("no"));
227
228                 /* flash mode (bits 3, 4) */
229                 v = (n >> 3) & 0x03;
230                 if (v) string = append_comma_text(string, _("mode:"));
231                 switch (v)
232                         {
233                         case 1:
234                                 string = g_string_append(string, _("on"));
235                                 break;
236                         case 2:
237                                 string = g_string_append(string, _("off"));
238                                 break;
239                         case 3:
240                                 string = g_string_append(string, _("auto"));
241                                 break;
242                         }
243
244                 /* return light (bits 1, 2) */
245                 v = (n >> 1) & 0x03;
246                 if (v == 2) string = append_comma_text(string, _("not detected by strobe"));
247                 if (v == 3) string = append_comma_text(string, _("detected by strobe"));
248
249                 /* we ignore flash function (bit 5) */
250
251                 /* red-eye (bit 6) */
252                 if ((n >> 5) & 0x01) string = append_comma_text(string, _("red-eye reduction"));
253
254                 text = string->str;
255                 g_string_free(string, FALSE);
256                 return text;
257                 }
258         if (strcmp(key, "fResolution") == 0)
259                 {
260                 ExifRational *rx, *ry;
261                 gchar *units;
262                 gchar *text;
263
264                 rx = exif_get_rational(exif, "Exif.Image.XResolution", NULL);
265                 ry = exif_get_rational(exif, "Exif.Image.YResolution", NULL);
266                 if (!rx || !ry) return NULL;
267
268                 units = exif_get_data_as_text(exif, "Exif.Image.ResolutionUnit");
269                 text = g_strdup_printf("%0.f x %0.f (%s/%s)", rx->den ? (double)rx->num / rx->den : 1.0,
270                                                               ry->den ? (double)ry->num / ry->den : 1.0,
271                                                               _("dot"), (units) ? units : _("unknown"));
272
273                 g_free(units);
274                 return text;
275                 }
276
277         if (key_valid) *key_valid = FALSE;
278         return NULL;
279 }
280
281 const gchar *exif_get_description_by_key(const gchar *key)
282 {
283         gint i;
284
285         if (!key) return NULL;
286
287         i = 0;
288         while (ExifFormattedList[i].key != NULL)
289                 {
290                 if (strcmp(key, ExifFormattedList[i].key) == 0) return _(ExifFormattedList[i].description);
291                 i++;
292                 }
293
294         return exif_get_tag_description_by_key(key);
295 }
296
297 gint exif_get_integer(ExifData *exif, const gchar *key, gint *value)
298 {
299         ExifItem *item;
300
301         item = exif_get_item(exif, key);
302         return exif_item_get_integer(item, value);
303 }
304
305 ExifRational *exif_get_rational(ExifData *exif, const gchar *key, gint *sign)
306 {
307         ExifItem *item;
308
309         item = exif_get_item(exif, key);
310         return exif_item_get_rational(item, sign);
311 }
312
313 gchar *exif_get_data_as_text(ExifData *exif, const gchar *key)
314 {
315         ExifItem *item;
316         gchar *text;
317         gint key_valid;
318
319         if (!key) return NULL;
320
321         text = exif_get_formatted_by_key(exif, key, &key_valid);
322         if (key_valid) return text;
323
324         item = exif_get_item(exif, key);
325         if (item) return exif_item_get_data_as_text(item);
326
327         return NULL;
328 }