Fri Jun 10 20:57:42 2005 John Ellis <johne@verizon.net>
[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
15 #include <stdio.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 #include <glib.h>
20
21 #include "intl.h"
22
23 #include "format_olympus.h"
24 #include "format_raw.h"
25
26 #include "exif.h"
27
28
29 /*
30  *-----------------------------------------------------------------------------
31  * EXIF Makernote for Olympus
32  *-----------------------------------------------------------------------------
33  */
34
35 static ExifTextList KonMinTagColorMode[]= {
36         { 0,    "natural" },
37         { 1,    "black and white" },
38         { 2,    "vivid" },
39         { 3,    "solarization" },
40         { 4,    "Adobe RGB" },
41         EXIF_TEXT_LIST_END
42 };
43
44 static ExifTextList KonMinTagQuality[]= {
45         { 0,    "raw" },
46         { 1,    "super fine" },
47         { 2,    "find" },
48         { 3,    "standard" },
49         { 4,    "extra fine" },
50         EXIF_TEXT_LIST_END
51 };
52
53 static ExifTextList OlympusTagJpegQuality[]= {
54         { 1,    "standard" },
55         { 2,    "high" },
56         { 3,    "super high" },
57         EXIF_TEXT_LIST_END
58 };
59
60 static ExifTextList OlympusTagMacro[]= {
61         { 0,    "off" },
62         { 1,    "on" },
63         { 2,    "view" },
64         { 3,    "manual" },
65         EXIF_TEXT_LIST_END
66 };
67
68 static ExifTextList OlympusTagFlashMode[]= {
69         { 0,    "auto" },
70         { 1,    "red-eye reduction" },
71         { 2,    "fill" },
72         { 3,    "off" },
73         EXIF_TEXT_LIST_END
74 };
75
76 static ExifTextList OlympusTagFocusMode[]= {
77         { 0,    "auto" },
78         { 1,    "manual" },
79         EXIF_TEXT_LIST_END
80 };
81
82 static ExifTextList OlympusTagSharpness[]= {
83         { 0,    "normal" },
84         { 1,    "hard" },
85         { 2,    "soft" },
86         EXIF_TEXT_LIST_END
87 };
88
89 static ExifTextList OlympusTagContrast[]= {
90         { 0,    "hard" },
91         { 1,    "normal" },
92         { 2,    "soft" },
93         EXIF_TEXT_LIST_END
94 };
95
96 #if 0
97 static ExifTextList OlympusTag[]= {
98         { ,     "" },
99         { ,     "" },
100         EXIF_TEXT_LIST_END
101 };
102 #endif
103
104
105 static ExifMarker OlympusExifMarkersList[] = {
106 { 0x0001, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", NULL },
107 { 0x0003, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", NULL },
108 { 0x0040, EXIF_FORMAT_LONG_UNSIGNED, -1, "CompressedImageSize", "Compressed image size", NULL },
109 { 0x0081, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailOffset",     "Thumbnail offset",     NULL },
110 { 0x0088, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailOffset",     "Thumbnail offset",     NULL },
111 { 0x0089, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailLength",     "Thumbnail length",     NULL },
112 { 0x0101, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.ColorMode", "Color mode",      KonMinTagColorMode },
113 { 0x0102, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.Quality", "Quality",           KonMinTagQuality },
114 { 0x0103, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.Quality", "Quality",           KonMinTagQuality },
115 { 0x0200, EXIF_FORMAT_LONG_UNSIGNED, 3,  "Olympus.SpecialMode", "Special mode",         NULL },
116 { 0x0201, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.JpegQuality", "Jpeg quality",         OlympusTagJpegQuality },
117 { 0x0202, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Macro",       "Macro",                OlympusTagMacro },
118 { 0x0204, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Olympus.DigitalZoom", "Digital zoom",      NULL },
119 { 0x0207, EXIF_FORMAT_STRING, -1,        "Olympus.Firmware",    "Firmware version",     NULL },
120 { 0x0208, EXIF_FORMAT_STRING, -1,        "Olympus.PictureInfo", "Picture info",         NULL },
121 { 0x0209, EXIF_FORMAT_UNDEFINED, -1,     "Olympus.CameraID",    "Camera ID",            NULL },
122 { 0x020b, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Epson.ImageWidth",    "Image width",          NULL },
123 { 0x020c, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Epson.ImageHeight",   "Image height",         NULL },
124 { 0x020d, EXIF_FORMAT_STRING, -1,        "Epson.Manufacturer",  "Manufacturer",         NULL },
125 { 0x0e00, EXIF_FORMAT_BYTE, -1,          "Olympus.PrintImageMatching", "Print image matching", NULL },
126 { 0x1004, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FlashMode",   "Flash mode",           OlympusTagFlashMode },
127 { 0x1006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Bracket",     "Bracket",              NULL },
128 { 0x100b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FocusMode",   "Focus mode",           OlympusTagFocusMode },
129 { 0x100c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FocusDistance", "Focus distance",     NULL },
130 { 0x100d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Zoom",        "Zoom",                 NULL },
131 { 0x1006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.MacroFocus",  "Macro focus",          NULL },
132 { 0x100f, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Sharpness",   "Sharpness",            OlympusTagSharpness },
133 { 0x1011, EXIF_FORMAT_SHORT_UNSIGNED, 9, "Olympus.ColorMatrix", "Color matrix",         NULL },
134 { 0x1012, EXIF_FORMAT_SHORT_UNSIGNED, 4, "Olympus.BlackLevel",  "Black level",          NULL },
135 { 0x1015, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.WhiteBalance", "White balance",       NULL },
136 { 0x1017, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.RedBias",     "Red bias",             NULL },
137 { 0x1018, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.BlueBias",    "Blue bias",            NULL },
138 { 0x101a, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.SerialNumber", "Serial number",       NULL },
139 { 0x1023, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FlashBias",   "Flash bias",           NULL },
140 { 0x1029, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Contrast",    "Contrast",             OlympusTagContrast },
141 { 0x102a, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.SharpnessFactor", "Sharpness factor", NULL },
142 { 0x102b, EXIF_FORMAT_SHORT_UNSIGNED, 6, "Olympus.ColorControl", "Color control",       NULL },
143 { 0x102c, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.ValidBits",   "Valid bits",           NULL },
144 { 0x102d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CoringFilter", "Coring filter",       NULL },
145 { 0x102e, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Olympus.FinalWidth",  "Final width",          NULL },
146 { 0x102f, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Olympus.FinalHeight", "Final height",         NULL },
147 { 0x1034, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CompressionRatio", "Compression ratio", NULL },
148 EXIF_MARKER_LIST_END
149 };
150
151 static ExifTextList OlympusShootingMode[]= {
152         { 0,    "normal" },
153         { 1,    "unknown" },
154         { 2,    "fast" },
155         { 3,    "panorama" },
156         EXIF_TEXT_LIST_END
157 };
158
159 static ExifTextList OlympusPanoramaDirection[]= {
160         { 1,    "left to right" },
161         { 2,    "right to left" },
162         { 3,    "bottom to top" },
163         { 4,    "top to bottom" },
164         EXIF_TEXT_LIST_END
165 };
166
167 static ExifTextList OlympusWB[]= {
168         { 1,    "auto" },
169         { 2,    "manual" },
170         { 3,    "one-touch" },
171         EXIF_TEXT_LIST_END
172 };
173
174 static ExifTextList OlympusWBColorTemp[]= {
175         { 2,    "3000" },
176         { 3,    "3700" },
177         { 4,    "4000" },
178         { 5,    "4500" },
179         { 6,    "5500" },
180         { 7,    "6500" },
181         { 8,    "7500" },
182         EXIF_TEXT_LIST_END
183 };
184
185 gint format_olympus_makernote(ExifData *exif, unsigned char *tiff, guint offset,
186                               guint size, ExifByteOrder bo)
187 {
188         unsigned char *data;
189         ExifItem *item;
190
191         if (offset + 8 + 4 >= size) return FALSE;
192
193         data = tiff + offset;
194
195         /* Olympus tag format starts with "OLYMP\x00\x01" or "OLYMP\x00\x02",
196          * plus an unknown byte,
197          * followed by IFD data using Olympus tags.
198          */
199         if (memcmp(data, "OLYMP\x00\x01", 7) != 0 &&
200             memcmp(data, "OLYMP\x00\x02", 7) != 0) return FALSE;
201
202         if (exif_parse_IFD_table(exif, tiff, offset + 8, size,
203                                  bo, 0, OlympusExifMarkersList) != 0)
204                 {
205                 return FALSE;
206                 }
207
208         item = exif_get_item(exif, "Olympus.SpecialMode");
209         if (item && item->data_len == 3 * sizeof(guint32))
210                 {
211                 static ExifMarker marker = { 0x0200, EXIF_FORMAT_STRING, -1,
212                                              "Olympus.ShootingMode", "Shooting mode", NULL };
213                 guint32 *array = item->data;
214                 const gchar *mode;
215                 const gchar *pdir = NULL;
216                 gchar *text;
217                 gint l;
218
219                 mode = exif_text_list_find_value(OlympusShootingMode, array[0]);
220                 if (array[0] == 3)
221                         {
222                         pdir = exif_text_list_find_value(OlympusPanoramaDirection, array[2]);
223                         }
224
225                 text = g_strdup_printf("%s%s%s, seq %d", (mode) ? mode : "unknown",
226                                        (pdir) ? " " : "", (pdir) ? pdir : "",
227                                        array[1] + 1);
228                 l = strlen(text) + 1;
229                 item = exif_item_new(marker.format, marker.tag, l, &marker);
230                 memcpy(item->data, text, l);
231                 g_free(text);
232
233                 exif->items = g_list_prepend(exif->items, item);
234                 }
235
236         item = exif_get_item(exif, "Olympus.WhiteBalance");
237         if (item && item->data_len == 2 * sizeof(guint16))
238                 {
239                 static ExifMarker marker = { 0x1015, EXIF_FORMAT_STRING, -1,
240                                              "Olympus.WhiteBalance", "White balance", NULL };
241                 guint16 *array = item->data;
242                 const gchar *mode;
243                 const gchar *color = NULL;
244                 gchar *text;
245                 gint l;
246
247                 mode = exif_text_list_find_value(OlympusWB, array[0]);
248                 if (array[0] == 2)
249                         {
250                         color = exif_text_list_find_value(OlympusWBColorTemp, array[1]);
251                         }
252
253                 text = g_strdup_printf("%s%s%s", (mode) ? mode : "unknown",
254                                        (color) ? " " : "", (color) ? color : "");
255                 l = strlen(text) + 1;
256                 item = exif_item_new(marker.format, marker.tag, l, &marker);
257                 memcpy(item->data, text, l);
258                 g_free(text);
259
260                 exif->items = g_list_prepend(exif->items, item);
261                 }
262
263         return TRUE;
264 }
265
266