changeset 53:00843150f7c8

Tue Jun 7 03:47:03 2005 John Ellis <johne@verizon.net> * filelist.c (filter_add_defaults): Add Nikon file extension for nef. * format_canon.[ch], format_fuji.[ch]: Add comment tile, and description field for MakerNote parser. * format_nikon.[ch]: Add support for jpegs embedded in Nikon nef files. * format_raw.c: Add debug description output and Nikon raw parser hook. ##### Note: GQview CVS on sourceforge is not always up to date, please use ##### ##### an offical release when making enhancements and translation updates. #####
author gqview
date Tue, 07 Jun 2005 07:55:00 +0000
parents a210a19f26da
children b58cac75ad12
files ChangeLog TODO src/filelist.c src/format_canon.c src/format_canon.h src/format_fuji.c src/format_fuji.h src/format_nikon.c src/format_nikon.h src/format_raw.c
diffstat 10 files changed, 254 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Jun 05 07:09:12 2005 +0000
+++ b/ChangeLog	Tue Jun 07 07:55:00 2005 +0000
@@ -1,3 +1,11 @@
+Tue Jun  7 03:47:03 2005  John Ellis  <johne@verizon.net>
+
+	* filelist.c (filter_add_defaults): Add Nikon file extension for nef.
+	* format_canon.[ch], format_fuji.[ch]: Add comment tile, and
+	description field for MakerNote parser.
+	* format_nikon.[ch]: Add support for jpegs embedded in Nikon nef files.
+	* format_raw.c: Add debug description output and Nikon raw parser hook.
+
 Sun Jun  5 03:05:39 2005  John Ellis  <johne@verizon.net>
 
 	* filelist.c (path_list_recursive_append): Fix memory leak by using
--- a/TODO	Sun Jun 05 07:09:12 2005 +0000
+++ b/TODO	Tue Jun 07 07:55:00 2005 +0000
@@ -18,6 +18,28 @@
  > cache-load.c:
    > should honor enable_thumbnails setting
 
+  ---
+
+ >raw + exif formats:
+
+   > rethink raw format header parser, apparently canon and nikon both use the TIFF file format,
+     so it is possible that the same magic header can be in both formats - it only works now
+     because Canon header list ignores Motorola alignment, which is what Nikon uses. Additionally
+     matching CRW format uses a magic "HEADCCDR" offset 6 bytes into the file, first two bytes are
+     similar to tiff for specifying byte alignment (II or MM), so the current code will also pick
+     up tiff files. Whatever happens here, we want to avoid mmap'ing the file until we are sure.
+
+   > make a generic tiff header and directory parser from the nikon parser for use by all raw
+     parsers that involve tiff.
+
+   > clean up canon parser (canon_read_int can be substituted with, or wrap exif_get_int16/32).
+
+   > support olympus MakerNote, investigate RAW
+   > support konica / minolta MakerNote, investigate RAW
+
+   > exif.c parser should not be using EXIF tags during tiff directory search for EXIF tag.
+
+  ---
 
  > work on pan view:
    > Pick a better keyboard shortcut than Control + J :)
@@ -57,6 +79,8 @@
    > under consideration:
      > split view
 
+  ---
+
 d> fix window size hints not to use USER_SIZE as we do not use gtk_window_resize to set the hint's attribute, and
    apparently GTK passes in unitialized values for this case (definite programming error, but also a GTK bug?).
 
@@ -88,9 +112,6 @@
    > collection window
    > search window
 
-d> clean up exif.c to be portable (don't assume sizeof(short)==2 and sizeof(long)==4)
-
-
 Wishlist?:
 ----------------------------------------------
 
--- a/src/filelist.c	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/filelist.c	Tue Jun 07 07:55:00 2005 +0000
@@ -211,8 +211,9 @@
 	/* These are the raw camera formats with embedded jpeg/exif.
 	 * (see format_raw.c)
 	 */
+	filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", TRUE);
 	filter_add_if_missing("raf", "Fujifilm raw format", ".raf", TRUE);
-	filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", TRUE);
+	filter_add_if_missing("nef", "Nikon raw format", ".nef", TRUE);
 }
 
 static GList *filter_to_list(const gchar *extensions)
--- a/src/format_canon.c	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/format_canon.c	Tue Jun 07 07:55:00 2005 +0000
@@ -34,6 +34,13 @@
 #include "exif.h"
 
 
+/*
+ *-----------------------------------------------------------------------------
+ * Raw (CR2, CRW) embedded jpeg extraction for Canon
+ *-----------------------------------------------------------------------------
+ */
+
+
 #if 0
   #define CANON_DEBUG
 #endif
--- a/src/format_canon.h	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/format_canon.h	Tue Jun 07 07:55:00 2005 +0000
@@ -33,7 +33,7 @@
 gint format_canon_makernote(ExifData *exif, unsigned char *tiff, guint offset,
 			    guint size, ExifByteOrder byte_order);
 
-#define FORMAT_EXIF_CANON { FORMAT_EXIF_MATCH_MAKE, "Canon", 5, format_canon_makernote }
+#define FORMAT_EXIF_CANON { FORMAT_EXIF_MATCH_MAKE, "Canon", 5, "Canon", format_canon_makernote }
 
 
 #endif
--- a/src/format_fuji.c	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/format_fuji.c	Tue Jun 07 07:55:00 2005 +0000
@@ -29,6 +29,13 @@
 #include "exif.h"
 
 
+/*
+ *-----------------------------------------------------------------------------
+ * Raw (RAF) embedded jpeg extraction for Fujifilm
+ *-----------------------------------------------------------------------------
+ */
+
+
 gint format_fuji_raw(const void *data, const guint len,
 		     guint *image_offset, guint *exif_offset)
 {
--- a/src/format_fuji.h	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/format_fuji.h	Tue Jun 07 07:55:00 2005 +0000
@@ -27,7 +27,7 @@
 gint format_fuji_makernote(ExifData *exif, unsigned char *tiff, guint offset,
 			   guint size, ExifByteOrder byte_order);
 
-#define FORMAT_EXIF_FUJI { FORMAT_EXIF_MATCH_MAKERNOTE, "FUJIFILM", 8, format_fuji_makernote }
+#define FORMAT_EXIF_FUJI { FORMAT_EXIF_MATCH_MAKERNOTE, "FUJIFILM", 8, "Fujifilm", format_fuji_makernote }
 
 
 
--- a/src/format_nikon.c	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/format_nikon.c	Tue Jun 07 07:55:00 2005 +0000
@@ -2,6 +2,10 @@
  *  GQView
  *  (C) 2005 John Ellis
  *
+ *  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!
@@ -27,6 +31,188 @@
 
 /*
  *-----------------------------------------------------------------------------
+ * Raw NEF embedded jpeg extraction for Nikon
+ *-----------------------------------------------------------------------------
+ */
+
+static guint tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
+			guint *image_offset, guint *jpeg_len);
+
+
+static void tiff_entry(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
+		       guint *image_offset, guint *image_length, guint *jpeg_start, guint *jpeg_len)
+{
+	static gint size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+	guint tag;
+	guint type;
+	guint count;
+	guint segment;
+
+	tag = exif_byte_get_int16(data + offset, byte_order);
+	type = exif_byte_get_int16(data + offset + 2, byte_order);
+	count = exif_byte_get_int32(data + offset + 4, byte_order);
+
+	if (type > 12) return;
+	if (count * size[type] > 4)
+		{
+		segment = exif_byte_get_int32(data + offset + 8, byte_order);
+		if (len < segment + count * size[type]) return;
+		}
+	else
+		{
+		segment = offset + 8;
+		}
+
+	if (tag == 0x14a &&
+	    type == EXIF_FORMAT_LONG_UNSIGNED)
+		{
+		/* sub IFD table */
+		gint i;
+
+		for (i = 0; i < count; i++)
+			{
+			guint subset;
+
+			subset = exif_byte_get_int32(data + segment + i * 4, byte_order);
+			tiff_table(data, len, subset, byte_order, image_offset, image_length);
+			}
+
+		}
+	else if (tag == 0x201)
+		{
+		/* jpeg data start offset */
+		*jpeg_start = exif_byte_get_int32(data + segment, byte_order);
+		}
+	else if (tag == 0x202)
+		{
+		/* jpeg data length */
+		*jpeg_len = exif_byte_get_int32(data + segment, byte_order);
+		}
+}
+
+static guint tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
+			guint *image_offset, guint *image_length)
+{
+	guint count;
+	guint i;
+	guint jpeg_start = 0;
+	guint jpeg_len = 0;
+
+	if (len < offset + 2) return FALSE;
+
+	count = exif_byte_get_int16((unsigned char *)data + offset, byte_order);
+
+	if (len < offset + count * 12 + 4) return 0;
+	offset += 2;
+
+	for (i = 0; i < count; i++)
+		{
+		tiff_entry(data, len, offset + i * 12, byte_order,
+			   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((unsigned char *)data + offset + count * 12, byte_order);
+}
+
+/*
+ * Walk the first TIFF IFD table and check for existence of a "make" tag (0x10f) that
+ * identifies NIKON CORPORATION, so that we can abort quickly if it is not a raw NEF.
+ */
+static gint tiff_nikon_verify(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order)
+{
+	guint nb_entries;
+	guint i;
+
+	if (len < offset + 2) return FALSE;
+
+	nb_entries = exif_byte_get_int16(data + offset, byte_order);
+	offset += 2;
+	if (len < offset + nb_entries * 12 + 4) return FALSE;
+
+	for (i = 0; i < nb_entries; i++)
+		{
+		guint segment;
+
+		segment = offset + i * 12;
+		if (exif_byte_get_int16(data + segment, byte_order) == 0x10f &&
+		    exif_byte_get_int16(data + segment + 2, byte_order) == EXIF_FORMAT_STRING)
+			{
+			guint count;
+			guint make_text;
+
+			count = exif_byte_get_int32(data + segment + 4, byte_order);
+			make_text = exif_byte_get_int32(data + segment + 8, byte_order);
+
+			if (count >= 17 &&
+			    memcmp(data + make_text, "NIKON CORPORATION", 17) == 0)
+				{
+				return TRUE;
+				}
+
+			return FALSE;
+			}
+		}
+
+	return FALSE;
+}
+
+gint format_nikon_raw(const void *data, const guint len,
+		      guint *image_offset, guint *exif_offset)
+{
+	guint i_off = 0;
+	guint i_len = 0;
+	ExifByteOrder byte_order;
+	guint offset;
+
+	if (len < 8) return FALSE;
+
+	if (memcmp(data, "II", 2) == 0)
+		{
+		byte_order = EXIF_BYTE_ORDER_INTEL;
+		}
+	else if (memcmp(data, "MM", 2) == 0)
+		{
+		byte_order = EXIF_BYTE_ORDER_MOTOROLA;
+		}
+	else
+		{
+		return FALSE;
+		}
+
+	if (exif_byte_get_int16((unsigned char *)data + 2, byte_order) != 0x002A)
+		{
+		return FALSE;
+		}
+
+	offset = exif_byte_get_int32((unsigned char *)data + 4, byte_order);
+	if (!tiff_nikon_verify((unsigned char *)data, len, offset, byte_order)) return FALSE;
+
+	while (offset != 0)
+		{
+		guint next_offset = 0;
+		tiff_table((unsigned char *)data, len, offset, byte_order, &i_off, &i_len);
+		offset = next_offset;
+		}
+
+	if (i_off != 0)
+		{
+		if (image_offset) *image_offset = i_off;
+		return TRUE;
+		}
+
+	return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
  * EXIF Makernote for Nikon
  *-----------------------------------------------------------------------------
  */
--- a/src/format_nikon.h	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/format_nikon.h	Tue Jun 07 07:55:00 2005 +0000
@@ -13,12 +13,18 @@
 
 #include "exif.h"
 
+gint format_nikon_raw(const void *data, const guint len,
+		      guint *image_offset, guint *exif_offset);
+
+#define FORMAT_RAW_NIKON { "II\x2a\x00", 4, "Nikon tiff raw", format_nikon_raw }, \
+			 { "MM\x00\x2a", 4, "Nikon tiff raw", format_nikon_raw }
+
 
 gint format_nikon_makernote(ExifData *exif, unsigned char *tiff, guint offset,
 			    guint size, ExifByteOrder byte_order);
 
-#define FORMAT_EXIF_NIKON { FORMAT_EXIF_MATCH_MAKERNOTE, "Nikon\x00", 6, format_nikon_makernote }, \
-			  { FORMAT_EXIF_MATCH_MAKE,      "NIKON",     5, format_nikon_makernote }
+#define FORMAT_EXIF_NIKON { FORMAT_EXIF_MATCH_MAKERNOTE, "Nikon\x00", 6, "Nikon", format_nikon_makernote }, \
+			  { FORMAT_EXIF_MATCH_MAKE,      "NIKON",     5, "Nikon", format_nikon_makernote }
 
 
 #endif
--- a/src/format_raw.c	Sun Jun 05 07:09:12 2005 +0000
+++ b/src/format_raw.c	Tue Jun 07 07:55:00 2005 +0000
@@ -33,6 +33,10 @@
 #include "format_nikon.h"
 
 
+/* so that debugging is honored */
+extern gint debug;
+
+
 typedef struct _FormatRawEntry FormatRawEntry;
 struct _FormatRawEntry {
 	const void *header_pattern;
@@ -44,6 +48,7 @@
 static FormatRawEntry format_raw_list[] = {
 	FORMAT_RAW_CANON,
 	FORMAT_RAW_FUJI,
+	FORMAT_RAW_NIKON,
 	{ NULL, 0, NULL, NULL }
 };
 
@@ -53,6 +58,7 @@
 	FormatExifMatchType header_type;
 	const void *header_pattern;
 	const guint header_length;
+	const gchar *description;
 	FormatExifParseFunc func_parse;
 };
 
@@ -92,6 +98,8 @@
 
 	if (!entry || !entry->func_parse) return FALSE;
 
+	if (debug) printf("RAW using file parser for %s\n", entry->description);
+
 	found = entry->func_parse(data, len, &io, &eo);
 
 	if (!found ||
@@ -219,6 +227,8 @@
 
 	if (!entry || !entry->func_parse) return FALSE;
 
+	if (debug) printf("EXIF using makernote parser for %s\n", entry->description);
+
 	return entry->func_parse(exif, tiff, offset, size, byte_order);
 }