2 * Copyright (C) 2005 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "format-nikon.h"
32 *-----------------------------------------------------------------------------
33 * Raw NEF embedded jpeg extraction for Nikon
34 *-----------------------------------------------------------------------------
37 static guint nikon_tiff_table(guchar *data, guint len, guint offset, ExifByteOrder bo,
39 guint *image_offset, guint *jpeg_len);
42 static void nikon_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo,
44 guint *image_offset, guint *image_length, guint *jpeg_start, guint *jpeg_len)
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);
56 /* so far, we only care about tags with type long */
57 if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return;
59 seg_len = ExifFormatList[type].size * count;
62 segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo);
63 if (segment + seg_len > len) return;
67 segment = offset + EXIF_TIFD_OFFSET_DATA;
75 for (i = 0; i < count; i++)
79 subset = exif_byte_get_int32(data + segment + i * 4, bo);
80 nikon_tiff_table(data, len, subset, bo, level + 1, image_offset, image_length);
84 else if (tag == 0x201)
86 /* jpeg data start offset */
87 *jpeg_start = exif_byte_get_int32(data + segment, bo);
89 else if (tag == 0x202)
91 /* jpeg data length */
92 *jpeg_len = exif_byte_get_int32(data + segment, bo);
96 static guint nikon_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
98 guint *image_offset, guint *image_length)
102 guint jpeg_start = 0;
105 /* limit damage from infinite loops */
106 if (level > EXIF_TIFF_MAX_LEVELS) return 0;
108 if (len < offset + 2) return FALSE;
110 count = exif_byte_get_int16(data + offset, bo);
112 if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0;
114 for (i = 0; i < count; i++)
116 nikon_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level,
117 image_offset, image_length, &jpeg_start, &jpeg_len);
120 if (jpeg_start > 0 &&
121 jpeg_len > *image_length)
123 *image_offset = jpeg_start;
124 *image_length = jpeg_len;
127 return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);
130 gboolean format_nikon_raw(guchar *data, const guint len,
131 guint *image_offset, guint *)
139 if (!exif_tiff_directory_offset(data, len, &offset, &bo)) return FALSE;
142 while (offset && level < EXIF_TIFF_MAX_LEVELS)
144 offset = nikon_tiff_table(data, len, offset, bo, 0, &i_off, &i_len);
150 if (image_offset) *image_offset = i_off;
159 *-----------------------------------------------------------------------------
160 * EXIF Makernote for Nikon
161 *-----------------------------------------------------------------------------
164 static ExifTextList NikonTagQuality[]= {
169 { 5, "SXGA normal" },
171 { 7, "XGA basic (?)" },
172 { 8, "XGA normal (?)" },
173 { 9, "XGA fine (?)" },
174 { 10, "UXGA basic" },
175 { 11, "UXGA normal" },
180 static ExifTextList NikonTagColorMode[]= {
186 static ExifTextList NikonTagImgAdjust[]= {
195 static ExifTextList NikonTagISOSensitivity[]= {
203 static ExifTextList NikonTagWhiteBalance[]= {
207 { 3, "incandescent" },
208 { 4, "fluorescence" },
214 static ExifTextList NikonTagConverter[]= {
220 static ExifMarker NikonExifMarkersList1[] = {
221 { 0x0002, EXIF_FORMAT_STRING, 6, "Nikon.unknown", nullptr, nullptr },
222 { 0x0003, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.Quality", "Quality", NikonTagQuality },
223 { 0x0004, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ColorMode", "Color mode", NikonTagColorMode },
224 { 0x0005, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ImageAdjustment",
225 "Image adjustment", NikonTagImgAdjust },
226 { 0x0006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ISOSensitivity",
227 "ISO sensitivity", NikonTagISOSensitivity },
228 { 0x0007, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.WhiteBalance", "White balance",NikonTagWhiteBalance },
229 { 0x0008, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Nikon.Focus", "Focus", nullptr },
230 { 0x000a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Nikon.DigitalZoom", "Digital zoom", nullptr },
231 { 0x000b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.Converter", "Converter", NikonTagConverter },
235 static ExifTextList NikonTag2FlashComp[]= {
256 static ExifTextList NikonTag2LensType[]= {
259 { 2, "AF-D or AF-s" },
265 static ExifTextList NikonTag2FlashUsed[]= {
267 { 4, "unit unknown" },
274 static ExifMarker NikonExifMarkersList2[] = {
275 { 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Nikon.ISOSpeed", "ISO speed", nullptr },
276 { 0x0003, EXIF_FORMAT_STRING, -1, "Nikon.ColorMode", "Color mode", nullptr },
277 { 0x0004, EXIF_FORMAT_STRING, -1, "Nikon.Quality", "Quality", nullptr },
278 { 0x0005, EXIF_FORMAT_STRING, -1, "Nikon.WhiteBalance", "White balance",nullptr },
279 { 0x0006, EXIF_FORMAT_STRING, -1, "Nikon.Sharpening", "Sharpening", nullptr },
280 { 0x0007, EXIF_FORMAT_STRING, -1, "Nikon.FocusMode", "Focus mode", nullptr },
281 { 0x0008, EXIF_FORMAT_STRING, -1, "Nikon.FlashSetting", "Flash setting",nullptr },
282 { 0x0009, EXIF_FORMAT_STRING, -1, "Nikon.AutoFlashMode","Auto flash mode",nullptr },
283 { 0x000b, EXIF_FORMAT_SHORT, 1, "Nikon.WhiteBalanceBias",
284 "White balance bias value", nullptr },
285 /* { 0x000c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.WhiteBalanceRB",
286 "White balance red/blue coefficients", NULL }, */
287 /* { 0x000f, EXIF_FORMAT_STRING, -1, "Nikon.ISOSelect", "ISO selection",NULL }, */
288 { 0x0012, EXIF_FORMAT_UNDEFINED, 4, "Nikon.FlashCompensation",
289 "Flash compensation", NikonTag2FlashComp },
290 { 0x0013, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Nikon.ISOSpeedRequest",
291 "ISO speed requested", nullptr },
292 { 0x0016, EXIF_FORMAT_SHORT_UNSIGNED, 4, "Nikon.CornerCoord",
293 "Corner coordinates", nullptr },
294 { 0x0018, EXIF_FORMAT_UNDEFINED, 4, "Nikon.FlashBracketCompensation",
295 "Flash bracket compensation", NikonTag2FlashComp },
296 { 0x0019, EXIF_FORMAT_RATIONAL, 1, "Nikon.AEBracketCompensation",
297 "AE bracket compensation", nullptr },
298 { 0x0080, EXIF_FORMAT_STRING, -1, "Nikon.ImageAdjustment",
299 "Image adjustment", nullptr },
300 { 0x0081, EXIF_FORMAT_STRING, -1, "Nikon.Contrast", "Contrast", nullptr },
301 { 0x0082, EXIF_FORMAT_STRING, -1, "Nikon.AuxLens", "Aux lens adapter", nullptr },
302 { 0x0083, EXIF_FORMAT_BYTE_UNSIGNED, -1, "Nikon.LensType", "Lens type", NikonTag2LensType },
303 { 0x0084, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Nikon.LensFocalLength",
304 "Lens min/max focal length and aperture", nullptr },
305 { 0x0085, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ManualFocusDistance",
306 "Manual focus distance", nullptr },
307 { 0x0086, EXIF_FORMAT_RATIONAL, 1, "Nikon.DigitalZoomFactor",
308 "Digital zoom factor", nullptr },
309 { 0x0087, EXIF_FORMAT_BYTE_UNSIGNED, 1, "Nikon.FlashUsed", "Flash used", NikonTag2FlashUsed },
310 { 0x0088, EXIF_FORMAT_UNDEFINED, 4, "Nikon.AutoFocusArea","Auto focus area",nullptr },
311 /* { 0x0089, EXIF_FORMAT_SHORT_UNSIGNED, -1, "Nikon.Bracket/ShootingMode", NULL, NULL }, */
312 { 0x008d, EXIF_FORMAT_STRING, -1, "Nikon.ColorMode", "Color mode", nullptr },
313 { 0x008f, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.SceneMode", "Scene mode", nullptr },
314 { 0x0090, EXIF_FORMAT_STRING, -1, "Nikon.LightingType", "Lighting type",nullptr },
315 { 0x0092, EXIF_FORMAT_SHORT, 1, "Nikon.HueAdjust", "Hue adjustment",nullptr },
316 /* { 0x0094, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.Saturation", "Saturation", NikonTag2Saturation }, */
317 { 0x0095, EXIF_FORMAT_STRING, -1, "Nikon.NoiseReduction", "Noise reduction", nullptr },
318 { 0x00a7, EXIF_FORMAT_LONG_UNSIGNED, 1, "Nikon.ShutterCount", "Shutter release count", nullptr },
319 { 0x00a9, EXIF_FORMAT_STRING, -1, "Nikon.ImageOptimization", "Image optimization", nullptr },
320 { 0x00aa, EXIF_FORMAT_STRING, -1, "Nikon.Saturation", "Saturation", nullptr },
321 { 0x00ab, EXIF_FORMAT_STRING, -1, "Nikon.DigitalVariProg", "Digital Vari-program", nullptr },
325 static ExifTextList NikonAFPoint[]= {
335 gboolean format_nikon_makernote(ExifData *exif, guchar *tiff, guint offset,
336 guint size, ExifByteOrder bo)
341 if (offset + 8 + 4 >= size) return FALSE;
343 data = tiff + offset;
345 /* Nikon tag format 1 */
346 if (memcmp(data, "Nikon\x00\x01\x00", 8) == 0)
348 if (exif_parse_IFD_table(exif, tiff, offset + 8, size,
349 bo, 0, NikonExifMarkersList1) != 0)
356 /* Nikon tag format 2 uses Embedded tiff header */
357 if (memcmp(data, "Nikon\x00\x02\x00\x00\x00", 10) == 0 ||
358 memcmp(data, "Nikon\x00\x02\x10\x00\x00", 10) == 0)
362 tiff_header = offset + 10;
363 if (exif_tiff_parse(exif, tiff + tiff_header, size - tiff_header,
364 NikonExifMarkersList2) != 0)
369 /* Nikon tag format 3 uses format 2 tags without "Nikon" and tiff header */
370 else if (exif_parse_IFD_table(exif, tiff, offset, size,
371 bo, 0, NikonExifMarkersList2) != 0)
376 item = exif_get_item(exif, "Nikon.AutoFocusArea");
377 if (item && item->data_len == 4 * sizeof(guchar))
379 static ExifMarker marker = { 0x0088, EXIF_FORMAT_STRING, -1,
380 "Nikon.AutoFocusPoint", "Auto focus point", nullptr };
381 auto array = static_cast<guchar*>(item->data);
385 text = exif_text_list_find_value(NikonAFPoint, static_cast<gint>(array[1]));
386 l = strlen(text) + 1;
388 item = exif_item_new(marker.format, marker.tag, l, &marker);
389 memcpy(item->data, text, l);
393 exif->items = g_list_prepend(exif->items, item);
396 item = exif_get_item(exif, "Nikon.ISOSpeed");
397 if (item && item->data_len == 2 * 2)
399 static ExifMarker marker = { 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 1,
400 "ISOSpeedRatings", "ISO speed", nullptr };
403 shadow = exif_item_new(marker.format, marker.tag, 1, &marker);
404 memcpy(shadow->data, static_cast<char *>(item->data) + 2, 2);
406 exif->items = g_list_prepend(exif->items, shadow);
409 item = exif_get_item(exif, "Nikon.WhiteBalance");
410 if (item && item->format == EXIF_FORMAT_STRING)
412 static ExifMarker marker = { 0x0005, EXIF_FORMAT_STRING, -1,
413 "LightSource", "Light source", nullptr };
416 shadow = exif_item_new(marker.format, marker.tag, item->data_len, &marker);
417 memcpy(shadow->data, item->data, item->data_len);
419 exif->items = g_list_prepend(exif->items, shadow);
425 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */