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