Mercurial > geeqie
view src/format_nikon.c @ 1802:956aab097ea7
added 2010 to copyright text
author | nadvornik |
---|---|
date | Tue, 16 Feb 2010 21:18:03 +0000 |
parents | bc3f5c0432f6 |
children |
line wrap: on
line source
/* * Geeqie * (C) 2005 John Ellis * Copyright (C) 2008 - 2010 The Geeqie Team * * Authors: * Raw NEF jpeg extraction based on nefextract.c by Joseph Heled, * in addition nefextract.c is based on dcraw by Dave Coffin. * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef HAVE_EXIV2 #include <stdio.h> #include <string.h> #include <unistd.h> #include <glib.h> #include "intl.h" #include "main.h" #include "format_nikon.h" #include "exif.h" /* *----------------------------------------------------------------------------- * Raw NEF embedded jpeg extraction for Nikon *----------------------------------------------------------------------------- */ static guint nikon_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo, gint level, guint *image_offset, guint *jpeg_len); static void nikon_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo, gint level, guint *image_offset, guint *image_length, guint *jpeg_start, guint *jpeg_len) { guint tag; guint type; guint count; guint segment; guint seg_len; tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo); type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo); count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo); /* so far, we only care about tags with type long */ if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return; seg_len = ExifFormatList[type].size * count; if (seg_len > 4) { segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo); if (segment + seg_len > len) return; } else { segment = offset + EXIF_TIFD_OFFSET_DATA; } if (tag == 0x14a) { /* sub IFD table */ guint i; for (i = 0; i < count; i++) { guint subset; subset = exif_byte_get_int32(data + segment + i * 4, bo); nikon_tiff_table(data, len, subset, bo, level + 1, image_offset, image_length); } } else if (tag == 0x201) { /* jpeg data start offset */ *jpeg_start = exif_byte_get_int32(data + segment, bo); } else if (tag == 0x202) { /* jpeg data length */ *jpeg_len = exif_byte_get_int32(data + segment, bo); } } static guint nikon_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo, gint level, guint *image_offset, guint *image_length) { guint count; guint i; guint jpeg_start = 0; guint jpeg_len = 0; /* limit damage from infinite loops */ if (level > EXIF_TIFF_MAX_LEVELS) return 0; if (len < offset + 2) return FALSE; count = exif_byte_get_int16(data + offset, bo); offset += 2; if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0; for (i = 0; i < count; i++) { nikon_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level, image_offset, image_length, &jpeg_start, &jpeg_len); } if (jpeg_start > 0 && jpeg_len > *image_length) { *image_offset = jpeg_start; *image_length = jpeg_len; } return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo); } gboolean format_nikon_raw(guchar *data, const guint len, guint *image_offset, guint *exif_offset) { guint i_off = 0; guint i_len = 0; ExifByteOrder bo; guint offset; gint level; if (!exif_tiff_directory_offset(data, len, &offset, &bo)) return FALSE; level = 0; while (offset && level < EXIF_TIFF_MAX_LEVELS) { offset = nikon_tiff_table(data, len, offset, bo, 0, &i_off, &i_len); level++; } if (i_off != 0) { if (image_offset) *image_offset = i_off; return TRUE; } return FALSE; } /* *----------------------------------------------------------------------------- * EXIF Makernote for Nikon *----------------------------------------------------------------------------- */ static ExifTextList NikonTagQuality[]= { { 1, "VGA basic" }, { 2, "VGA normal" }, { 3, "VGA fine" }, { 4, "SXGA basic" }, { 5, "SXGA normal" }, { 6, "SXGA fine" }, { 7, "XGA basic (?)" }, { 8, "XGA normal (?)" }, { 9, "XGA fine (?)" }, { 10, "UXGA basic" }, { 11, "UXGA normal" }, { 12, "UXGA fine" }, EXIF_TEXT_LIST_END }; static ExifTextList NikonTagColorMode[]= { { 1, "color" }, { 2, "monochrome" }, EXIF_TEXT_LIST_END }; static ExifTextList NikonTagImgAdjust[]= { { 0, "normal" }, { 1, "bright+" }, { 2, "bright-" }, { 3, "contrast+" }, { 4, "contrast-" }, EXIF_TEXT_LIST_END }; static ExifTextList NikonTagISOSensitivity[]= { { 0, "80" }, { 2, "160" }, { 4, "320" }, { 5, "100" }, EXIF_TEXT_LIST_END }; static ExifTextList NikonTagWhiteBalance[]= { { 0, "auto" }, { 1, "preset" }, { 2, "daylight" }, { 3, "incandescent" }, { 4, "fluorescence" }, { 5, "cloudy" }, { 6, "speedlight" }, EXIF_TEXT_LIST_END }; static ExifTextList NikonTagConverter[]= { { 0, "none" }, { 1, "Fisheye" }, EXIF_TEXT_LIST_END }; #if 0 static ExifTextList NikonTag[]= { { , "" }, { , "" }, EXIF_TEXT_LIST_END }; #endif static ExifMarker NikonExifMarkersList1[] = { { 0x0002, EXIF_FORMAT_STRING, 6, "Nikon.unknown", NULL, NULL }, { 0x0003, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.Quality", "Quality", NikonTagQuality }, { 0x0004, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ColorMode", "Color mode", NikonTagColorMode }, { 0x0005, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ImageAdjustment", "Image adjustment", NikonTagImgAdjust }, { 0x0006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ISOSensitivity", "ISO sensitivity", NikonTagISOSensitivity }, { 0x0007, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.WhiteBalance", "White balance",NikonTagWhiteBalance }, { 0x0008, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Nikon.Focus", "Focus", NULL }, { 0x000a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Nikon.DigitalZoom", "Digital zoom", NULL }, { 0x000b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.Converter", "Converter", NikonTagConverter }, EXIF_MARKER_LIST_END }; static ExifTextList NikonTag2FlashComp[]= { { 0x06, "+1.0 EV" }, { 0x04, "+0.7 EV" }, { 0x03, "+0.5 EV" }, { 0x02, "+0.3 EV" }, { 0x00, "0.0 EV" }, { 0xfe, "-0.3 EV" }, { 0xfd, "-0.5 EV" }, { 0xfc, "-0.7 EV" }, { 0xfa, "-1.0 EV" }, { 0xf8, "-1.3 EV" }, { 0xf7, "-1.5 EV" }, { 0xf6, "-1.7 EV" }, { 0xf4, "-2.0 EV" }, { 0xf2, "-2.3 EV" }, { 0xf1, "-2.5 EV" }, { 0xf0, "-2.7 EV" }, { 0xee, "-3.0 EV" }, EXIF_TEXT_LIST_END }; static ExifTextList NikonTag2LensType[]= { { 0, "AF non D" }, { 1, "manual" }, { 2, "AF-D or AF-s" }, { 6, "AF-D G" }, { 10, "AF-D VR" }, EXIF_TEXT_LIST_END }; static ExifTextList NikonTag2FlashUsed[]= { { 0, "no" }, { 4, "unit unknown" }, { 7, "external" }, { 9, "yes" }, EXIF_TEXT_LIST_END }; #if 0 static ExifTextList NikonTagi2Saturation[]= { { -3, "black and white" }, { -2, "-2" }, { -1, "-1" }, { 0, "normal" }, { 1, "+1" }, { 2, "+2" }, EXIF_TEXT_LIST_END }; #endif static ExifMarker NikonExifMarkersList2[] = { { 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Nikon.ISOSpeed", "ISO speed", NULL }, { 0x0003, EXIF_FORMAT_STRING, -1, "Nikon.ColorMode", "Color mode", NULL }, { 0x0004, EXIF_FORMAT_STRING, -1, "Nikon.Quality", "Quality", NULL }, { 0x0005, EXIF_FORMAT_STRING, -1, "Nikon.WhiteBalance", "White balance",NULL }, { 0x0006, EXIF_FORMAT_STRING, -1, "Nikon.Sharpening", "Sharpening", NULL }, { 0x0007, EXIF_FORMAT_STRING, -1, "Nikon.FocusMode", "Focus mode", NULL }, { 0x0008, EXIF_FORMAT_STRING, -1, "Nikon.FlashSetting", "Flash setting",NULL }, { 0x0009, EXIF_FORMAT_STRING, -1, "Nikon.AutoFlashMode","Auto flash mode",NULL }, { 0x000b, EXIF_FORMAT_SHORT, 1, "Nikon.WhiteBalanceBias", "White balance bias value", NULL }, /* { 0x000c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.WhiteBalanceRB", "White balance red/blue coefficients", NULL }, */ /* { 0x000f, EXIF_FORMAT_STRING, -1, "Nikon.ISOSelect", "ISO selection",NULL }, */ { 0x0012, EXIF_FORMAT_UNDEFINED, 4, "Nikon.FlashCompensation", "Flash compensation", NikonTag2FlashComp }, { 0x0013, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Nikon.ISOSpeedRequest", "ISO speed requested", NULL }, { 0x0016, EXIF_FORMAT_SHORT_UNSIGNED, 4, "Nikon.CornerCoord", "Corner coordinates", NULL }, { 0x0018, EXIF_FORMAT_UNDEFINED, 4, "Nikon.FlashBracketCompensation", "Flash bracket compensation", NikonTag2FlashComp }, { 0x0019, EXIF_FORMAT_RATIONAL, 1, "Nikon.AEBracketCompensation", "AE bracket compensation", NULL }, { 0x0080, EXIF_FORMAT_STRING, -1, "Nikon.ImageAdjustment", "Image adjustment", NULL }, { 0x0081, EXIF_FORMAT_STRING, -1, "Nikon.Contrast", "Contrast", NULL }, { 0x0082, EXIF_FORMAT_STRING, -1, "Nikon.AuxLens", "Aux lens adapter", NULL }, { 0x0083, EXIF_FORMAT_BYTE_UNSIGNED, -1, "Nikon.LensType", "Lens type", NikonTag2LensType }, { 0x0084, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Nikon.LensFocalLength", "Lens min/max focal length and aperture", NULL }, { 0x0085, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.ManualFocusDistance", "Manual focus distance", NULL }, { 0x0086, EXIF_FORMAT_RATIONAL, 1, "Nikon.DigitalZoomFactor", "Digital zoom factor", NULL }, { 0x0087, EXIF_FORMAT_BYTE_UNSIGNED, 1, "Nikon.FlashUsed", "Flash used", NikonTag2FlashUsed }, { 0x0088, EXIF_FORMAT_UNDEFINED, 4, "Nikon.AutoFocusArea","Auto focus area",NULL }, /* { 0x0089, EXIF_FORMAT_SHORT_UNSIGNED, -1, "Nikon.Bracket/ShootingMode", NULL, NULL }, */ { 0x008d, EXIF_FORMAT_STRING, -1, "Nikon.ColorMode", "Color mode", NULL }, { 0x008f, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.SceneMode", "Scene mode", NULL }, { 0x0090, EXIF_FORMAT_STRING, -1, "Nikon.LightingType", "Lighting type",NULL }, { 0x0092, EXIF_FORMAT_SHORT, 1, "Nikon.HueAdjust", "Hue adjustment",NULL }, /* { 0x0094, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Nikon.Saturation", "Saturation", NikonTag2Saturation }, */ { 0x0095, EXIF_FORMAT_STRING, -1, "Nikon.NoiseReduction", "Noise reduction", NULL }, { 0x00a7, EXIF_FORMAT_LONG_UNSIGNED, 1, "Nikon.ShutterCount", "Shutter release count", NULL }, { 0x00a9, EXIF_FORMAT_STRING, -1, "Nikon.ImageOptimization", "Image optimization", NULL }, { 0x00aa, EXIF_FORMAT_STRING, -1, "Nikon.Saturation", "Saturation", NULL }, { 0x00ab, EXIF_FORMAT_STRING, -1, "Nikon.DigitalVariProg", "Digital Vari-program", NULL }, EXIF_MARKER_LIST_END }; static ExifTextList NikonAFPoint[]= { { 0, "center" }, { 1, "top" }, { 2, "bottom" }, { 3, "left" }, { 4, "right" }, EXIF_TEXT_LIST_END }; gboolean format_nikon_makernote(ExifData *exif, guchar *tiff, guint offset, guint size, ExifByteOrder bo) { guchar *data; ExifItem *item; if (offset + 8 + 4 >= size) return FALSE; data = tiff + offset; /* Nikon tag format 1 */ if (memcmp(data, "Nikon\x00\x01\x00", 8) == 0) { if (exif_parse_IFD_table(exif, tiff, offset + 8, size, bo, 0, NikonExifMarkersList1) != 0) { return FALSE; } return TRUE; } /* Nikon tag format 2 uses Embedded tiff header */ if (memcmp(data, "Nikon\x00\x02\x00\x00\x00", 10) == 0 || memcmp(data, "Nikon\x00\x02\x10\x00\x00", 10) == 0) { guint tiff_header; tiff_header = offset + 10; if (exif_tiff_parse(exif, tiff + tiff_header, size - tiff_header, NikonExifMarkersList2) != 0) { return FALSE; } } /* Nikon tag format 3 uses format 2 tags without "Nikon" and tiff header */ else if (exif_parse_IFD_table(exif, tiff, offset, size, bo, 0, NikonExifMarkersList2) != 0) { return FALSE; } item = exif_get_item(exif, "Nikon.AutoFocusArea"); if (item && item->data_len == 4 * sizeof(guchar)) { static ExifMarker marker = { 0x0088, EXIF_FORMAT_STRING, -1, "Nikon.AutoFocusPoint", "Auto focus point", NULL }; guchar *array = item->data; gchar *text; gint l; text = exif_text_list_find_value(NikonAFPoint, (gint)array[1]); l = strlen(text) + 1; item = exif_item_new(marker.format, marker.tag, l, &marker); memcpy(item->data, text, l); g_free(text); exif->items = g_list_prepend(exif->items, item); } item = exif_get_item(exif, "Nikon.ISOSpeed"); if (item && item->data_len == 2 * 2) { static ExifMarker marker = { 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ISOSpeedRatings", "ISO speed", NULL }; ExifItem *shadow; shadow = exif_item_new(marker.format, marker.tag, 1, &marker); memcpy(shadow->data, item->data + 2, 2); exif->items = g_list_prepend(exif->items, shadow); } item = exif_get_item(exif, "Nikon.WhiteBalance"); if (item && item->format == EXIF_FORMAT_STRING) { static ExifMarker marker = { 0x0005, EXIF_FORMAT_STRING, -1, "LightSource", "Light source", NULL }; ExifItem *shadow; shadow = exif_item_new(marker.format, marker.tag, item->data_len, &marker); memcpy(shadow->data, item->data, item->data_len); exif->items = g_list_prepend(exif->items, shadow); } return TRUE; } #endif /* not HAVE_EXIV2 */ /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */