Simplify vflist_get_formatted()
[geeqie.git] / src / format_olympus.c
1 /*
2  * Copyright (C) 2005 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #ifndef HAVE_EXIV2
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <glib.h>
31
32 #include "intl.h"
33
34 #include "main.h"
35 #include "format_olympus.h"
36 #include "format_raw.h"
37
38 #include "exif.h"
39
40
41 /*
42  *-----------------------------------------------------------------------------
43  * Raw ORF embedded jpeg extraction for Olympus
44  *-----------------------------------------------------------------------------
45  */
46
47 static guint olympus_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
48                                 gint level,
49                                 guint *image_offset, guint *exif_offset);
50
51
52 static void olympus_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo,
53                                gint level,
54                                guint *image_offset, guint *exif_offset)
55 {
56         guint tag;
57         guint type;
58         guint count;
59         guint segment;
60         guint seg_len;
61
62         tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo);
63         type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo);
64         count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo);
65
66         /* so far, we only care about tags with type long */
67         if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return;
68
69         seg_len = ExifFormatList[type].size * count;
70         if (seg_len > 4)
71                 {
72                 segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo);
73                 if (segment + seg_len > len) return;
74                 }
75         else
76                 {
77                 segment = offset + EXIF_TIFD_OFFSET_DATA;
78                 }
79
80         if (tag == 0x201)
81                 {
82                 /* start of embedded jpeg, not all olympus cameras embed a jpeg */
83                 *image_offset = exif_byte_get_int32(data + segment, bo);
84                 }
85
86         if (tag == 0x8769)
87                 {
88                 /* This is the Exif info */
89                 *exif_offset = exif_byte_get_int32(data + segment, bo);
90                 }
91 }
92
93 static guint olympus_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
94                                 gint level,
95                                 guint *image_offset, guint *exif_offset)
96 {
97         guint count;
98         guint i;
99
100         if (level > EXIF_TIFF_MAX_LEVELS) return 0;
101
102         if (len < offset + 2) return FALSE;
103
104         count = exif_byte_get_int16(data + offset, bo);
105         offset += 2;
106         if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0;
107
108         for (i = 0; i < count; i++)
109                 {
110                 olympus_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level,
111                                    image_offset, exif_offset);
112                 }
113
114         return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);
115 }
116
117 gboolean format_olympus_raw(guchar *data, const guint len,
118                             guint *image_offset, guint *exif_offset)
119 {
120         guint i_off = 0;
121         guint e_off = 0;
122         guint offset;
123         gint level;
124
125         if (len < 8) return FALSE;
126
127         /* these are in tiff file format with a different magick header */
128         if (memcmp(data, "IIR", 3) != 0) return FALSE;
129
130         offset = exif_byte_get_int32(data + 4, EXIF_BYTE_ORDER_INTEL);
131
132         level = 0;
133         while (offset && level < EXIF_TIFF_MAX_LEVELS)
134                 {
135                 offset = olympus_tiff_table(data, len, offset, EXIF_BYTE_ORDER_INTEL, 0, &i_off, &e_off);
136                 level++;
137                 }
138
139         if (i_off != 0 || e_off != 0)
140                 {
141                 if (image_offset) *image_offset = i_off;
142                 if (exif_offset) *exif_offset = e_off;
143                 return TRUE;
144                 }
145
146         return FALSE;
147 }
148
149
150 /*
151  *-----------------------------------------------------------------------------
152  * EXIF Makernote for Olympus
153  *-----------------------------------------------------------------------------
154  */
155
156 static ExifTextList KonMinTagColorMode[]= {
157         { 0,    "natural" },
158         { 1,    "black and white" },
159         { 2,    "vivid" },
160         { 3,    "solarization" },
161         { 4,    "Adobe RGB" },
162         EXIF_TEXT_LIST_END
163 };
164
165 static ExifTextList KonMinTagQuality[]= {
166         { 0,    "raw" },
167         { 1,    "super fine" },
168         { 2,    "find" },
169         { 3,    "standard" },
170         { 4,    "extra fine" },
171         EXIF_TEXT_LIST_END
172 };
173
174 static ExifTextList OlympusTagJpegQuality[]= {
175         { 1,    "standard" },
176         { 2,    "high" },
177         { 3,    "super high" },
178         EXIF_TEXT_LIST_END
179 };
180
181 static ExifTextList OlympusTagMacro[]= {
182         { 0,    "off" },
183         { 1,    "on" },
184         { 2,    "view" },
185         { 3,    "manual" },
186         EXIF_TEXT_LIST_END
187 };
188
189 static ExifTextList OlympusTagFlashMode[]= {
190         { 0,    "auto" },
191         { 1,    "red-eye reduction" },
192         { 2,    "fill" },
193         { 3,    "off" },
194         EXIF_TEXT_LIST_END
195 };
196
197 static ExifTextList OlympusTagFocusMode[]= {
198         { 0,    "auto" },
199         { 1,    "manual" },
200         EXIF_TEXT_LIST_END
201 };
202
203 static ExifTextList OlympusTagSharpness[]= {
204         { 0,    "normal" },
205         { 1,    "hard" },
206         { 2,    "soft" },
207         EXIF_TEXT_LIST_END
208 };
209
210 static ExifTextList OlympusTagContrast[]= {
211         { 0,    "hard" },
212         { 1,    "normal" },
213         { 2,    "soft" },
214         EXIF_TEXT_LIST_END
215 };
216
217
218 static ExifMarker OlympusExifMarkersList[] = {
219 { 0x0001, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", NULL },
220 { 0x0003, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", NULL },
221 { 0x0040, EXIF_FORMAT_LONG_UNSIGNED, -1, "CompressedImageSize", "Compressed image size", NULL },
222 { 0x0081, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailOffset",     "Thumbnail offset",     NULL },
223 { 0x0088, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailOffset",     "Thumbnail offset",     NULL },
224 { 0x0089, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailLength",     "Thumbnail length",     NULL },
225 { 0x0101, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.ColorMode", "Color mode",      KonMinTagColorMode },
226 { 0x0102, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.Quality", "Quality",           KonMinTagQuality },
227 { 0x0103, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.Quality", "Quality",           KonMinTagQuality },
228 { 0x0200, EXIF_FORMAT_LONG_UNSIGNED, 3,  "Olympus.SpecialMode", "Special mode",         NULL },
229 { 0x0201, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.JpegQuality", "Jpeg quality",         OlympusTagJpegQuality },
230 { 0x0202, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Macro",       "Macro",                OlympusTagMacro },
231 { 0x0204, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Olympus.DigitalZoom", "Digital zoom",      NULL },
232 { 0x0207, EXIF_FORMAT_STRING, -1,        "Olympus.Firmware",    "Firmware version",     NULL },
233 { 0x0208, EXIF_FORMAT_STRING, -1,        "Olympus.PictureInfo", "Picture info",         NULL },
234 { 0x0209, EXIF_FORMAT_UNDEFINED, -1,     "Olympus.CameraID",    "Camera ID",            NULL },
235 { 0x020b, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Epson.ImageWidth",    "Image width",          NULL },
236 { 0x020c, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Epson.ImageHeight",   "Image height",         NULL },
237 { 0x020d, EXIF_FORMAT_STRING, -1,        "Epson.Manufacturer",  "Manufacturer",         NULL },
238 { 0x0e00, EXIF_FORMAT_BYTE, -1,          "Olympus.PrintImageMatching", "Print image matching", NULL },
239 { 0x1004, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FlashMode",   "Flash mode",           OlympusTagFlashMode },
240 { 0x1006, EXIF_FORMAT_RATIONAL, 1,       "Olympus.Bracket",     "Bracket",              NULL },
241 { 0x100b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FocusMode",   "Focus mode",           OlympusTagFocusMode },
242 { 0x100c, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Olympus.FocusDistance", "Focus distance",  NULL },
243 { 0x100d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Zoom",        "Zoom",                 NULL },
244 { 0x1006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.MacroFocus",  "Macro focus",          NULL },
245 { 0x100f, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Sharpness",   "Sharpness",            OlympusTagSharpness },
246 { 0x1011, EXIF_FORMAT_SHORT_UNSIGNED, 9, "Olympus.ColorMatrix", "Color matrix",         NULL },
247 { 0x1012, EXIF_FORMAT_SHORT_UNSIGNED, 4, "Olympus.BlackLevel",  "Black level",          NULL },
248 { 0x1015, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.WhiteBalance", "White balance",       NULL },
249 { 0x1017, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.RedBias",     "Red bias",             NULL },
250 { 0x1018, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.BlueBias",    "Blue bias",            NULL },
251 { 0x101a, EXIF_FORMAT_STRING, -1,        "Olympus.SerialNumber", "Serial number",       NULL },
252 { 0x1023, EXIF_FORMAT_RATIONAL, 1,       "Olympus.FlashBias",   "Flash bias",           NULL },
253 { 0x1029, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Contrast",    "Contrast",             OlympusTagContrast },
254 { 0x102a, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.SharpnessFactor", "Sharpness factor", NULL },
255 { 0x102b, EXIF_FORMAT_SHORT_UNSIGNED, 6, "Olympus.ColorControl", "Color control",       NULL },
256 { 0x102c, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.ValidBits",   "Valid bits",           NULL },
257 { 0x102d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CoringFilter", "Coring filter",       NULL },
258 { 0x102e, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Olympus.FinalWidth",  "Final width",          NULL },
259 { 0x102f, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Olympus.FinalHeight", "Final height",         NULL },
260 { 0x1034, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CompressionRatio", "Compression ratio", NULL },
261 EXIF_MARKER_LIST_END
262 };
263
264 static ExifTextList OlympusShootingMode[]= {
265         { 0,    "normal" },
266         { 1,    "unknown" },
267         { 2,    "fast" },
268         { 3,    "panorama" },
269         EXIF_TEXT_LIST_END
270 };
271
272 static ExifTextList OlympusPanoramaDirection[]= {
273         { 1,    "left to right" },
274         { 2,    "right to left" },
275         { 3,    "bottom to top" },
276         { 4,    "top to bottom" },
277         EXIF_TEXT_LIST_END
278 };
279
280 static ExifTextList OlympusWB[]= {
281         { 1,    "auto" },
282         { 2,    "manual" },
283         { 3,    "one-touch" },
284         EXIF_TEXT_LIST_END
285 };
286
287 static ExifTextList OlympusWBColorTemp[]= {
288         { 2,    "3000" },
289         { 3,    "3700" },
290         { 4,    "4000" },
291         { 5,    "4500" },
292         { 6,    "5500" },
293         { 7,    "6500" },
294         { 8,    "7500" },
295         EXIF_TEXT_LIST_END
296 };
297
298 gboolean format_olympus_makernote(ExifData *exif, guchar *tiff, guint offset,
299                                   guint size, ExifByteOrder bo)
300 {
301         guchar *data;
302         ExifItem *item;
303
304         if (offset + 8 + 4 >= size) return FALSE;
305
306         data = tiff + offset;
307
308         /* Olympus tag format starts with "OLYMP\x00\x01" or "OLYMP\x00\x02",
309          * plus an unknown byte,
310          * followed by IFD data using Olympus tags.
311          */
312         if (memcmp(data, "OLYMP\x00\x01", 7) != 0 &&
313             memcmp(data, "OLYMP\x00\x02", 7) != 0) return FALSE;
314
315         if (exif_parse_IFD_table(exif, tiff, offset + 8, size,
316                                  bo, 0, OlympusExifMarkersList) != 0)
317                 {
318                 return FALSE;
319                 }
320
321         item = exif_get_item(exif, "Olympus.SpecialMode");
322         if (item && item->data_len == 3 * sizeof(guint32))
323                 {
324                 static ExifMarker marker = { 0x0200, EXIF_FORMAT_STRING, -1,
325                                              "Olympus.ShootingMode", "Shooting mode", NULL };
326                 guint32 *array = item->data;
327                 gchar *mode;
328                 gchar *pdir = NULL;
329                 gchar *text;
330                 gint l;
331
332                 mode = exif_text_list_find_value(OlympusShootingMode, array[0]);
333                 if (array[0] == 3)
334                         {
335                         pdir = exif_text_list_find_value(OlympusPanoramaDirection, array[2]);
336                         }
337
338                 text = g_strdup_printf("%s%s%s, seq %d", mode,
339                                        (pdir) ? " " : "", (pdir) ? pdir : "",
340                                        array[1] + 1);
341                 l = strlen(text) + 1;
342                 item = exif_item_new(marker.format, marker.tag, l, &marker);
343                 memcpy(item->data, text, l);
344
345                 g_free(text);
346                 g_free(pdir);
347                 g_free(mode);
348
349                 exif->items = g_list_prepend(exif->items, item);
350                 }
351
352         item = exif_get_item(exif, "Olympus.WhiteBalance");
353         if (item && item->data_len == 2 * sizeof(guint16))
354                 {
355                 static ExifMarker marker = { 0x1015, EXIF_FORMAT_STRING, -1,
356                                              "Olympus.WhiteBalance", "White balance", NULL };
357                 guint16 *array = item->data;
358                 gchar *mode;
359                 gchar *color = NULL;
360                 gchar *text;
361                 gint l;
362
363                 mode = exif_text_list_find_value(OlympusWB, array[0]);
364                 if (array[0] == 2)
365                         {
366                         color = exif_text_list_find_value(OlympusWBColorTemp, array[1]);
367                         }
368
369                 text = g_strdup_printf("%s%s%s", mode,
370                                        (color) ? " " : "", (color) ? color : "");
371                 l = strlen(text) + 1;
372                 item = exif_item_new(marker.format, marker.tag, l, &marker);
373                 memcpy(item->data, text, l);
374
375                 g_free(text);
376                 g_free(color);
377                 g_free(mode);
378
379                 exif->items = g_list_prepend(exif->items, item);
380                 }
381
382         return TRUE;
383 }
384
385
386 #endif
387 /* not HAVE_EXIV2 */
388 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */