Tue Jun 7 03:47:03 2005 John Ellis <johne@verizon.net>
[geeqie.git] / src / format_canon.c
1 /*
2  *  GQView
3  *  (C) 2005 John Ellis
4  *
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!
8  *
9  *
10  * Code to add support for Canon CR2 and CRW files, version 0.2
11  *
12  * Developed by Daniel M. German, dmgerman at uvic.ca 
13  *
14  * you can find the sources for this patch at http://turingmachine.org/~dmg/libdcraw/gqview/
15  *
16  */
17
18 #ifdef HAVE_CONFIG_H
19 #  include "config.h"
20 #endif
21
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <glib.h>
28
29 #include "intl.h"
30
31 #include "format_canon.h"
32 #include "format_raw.h"
33
34 #include "exif.h"
35
36
37 /*
38  *-----------------------------------------------------------------------------
39  * Raw (CR2, CRW) embedded jpeg extraction for Canon
40  *-----------------------------------------------------------------------------
41  */
42
43
44 #if 0
45   #define CANON_DEBUG
46 #endif
47
48 #ifdef CANON_DEBUG
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 */
54
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__))
60
61 #else
62 #define DEBUG_ENABLE
63 #define DEBUG_DISABLE 
64 #define DEBUG_ENTRY(a)
65 #define DEBUG_EXIT(a)
66
67 #define DEBUG_1(a) 
68 #define DEBUG_2(a,b)
69 #define DEBUG_3(a,b,c)
70 #endif
71
72
73 /* canon_read_int4 
74
75
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
79
80 This function reads a 4 byte unsigned integer, and fixes its endianism.
81
82 If fd >= 0 then the value is read from the corresponding file descriptor
83    
84    in that case, if offset is > 0, then the value is read from that offset
85
86    otherwise it is read from the current file pointer 
87
88 if fd < 0 then the value is read from the memory pointed by data + offset
89
90
91 offset is a pointer to the actual offset of the file.
92
93 sizeInt can be 2 or 4 (it is the number of bytes to read)
94
95 RETURNS true is no error, false if it can't read the value
96
97
98 */
99 static int canon_read_int(unsigned int *offset, const void *data, int sizeInt, unsigned int *value )
100 {
101   DEBUG_DISABLE;
102
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;
110
111   if (sizeInt == 4) {
112     *value = GUINT32_FROM_LE(*(guint32*)(data + *offset));      
113     *offset +=4;
114     DEBUG_3("Read 4 bytes %d %x", *value, *value);
115   } else {
116     *value = GUINT16_FROM_LE(*(guint16*)(data + *offset));
117     *offset +=2;
118     DEBUG_3("Read 2 bytes %d %x", *value, *value);
119   }
120
121   DEBUG_EXIT("canon_read_int");
122
123   DEBUG_ENABLE;
124   return TRUE;
125 }
126
127 #define CANON_HEADER_SIZE                   26
128
129 /*
130
131  The CR2 format is really a TIFF format. It is nicely documented in the TIFF V 6.0 document available from adobe.
132
133   The CR2 file contains two thumbnails, one tiny and one decent sized. The record Id of the latter is 0x0111.
134
135   The photo info is also available, in EXIF, and it looks like I don't need to do anything! Yeah!
136
137 */
138
139 static int canon_cr2_process_directory(void *data, int offsetIFD, guint *jpegLocation, guint *exifLocation) 
140 {
141   unsigned int offset;
142   int returnValue = FALSE;
143
144   DEBUG_ENTRY("canon_cr2_process_directory");
145
146   /* The directory is a link list, after an array of records, the next 4 byptes point to the offset of the next directory.
147
148   All offsets are absolution within the file (in CRWs the offsets are relative ).
149
150   */
151
152   while (offsetIFD != 0 && offsetIFD != 0xFFFF) {
153     int countEntries=0;
154     int i;
155     /* Read directory, we start by reading number of entries in the directory */
156
157     offset = offsetIFD;
158     if (!canon_read_int(&offset, data, 2, &countEntries)) {
159       goto return_only;
160     }
161     DEBUG_2("Number of entries: %d\n", countEntries);
162
163     for (i=0;i<countEntries;i++) {
164       /* read each entry */
165
166       int recordId;
167 #if 0
168       int format;
169       int size;
170 #endif
171
172       /* read record type */
173       if (!canon_read_int(&offset, data, 2, &recordId)) {
174         goto return_only;
175       }
176
177       /* Did we find the JPEG */
178       if (recordId == 0x0111) { 
179         DEBUG_1("This is the record to find**********************\n");
180         offset +=6;
181         if (!canon_read_int(&offset, data, 4, jpegLocation)) {
182           goto return_only;
183         }
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 */
187         returnValue = TRUE;
188         goto return_only;
189       } else {
190         /* advance pointer by skipping rest of record */
191         offset += 10;
192       }
193     }
194     /* The next 4 bytes are the offset of next directory, if zero we are done
195        
196      */
197     if (!canon_read_int(&offset, data, 4, &offsetIFD)) {
198       goto return_only;
199     }
200     DEBUG_3("Value of NEXT offsetIFD: %d 0x%x\n", offsetIFD, offsetIFD);
201   }
202
203   returnValue = TRUE;
204   DEBUG_1("Going to return true");
205
206  return_only:
207   DEBUG_EXIT("canon_cr2_process_directory");
208
209   return TRUE;
210
211
212 }
213
214
215 static int format_raw_test_canon_cr2(void *data, const guint len,
216                                      guint *image_offset, guint *exif_offset)
217 {
218 #if 0
219   char signature[4];
220   unsigned int offset = 4;
221 #endif
222   int offsetIFD;
223   int returnValue = FALSE;
224   void *jpgInDataOffset;
225
226   DEBUG_ENTRY("format_raw_test_canon_cr2");
227
228   /* Verify signature */
229   if (memcmp(data, "\x49\x49\x2a\00", 4) != 0) {
230     DEBUG_1("This is not a CR2");
231     goto return_only;
232   }
233
234   /* Get address of first directory */
235   offsetIFD = GUINT32_FROM_LE(*(guint32*)(data + 4));
236
237
238   DEBUG_2("Value of offsetIFD: %d\n", offsetIFD);
239
240   returnValue = canon_cr2_process_directory(data, offsetIFD, image_offset, exif_offset);
241
242   if (returnValue) {
243     jpgInDataOffset = data + *image_offset;
244
245     /* Make sure we really got a JPEG */
246
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);
250       returnValue = FALSE;
251     }
252   }
253
254 return_only:
255   DEBUG_EXIT("format_raw_test_canon_cr2");
256
257   return returnValue;
258 }
259
260
261 gint format_canon_raw(const void *data, const guint len,
262                       guint *image_offset, guint *exif_offset)
263 {
264
265
266   /* There are at least 2 types of Canon raw files. CRW and CR2 
267
268   CRW files have a proprietary format. 
269
270   HEADER
271   Heap
272     RAW   data
273     JPEG  data
274     PHoto data
275
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
280    int2     version;
281    int2     subversion;
282    char     unused[14]; 
283   */
284
285   int returnValue = FALSE;
286   int heapHeaderOffset = 0;
287   int heapRecordsCount = 0;
288 #if 0
289   guint32 rawInt4;
290   guint16 rawInt2;
291 #endif
292   int i;
293   unsigned int currentOffset;
294   /* File has to be little endian, first two bytes II */
295
296   if (len < 100) 
297     return FALSE;
298
299   if (format_raw_test_canon_cr2((void *)data, len, image_offset, exif_offset)) {
300     return TRUE;
301   }
302
303   if (memcmp("II", data, 2) != 0) {
304     return FALSE;
305   }
306   /* NO DEBUG BEFORE THIS POINT, we want to debug only Canon */
307   
308   DEBUG_ENTRY("format_raw_test_canon");
309
310   DEBUG_2("Length of buffer read %u", len);
311
312   DEBUG_2("CRW header length Data %d", GUINT32_FROM_LE(*(guint32*)(data + 2)));
313
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");
317     goto return_only;
318   }
319   
320   if (!memcmp("HEAPCCDR", data+6, 8) == 0) {
321     DEBUG_1("This file is not a Canon CRW raw photo");
322     goto return_only;
323
324    }
325    
326   /* Ok, so now we know that this is a CRW file */
327
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. 
332
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
335
336    +-----------------+
337    | data raw        |
338    +-----------------+
339    | data jpeg       |
340    +-----------------+
341    | data photo info |
342    +-----------------+
343    |header of heap   |
344    | # records       |   it should be 3
345    |      raw info   |
346    |      jpeg info  |
347    |      photo info |
348    +-----------------+
349
350    The header contains 
351       number of records: 2 bytes
352       for each record (10 bytes long)
353           type:    2 bytes
354           length:  4 bytes 
355           offset:  4 bytes 
356           
357      In some records the length and offset are actually data,
358      but none for the ones in the first heap.
359      
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"
362
363    For the purpose of finding the JPEG, all we need is to scan the fist heap,
364    which contains the following record types:
365
366     0x2005 Record RAW data
367     0x2007 Record JPEG data
368     0x300a Record with photo info
369
370   */
371
372
373   if (len < 0x10000) {
374     DEBUG_2("We have a problem, the length is too small %d ", len);
375     goto return_only;
376   }
377   currentOffset = len-4;
378
379
380   /* The last 4 bytes have the offset of the header of the heap */
381   if (!canon_read_int(&currentOffset, data, 4, &heapHeaderOffset)) 
382     goto return_only;
383   
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);
387   
388   /* Just check, it does not hurt, we don't want to crash */
389   if (heapHeaderOffset > len) 
390     goto return_only;
391
392   currentOffset =   heapHeaderOffset;
393   /* Let us read the number of records in the heap */
394   if (!canon_read_int(&currentOffset, data, 2, &heapRecordsCount))
395     goto return_only;
396   
397   DEBUG_2("heap record count %d ", heapRecordsCount);
398     
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 */
402     goto return_only;
403   }
404     
405   for (i=0;i<3;i++) {
406     int recordType;
407     int recordOffset;
408     int recordLength;
409     const void *jpgInDataOffset;
410     /* Read each record, to find jpg, it should be second */
411     
412     if (!canon_read_int(&currentOffset, data, 2, &recordType))
413       goto return_only;
414     
415     DEBUG_2("record type 0x%x ", recordType);
416     
417     if (recordType != 0x2007) {
418       /* Go to the next record, don't waste time, 
419          but first, eat 8 bytes from header */
420       currentOffset += 8;
421       continue; /* Nah, wrong record, go to next */
422     }
423     /* Bingo, we are at the JPEG record */
424     
425     /* Read length */
426     if (!canon_read_int(&currentOffset, data, 4, &recordLength))
427       goto return_only;
428     
429     DEBUG_2("record length %d ", recordLength);
430     
431     /* Read offset */
432     
433     if (!canon_read_int(&currentOffset, data, 4, &recordOffset))
434       goto return_only;
435     
436     DEBUG_2("record offset 0x%d ", recordOffset);
437     
438     /* Great, we now know where the JPEG is! 
439        it is CANON_HEADER_SIZE (size of CRW header) + recordOffset 
440     */
441     
442     *image_offset =  CANON_HEADER_SIZE + recordOffset;
443     DEBUG_2("image offset %d ", *image_offset);
444     
445     /* keep checking for potential errors */
446     if (*image_offset > len) {
447       goto return_only;
448     }
449     /* Get the JPEG is */
450     
451     jpgInDataOffset = data + *image_offset;
452
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);
456       goto return_only;
457     }
458     returnValue = TRUE;
459     goto return_only;
460   }
461  /* undo whatever we need in case of an error*/
462   DEBUG_1("We scan all records, but nothing was found!!!!!!!!!!!!!!!!!!");
463
464
465   /* At this point we are returning */
466 return_only:
467   if (returnValue) {
468     DEBUG_1("****We got an embedded  JPEG for a canon CRW");
469
470   }
471
472   DEBUG_EXIT("format_raw_test_canon");
473   return returnValue;
474
475 #undef DEBUG_2
476 #undef DEBUG
477 #undef DEBUG_ENTRY
478 #undef DEBUG_EXIT
479
480 }
481
482 /*
483  *-----------------------------------------------------------------------------
484  * EXIF Makernote for Canon
485  *-----------------------------------------------------------------------------
486  */
487
488 static ExifTextList CanonSet1MacroMode[] = {
489         { 1,    "macro" },
490         { 2,    "normal" },
491         EXIF_TEXT_LIST_END
492 };
493
494 static ExifTextList CanonSet1Quality[] = {
495         { 2,    "normal" },
496         { 3,    "fine" },
497         { 5,    "superfine" },
498         EXIF_TEXT_LIST_END
499 };
500
501 static ExifTextList CanonSet1FlashMode[] = {
502         { 0,    "flash not fired" },
503         { 1,    "auto" },
504         { 2,    "on" },
505         { 3,    "red eye reduction" },
506         { 4,    "slow synchro" },
507         { 5,    "auto with red eye reduction" },
508         { 6,    "on with red eye reduction" },
509         { 16,   "external flash" },
510         EXIF_TEXT_LIST_END
511 };
512
513 static ExifTextList CanonSet1DriveMode[] = {
514         { 0,    "single or timer" },
515         { 1,    "continuous" },
516         EXIF_TEXT_LIST_END
517 };
518
519 static ExifTextList CanonSet1FocusMode[] = {
520         { 0,    "one-shot" },
521         { 1,    "AI servo" },
522         { 2,    "AI focus" },
523         { 3,    "manual" },
524         { 4,    "single" },
525         { 5,    "continuous" },
526         { 6,    "manual" },
527         EXIF_TEXT_LIST_END
528 };
529
530 static ExifTextList CanonSet1ImageSize[] = {
531         { 0,    "large" },
532         { 1,    "medium" },
533         { 2,    "small" },
534         /* where (or) does Medium 1/2 fit in here ? */
535         EXIF_TEXT_LIST_END
536 };
537
538 static ExifTextList CanonSet1ShootingMode[] = {
539         { 0,    "auto" },
540         { 1,    "manual" },
541         { 2,    "landscape" },
542         { 3,    "fast shutter" },
543         { 4,    "slow shutter" },
544         { 5,    "night" },
545         { 6,    "black and white" },
546         { 7,    "sepia" },
547         { 8,    "portrait" },
548         { 9,    "sports" },
549         { 10,   "macro" },
550         { 11,   "panoramic focus" },
551         EXIF_TEXT_LIST_END
552 };
553
554 /* Don't think this is interpreted correctly/completely, A60 at 2.5x Digital sets value of 3 */
555 static ExifTextList CanonSet1DigitalZoom[] = {
556         { 0,    "none" },
557         { 1,    "2x" },
558         { 2,    "4x" },
559         EXIF_TEXT_LIST_END
560 };
561
562 static ExifTextList CanonSet1ConSatSharp[] = {
563         { 0,    "normal" },
564         { 1,    "high" },
565         { 65535,"low" },
566         EXIF_TEXT_LIST_END
567 };
568
569 static ExifTextList CanonSet1ISOSpeed[] = {
570 /*      { 0,    "not set/see EXIF tag" }, */
571         { 15,   "auto" },
572         { 16,   "50" },
573         { 17,   "100" },
574         { 18,   "200" },
575         { 19,   "400" },
576         EXIF_TEXT_LIST_END
577 };
578
579 static ExifTextList CanonSet1MeteringMode[] = {
580         { 3,    "evaluative" },
581         { 4,    "partial" },
582         { 5,    "center-weighted" },
583         EXIF_TEXT_LIST_END
584 };
585
586 static ExifTextList CanonSet1FocusType[] = {
587         { 0,    "manual" },
588         { 1,    "auto" },
589         { 3,    "macro" },
590         { 8,    "locked" },
591         EXIF_TEXT_LIST_END
592 };
593
594 static ExifTextList CanonSet1AutoFocusPoint[] = {
595         { 12288,        "manual focus" },
596         { 12289,        "auto" },
597         { 12290,        "right" },
598         { 12291,        "center" },
599         { 12292,        "left" },
600         EXIF_TEXT_LIST_END
601 };
602
603 static ExifTextList CanonSet1ExposureMode[] = {
604         { 0,    "auto" },
605         { 1,    "program" },
606         { 2,    "Tv priority" },
607         { 3,    "Av priority" },
608         { 4,    "manual" },
609         { 5,    "A-DEP" },
610         EXIF_TEXT_LIST_END
611 };
612
613 static ExifTextList CanonSet1FlashFired[] = {
614         { 0,    "no" },
615         { 1,    "yes" },
616         EXIF_TEXT_LIST_END
617 };
618
619 static ExifTextList CanonSet1FocusCont[] = {
620         { 0,    "no (single)" },
621         { 1,    "yes" },
622         EXIF_TEXT_LIST_END
623 };
624
625 static ExifMarker CanonSet1[] = {
626 /* 0 is length of array in bytes (2 x array size) */
627 { 1,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MacroMode",   "Macro mode",           CanonSet1MacroMode },
628 { 2,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SelfTimer",   "Self timer (10ths of second)", NULL },
629 { 3,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Quality",     "Quality",              CanonSet1Quality },
630 { 4,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashMode",   "Flash mode",           CanonSet1FlashMode },
631 { 5,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DriveMode",   "Drive mode",           CanonSet1DriveMode },
632 { 7,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusMode",   "Focus mode",           CanonSet1FocusMode },
633 { 10,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ImageSize",   "Image size",           CanonSet1ImageSize },
634 { 11,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ShootingMode","Shooting mode",        CanonSet1ShootingMode },
635  { 11,  EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureProgram",       "ExposureProgram",      CanonSet1ShootingMode },
636 { 12,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DigitalZoom", "Digital zoom",         CanonSet1DigitalZoom },
637 { 13,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Contrast",    "Contrast",             CanonSet1ConSatSharp },
638 { 14,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Saturation",  "Saturation",           CanonSet1ConSatSharp },
639 { 15,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Sharpness",   "Sharpness",            CanonSet1ConSatSharp },
640 { 16,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ISOSpeed",    "ISO speed",            CanonSet1ISOSpeed },
641  { 16,  EXIF_FORMAT_SHORT_UNSIGNED, 1, "ISOSpeedRatings",       "ISO speed",            CanonSet1ISOSpeed },
642 { 17,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MeteringMode","Metering mode",        CanonSet1MeteringMode },
643 { 18,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusType",   "Focus type",           CanonSet1FocusType },
644 { 19,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.AutoFocus",   "AutoFocus point",      CanonSet1AutoFocusPoint },
645 { 20,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ExposureMode","Exposure mode",        CanonSet1ExposureMode },
646  { 20,  EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureMode",          "Exposure mode",        CanonSet1ExposureMode },
647 { 23,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthLong","Long focal length", NULL },
648 { 24,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthShort","Short focal length", NULL },
649 { 25,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthUnits","Focal units per mm", NULL },
650 { 28,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashFired",  "Flash fired",          CanonSet1FlashFired },
651 { 29,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashDetails","Flash details",        NULL },
652 { 32,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ContinuousFocus","Continuous focus",  CanonSet1FocusCont },
653 EXIF_MARKER_LIST_END
654 };
655
656 static ExifTextList CanonSet2WhiteBalance[] = {
657         { 0,    "auto" },
658         { 1,    "sunny" },
659         { 2,    "cloudy" },
660         { 3,    "tungsten" },
661         { 4,    "flourescent" },
662         { 5,    "flash" },
663         { 6,    "custom" },
664         EXIF_TEXT_LIST_END
665 };
666
667 static ExifTextList CanonSet2FlashBias[] = {
668         { 0x0000,       "0" },
669         { 0x000c,       "0.33" },
670         { 0x0010,       "0.5" },
671         { 0x0014,       "0.67" },
672         { 0x0020,       "1" },
673         { 0x002c,       "1.33" },
674         { 0x0030,       "1.5" },
675         { 0x0034,       "1.67" },
676         { 0x0040,       "2" },
677         { 0xffc0,       "-2" },
678         { 0xffcc,       "-1.67" },
679         { 0xffd0,       "-1.5" },
680         { 0xffd4,       "-1.33" },
681         { 0xffe0,       "-1" },
682         { 0xffec,       "-0.67" },
683         { 0xfff0,       "-0.5" },
684         { 0xfff4,       "-0.33" },
685         EXIF_TEXT_LIST_END
686 };
687
688 static ExifMarker CanonSet2[] = {
689 /* 0 is length of array in bytes (2 x array size) */
690 { 7,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.WhiteBalance","White balance",        CanonSet2WhiteBalance },
691  { 7,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "LightSource",           "White balance",        CanonSet2WhiteBalance },
692 { 9,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SequenceNumber","Sequence number",    NULL },
693 { 15,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashBias",   "Flash bias",           CanonSet2FlashBias },
694 /* distance needs more than just this (metric) value */
695 { 19,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SubjectDistance",     "Subject Distance", NULL },
696 EXIF_MARKER_LIST_END
697 };
698
699 #if 0
700
701 static ExifTextList CanonCustomEnable[] = {
702         { 0,    "off" },
703         { 1,    "on" },
704         EXIF_TEXT_LIST_END
705 };
706
707 static ExifTextList CanonCustomEnableInvert[] = {
708         { 0,    "on" },
709         { 1,    "off" },
710         EXIF_TEXT_LIST_END
711 };
712
713 static ExifTextList CanonCustomExposureLevel[] = {
714         { 0,    "1/2 stop" },
715         { 1,    "1/3 stop" },
716         EXIF_TEXT_LIST_END
717 };
718
719 static ExifTextList CanonCustomAVShutterSpeed[] = {
720         { 0,    "auto" },
721         { 1,    "1/200 (fixed)" },
722         EXIF_TEXT_LIST_END
723 };
724
725 static ExifTextList CanonCustomShutterCurtainSync[] = {
726         { 0,    "1st" },
727         { 1,    "2nd" },
728         EXIF_TEXT_LIST_END
729 };
730
731 static ExifMarker CanonCustom[] = {
732 { 1,    EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.NoiseReduction", "Noise reduction",  CanonCustomEnable },
733 /*{ 2,  EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.BtnFuncShutter",
734                                                 "Shutter/Auto exposure button function",CanonCustomBTNShutter }, */
735 { 3,    EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.MirrorLockup", "Mirror lockup",      CanonCustomEnable },
736 { 4,    EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.TvAvExposureLevel",
737                                                         "Tv/Av and exposure level",     CanonCustomExposureLevel },
738 { 5,    EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.AFAssistLight", "AF assist light",   CanonCustomEnableInvert },
739 { 6,    EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.AvShutterSpeed",
740                                                         "Shutter speed in Av mode",     CanonCustomAVShutterSpeed },
741 /*{ 7,  EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.AutoBracket",
742                                 "Auto-Exposure bracketting sequence/auto cancellation", CanonCustom }, */
743 { 8,    EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.ShutterSync", "Shutter sync",        CanonCustomShutterCurtainSync },
744 /* { 9, EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.BtnFuncAF",  "AF button function",   CanonCustom }, */
745 { 10,   EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.FillFlashReduction",
746                                                         "Fill flash auto reduction",    CanonCustomEnableInvert },
747 /*{ 11, EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.BtnFuncMenu",
748                                                         "Menu button function",         CanonCustom }, */
749 /*{ 12, EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.BtnFuncSet", "Set button function",  CanonCustom }, */
750 { 13,   EXIF_FORMAT_SHORT_UNSIGNED, 1,  "MkN.Canon.SensorCleaning", "Sensor cleaning",  CanonCustomEnable },
751 EXIF_MARKER_LIST_END
752 };
753
754 #endif
755
756 static ExifMarker CanonExifMarkersList[] = {
757         { 1,    EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings1",          NULL, NULL },
758         { 4,    EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings2",          NULL, NULL },
759         { 6,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.ImageType",          "Image type", NULL },
760         { 7,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.FirmwareVersion",    "Firmware version", NULL },
761         { 8,    EXIF_FORMAT_LONG_UNSIGNED, 1,   "MkN.Canon.ImageNumber",        "Image number", NULL },
762         { 9,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.OwnerName",          "Owner name", NULL },
763         { 12,   EXIF_FORMAT_LONG_UNSIGNED, -1,  "MkN.Canon.SerialNumber",       "Camera serial number", NULL },
764         { 15,   EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.CustomFunctions",    NULL, NULL },
765         EXIF_MARKER_LIST_END
766 };
767
768 static void canon_mknote_parse_settings(ExifData *exif,
769                                         guint16 *data, guint32 len, ExifByteOrder byte_order,
770                                         ExifMarker *list)
771 {
772         gint i;
773
774         i = 0;
775         while (list[i].tag != 0)
776                 {
777                 if (list[i].tag < len)
778                         {
779                         ExifItem *item;
780
781                         item = exif_item_new(EXIF_FORMAT_SHORT_UNSIGNED, list[i].tag, 1, &list[i]);
782                         exif_item_copy_data(item, &data[list[i].tag], 1, EXIF_FORMAT_SHORT_UNSIGNED, byte_order);
783                         exif->items = g_list_prepend(exif->items, item);
784                         }
785
786                 i++;
787                 }
788 }
789
790 #if 0
791 static void canon_mknote_parse_convert(ExifData *exif)
792 {
793         gint value;
794         ExifItem *result;
795
796         /* seems we need more than only this value for distance */
797         if (exif_get_integer(exif, "MkN.Canon.SubjectDistance", &value))
798                 {
799                 static ExifMarker marker= { 0x9206, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,
800                                             "SubjectDistance", "Subject distance", NULL };
801                 ExifItem *item;
802                 ExifRational *rational;
803
804                 item = exif_item_new(marker.format, marker.tag, 1, &marker);
805                 rational = item->data;
806                 rational->num = value;
807                 rational->den = 100;
808
809                 exif->items = g_list_prepend(exif->items, item);
810                 }
811
812         result = exif_get_item(exif, "MkN.Canon.SerialNumber");
813         if (result && result->format == EXIF_FORMAT_LONG_UNSIGNED && result->data_len == 4)
814                 {
815                 static ExifMarker marker= { 12, EXIF_FORMAT_STRING, -1,
816                                             "SerialNumber", "Camera serial number", NULL };
817                 ExifItem *item;
818                 gchar *text;
819                 gint l;
820                 guint32 n;
821
822                 n = (guint32)((guint32 *)(result->data))[0];
823                 text = g_strdup_printf("%04X%05d", n & 0xffff0000 >> 8, n & 0x0000ffff);
824                 l = strlen(text);
825                 item = exif_item_new(marker.format, marker.tag, l, &marker);
826                 memcpy(item->data, text, l);
827                 g_free(text);
828
829                 exif->items = g_list_prepend(exif->items, item);
830                 }
831 }
832 #endif
833
834 gint format_canon_makernote(ExifData *exif, unsigned char *tiff, guint offset,
835                             guint size, ExifByteOrder byte_order)
836 {
837         ExifItem *item;
838
839         if (exif_parse_IFD_table(exif, tiff, offset, size, byte_order, CanonExifMarkersList) != 0)
840                 {
841                 return FALSE;
842                 }
843
844         item = exif_get_item(exif, "MkN.Canon.Settings1");
845         if (item)
846                 {
847                 canon_mknote_parse_settings(exif, item->data, item->data_len, byte_order, CanonSet1);
848                 }
849
850         item = exif_get_item(exif, "MkN.Canon.Settings2");
851         if (item)
852                 {
853                 canon_mknote_parse_settings(exif, item->data, item->data_len, byte_order, CanonSet2);
854                 }
855
856 #if 0
857         canon_mknote_parse_convert(exif);
858 #endif
859
860         return TRUE;
861 }
862
863