changeset 47:aa4c0e1b54b0

Fri Jun 3 01:49:20 2005 John Ellis <johne@verizon.net> * exif.[ch]: Export several parsing functions for use by the exif makernote parsers, and add hook for MakerNote data parsing. * format_canon.[ch]: Add Canon EXIF MakerNote support. * format_raw.c: Fix warning printf grammar. ##### 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 Fri, 03 Jun 2005 06:07:02 +0000
parents 905f8fa583a3
children 6948407f52a5
files ChangeLog src/exif.c src/exif.h src/format_canon.c src/format_canon.h src/format_raw.c
diffstat 6 files changed, 457 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri May 27 02:17:18 2005 +0000
+++ b/ChangeLog	Fri Jun 03 06:07:02 2005 +0000
@@ -1,3 +1,10 @@
+Fri Jun  3 01:49:20 2005  John Ellis  <johne@verizon.net>
+
+	* exif.[ch]: Export several parsing functions for use by the exif
+	makernote parsers, and add hook for MakerNote data parsing.
+	* format_canon.[ch]: Add Canon EXIF MakerNote support.
+	* format_raw.c: Fix warning printf grammar.
+
 Thu May 26 22:14:53 2005  John Ellis  <johne@verizon.net>
 
 	* format_raw.c (format_raw_parse): Use unsigned int to match arguments.
--- a/src/exif.c	Fri May 27 02:17:18 2005 +0000
+++ b/src/exif.c	Fri Jun 03 06:07:02 2005 +0000
@@ -73,6 +73,8 @@
 #include "format_raw.h"
 #include "ui_fileops.h"
 
+/* makernote parsers */
+#include "format_canon.h"
 
 /*
  *-----------------------------------------------------------------------------
@@ -99,6 +101,7 @@
 
 /* tags that are special, or need special treatment */
 #define TAG_EXIFOFFSET          0x8769
+#define TAG_EXIFMAKERNOTE	0x927c
 
 
 /*
@@ -107,8 +110,6 @@
  *-----------------------------------------------------------------------------
  */
 
-#define EXIF_TEXT_LIST_END { -1, NULL }
-
 static ExifTextList ExifOrientationList[] = {
 	{ EXIF_ORIENTATION_UNKNOWN,	N_("unknown") },
 	{ EXIF_ORIENTATION_TOP_LEFT,	N_("top left") },
@@ -393,8 +394,7 @@
 { 0x9215, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,	"ExposureIndex",	NULL, NULL },
 { 0x9216, EXIF_FORMAT_BYTE_UNSIGNED, 4,		"TIFF/EPStandardID",	NULL, NULL },
 
-	/* end is marked by 0 tag */
-{ 0x0000, EXIF_FORMAT_UNKNOWN, 0, NULL, NULL, NULL }
+EXIF_MARKER_LIST_END
 };
 
 ExifMarker ExifUnknownMarkersList[] = {
@@ -461,9 +461,7 @@
 } IFDEntry;
 
 
-static ExifMarker *exif_marker_from_tag(uint16_t tag);
-static int parse_IFD_table(ExifData *exif, unsigned char *tiff, int offset,
-			   int size, int byte_order);
+static const ExifMarker *exif_marker_from_tag(uint16_t tag, const ExifMarker *list);
 
 /*
  *-----------------------------------------------------------------------------
@@ -471,7 +469,8 @@
  *-----------------------------------------------------------------------------
  */
 
-static ExifItem *exif_item_new(ExifFormatType format, unsigned int tag, unsigned int elements, ExifMarker *marker)
+ExifItem *exif_item_new(ExifFormatType format, unsigned int tag,
+			unsigned int elements, const ExifMarker *marker)
 {
 	ExifItem *item;
 
@@ -714,17 +713,18 @@
  *-------------------------------------------------------------------
  */
 
-static ExifMarker *exif_marker_from_tag(uint16_t tag)
+static const ExifMarker *exif_marker_from_tag(uint16_t tag, const ExifMarker *list)
 {
-	static int len = sizeof(ExifKnownMarkersList)/sizeof(ExifMarker) - 1;
 	int i = 0;
 
-	while (i < len && ExifKnownMarkersList[i].tag != tag)
+	if (!list) return NULL;
+
+	while (list[i].tag != 0 && list[i].tag != tag)
 		{
 		i++;
 		}
 
-	return (i >= len ? NULL : &ExifKnownMarkersList[i]);
+	return (list[i].tag == 0 ? NULL : &list[i]);
 }
 
 static void rational_from_data(ExifRational *r, void *src, int byte_order)
@@ -733,7 +733,7 @@
 	r->den = swab_int32(*(uint32_t*)(src + sizeof(uint32_t)), byte_order);
 }
 
-static void exif_item_copy_data(ExifItem *item, void *src, int len, ExifFormatType src_format, int byte_order)
+void exif_item_copy_data(ExifItem *item, void *src, int len, ExifFormatType src_format, int byte_order)
 {
 	int bs;
 	int ne;
@@ -818,14 +818,15 @@
 		}
 }
 
-static int parse_IFD_entry(ExifData *exif, unsigned char *tiff, int offset,
-			   int size, int byte_order)
+static int exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, int offset,
+				int size, int byte_order,
+				const ExifMarker *list)
 {
 	IFDEntry *ent = (IFDEntry*)(tiff+offset);
 	uint32_t swabed_data;
 	void *data;
 	int data_len;
-	ExifMarker *marker;
+	const ExifMarker *marker;
 	ExifItem *item;
 
 	ent->tag = swab_int16(ent->tag, byte_order);
@@ -836,7 +837,7 @@
 	/* Check tag type. If it does not match, either the format is wrong,
 	 * either it is a unknown tag; so it is not really an error.
 	 */
-	marker = exif_marker_from_tag(ent->tag);
+	marker = exif_marker_from_tag(ent->tag, list);
 	if (!marker)
 		{
 		if (ent->format > EXIF_FORMAT_DOUBLE)
@@ -901,16 +902,26 @@
 	exif_item_copy_data(item, data, data_len, ent->format, byte_order);
 	exif->items = g_list_prepend(exif->items, item);
 
-	if (item->tag == TAG_EXIFOFFSET)
+	if (list == ExifKnownMarkersList)
 		{
-		parse_IFD_table(exif, tiff, swabed_data, size, byte_order);
+		switch (item->tag)
+			{
+			case TAG_EXIFOFFSET:
+				exif_parse_IFD_table(exif, tiff, swabed_data, size, byte_order, list);
+				break;
+			case TAG_EXIFMAKERNOTE:
+				format_exif_makernote_canon_parse(exif, tiff, swabed_data, size, byte_order);
+				break;
+			}
 		}
 
 	return 0;
 }
 
-static int parse_IFD_table(ExifData *exif, unsigned char *tiff, int offset,
-			   int size, int byte_order)
+int exif_parse_IFD_table(ExifData *exif,
+			 unsigned char *tiff, int offset,
+			 int size, int byte_order,
+			 const ExifMarker *list)
 {
 	int i, nb_entries;
 
@@ -924,7 +935,7 @@
 
 	for (i=0; i<nb_entries; ++i)
 		{
-		parse_IFD_entry(exif, tiff, offset+2+i*sizeof(IFDEntry), size, byte_order);
+		exif_parse_IFD_entry(exif, tiff, offset+2+i*sizeof(IFDEntry), size, byte_order, list);
 		}
 
 	return 0;
@@ -965,7 +976,7 @@
 
 	offset = swab_int32(((TIFFHeader*)tiff)->IFD_offset, byte_order);
 
-	return parse_IFD_table(exif, tiff, offset, size, byte_order);
+	return exif_parse_IFD_table(exif, tiff, offset, size, byte_order, ExifKnownMarkersList);
 }
 
 static int parse_JPEG(ExifData *exif, unsigned char *f, int size)
@@ -1132,7 +1143,7 @@
 
 gchar *exif_item_get_data_as_text(ExifItem *item)
 {
-	ExifMarker *marker;
+	const ExifMarker *marker;
 	gpointer data;
 	GString *string;
 	gchar *text;
--- a/src/exif.h	Fri May 27 02:17:18 2005 +0000
+++ b/src/exif.h	Fri Jun 03 06:07:02 2005 +0000
@@ -90,7 +90,7 @@
 {
 	ExifFormatType format;
 	int tag;
-	ExifMarker *marker;
+	const ExifMarker *marker;
 	int elements;
 	gpointer data;
 	int data_len;
@@ -106,12 +106,16 @@
 	ExifTextList	*list;
 };
 
+#define EXIF_MARKER_LIST_END { 0x0000, EXIF_FORMAT_UNKNOWN, 0, NULL, NULL, NULL }
+
 struct _ExifTextList
 {
 	int value;
 	const char* description;
 };
 
+#define EXIF_TEXT_LIST_END { -1, NULL }
+
 
 typedef struct _ExifFormattedText ExifFormattedText;
 struct _ExifFormattedText
@@ -188,4 +192,18 @@
 void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list);
 
 
+
+/* These funcs for use by makernote parsers only */
+
+ExifItem *exif_item_new(ExifFormatType format, unsigned int tag,
+			unsigned int elements, const ExifMarker *marker);
+void exif_item_copy_data(ExifItem *item, void *src, int len, ExifFormatType src_format, int byte_order);
+
+gint exif_parse_IFD_table(ExifData *exif,
+			  unsigned char *tiff, int offset,
+			  int size, int byte_order,
+			  const ExifMarker *list);
+
+
+
 #endif
--- a/src/format_canon.c	Fri May 27 02:17:18 2005 +0000
+++ b/src/format_canon.c	Fri Jun 03 06:07:02 2005 +0000
@@ -31,6 +31,8 @@
 #include "format_canon.h"
 #include "format_raw.h"
 
+#include "exif.h"
+
 
 #if 0
   #define CANON_DEBUG
@@ -470,4 +472,390 @@
 
 }
 
+/*
+ *-----------------------------------------------------------------------------
+ * EXIF Makernote for Canon
+ *-----------------------------------------------------------------------------
+ */
 
+typedef struct _CanonTag CanonTag;
+struct _CanonTag {
+	guint id;
+	const gchar *description;
+	ExifTextList *list;
+};
+
+static ExifTextList CanonSet1MacroMode[] = {
+	{ 1,	"macro" },
+	{ 2,	"normal" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1Quality[] = {
+	{ 2,	"normal" },
+	{ 3,	"fine" },
+	{ 5,	"superfine" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1FlashMode[] = {
+	{ 0,	"flash not fired" },
+	{ 1,	"auto" },
+	{ 2,	"on" },
+	{ 3,	"red eye reduction" },
+	{ 4,	"slow synchro" },
+	{ 5,	"auto with red eye reduction" },
+	{ 6,	"on with red eye reduction" },
+	{ 16,	"external flash" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1DriveMode[] = {
+	{ 0,	"single or timer" },
+	{ 1,	"continuous" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1FocusMode[] = {
+	{ 0,	"one-shot" },
+	{ 1,	"AI servo" },
+	{ 2,	"AI focus" },
+	{ 3,	"manual" },
+	{ 4,	"single" },
+	{ 5,	"continuous" },
+	{ 6,	"manual" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1ImageSize[] = {
+	{ 0,	"large" },
+	{ 1,	"medium" },
+	{ 2,	"small" },
+	/* where (or) does Medium 1/2 fit in here ? */
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1ShootingMode[] = {
+	{ 0,	"auto" },
+	{ 1,	"manual" },
+	{ 2,	"landscape" },
+	{ 3,	"fast shutter" },
+	{ 4,	"slow shutter" },
+	{ 5,	"night" },
+	{ 6,	"black and white" },
+	{ 7,	"sepia" },
+	{ 8,	"portrait" },
+	{ 9,	"sports" },
+	{ 10,	"macro" },
+	{ 11,	"panoramic focus" },
+	EXIF_TEXT_LIST_END
+};
+
+/* Don't think this is interpreted correctly/completely, A60 at 2.5x Digital sets value of 3 */
+static ExifTextList CanonSet1DigitalZoom[] = {
+	{ 0,	"none" },
+	{ 1,	"2x" },
+	{ 2,	"4x" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1ConSatSharp[] = {
+	{ 0,	"normal" },
+	{ 1,	"high" },
+	{ 65535,"low" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1ISOSpeed[] = {
+/*	{ 0,	"not set/see EXIF tag" }, */
+	{ 15,	"auto" },
+	{ 16,	"50" },
+	{ 17,	"100" },
+	{ 18,	"200" },
+	{ 19,	"400" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1MeteringMode[] = {
+	{ 3,	"evaluative" },
+	{ 4,	"partial" },
+	{ 5,	"center-weighted" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1FocusType[] = {
+	{ 0,	"manual" },
+	{ 1,	"auto" },
+	{ 3,	"macro" },
+	{ 8,	"locked" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1AutoFocusPoint[] = {
+	{ 12288,	"manual focus" },
+	{ 12289,	"auto" },
+	{ 12290,	"right" },
+	{ 12291,	"center" },
+	{ 12292,	"left" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1ExposureMode[] = {
+	{ 0,	"auto" },
+	{ 1,	"program" },
+	{ 2,	"Tv priority" },
+	{ 3,	"Av priority" },
+	{ 4,	"manual" },
+	{ 5,	"A-DEP" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1FlashFired[] = {
+	{ 0,	"no" },
+	{ 1,	"yes" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet1FocusCont[] = {
+	{ 0,	"no (single)" },
+	{ 1,	"yes" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifMarker CanonSet1[] = {
+/* 0 is length of array in bytes (2 x array size) */
+{ 1,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MacroMode",	"Macro mode",		CanonSet1MacroMode },
+{ 2,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SelfTimer",	"Self timer (10ths of second)", NULL },
+{ 3,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Quality",	"Quality",		CanonSet1Quality },
+{ 4,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashMode",	"Flash mode",		CanonSet1FlashMode },
+{ 5,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DriveMode",	"Drive mode",		CanonSet1DriveMode },
+{ 7,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusMode",	"Focus mode",		CanonSet1FocusMode },
+{ 10,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ImageSize",	"Image size",		CanonSet1ImageSize },
+{ 11,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ShootingMode","Shooting mode",	CanonSet1ShootingMode },
+ { 11,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureProgram",	"ExposureProgram",	CanonSet1ShootingMode },
+{ 12,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DigitalZoom",	"Digital zoom",		CanonSet1DigitalZoom },
+{ 13,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Contrast",	"Contrast",		CanonSet1ConSatSharp },
+{ 14,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Saturation",	"Saturation",		CanonSet1ConSatSharp },
+{ 15,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Sharpness",	"Sharpness",		CanonSet1ConSatSharp },
+{ 16,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ISOSpeed",	"ISO speed",		CanonSet1ISOSpeed },
+ { 16,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "ISOSpeedRatings",	"ISO speed",		CanonSet1ISOSpeed },
+{ 17,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MeteringMode","Metering mode",	CanonSet1MeteringMode },
+{ 18,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusType",	"Focus type",		CanonSet1FocusType },
+{ 19,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.AutoFocus",	"AutoFocus point",	CanonSet1AutoFocusPoint },
+{ 20,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ExposureMode","Exposure mode",	CanonSet1ExposureMode },
+ { 20,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureMode",		"Exposure mode",	CanonSet1ExposureMode },
+{ 23,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthLong","Long focal length", NULL },
+{ 24,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthShort","Short focal length", NULL },
+{ 25,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthUnits","Focal units per mm", NULL },
+{ 28,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashFired",	"Flash fired",		CanonSet1FlashFired },
+{ 29,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashDetails","Flash details",	NULL },
+{ 32,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ContinuousFocus","Continuous focus",	CanonSet1FocusCont },
+EXIF_MARKER_LIST_END
+};
+
+static ExifTextList CanonSet2WhiteBalance[] = {
+	{ 0,	"auto" },
+	{ 1,	"sunny" },
+	{ 2,	"cloudy" },
+	{ 3,	"tungsten" },
+	{ 4,	"flourescent" },
+	{ 5,	"flash" },
+	{ 6,	"custom" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonSet2FlashBias[] = {
+	{ 0x0000,	"0" },
+	{ 0x000c,	"0.33" },
+	{ 0x0010,	"0.5" },
+	{ 0x0014,	"0.67" },
+	{ 0x0020,	"1" },
+	{ 0x002c,	"1.33" },
+	{ 0x0030,	"1.5" },
+	{ 0x0034,	"1.67" },
+	{ 0x0040,	"2" },
+	{ 0xffc0,	"-2" },
+	{ 0xffcc,	"-1.67" },
+	{ 0xffd0,	"-1.5" },
+	{ 0xffd4,	"-1.33" },
+	{ 0xffe0,	"-1" },
+	{ 0xffec,	"-0.67" },
+	{ 0xfff0,	"-0.5" },
+	{ 0xfff4,	"-0.33" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifMarker CanonSet2[] = {
+/* 0 is length of array in bytes (2 x array size) */
+{ 7,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.WhiteBalance","White balance",	CanonSet2WhiteBalance },
+ { 7,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "LightSource",		"White balance",	CanonSet2WhiteBalance },
+{ 9,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SequenceNumber","Sequence number",	NULL },
+{ 15,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashBias",	"Flash bias",		CanonSet2FlashBias },
+/* distance needs more than just this (metric) value */
+{ 19,	EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SubjectDistance",	"Subject Distance", NULL },
+EXIF_MARKER_LIST_END
+};
+
+#if 0
+
+static ExifTextList CanonCustomEnable[] = {
+	{ 0,	"off" },
+	{ 1,	"on" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonCustomEnableInvert[] = {
+	{ 0,	"on" },
+	{ 1,	"off" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonCustomExposureLevel[] = {
+	{ 0,	"1/2 stop" },
+	{ 1,	"1/3 stop" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonCustomAVShutterSpeed[] = {
+	{ 0,	"auto" },
+	{ 1,	"1/200 (fixed)" },
+	EXIF_TEXT_LIST_END
+};
+
+static ExifTextList CanonCustomShutterCurtainSync[] = {
+	{ 0,	"1st" },
+	{ 1,	"2nd" },
+	EXIF_TEXT_LIST_END
+};
+
+static CanonTag CanonCustom[] = {
+	{ 1,	"Noise reduction",		CanonCustomEnable },
+/*	{ 2,	"Shutter/Auto Exposure Button Function", CanonCustomBTNShutter }, */
+	{ 3,	"Mirror lockup",		CanonCustomEnable },
+	{ 4,	"Tv/Av and exposure level",	CanonCustomExposureLevel },
+	{ 5,	"AF assist light",		CanonCustomEnableInvert },
+	{ 6,	"Shutter speed in Av mode",	CanonCustomAVShutterSpeed },
+/*	{ 7,	"Auto-Exposure bracketting sequence/auto cancellation",	CanonCustom }, */
+	{ 8,	"Shutter sync",			CanonCustomShutterCurtainSync },
+/*	{ 9,	"AF button function",		CanonCustom }, */
+	{ 10,	"Fill flash auto reduction",	CanonCustomEnableInvert },
+/*	{ 11,	"Menu button function",		CanonCustom }, */
+/*	{ 12,	"Set button function",		CanonCustom }, */
+	{ 13,	"Sensor cleaning",		CanonCustomEnable },
+	{ 0,    NULL, NULL }
+};
+
+#endif
+
+static ExifMarker CanonExifMarkersList[] = {
+ 	{ 1,	EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings1",		NULL, NULL },
+	{ 4,	EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings2",		NULL, NULL },
+	{ 6,	EXIF_FORMAT_STRING, -1,		"MkN.Canon.ImageType",		"Image type", NULL },
+	{ 7,	EXIF_FORMAT_STRING, -1,		"MkN.Canon.FirmwareVersion",	"Firmware version", NULL },
+	{ 8,	EXIF_FORMAT_LONG_UNSIGNED, 1,	"MkN.Canon.ImageNumber",	"Image number", NULL },
+	{ 9,	EXIF_FORMAT_STRING, -1,		"MkN.Canon.OwnerName",		"Owner name", NULL },
+	{ 12,	EXIF_FORMAT_BYTE_UNSIGNED, -1,	"MkN.Canon.SerialNumber",	"Camera serial number", NULL },
+	{ 15,	EXIF_FORMAT_SHORT_UNSIGNED, -1,	"MkN.Canon.CustomFunctions",	NULL, NULL },
+	EXIF_MARKER_LIST_END
+};
+
+static void canon_mknote_parse_settings(ExifData *exif,
+					guint16 *data, guint32 len, int byte_order,
+					ExifMarker *list)
+{
+	gint i;
+
+	i = 0;
+	while (list[i].tag != 0)
+		{
+		if (list[i].tag < len)
+			{
+			ExifItem *item;
+
+			item = exif_item_new(EXIF_FORMAT_SHORT_UNSIGNED, list[i].tag, 1, &list[i]);
+			exif_item_copy_data(item, &data[list[i].tag], 1, EXIF_FORMAT_SHORT_UNSIGNED, byte_order);
+			exif->items = g_list_prepend(exif->items, item);
+			}
+
+		i++;
+		}
+}
+
+#if 0
+static void canon_mknote_parse_convert(ExifData *exif)
+{
+	gint value;
+
+	/* seems we need more than only this value for distance */
+	if (exif_get_integer(exif, "MkN.Canon.SubjectDistance", &value))
+		{
+		static ExifMarker marker= { 0x9206, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,
+					    "SubjectDistance", "Subject distance", NULL };
+		ExifItem *item;
+		ExifRational *rational;
+
+		item = exif_item_new(marker.format, marker.tag, 1, &marker);
+		rational = item->data;
+		rational->num = value;
+		rational->den = 100;
+
+		exif->items = g_list_prepend(exif->items, item);
+		}
+
+	/* Serial Number untested */
+	if (exif_get_integer(exif, "MkN.Canon.SerialNumber", &value))
+		{
+		static ExifMarker marker= { 12, EXIF_FORMAT_STRING, -1,
+					    "SerialNumber", "Camera serial number", NULL };
+		ExifItem *item;
+		gchar *text;
+		gint l;
+
+		text = g_strdup_printf("%04X%05d", value & 0xff00 >> 8, value & 0x00ff);
+		l = strlen(text);
+		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);
+		}
+}
+#endif
+
+gint format_exif_makernote_canon_parse(ExifData *exif, unsigned char *tiff, int offset,
+				       int size, int byte_order)
+{
+	ExifItem *item;
+	gchar *text;
+	gint found;
+
+	text = exif_get_data_as_text(exif, "Make");
+	found = (text && strncasecmp(text, "Canon", 5) == 0);
+	g_free(text);
+
+	if (!found ||
+	    exif_parse_IFD_table(exif, tiff, offset, size, byte_order, CanonExifMarkersList) != 0)
+		{
+		return FALSE;
+		}
+
+	item = exif_get_item(exif, "MkN.Canon.Settings1");
+	if (item)
+		{
+		canon_mknote_parse_settings(exif, item->data, item->data_len, byte_order, CanonSet1);
+		}
+
+	item = exif_get_item(exif, "MkN.Canon.Settings2");
+	if (item)
+		{
+		canon_mknote_parse_settings(exif, item->data, item->data_len, byte_order, CanonSet2);
+		}
+
+#if 0
+	canon_mknote_parse_convert(exif);
+#endif
+
+	return TRUE;
+}
+
+
--- a/src/format_canon.h	Fri May 27 02:17:18 2005 +0000
+++ b/src/format_canon.h	Fri Jun 03 06:07:02 2005 +0000
@@ -19,6 +19,9 @@
 #define __FORMAT_RAW_CANON_H
 
 
+#include "exif.h"
+
+
 gint format_raw_test_canon(const void *data, const guint len,
 			   guint *image_offset, guint *exif_offset);
 
@@ -27,5 +30,9 @@
 			 { "\x49\x49\x2a\00", 4, "Canon cr2 format", format_raw_test_canon }
 
 
+gint format_exif_makernote_canon_parse(ExifData *exif, unsigned char *tiff, int offset,
+				       int size, int byte_order);
+
+
 #endif
 
--- a/src/format_raw.c	Fri May 27 02:17:18 2005 +0000
+++ b/src/format_raw.c	Fri Jun 03 06:07:02 2005 +0000
@@ -130,7 +130,7 @@
 	map_data = mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
 	if (map_data == MAP_FAILED)
 		{
-		printf("Failed to mmap of file %d\n", fd);
+		printf("Failed to mmap file %d\n", fd);
 		return FALSE;
 		}