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