Fri Jun 3 20:02:23 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 #if 0
38   #define CANON_DEBUG
39 #endif
40
41 #ifdef CANON_DEBUG
42 int canonEnableDebug = 0;
43 /* This should be really a stack, but I am too lazy to implement */
44 #define DEBUG_ENABLE (canonEnableDebug = 0)
45 #define DEBUG_DISABLE (canonEnableDebug = 1)
46 /* It would be nice if these functions indented according to depth in the stack, but I am too lazy to implement */
47
48 #define DEBUG_ENTRY(a) (canonEnableDebug || fprintf(stderr, "Entering function: %s [%s:%d]\n", a, __FILE__, __LINE__))
49 #define DEBUG_EXIT(a) (canonEnableDebug || fprintf(stderr, "Exiting function: %s [%s:%d]\n", a, __FILE__, __LINE__))
50 #define DEBUG_1(a) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n", __FILE__, __LINE__))
51 #define DEBUG_2(a,b) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b,  __FILE__, __LINE__))
52 #define DEBUG_3(a,b,c) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, c,  __FILE__, __LINE__))
53
54 #else
55 #define DEBUG_ENABLE
56 #define DEBUG_DISABLE 
57 #define DEBUG_ENTRY(a)
58 #define DEBUG_EXIT(a)
59
60 #define DEBUG_1(a) 
61 #define DEBUG_2(a,b)
62 #define DEBUG_3(a,b,c)
63 #endif
64
65
66 /* canon_read_int4 
67
68
69 The problem with gqview is that sometimes the data is to be read from
70 a file, and sometimes it is in memory. This function tries to isolate
71 the rest of the code from having to deal with both cases
72
73 This function reads a 4 byte unsigned integer, and fixes its endianism.
74
75 If fd >= 0 then the value is read from the corresponding file descriptor
76    
77    in that case, if offset is > 0, then the value is read from that offset
78
79    otherwise it is read from the current file pointer 
80
81 if fd < 0 then the value is read from the memory pointed by data + offset
82
83
84 offset is a pointer to the actual offset of the file.
85
86 sizeInt can be 2 or 4 (it is the number of bytes to read)
87
88 RETURNS true is no error, false if it can't read the value
89
90
91 */
92 static int canon_read_int(unsigned int *offset, const void *data, int sizeInt, unsigned int *value )
93 {
94   DEBUG_DISABLE;
95
96   DEBUG_ENTRY("canon_read_int");
97   /* Verify values before we do anything */
98   if (sizeInt != 2 && sizeInt != 4) return FALSE;
99   if (offset == NULL) return FALSE;
100   if (*offset <= 0) return FALSE;
101   if (data == NULL) return FALSE;
102   if (value == NULL) return FALSE;
103
104   if (sizeInt == 4) {
105     *value = GUINT32_FROM_LE(*(guint32*)(data + *offset));      
106     *offset +=4;
107     DEBUG_3("Read 4 bytes %d %x", *value, *value);
108   } else {
109     *value = GUINT16_FROM_LE(*(guint32*)(data + *offset));
110     *offset +=2;
111     DEBUG_3("Read 2 bytes %d %x", *value, *value);
112   }
113
114   DEBUG_EXIT("canon_read_int");
115
116   DEBUG_ENABLE;
117   return TRUE;
118 }
119
120 #define CANON_HEADER_SIZE                   26
121
122 /*
123
124  The CR2 format is really a TIFF format. It is nicely documented in the TIFF V 6.0 document available from adobe.
125
126   The CR2 file contains two thumbnails, one tiny and one decent sized. The record Id of the latter is 0x0111.
127
128   The photo info is also available, in EXIF, and it looks like I don't need to do anything! Yeah!
129
130 */
131
132 static int canon_cr2_process_directory(void *data, int offsetIFD, guint *jpegLocation, guint *exifLocation) 
133 {
134   unsigned int offset;
135   int returnValue = FALSE;
136
137   DEBUG_ENTRY("canon_cr2_process_directory");
138
139   /* The directory is a link list, after an array of records, the next 4 byptes point to the offset of the next directory.
140
141   All offsets are absolution within the file (in CRWs the offsets are relative ).
142
143   */
144
145   while (offsetIFD != 0 && offsetIFD != 0xFFFF) {
146     int countEntries=0;
147     int i;
148     /* Read directory, we start by reading number of entries in the directory */
149
150     offset = offsetIFD;
151     if (!canon_read_int(&offset, data, 2, &countEntries)) {
152       goto return_only;
153     }
154     DEBUG_2("Number of entries: %d\n", countEntries);
155
156     for (i=0;i<countEntries;i++) {
157       /* read each entry */
158
159       int recordId;
160 #if 0
161       int format;
162       int size;
163 #endif
164
165       /* read record type */
166       if (!canon_read_int(&offset, data, 2, &recordId)) {
167         goto return_only;
168       }
169
170       /* Did we find the JPEG */
171       if (recordId == 0x0111) { 
172         DEBUG_1("This is the record to find**********************\n");
173         offset +=6;
174         if (!canon_read_int(&offset, data, 4, jpegLocation)) {
175           goto return_only;
176         }
177         DEBUG_3("JPEG Location %d 0x%x\n", *jpegLocation, *jpegLocation);
178         /* We don't want to keep reading, because there is another
179            0x0111 record at the end that contains the raw data */
180         returnValue = TRUE;
181         goto return_only;
182       } else {
183         /* advance pointer by skipping rest of record */
184         offset += 10;
185       }
186     }
187     /* The next 4 bytes are the offset of next directory, if zero we are done
188        
189      */
190     if (!canon_read_int(&offset, data, 4, &offsetIFD)) {
191       goto return_only;
192     }
193     DEBUG_3("Value of NEXT offsetIFD: %d 0x%x\n", offsetIFD, offsetIFD);
194   }
195
196   returnValue = TRUE;
197   DEBUG_1("Going to return true");
198
199  return_only:
200   DEBUG_EXIT("canon_cr2_process_directory");
201
202   return TRUE;
203
204
205 }
206
207
208 static int format_raw_test_canon_cr2(void *data, const guint len,
209                                      guint *image_offset, guint *exif_offset)
210 {
211 #if 0
212   char signature[4];
213   unsigned int offset = 4;
214 #endif
215   int offsetIFD;
216   int returnValue = FALSE;
217   void *jpgInDataOffset;
218
219   DEBUG_ENTRY("format_raw_test_canon_cr2");
220
221   /* Verify signature */
222   if (memcmp(data, "\x49\x49\x2a\00", 4) != 0) {
223     DEBUG_1("This is not a CR2");
224     goto return_only;
225   }
226
227   /* Get address of first directory */
228   offsetIFD = GUINT32_FROM_LE(*(guint32*)(data + 4));
229
230
231   DEBUG_2("Value of offsetIFD: %d\n", offsetIFD);
232
233   returnValue = canon_cr2_process_directory(data, offsetIFD, image_offset, exif_offset);
234
235   if (returnValue) {
236     jpgInDataOffset = data + *image_offset;
237
238     /* Make sure we really got a JPEG */
239
240     if (memcmp(jpgInDataOffset, "\xff\xd8",2) != 0) {
241       /* It is not at the JPEG! */
242       DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset);
243       returnValue = FALSE;
244     }
245   }
246
247 return_only:
248   DEBUG_EXIT("format_raw_test_canon_cr2");
249
250   return returnValue;
251 }
252
253
254 gint format_raw_test_canon(const void *data, const guint len,
255                            guint *image_offset, guint *exif_offset)
256 {
257
258
259   /* There are at least 2 types of Canon raw files. CRW and CR2 
260
261   CRW files have a proprietary format. 
262
263   HEADER
264   Heap
265     RAW   data
266     JPEG  data
267     PHoto data
268
269   HEADER_LENGTH            32  bytes
270    int2     byteOrder; Always II (MM Motorola ---big endian, II Intel --little endian)
271    int4     length;    Should be 26 
272    char     identifier[8];type HEAP, subtype heap  CCDR
273    int2     version;
274    int2     subversion;
275    char     unused[14]; 
276   */
277
278   int returnValue = FALSE;
279   int heapHeaderOffset = 0;
280   int heapRecordsCount = 0;
281 #if 0
282   guint32 rawInt4;
283   guint16 rawInt2;
284 #endif
285   int i;
286   unsigned int currentOffset;
287   /* File has to be little endian, first two bytes II */
288
289   if (len < 100) 
290     return FALSE;
291
292   if (format_raw_test_canon_cr2((void *)data, len, image_offset, exif_offset)) {
293     return TRUE;
294   }
295
296   if (memcmp("II", data, 2) != 0) {
297     return FALSE;
298   }
299   /* NO DEBUG BEFORE THIS POINT, we want to debug only Canon */
300   
301   DEBUG_ENTRY("format_raw_test_canon");
302
303   DEBUG_2("Length of buffer read %u", len);
304
305   DEBUG_2("CRW header length Data %d", GUINT32_FROM_LE(*(guint32*)(data + 2)));
306
307   /* the length has to be CANON_HEADER_SIZE  */
308   if (GUINT32_FROM_LE(*(guint32*)(data + 2)) != CANON_HEADER_SIZE) {
309     DEBUG_1("It is not the right size");
310     goto return_only;
311   }
312   
313   if (!memcmp("HEAPCCDR", data+6, 8) == 0) {
314     DEBUG_1("This file is not a Canon CRW raw photo");
315     goto return_only;
316
317    }
318    
319   /* Ok, so now we know that this is a CRW file */
320
321   /* The heap is a strange data structure. It is recursive, so a record
322     can contain a heap itself. That is indeed the case for the photo information
323     reecord. Luckily the first heap contains the jpeg, so we don't need to do
324     any recursive processing. 
325
326     Its "header" is a the end. The header is a sequence of records,
327      and the data of each record is at the beginning of the heap
328
329    +-----------------+
330    | data raw        |
331    +-----------------+
332    | data jpeg       |
333    +-----------------+
334    | data photo info |
335    +-----------------+
336    |header of heap   |
337    | # records       |   it should be 3
338    |      raw info   |
339    |      jpeg info  |
340    |      photo info |
341    +-----------------+
342
343    The header contains 
344       number of records: 2 bytes
345       for each record (10 bytes long)
346           type:    2 bytes
347           length:  4 bytes 
348           offset:  4 bytes 
349           
350      In some records the length and offset are actually data,
351      but none for the ones in the first heap.
352      
353      the offset is with respect to the beginning of the heap, not the
354      beginning of the file. That allows heaps to be "movable"
355
356    For the purpose of finding the JPEG, all we need is to scan the fist heap,
357    which contains the following record types:
358
359     0x2005 Record RAW data
360     0x2007 Record JPEG data
361     0x300a Record with photo info
362
363   */
364
365
366   if (len < 0x10000) {
367     DEBUG_2("We have a problem, the length is too small %d ", len);
368     goto return_only;
369   }
370   currentOffset = len-4;
371
372
373   /* The last 4 bytes have the offset of the header of the heap */
374   if (!canon_read_int(&currentOffset, data, 4, &heapHeaderOffset)) 
375     goto return_only;
376   
377   /* The heapoffset has to be adjusted to the actual file size, the header is CANON_HEADER_SIZE bytes long */
378   heapHeaderOffset += CANON_HEADER_SIZE;
379   DEBUG_2("heap header Offset %d ", heapHeaderOffset);
380   
381   /* Just check, it does not hurt, we don't want to crash */
382   if (heapHeaderOffset > len) 
383     goto return_only;
384
385   currentOffset =   heapHeaderOffset;
386   /* Let us read the number of records in the heap */
387   if (!canon_read_int(&currentOffset, data, 2, &heapRecordsCount))
388     goto return_only;
389   
390   DEBUG_2("heap record count %d ", heapRecordsCount);
391     
392   if (heapRecordsCount != 3) {
393     /* In all the cameras I have seen, this is always 3
394        if not, something is wrong, so just quit */
395     goto return_only;
396   }
397     
398   for (i=0;i<3;i++) {
399     int recordType;
400     int recordOffset;
401     int recordLength;
402     const void *jpgInDataOffset;
403     /* Read each record, to find jpg, it should be second */
404     
405     if (!canon_read_int(&currentOffset, data, 2, &recordType))
406       goto return_only;
407     
408     DEBUG_2("record type 0x%x ", recordType);
409     
410     if (recordType != 0x2007) {
411       /* Go to the next record, don't waste time, 
412          but first, eat 8 bytes from header */
413       currentOffset += 8;
414       continue; /* Nah, wrong record, go to next */
415     }
416     /* Bingo, we are at the JPEG record */
417     
418     /* Read length */
419     if (!canon_read_int(&currentOffset, data, 4, &recordLength))
420       goto return_only;
421     
422     DEBUG_2("record length %d ", recordLength);
423     
424     /* Read offset */
425     
426     if (!canon_read_int(&currentOffset, data, 4, &recordOffset))
427       goto return_only;
428     
429     DEBUG_2("record offset 0x%d ", recordOffset);
430     
431     /* Great, we now know where the JPEG is! 
432        it is CANON_HEADER_SIZE (size of CRW header) + recordOffset 
433     */
434     
435     *image_offset =  CANON_HEADER_SIZE + recordOffset;
436     DEBUG_2("image offset %d ", *image_offset);
437     
438     /* keep checking for potential errors */
439     if (*image_offset > len) {
440       goto return_only;
441     }
442     /* Get the JPEG is */
443     
444     jpgInDataOffset = data + *image_offset;
445
446     if (memcmp(jpgInDataOffset, "\xff\xd8\xff\xdb",4) != 0) {
447       /* It is not at the JPEG! */
448       DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset);
449       goto return_only;
450     }
451     returnValue = TRUE;
452     goto return_only;
453   }
454  /* undo whatever we need in case of an error*/
455   DEBUG_1("We scan all records, but nothing was found!!!!!!!!!!!!!!!!!!");
456
457
458   /* At this point we are returning */
459 return_only:
460   if (returnValue) {
461     DEBUG_1("****We got an embedded  JPEG for a canon CRW");
462
463   }
464
465   DEBUG_EXIT("format_raw_test_canon");
466   return returnValue;
467
468 #undef DEBUG_2
469 #undef DEBUG
470 #undef DEBUG_ENTRY
471 #undef DEBUG_EXIT
472
473 }
474
475 /*
476  *-----------------------------------------------------------------------------
477  * EXIF Makernote for Canon
478  *-----------------------------------------------------------------------------
479  */
480
481 typedef struct _CanonTag CanonTag;
482 struct _CanonTag {
483         guint id;
484         const gchar *description;
485         ExifTextList *list;
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 CanonTag CanonCustom[] = {
732         { 1,    "Noise reduction",              CanonCustomEnable },
733 /*      { 2,    "Shutter/Auto Exposure Button Function", CanonCustomBTNShutter }, */
734         { 3,    "Mirror lockup",                CanonCustomEnable },
735         { 4,    "Tv/Av and exposure level",     CanonCustomExposureLevel },
736         { 5,    "AF assist light",              CanonCustomEnableInvert },
737         { 6,    "Shutter speed in Av mode",     CanonCustomAVShutterSpeed },
738 /*      { 7,    "Auto-Exposure bracketting sequence/auto cancellation", CanonCustom }, */
739         { 8,    "Shutter sync",                 CanonCustomShutterCurtainSync },
740 /*      { 9,    "AF button function",           CanonCustom }, */
741         { 10,   "Fill flash auto reduction",    CanonCustomEnableInvert },
742 /*      { 11,   "Menu button function",         CanonCustom }, */
743 /*      { 12,   "Set button function",          CanonCustom }, */
744         { 13,   "Sensor cleaning",              CanonCustomEnable },
745         { 0,    NULL, NULL }
746 };
747
748 #endif
749
750 static ExifMarker CanonExifMarkersList[] = {
751         { 1,    EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings1",          NULL, NULL },
752         { 4,    EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings2",          NULL, NULL },
753         { 6,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.ImageType",          "Image type", NULL },
754         { 7,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.FirmwareVersion",    "Firmware version", NULL },
755         { 8,    EXIF_FORMAT_LONG_UNSIGNED, 1,   "MkN.Canon.ImageNumber",        "Image number", NULL },
756         { 9,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.OwnerName",          "Owner name", NULL },
757         { 12,   EXIF_FORMAT_LONG_UNSIGNED, -1,  "MkN.Canon.SerialNumber",       "Camera serial number", NULL },
758         { 15,   EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.CustomFunctions",    NULL, NULL },
759         EXIF_MARKER_LIST_END
760 };
761
762 static void canon_mknote_parse_settings(ExifData *exif,
763                                         guint16 *data, guint32 len, int byte_order,
764                                         ExifMarker *list)
765 {
766         gint i;
767
768         i = 0;
769         while (list[i].tag != 0)
770                 {
771                 if (list[i].tag < len)
772                         {
773                         ExifItem *item;
774
775                         item = exif_item_new(EXIF_FORMAT_SHORT_UNSIGNED, list[i].tag, 1, &list[i]);
776                         exif_item_copy_data(item, &data[list[i].tag], 1, EXIF_FORMAT_SHORT_UNSIGNED, byte_order);
777                         exif->items = g_list_prepend(exif->items, item);
778                         }
779
780                 i++;
781                 }
782 }
783
784 #if 0
785 static void canon_mknote_parse_convert(ExifData *exif)
786 {
787         gint value;
788         ExifItem *result;
789
790         /* seems we need more than only this value for distance */
791         if (exif_get_integer(exif, "MkN.Canon.SubjectDistance", &value))
792                 {
793                 static ExifMarker marker= { 0x9206, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,
794                                             "SubjectDistance", "Subject distance", NULL };
795                 ExifItem *item;
796                 ExifRational *rational;
797
798                 item = exif_item_new(marker.format, marker.tag, 1, &marker);
799                 rational = item->data;
800                 rational->num = value;
801                 rational->den = 100;
802
803                 exif->items = g_list_prepend(exif->items, item);
804                 }
805
806         result = exif_get_item(exif, "MkN.Canon.SerialNumber");
807         if (result && result->format == EXIF_FORMAT_LONG_UNSIGNED && result->data_len == 4)
808                 {
809                 static ExifMarker marker= { 12, EXIF_FORMAT_STRING, -1,
810                                             "SerialNumber", "Camera serial number", NULL };
811                 ExifItem *item;
812                 gchar *text;
813                 gint l;
814                 guint32 n;
815
816                 n = (guint32)((guint32 *)(result->data))[0];
817                 text = g_strdup_printf("%04X%05d", n & 0xffff0000 >> 8, n & 0x0000ffff);
818                 l = strlen(text);
819                 item = exif_item_new(marker.format, marker.tag, l, &marker);
820                 memcpy(item->data, text, l);
821                 g_free(text);
822
823                 exif->items = g_list_prepend(exif->items, item);
824                 }
825 }
826 #endif
827
828 gint format_exif_makernote_canon_parse(ExifData *exif, unsigned char *tiff, int offset,
829                                        int size, int byte_order)
830 {
831         ExifItem *item;
832         gchar *text;
833         gint found;
834
835         text = exif_get_data_as_text(exif, "Make");
836         found = (text && strncasecmp(text, "Canon", 5) == 0);
837         g_free(text);
838
839         if (!found ||
840             exif_parse_IFD_table(exif, tiff, offset, size, byte_order, CanonExifMarkersList) != 0)
841                 {
842                 return FALSE;
843                 }
844
845         item = exif_get_item(exif, "MkN.Canon.Settings1");
846         if (item)
847                 {
848                 canon_mknote_parse_settings(exif, item->data, item->data_len, byte_order, CanonSet1);
849                 }
850
851         item = exif_get_item(exif, "MkN.Canon.Settings2");
852         if (item)
853                 {
854                 canon_mknote_parse_settings(exif, item->data, item->data_len, byte_order, CanonSet2);
855                 }
856
857 #if 0
858         canon_mknote_parse_convert(exif);
859 #endif
860
861         return TRUE;
862 }
863
864