2 * Copyright (C) 2005 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
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.
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.
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.
33 #include "format-olympus.h"
34 #include "format-raw.h"
40 *-----------------------------------------------------------------------------
41 * Raw ORF embedded jpeg extraction for Olympus
42 *-----------------------------------------------------------------------------
45 static guint olympus_tiff_table(guchar *data, guint len, guint offset, ExifByteOrder bo,
47 guint *image_offset, guint *exif_offset);
50 static void olympus_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo,
52 guint *image_offset, guint *exif_offset)
60 tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo);
61 type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo);
62 count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo);
64 /* so far, we only care about tags with type long */
65 if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return;
67 seg_len = ExifFormatList[type].size * count;
70 segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo);
71 if (segment + seg_len > len) return;
75 segment = offset + EXIF_TIFD_OFFSET_DATA;
80 /* start of embedded jpeg, not all olympus cameras embed a jpeg */
81 *image_offset = exif_byte_get_int32(data + segment, bo);
86 /* This is the Exif info */
87 *exif_offset = exif_byte_get_int32(data + segment, bo);
91 static guint olympus_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
93 guint *image_offset, guint *exif_offset)
98 if (level > EXIF_TIFF_MAX_LEVELS) return 0;
100 if (len < offset + 2) return FALSE;
102 count = exif_byte_get_int16(data + offset, bo);
104 if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0;
106 for (i = 0; i < count; i++)
108 olympus_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level,
109 image_offset, exif_offset);
112 return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);
115 gboolean format_olympus_raw(guchar *data, const guint len,
116 guint *image_offset, guint *exif_offset)
123 if (len < 8) return FALSE;
125 /* these are in tiff file format with a different magick header */
126 if (memcmp(data, "IIR", 3) != 0) return FALSE;
128 offset = exif_byte_get_int32(data + 4, EXIF_BYTE_ORDER_INTEL);
131 while (offset && level < EXIF_TIFF_MAX_LEVELS)
133 offset = olympus_tiff_table(data, len, offset, EXIF_BYTE_ORDER_INTEL, 0, &i_off, &e_off);
137 if (i_off != 0 || e_off != 0)
139 if (image_offset) *image_offset = i_off;
140 if (exif_offset) *exif_offset = e_off;
149 *-----------------------------------------------------------------------------
150 * EXIF Makernote for Olympus
151 *-----------------------------------------------------------------------------
154 static ExifTextList KonMinTagColorMode[]= {
156 { 1, "black and white" },
158 { 3, "solarization" },
163 static ExifTextList KonMinTagQuality[]= {
172 static ExifTextList OlympusTagJpegQuality[]= {
179 static ExifTextList OlympusTagMacro[]= {
187 static ExifTextList OlympusTagFlashMode[]= {
189 { 1, "red-eye reduction" },
195 static ExifTextList OlympusTagFocusMode[]= {
201 static ExifTextList OlympusTagSharpness[]= {
208 static ExifTextList OlympusTagContrast[]= {
216 static ExifMarker OlympusExifMarkersList[] = {
217 { 0x0001, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", nullptr },
218 { 0x0003, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", nullptr },
219 { 0x0040, EXIF_FORMAT_LONG_UNSIGNED, -1, "CompressedImageSize", "Compressed image size", nullptr },
220 { 0x0081, EXIF_FORMAT_LONG_UNSIGNED, 1, "ThumbnailOffset", "Thumbnail offset", nullptr },
221 { 0x0088, EXIF_FORMAT_LONG_UNSIGNED, 1, "ThumbnailOffset", "Thumbnail offset", nullptr },
222 { 0x0089, EXIF_FORMAT_LONG_UNSIGNED, 1, "ThumbnailLength", "Thumbnail length", nullptr },
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", nullptr },
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", nullptr },
230 { 0x0207, EXIF_FORMAT_STRING, -1, "Olympus.Firmware", "Firmware version", nullptr },
231 { 0x0208, EXIF_FORMAT_STRING, -1, "Olympus.PictureInfo", "Picture info", nullptr },
232 { 0x0209, EXIF_FORMAT_UNDEFINED, -1, "Olympus.CameraID", "Camera ID", nullptr },
233 { 0x020b, EXIF_FORMAT_LONG_UNSIGNED, 1, "Epson.ImageWidth", "Image width", nullptr },
234 { 0x020c, EXIF_FORMAT_LONG_UNSIGNED, 1, "Epson.ImageHeight", "Image height", nullptr },
235 { 0x020d, EXIF_FORMAT_STRING, -1, "Epson.Manufacturer", "Manufacturer", nullptr },
236 { 0x0e00, EXIF_FORMAT_BYTE, -1, "Olympus.PrintImageMatching", "Print image matching", nullptr },
237 { 0x1004, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FlashMode", "Flash mode", OlympusTagFlashMode },
238 { 0x1006, EXIF_FORMAT_RATIONAL, 1, "Olympus.Bracket", "Bracket", nullptr },
239 { 0x100b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FocusMode", "Focus mode", OlympusTagFocusMode },
240 { 0x100c, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Olympus.FocusDistance", "Focus distance", nullptr },
241 { 0x100d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Zoom", "Zoom", nullptr },
242 { 0x1006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.MacroFocus", "Macro focus", nullptr },
243 { 0x100f, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Sharpness", "Sharpness", OlympusTagSharpness },
244 { 0x1011, EXIF_FORMAT_SHORT_UNSIGNED, 9, "Olympus.ColorMatrix", "Color matrix", nullptr },
245 { 0x1012, EXIF_FORMAT_SHORT_UNSIGNED, 4, "Olympus.BlackLevel", "Black level", nullptr },
246 { 0x1015, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.WhiteBalance", "White balance", nullptr },
247 { 0x1017, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.RedBias", "Red bias", nullptr },
248 { 0x1018, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.BlueBias", "Blue bias", nullptr },
249 { 0x101a, EXIF_FORMAT_STRING, -1, "Olympus.SerialNumber", "Serial number", nullptr },
250 { 0x1023, EXIF_FORMAT_RATIONAL, 1, "Olympus.FlashBias", "Flash bias", nullptr },
251 { 0x1029, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Contrast", "Contrast", OlympusTagContrast },
252 { 0x102a, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.SharpnessFactor", "Sharpness factor", nullptr },
253 { 0x102b, EXIF_FORMAT_SHORT_UNSIGNED, 6, "Olympus.ColorControl", "Color control", nullptr },
254 { 0x102c, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.ValidBits", "Valid bits", nullptr },
255 { 0x102d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CoringFilter", "Coring filter", nullptr },
256 { 0x102e, EXIF_FORMAT_LONG_UNSIGNED, 1, "Olympus.FinalWidth", "Final width", nullptr },
257 { 0x102f, EXIF_FORMAT_LONG_UNSIGNED, 1, "Olympus.FinalHeight", "Final height", nullptr },
258 { 0x1034, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CompressionRatio", "Compression ratio", nullptr },
262 static ExifTextList OlympusShootingMode[]= {
270 static ExifTextList OlympusPanoramaDirection[]= {
271 { 1, "left to right" },
272 { 2, "right to left" },
273 { 3, "bottom to top" },
274 { 4, "top to bottom" },
278 static ExifTextList OlympusWB[]= {
285 static ExifTextList OlympusWBColorTemp[]= {
296 gboolean format_olympus_makernote(ExifData *exif, guchar *tiff, guint offset,
297 guint size, ExifByteOrder bo)
302 if (offset + 8 + 4 >= size) return FALSE;
304 data = tiff + offset;
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.
310 if (memcmp(data, "OLYMP\x00\x01", 7) != 0 &&
311 memcmp(data, "OLYMP\x00\x02", 7) != 0) return FALSE;
313 if (exif_parse_IFD_table(exif, tiff, offset + 8, size,
314 bo, 0, OlympusExifMarkersList) != 0)
319 item = exif_get_item(exif, "Olympus.SpecialMode");
320 if (item && item->data_len == 3 * sizeof(guint32))
322 static ExifMarker marker = { 0x0200, EXIF_FORMAT_STRING, -1,
323 "Olympus.ShootingMode", "Shooting mode", nullptr };
324 auto array = static_cast<guint32 *>(item->data);
326 gchar *pdir = nullptr;
330 mode = exif_text_list_find_value(OlympusShootingMode, array[0]);
333 pdir = exif_text_list_find_value(OlympusPanoramaDirection, array[2]);
336 text = g_strdup_printf("%s%s%s, seq %d", mode,
337 (pdir) ? " " : "", (pdir) ? pdir : "",
339 l = strlen(text) + 1;
340 item = exif_item_new(marker.format, marker.tag, l, &marker);
341 memcpy(item->data, text, l);
347 exif->items = g_list_prepend(exif->items, item);
350 item = exif_get_item(exif, "Olympus.WhiteBalance");
351 if (item && item->data_len == 2 * sizeof(guint16))
353 static ExifMarker marker = { 0x1015, EXIF_FORMAT_STRING, -1,
354 "Olympus.WhiteBalance", "White balance", nullptr };
355 auto array = static_cast<guint16 *>(item->data);
357 gchar *color = nullptr;
361 mode = exif_text_list_find_value(OlympusWB, array[0]);
364 color = exif_text_list_find_value(OlympusWBColorTemp, array[1]);
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);
377 exif->items = g_list_prepend(exif->items, item);
384 using dummy_variable = int;
387 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */