5 * This software is released under the GNU General Public License (GNU GPL).
6 * Please read the included file COPYING for more information.
7 * This software comes with no warranty of any kind, use at your own risk!
10 * Code to add support for Canon CR2 and CRW files, version 0.2
12 * Developed by Daniel M. German, dmgerman at uvic.ca
14 * you can find the sources for this patch at http://turingmachine.org/~dmg/libdcraw/gqview/
31 #include "format_canon.h"
32 #include "format_raw.h"
38 *-----------------------------------------------------------------------------
39 * Raw (CR2, CRW) embedded jpeg extraction for Canon
40 *-----------------------------------------------------------------------------
49 int canonEnableDebug = 0;
50 /* This should be really a stack, but I am too lazy to implement */
51 #define DEBUG_ENABLE (canonEnableDebug = 0)
52 #define DEBUG_DISABLE (canonEnableDebug = 1)
53 /* It would be nice if these functions indented according to depth in the stack, but I am too lazy to implement */
55 #define DEBUG_ENTRY(a) (canonEnableDebug || fprintf(stderr, "Entering function: %s [%s:%d]\n", a, __FILE__, __LINE__))
56 #define DEBUG_EXIT(a) (canonEnableDebug || fprintf(stderr, "Exiting function: %s [%s:%d]\n", a, __FILE__, __LINE__))
57 #define DEBUG_1(a) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n", __FILE__, __LINE__))
58 #define DEBUG_2(a,b) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, __FILE__, __LINE__))
59 #define DEBUG_3(a,b,c) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, c, __FILE__, __LINE__))
64 #define DEBUG_ENTRY(a)
69 #define DEBUG_3(a,b,c)
76 The problem with gqview is that sometimes the data is to be read from
77 a file, and sometimes it is in memory. This function tries to isolate
78 the rest of the code from having to deal with both cases
80 This function reads a 4 byte unsigned integer, and fixes its endianism.
82 If fd >= 0 then the value is read from the corresponding file descriptor
84 in that case, if offset is > 0, then the value is read from that offset
86 otherwise it is read from the current file pointer
88 if fd < 0 then the value is read from the memory pointed by data + offset
91 offset is a pointer to the actual offset of the file.
93 sizeInt can be 2 or 4 (it is the number of bytes to read)
95 RETURNS true is no error, false if it can't read the value
99 static int canon_read_int(unsigned int *offset, const void *data, int sizeInt, unsigned int *value )
103 DEBUG_ENTRY("canon_read_int");
104 /* Verify values before we do anything */
105 if (sizeInt != 2 && sizeInt != 4) return FALSE;
106 if (offset == NULL) return FALSE;
107 if (*offset <= 0) return FALSE;
108 if (data == NULL) return FALSE;
109 if (value == NULL) return FALSE;
112 *value = GUINT32_FROM_LE(*(guint32*)(data + *offset));
114 DEBUG_3("Read 4 bytes %d %x", *value, *value);
116 *value = GUINT16_FROM_LE(*(guint16*)(data + *offset));
118 DEBUG_3("Read 2 bytes %d %x", *value, *value);
121 DEBUG_EXIT("canon_read_int");
127 #define CANON_HEADER_SIZE 26
131 The CR2 format is really a TIFF format. It is nicely documented in the TIFF V 6.0 document available from adobe.
133 The CR2 file contains two thumbnails, one tiny and one decent sized. The record Id of the latter is 0x0111.
135 The photo info is also available, in EXIF, and it looks like I don't need to do anything! Yeah!
139 static int canon_cr2_process_directory(void *data, int offsetIFD, guint *jpegLocation, guint *exifLocation)
142 int returnValue = FALSE;
144 DEBUG_ENTRY("canon_cr2_process_directory");
146 /* The directory is a link list, after an array of records, the next 4 byptes point to the offset of the next directory.
148 All offsets are absolution within the file (in CRWs the offsets are relative ).
152 while (offsetIFD != 0 && offsetIFD != 0xFFFF) {
155 /* Read directory, we start by reading number of entries in the directory */
158 if (!canon_read_int(&offset, data, 2, &countEntries)) {
161 DEBUG_2("Number of entries: %d\n", countEntries);
163 for (i=0;i<countEntries;i++) {
164 /* read each entry */
172 /* read record type */
173 if (!canon_read_int(&offset, data, 2, &recordId)) {
177 /* Did we find the JPEG */
178 if (recordId == 0x0111) {
179 DEBUG_1("This is the record to find**********************\n");
181 if (!canon_read_int(&offset, data, 4, jpegLocation)) {
184 DEBUG_3("JPEG Location %d 0x%x\n", *jpegLocation, *jpegLocation);
185 /* We don't want to keep reading, because there is another
186 0x0111 record at the end that contains the raw data */
190 /* advance pointer by skipping rest of record */
194 /* The next 4 bytes are the offset of next directory, if zero we are done
197 if (!canon_read_int(&offset, data, 4, &offsetIFD)) {
200 DEBUG_3("Value of NEXT offsetIFD: %d 0x%x\n", offsetIFD, offsetIFD);
204 DEBUG_1("Going to return true");
207 DEBUG_EXIT("canon_cr2_process_directory");
215 static int format_raw_test_canon_cr2(void *data, const guint len,
216 guint *image_offset, guint *exif_offset)
220 unsigned int offset = 4;
223 int returnValue = FALSE;
224 void *jpgInDataOffset;
226 DEBUG_ENTRY("format_raw_test_canon_cr2");
228 /* Verify signature */
229 if (memcmp(data, "\x49\x49\x2a\00", 4) != 0) {
230 DEBUG_1("This is not a CR2");
234 /* Get address of first directory */
235 offsetIFD = GUINT32_FROM_LE(*(guint32*)(data + 4));
238 DEBUG_2("Value of offsetIFD: %d\n", offsetIFD);
240 returnValue = canon_cr2_process_directory(data, offsetIFD, image_offset, exif_offset);
243 jpgInDataOffset = data + *image_offset;
245 /* Make sure we really got a JPEG */
247 if (memcmp(jpgInDataOffset, "\xff\xd8",2) != 0) {
248 /* It is not at the JPEG! */
249 DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset);
255 DEBUG_EXIT("format_raw_test_canon_cr2");
261 gint format_canon_raw(unsigned char *data, const guint len,
262 guint *image_offset, guint *exif_offset)
266 /* There are at least 2 types of Canon raw files. CRW and CR2
268 CRW files have a proprietary format.
276 HEADER_LENGTH 32 bytes
277 int2 byteOrder; Always II (MM Motorola ---big endian, II Intel --little endian)
278 int4 length; Should be 26
279 char identifier[8];type HEAP, subtype heap CCDR
285 int returnValue = FALSE;
286 int heapHeaderOffset = 0;
287 int heapRecordsCount = 0;
293 unsigned int currentOffset;
294 /* File has to be little endian, first two bytes II */
299 if (format_raw_test_canon_cr2((void *)data, len, image_offset, exif_offset)) {
303 if (memcmp("II", data, 2) != 0) {
306 /* NO DEBUG BEFORE THIS POINT, we want to debug only Canon */
308 DEBUG_ENTRY("format_raw_test_canon");
310 DEBUG_2("Length of buffer read %u", len);
312 DEBUG_2("CRW header length Data %d", GUINT32_FROM_LE(*(guint32*)(data + 2)));
314 /* the length has to be CANON_HEADER_SIZE */
315 if (GUINT32_FROM_LE(*(guint32*)(data + 2)) != CANON_HEADER_SIZE) {
316 DEBUG_1("It is not the right size");
320 if (!memcmp("HEAPCCDR", data+6, 8) == 0) {
321 DEBUG_1("This file is not a Canon CRW raw photo");
326 /* Ok, so now we know that this is a CRW file */
328 /* The heap is a strange data structure. It is recursive, so a record
329 can contain a heap itself. That is indeed the case for the photo information
330 reecord. Luckily the first heap contains the jpeg, so we don't need to do
331 any recursive processing.
333 Its "header" is a the end. The header is a sequence of records,
334 and the data of each record is at the beginning of the heap
344 | # records | it should be 3
351 number of records: 2 bytes
352 for each record (10 bytes long)
357 In some records the length and offset are actually data,
358 but none for the ones in the first heap.
360 the offset is with respect to the beginning of the heap, not the
361 beginning of the file. That allows heaps to be "movable"
363 For the purpose of finding the JPEG, all we need is to scan the fist heap,
364 which contains the following record types:
366 0x2005 Record RAW data
367 0x2007 Record JPEG data
368 0x300a Record with photo info
374 DEBUG_2("We have a problem, the length is too small %d ", len);
377 currentOffset = len-4;
380 /* The last 4 bytes have the offset of the header of the heap */
381 if (!canon_read_int(¤tOffset, data, 4, &heapHeaderOffset))
384 /* The heapoffset has to be adjusted to the actual file size, the header is CANON_HEADER_SIZE bytes long */
385 heapHeaderOffset += CANON_HEADER_SIZE;
386 DEBUG_2("heap header Offset %d ", heapHeaderOffset);
388 /* Just check, it does not hurt, we don't want to crash */
389 if (heapHeaderOffset > len)
392 currentOffset = heapHeaderOffset;
393 /* Let us read the number of records in the heap */
394 if (!canon_read_int(¤tOffset, data, 2, &heapRecordsCount))
397 DEBUG_2("heap record count %d ", heapRecordsCount);
399 if (heapRecordsCount != 3) {
400 /* In all the cameras I have seen, this is always 3
401 if not, something is wrong, so just quit */
409 const void *jpgInDataOffset;
410 /* Read each record, to find jpg, it should be second */
412 if (!canon_read_int(¤tOffset, data, 2, &recordType))
415 DEBUG_2("record type 0x%x ", recordType);
417 if (recordType != 0x2007) {
418 /* Go to the next record, don't waste time,
419 but first, eat 8 bytes from header */
421 continue; /* Nah, wrong record, go to next */
423 /* Bingo, we are at the JPEG record */
426 if (!canon_read_int(¤tOffset, data, 4, &recordLength))
429 DEBUG_2("record length %d ", recordLength);
433 if (!canon_read_int(¤tOffset, data, 4, &recordOffset))
436 DEBUG_2("record offset 0x%d ", recordOffset);
438 /* Great, we now know where the JPEG is!
439 it is CANON_HEADER_SIZE (size of CRW header) + recordOffset
442 *image_offset = CANON_HEADER_SIZE + recordOffset;
443 DEBUG_2("image offset %d ", *image_offset);
445 /* keep checking for potential errors */
446 if (*image_offset > len) {
449 /* Get the JPEG is */
451 jpgInDataOffset = data + *image_offset;
453 if (memcmp(jpgInDataOffset, "\xff\xd8\xff\xdb",4) != 0) {
454 /* It is not at the JPEG! */
455 DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset);
461 /* undo whatever we need in case of an error*/
462 DEBUG_1("We scan all records, but nothing was found!!!!!!!!!!!!!!!!!!");
465 /* At this point we are returning */
468 DEBUG_1("****We got an embedded JPEG for a canon CRW");
472 DEBUG_EXIT("format_raw_test_canon");
483 *-----------------------------------------------------------------------------
484 * EXIF Makernote for Canon
485 *-----------------------------------------------------------------------------
488 static ExifTextList CanonSet1MacroMode[] = {
494 static ExifTextList CanonSet1Quality[] = {
502 static ExifTextList CanonSet1FlashMode[] = {
503 { 0, "flash not fired" },
506 { 3, "red-eye reduction" },
508 { 5, "auto + red-eye reduction" },
509 { 6, "on + red-eye reduction" },
510 { 16, "external flash" },
514 static ExifTextList CanonSet1DriveMode[] = {
515 { 0, "single or timer" },
520 static ExifTextList CanonSet1FocusMode[] = {
521 { 0, "one-shot AF" },
522 { 1, "AI servo AF" },
523 { 2, "AI focus AF" },
531 static ExifTextList CanonSet1ImageSize[] = {
535 /* where (or) does Medium 1/2 fit in here ? */
539 static ExifTextList CanonSet1ShootingMode[] = {
543 { 3, "fast shutter" },
544 { 4, "slow shutter" },
546 { 6, "black and white" },
555 /* Don't think this is interpreted correctly/completely, A60 at 2.5x Digital sets value of 3 */
556 static ExifTextList CanonSet1DigitalZoom[] = {
564 static ExifTextList CanonSet1ConSatSharp[] = {
571 static ExifTextList CanonSet1ISOSpeed[] = {
572 /* { 0, "not set/see EXIF tag" }, */
581 static ExifTextList CanonSet1MeteringMode[] = {
586 { 5, "center-weighted" },
590 static ExifTextList CanonSet1FocusType[] = {
600 static ExifTextList CanonSet1AutoFocusPoint[] = {
601 { 0x2005, "manual AF point selection" },
602 { 0x3000, "manual focus" },
605 { 0x3003, "center" },
607 { 0x4001, "auto AF point selection" },
611 static ExifTextList CanonSet1ExposureMode[] = {
614 { 2, "Tv priority" },
615 { 3, "Av priority" },
621 static ExifTextList CanonSet1FlashFired[] = {
627 static ExifTextList CanonSet1FocusCont[] = {
628 { 0, "no (single)" },
633 static ExifMarker CanonSet1[] = {
634 /* 0 is length of array in bytes (2 x array size) */
635 { 1, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MacroMode", "Macro mode", CanonSet1MacroMode },
636 { 2, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SelfTimer", "Self timer (10ths of second)", NULL },
637 { 3, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Quality", "Quality", CanonSet1Quality },
638 { 4, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashMode", "Flash mode", CanonSet1FlashMode },
639 { 5, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DriveMode", "Drive mode", CanonSet1DriveMode },
640 { 7, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusMode", "Focus mode", CanonSet1FocusMode },
641 { 10, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ImageSize", "Image size", CanonSet1ImageSize },
642 { 11, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ShootingMode","Shooting mode", CanonSet1ShootingMode },
643 { 11, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureProgram", "ExposureProgram", CanonSet1ShootingMode },
644 { 12, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DigitalZoom", "Digital zoom", CanonSet1DigitalZoom },
645 { 13, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Contrast", "Contrast", CanonSet1ConSatSharp },
646 { 14, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Saturation", "Saturation", CanonSet1ConSatSharp },
647 { 15, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Sharpness", "Sharpness", CanonSet1ConSatSharp },
648 { 16, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ISOSpeed", "ISO speed", CanonSet1ISOSpeed },
649 { 16, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ISOSpeedRatings", "ISO speed", CanonSet1ISOSpeed },
650 { 17, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MeteringMode","Metering mode", CanonSet1MeteringMode },
651 { 18, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusType", "Focus type", CanonSet1FocusType },
652 { 19, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.AutoFocus", "AutoFocus point", CanonSet1AutoFocusPoint },
653 { 20, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ExposureMode","Exposure mode", CanonSet1ExposureMode },
654 { 20, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureMode", "Exposure mode", CanonSet1ExposureMode },
655 { 23, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthLong","Long focal length", NULL },
656 { 24, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthShort","Short focal length", NULL },
657 { 25, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthUnits","Focal units per mm", NULL },
658 { 28, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashFired", "Flash fired", CanonSet1FlashFired },
659 { 29, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashDetails","Flash details", NULL },
660 { 32, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ContinuousFocus","Continuous focus", CanonSet1FocusCont },
664 static ExifTextList CanonSet2WhiteBalance[] = {
669 { 4, "fluorescent" },
672 { 7, "black and white" },
675 { 14, "daylight fluorescent" },
676 { 17, "underwater" },
680 static ExifTextList CanonSet2FlashBias[] = {
701 static ExifMarker CanonSet2[] = {
702 /* 0 is length of array in bytes (2 x array size) */
703 { 7, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.WhiteBalance","White balance", CanonSet2WhiteBalance },
704 { 7, EXIF_FORMAT_SHORT_UNSIGNED, 1, "LightSource", "White balance", CanonSet2WhiteBalance },
705 { 9, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SequenceNumber","Sequence number", NULL },
706 { 15, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashBias", "Flash bias", CanonSet2FlashBias },
707 /* distance needs more than just this (metric) value */
708 { 19, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SubjectDistance", "Subject Distance", NULL },
714 static ExifTextList CanonCustomEnable[] = {
720 static ExifTextList CanonCustomEnableInvert[] = {
726 static ExifTextList CanonCustomExposureLevel[] = {
732 static ExifTextList CanonCustomAVShutterSpeed[] = {
734 { 1, "1/200 (fixed)" },
738 static ExifTextList CanonCustomShutterCurtainSync[] = {
744 static ExifMarker CanonCustom[] = {
745 { 1, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.NoiseReduction", "Noise reduction", CanonCustomEnable },
746 /*{ 2, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.BtnFuncShutter",
747 "Shutter/Auto exposure button function",CanonCustomBTNShutter }, */
748 { 3, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MirrorLockup", "Mirror lockup", CanonCustomEnable },
749 { 4, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.TvAvExposureLevel",
750 "Tv/Av and exposure level", CanonCustomExposureLevel },
751 { 5, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.AFAssistLight", "AF assist light", CanonCustomEnableInvert },
752 { 6, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.AvShutterSpeed",
753 "Shutter speed in Av mode", CanonCustomAVShutterSpeed },
754 /*{ 7, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.AutoBracket",
755 "Auto-Exposure bracketting sequence/auto cancellation", CanonCustom }, */
756 { 8, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ShutterSync", "Shutter sync", CanonCustomShutterCurtainSync },
757 /* { 9, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.BtnFuncAF", "AF button function", CanonCustom }, */
758 { 10, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FillFlashReduction",
759 "Fill flash auto reduction", CanonCustomEnableInvert },
760 /*{ 11, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.BtnFuncMenu",
761 "Menu button function", CanonCustom }, */
762 /*{ 12, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.BtnFuncSet", "Set button function", CanonCustom }, */
763 { 13, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SensorCleaning", "Sensor cleaning", CanonCustomEnable },
769 static ExifMarker CanonExifMarkersList[] = {
770 { 1, EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings1", NULL, NULL },
771 { 4, EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings2", NULL, NULL },
772 { 6, EXIF_FORMAT_STRING, -1, "MkN.Canon.ImageType", "Image type", NULL },
773 { 7, EXIF_FORMAT_STRING, -1, "MkN.Canon.FirmwareVersion", "Firmware version", NULL },
774 { 8, EXIF_FORMAT_LONG_UNSIGNED, 1, "MkN.Canon.ImageNumber", "Image number", NULL },
775 { 9, EXIF_FORMAT_STRING, -1, "MkN.Canon.OwnerName", "Owner name", NULL },
776 { 12, EXIF_FORMAT_LONG_UNSIGNED, -1, "MkN.Canon.SerialNumber", "Camera serial number", NULL },
777 { 15, EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.CustomFunctions", NULL, NULL },
781 static void canon_mknote_parse_settings(ExifData *exif,
782 guint16 *data, guint32 len, ExifByteOrder bo,
788 while (list[i].tag != 0)
790 if (list[i].tag < len)
794 item = exif_item_new(EXIF_FORMAT_SHORT_UNSIGNED, list[i].tag, 1, &list[i]);
795 exif_item_copy_data(item, &data[list[i].tag], 2, EXIF_FORMAT_SHORT_UNSIGNED, bo);
796 exif->items = g_list_prepend(exif->items, item);
804 static void canon_mknote_parse_convert(ExifData *exif)
809 /* seems we need more than only this value for distance */
810 if (exif_get_integer(exif, "MkN.Canon.SubjectDistance", &value))
812 static ExifMarker marker= { 0x9206, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,
813 "SubjectDistance", "Subject distance", NULL };
815 ExifRational *rational;
817 item = exif_item_new(marker.format, marker.tag, 1, &marker);
818 rational = item->data;
819 rational->num = value;
822 exif->items = g_list_prepend(exif->items, item);
825 result = exif_get_item(exif, "MkN.Canon.SerialNumber");
826 if (result && result->format == EXIF_FORMAT_LONG_UNSIGNED && result->data_len == 4)
828 static ExifMarker marker= { 12, EXIF_FORMAT_STRING, -1,
829 "SerialNumber", "Camera serial number", NULL };
835 n = (guint32)((guint32 *)(result->data))[0];
836 text = g_strdup_printf("%04X%05d", n & 0xffff0000 >> 8, n & 0x0000ffff);
837 l = strlen(text) + 1;
838 item = exif_item_new(marker.format, marker.tag, l, &marker);
839 memcpy(item->data, text, l);
842 exif->items = g_list_prepend(exif->items, item);
847 gint format_canon_makernote(ExifData *exif, unsigned char *tiff, guint offset,
848 guint size, ExifByteOrder bo)
852 if (exif_parse_IFD_table(exif, tiff, offset, size, bo, 0, CanonExifMarkersList) != 0)
857 item = exif_get_item(exif, "MkN.Canon.Settings1");
860 canon_mknote_parse_settings(exif, item->data, item->data_len, bo, CanonSet1);
863 item = exif_get_item(exif, "MkN.Canon.Settings2");
866 canon_mknote_parse_settings(exif, item->data, item->data_len, bo, CanonSet2);
870 canon_mknote_parse_convert(exif);