6 * Raw NEF jpeg extraction based on nefextract.c by Joseph Heled,
7 * in addition nefextract.c is based on dcraw by Dave Coffin.
9 * This software is released under the GNU General Public License (GNU GPL).
10 * Please read the included file COPYING for more information.
11 * This software comes with no warranty of any kind, use at your own risk!
27 #include "format_nikon.h"
33 *-----------------------------------------------------------------------------
34 * Raw NEF embedded jpeg extraction for Nikon
35 *-----------------------------------------------------------------------------
38 static guint tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
39 guint *image_offset, guint *jpeg_len);
42 static void tiff_entry(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
43 guint *image_offset, guint *image_length, guint *jpeg_start, guint *jpeg_len)
45 static gint size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
51 tag = exif_byte_get_int16(data + offset, byte_order);
52 type = exif_byte_get_int16(data + offset + 2, byte_order);
53 count = exif_byte_get_int32(data + offset + 4, byte_order);
55 if (type > 12) return;
56 if (count * size[type] > 4)
58 segment = exif_byte_get_int32(data + offset + 8, byte_order);
59 if (len < segment + count * size[type]) return;
67 type == EXIF_FORMAT_LONG_UNSIGNED)
72 for (i = 0; i < count; i++)
76 subset = exif_byte_get_int32(data + segment + i * 4, byte_order);
77 tiff_table(data, len, subset, byte_order, image_offset, image_length);
81 else if (tag == 0x201)
83 /* jpeg data start offset */
84 *jpeg_start = exif_byte_get_int32(data + segment, byte_order);
86 else if (tag == 0x202)
88 /* jpeg data length */
89 *jpeg_len = exif_byte_get_int32(data + segment, byte_order);
93 static guint tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
94 guint *image_offset, guint *image_length)
101 if (len < offset + 2) return FALSE;
103 count = exif_byte_get_int16((unsigned char *)data + offset, byte_order);
105 if (len < offset + count * 12 + 4) return 0;
108 for (i = 0; i < count; i++)
110 tiff_entry(data, len, offset + i * 12, byte_order,
111 image_offset, image_length, &jpeg_start, &jpeg_len);
114 if (jpeg_start > 0 &&
115 jpeg_len > *image_length)
117 *image_offset = jpeg_start;
118 *image_length = jpeg_len;
121 return exif_byte_get_int32((unsigned char *)data + offset + count * 12, byte_order);
125 * Walk the first TIFF IFD table and check for existence of a "make" tag (0x10f) that
126 * identifies NIKON CORPORATION, so that we can abort quickly if it is not a raw NEF.
128 static gint tiff_nikon_verify(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order)
133 if (len < offset + 2) return FALSE;
135 nb_entries = exif_byte_get_int16(data + offset, byte_order);
137 if (len < offset + nb_entries * 12 + 4) return FALSE;
139 for (i = 0; i < nb_entries; i++)
143 segment = offset + i * 12;
144 if (exif_byte_get_int16(data + segment, byte_order) == 0x10f &&
145 exif_byte_get_int16(data + segment + 2, byte_order) == EXIF_FORMAT_STRING)
150 count = exif_byte_get_int32(data + segment + 4, byte_order);
151 make_text = exif_byte_get_int32(data + segment + 8, byte_order);
154 memcmp(data + make_text, "NIKON CORPORATION", 17) == 0)
166 gint format_nikon_raw(const void *data, const guint len,
167 guint *image_offset, guint *exif_offset)
171 ExifByteOrder byte_order;
174 if (len < 8) return FALSE;
176 if (memcmp(data, "II", 2) == 0)
178 byte_order = EXIF_BYTE_ORDER_INTEL;
180 else if (memcmp(data, "MM", 2) == 0)
182 byte_order = EXIF_BYTE_ORDER_MOTOROLA;
189 if (exif_byte_get_int16((unsigned char *)data + 2, byte_order) != 0x002A)
194 offset = exif_byte_get_int32((unsigned char *)data + 4, byte_order);
195 if (!tiff_nikon_verify((unsigned char *)data, len, offset, byte_order)) return FALSE;
199 guint next_offset = 0;
200 tiff_table((unsigned char *)data, len, offset, byte_order, &i_off, &i_len);
201 offset = next_offset;
206 if (image_offset) *image_offset = i_off;
215 *-----------------------------------------------------------------------------
216 * EXIF Makernote for Nikon
217 *-----------------------------------------------------------------------------
220 static ExifTextList NikonTagQuality[]= {
225 { 5, "SXGA normal" },
227 { 7, "XGA basic (?)" },
228 { 8, "XGA normal (?)" },
229 { 9, "XGA fine (?)" },
230 { 10, "UXGA basic" },
231 { 11, "UXGA normal" },
236 static ExifTextList NikonTagColorMode[]= {
242 static ExifTextList NikonTagImgAdjust[]= {
251 static ExifTextList NikonTagISOSensitivity[]= {
259 static ExifTextList NikonTagWhiteBalance[]= {
263 { 3, "incandescent" },
264 { 4, "fluorescence" },
270 static ExifTextList NikonTagConverter[]= {
277 static ExifTextList NikonTag[]= {
284 static ExifMarker NikonExifMarkersList1[] = {
285 { 0x0002, EXIF_FORMAT_STRING, 6, "MkN.Nikon.unknown", NULL, NULL },
286 { 0x0003, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.Quality", "Quality", NikonTagQuality },
287 { 0x0004, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.ColorMode", "Color mode", NikonTagColorMode },
288 { 0x0005, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.ImageAdjustment",
289 "Image adjustment", NikonTagImgAdjust },
290 { 0x0006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.ISOSensitivity",
291 "ISO sensitivity", NikonTagISOSensitivity },
292 { 0x0007, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.WhiteBalance",
293 "White balance", NikonTagWhiteBalance },
294 { 0x0008, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "MkN.Nikon.Focus", "Focus", NULL },
295 { 0x000a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "MkN.Nikon.DigitalZoom","Digital zoom", NULL },
296 { 0x000b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.Converter", "Converter", NikonTagConverter },
300 static ExifTextList NikonTag2FlashComp[]= {
321 static ExifTextList NikonTag2FlashUsed[]= {
328 static ExifTextList NikonTagi2Saturation[]= {
329 { -3, "black and white" },
339 static ExifMarker NikonExifMarkersList2[] = {
340 { 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 2, "MkN.Nikon.ISOSpeed", "ISO speed", NULL },
341 { 0x0003, EXIF_FORMAT_STRING, -1, "MkN.Nikon.ColorMode", "Color mode", NULL },
342 { 0x0004, EXIF_FORMAT_STRING, -1, "MkN.Nikon.Quality", "Quality", NULL },
343 { 0x0005, EXIF_FORMAT_STRING, -1, "MkN.Nikon.WhiteBalance",
344 "White balance", NULL },
345 { 0x0006, EXIF_FORMAT_STRING, -1, "MkN.Nikon.Sharpening", "Sharpening", NULL },
346 { 0x0007, EXIF_FORMAT_STRING, -1, "MkN.Nikon.FocusMode", "Focus mode", NULL },
347 { 0x0008, EXIF_FORMAT_STRING, -1, "MkN.Nikon.FlashSetting",
348 "Flash setting", NULL },
349 { 0x0009, EXIF_FORMAT_STRING, -1, "MkN.Nikon.AutoFlashMode","Auto flash mode",NULL },
350 { 0x000b, EXIF_FORMAT_SHORT, 1, "MkN.Nikon.WhiteBalanceBias",
351 "White balance bias value", NULL },
352 /* { 0x000c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.WhiteBalanceCoeff",
353 "White balance red/blue coefficents", NULL }, */
354 /* { 0x000f, EXIF_FORMAT_STRING, -1, "MkN.Nikon.ISOSelect", "ISO selection",NULL }, */
355 { 0x0012, EXIF_FORMAT_UNDEFINED, 4, "MkN.Nikon.FlashCompensation",
356 "Flash compensation", NikonTag2FlashComp },
357 { 0x0013, EXIF_FORMAT_SHORT_UNSIGNED, 2, "MkN.Nikon.ISOSpeedRequest",
358 "ISO speed requested", NULL },
359 { 0x0016, EXIF_FORMAT_SHORT_UNSIGNED, 4, "MkN.Nikon.CornerCoord",
360 "Corner coordinates", NULL },
361 { 0x0018, EXIF_FORMAT_UNDEFINED, 4, "MkN.Nikon.FlashBracketCompensation",
362 "Flash bracket compensation", NikonTag2FlashComp },
363 { 0x0019, EXIF_FORMAT_RATIONAL, 1, "MkN.Nikon.AEBracketCompensation",
364 "AE bracket compensation", NULL },
365 { 0x0080, EXIF_FORMAT_STRING, -1, "MkN.Nikon.ImageAdjustment",
366 "Image adjustment", NULL },
367 { 0x0081, EXIF_FORMAT_STRING, -1, "MkN.Nikon.Contrast", "Contrast", NULL },
368 { 0x0082, EXIF_FORMAT_STRING, -1, "MkN.Nikon.AuxLens","Aux lens adapter", NULL },
369 { 0x0083, EXIF_FORMAT_BYTE_UNSIGNED, -1, "MkN.Nikon.LensType", "Lens type", NULL },
370 { 0x0084, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "MkN.Nikon.LensFocalLength",
371 "Lens min/max focal length and aperture", NULL },
372 { 0x0085, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.ManualFocusDistance",
373 "Manual focus distance", NULL },
374 { 0x0086, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.DigitalZoomFactor",
375 "Digital zoom facotr", NULL },
376 { 0x0087, EXIF_FORMAT_BYTE_UNSIGNED, 1, "MkN.Nikon.FlashUsed", "Flash used", NikonTag2FlashUsed },
377 { 0x0088, EXIF_FORMAT_UNDEFINED, -1, "MkN.Nikon.AutoFocusArea", NULL, NULL },
378 /* { 0x0089, EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Nikon.Bracket/ShootingMode", NULL, NULL }, */
379 { 0x008d, EXIF_FORMAT_STRING, -1, "MkN.Nikon.ColorMode", "Color mode", NULL },
380 { 0x008f, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.SceneMode", NULL, NULL },
381 { 0x0090, EXIF_FORMAT_STRING, -1, "MkN.Nikon.LightingType", "Lighting type", NULL },
382 { 0x0092, EXIF_FORMAT_SHORT, 1, "MkN.Nikon.HueAdjust", "Hue adjustment", NULL },
383 /* { 0x0094, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Nikon.Saturation", "Saturation", NikonTag2Saturation }, */
384 { 0x0095, EXIF_FORMAT_STRING, -1, "MkN.Nikon.NoiseReduction", "Noise reduction", NULL },
385 { 0x00a7, EXIF_FORMAT_LONG_UNSIGNED, 1, "MkN.Nikon.ShutterCount", "Shutter release count", NULL },
386 { 0x00a9, EXIF_FORMAT_STRING, -1, "MkN.Nikon.ImageOptimization", "Image optimization", NULL },
387 { 0x00aa, EXIF_FORMAT_STRING, -1, "MkN.Nikon.Saturation", "Saturation", NULL },
388 { 0x00ab, EXIF_FORMAT_STRING, -1, "MkN.Nikon.DigitalVariProg", "Digital Vari-program", NULL },
393 gint format_nikon_makernote(ExifData *exif, unsigned char *tiff, guint offset,
394 guint size, ExifByteOrder byte_order)
398 if (offset + 8 + 4 >= size) return FALSE;
400 data = tiff + offset;
401 if (memcmp(data, "Nikon\x00\x01\x00", 8) == 0)
403 if (exif_parse_IFD_table(exif, tiff, offset + 8, size,
404 byte_order, NikonExifMarkersList1) != 0)
411 if (memcmp(data, "Nikon\x00\x02\x00\x00\x00", 10) == 0 ||
412 memcmp(data, "Nikon\x00\x02\x10\x00\x00", 10) == 0)
416 tiff_header = offset + 10;
417 if (exif_parse_TIFF(exif, tiff + tiff_header, size - tiff_header,
418 NikonExifMarkersList2) != 0)
425 /* fixme: support E990 and D1 */
426 if (exif_parse_IFD_table(exif, tiff, offset, size,
427 byte_order, NikonExifMarkersList2) != 0)