Mercurial > geeqie
comparison src/format_canon.c @ 45:7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
* format_raw.[ch]: Move camera specific code to manufacturer specific
format_*.c files. Change code so that file descripter version is now a
separate functions that wraps the standard parser by using mmap.
* format_canon.[ch]: Moved Canon specific raw support here, removed
file descriptor versions of parser. This Canon raw file parser written
by Daniel M. German.
* format_fuji.[ch]: Move Fuji specific raw support here, parser written
by Lars Ellenberg.
* exif.c: Update for change to format_raw_img_exif_offsets.
* filelist.c: Add cr2 extension to Canon raw format list.
* image-load.c: Fixes for changes to format_raw_img_exif_offset_fd so
that buffer is refilled using new offset of file descriptor.
* src/Makefile.am: Add format_canon.[ch], format_fuji.[ch] to build.
##### 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 | Thu, 26 May 2005 18:10:52 +0000 |
parents | |
children | aa4c0e1b54b0 |
comparison
equal
deleted
inserted
replaced
44:458e396d3f35 | 45:7cfa60beda76 |
---|---|
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 | |
35 #if 0 | |
36 #define CANON_DEBUG | |
37 #endif | |
38 | |
39 #ifdef CANON_DEBUG | |
40 int canonEnableDebug = 0; | |
41 /* This should be really a stack, but I am too lazy to implement */ | |
42 #define DEBUG_ENABLE (canonEnableDebug = 0) | |
43 #define DEBUG_DISABLE (canonEnableDebug = 1) | |
44 /* It would be nice if these functions indented according to depth in the stack, but I am too lazy to implement */ | |
45 | |
46 #define DEBUG_ENTRY(a) (canonEnableDebug || fprintf(stderr, "Entering function: %s [%s:%d]\n", a, __FILE__, __LINE__)) | |
47 #define DEBUG_EXIT(a) (canonEnableDebug || fprintf(stderr, "Exiting function: %s [%s:%d]\n", a, __FILE__, __LINE__)) | |
48 #define DEBUG_1(a) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n", __FILE__, __LINE__)) | |
49 #define DEBUG_2(a,b) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, __FILE__, __LINE__)) | |
50 #define DEBUG_3(a,b,c) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, c, __FILE__, __LINE__)) | |
51 | |
52 #else | |
53 #define DEBUG_ENABLE | |
54 #define DEBUG_DISABLE | |
55 #define DEBUG_ENTRY(a) | |
56 #define DEBUG_EXIT(a) | |
57 | |
58 #define DEBUG_1(a) | |
59 #define DEBUG_2(a,b) | |
60 #define DEBUG_3(a,b,c) | |
61 #endif | |
62 | |
63 | |
64 /* canon_read_int4 | |
65 | |
66 | |
67 The problem with gqview is that sometimes the data is to be read from | |
68 a file, and sometimes it is in memory. This function tries to isolate | |
69 the rest of the code from having to deal with both cases | |
70 | |
71 This function reads a 4 byte unsigned integer, and fixes its endianism. | |
72 | |
73 If fd >= 0 then the value is read from the corresponding file descriptor | |
74 | |
75 in that case, if offset is > 0, then the value is read from that offset | |
76 | |
77 otherwise it is read from the current file pointer | |
78 | |
79 if fd < 0 then the value is read from the memory pointed by data + offset | |
80 | |
81 | |
82 offset is a pointer to the actual offset of the file. | |
83 | |
84 sizeInt can be 2 or 4 (it is the number of bytes to read) | |
85 | |
86 RETURNS true is no error, false if it can't read the value | |
87 | |
88 | |
89 */ | |
90 static int canon_read_int(unsigned int *offset, const void *data, int sizeInt, unsigned int *value ) | |
91 { | |
92 DEBUG_DISABLE; | |
93 | |
94 DEBUG_ENTRY("canon_read_int"); | |
95 /* Verify values before we do anything */ | |
96 if (sizeInt != 2 && sizeInt != 4) return FALSE; | |
97 if (offset == NULL) return FALSE; | |
98 if (*offset <= 0) return FALSE; | |
99 if (data == NULL) return FALSE; | |
100 if (value == NULL) return FALSE; | |
101 | |
102 if (sizeInt == 4) { | |
103 *value = GUINT32_FROM_LE(*(guint32*)(data + *offset)); | |
104 *offset +=4; | |
105 DEBUG_3("Read 4 bytes %d %x", *value, *value); | |
106 } else { | |
107 *value = GUINT16_FROM_LE(*(guint32*)(data + *offset)); | |
108 *offset +=2; | |
109 DEBUG_3("Read 2 bytes %d %x", *value, *value); | |
110 } | |
111 | |
112 DEBUG_EXIT("canon_read_int"); | |
113 | |
114 DEBUG_ENABLE; | |
115 return TRUE; | |
116 } | |
117 | |
118 #define CANON_HEADER_SIZE 26 | |
119 | |
120 /* | |
121 | |
122 The CR2 format is really a TIFF format. It is nicely documented in the TIFF V 6.0 document available from adobe. | |
123 | |
124 The CR2 file contains two thumbnails, one tiny and one decent sized. The record Id of the latter is 0x0111. | |
125 | |
126 The photo info is also available, in EXIF, and it looks like I don't need to do anything! Yeah! | |
127 | |
128 */ | |
129 | |
130 static int canon_cr2_process_directory(void *data, int offsetIFD, guint *jpegLocation, guint *exifLocation) | |
131 { | |
132 unsigned int offset; | |
133 int returnValue = FALSE; | |
134 | |
135 DEBUG_ENTRY("canon_cr2_process_directory"); | |
136 | |
137 /* The directory is a link list, after an array of records, the next 4 byptes point to the offset of the next directory. | |
138 | |
139 All offsets are absolution within the file (in CRWs the offsets are relative ). | |
140 | |
141 */ | |
142 | |
143 while (offsetIFD != 0 && offsetIFD != 0xFFFF) { | |
144 int countEntries=0; | |
145 int i; | |
146 /* Read directory, we start by reading number of entries in the directory */ | |
147 | |
148 offset = offsetIFD; | |
149 if (!canon_read_int(&offset, data, 2, &countEntries)) { | |
150 goto return_only; | |
151 } | |
152 DEBUG_2("Number of entries: %d\n", countEntries); | |
153 | |
154 for (i=0;i<countEntries;i++) { | |
155 /* read each entry */ | |
156 | |
157 int recordId; | |
158 #if 0 | |
159 int format; | |
160 int size; | |
161 #endif | |
162 | |
163 /* read record type */ | |
164 if (!canon_read_int(&offset, data, 2, &recordId)) { | |
165 goto return_only; | |
166 } | |
167 | |
168 /* Did we find the JPEG */ | |
169 if (recordId == 0x0111) { | |
170 DEBUG_1("This is the record to find**********************\n"); | |
171 offset +=6; | |
172 if (!canon_read_int(&offset, data, 4, jpegLocation)) { | |
173 goto return_only; | |
174 } | |
175 DEBUG_3("JPEG Location %d 0x%x\n", *jpegLocation, *jpegLocation); | |
176 /* We don't want to keep reading, because there is another | |
177 0x0111 record at the end that contains the raw data */ | |
178 returnValue = TRUE; | |
179 goto return_only; | |
180 } else { | |
181 /* advance pointer by skipping rest of record */ | |
182 offset += 10; | |
183 } | |
184 } | |
185 /* The next 4 bytes are the offset of next directory, if zero we are done | |
186 | |
187 */ | |
188 if (!canon_read_int(&offset, data, 4, &offsetIFD)) { | |
189 goto return_only; | |
190 } | |
191 DEBUG_3("Value of NEXT offsetIFD: %d 0x%x\n", offsetIFD, offsetIFD); | |
192 } | |
193 | |
194 returnValue = TRUE; | |
195 DEBUG_1("Going to return true"); | |
196 | |
197 return_only: | |
198 DEBUG_EXIT("canon_cr2_process_directory"); | |
199 | |
200 return TRUE; | |
201 | |
202 | |
203 } | |
204 | |
205 | |
206 static int format_raw_test_canon_cr2(void *data, const guint len, | |
207 guint *image_offset, guint *exif_offset) | |
208 { | |
209 #if 0 | |
210 char signature[4]; | |
211 unsigned int offset = 4; | |
212 #endif | |
213 int offsetIFD; | |
214 int returnValue = FALSE; | |
215 void *jpgInDataOffset; | |
216 | |
217 DEBUG_ENTRY("format_raw_test_canon_cr2"); | |
218 | |
219 /* Verify signature */ | |
220 if (memcmp(data, "\x49\x49\x2a\00", 4) != 0) { | |
221 DEBUG_1("This is not a CR2"); | |
222 goto return_only; | |
223 } | |
224 | |
225 /* Get address of first directory */ | |
226 offsetIFD = GUINT32_FROM_LE(*(guint32*)(data + 4)); | |
227 | |
228 | |
229 DEBUG_2("Value of offsetIFD: %d\n", offsetIFD); | |
230 | |
231 returnValue = canon_cr2_process_directory(data, offsetIFD, image_offset, exif_offset); | |
232 | |
233 if (returnValue) { | |
234 jpgInDataOffset = data + *image_offset; | |
235 | |
236 /* Make sure we really got a JPEG */ | |
237 | |
238 if (memcmp(jpgInDataOffset, "\xff\xd8",2) != 0) { | |
239 /* It is not at the JPEG! */ | |
240 DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset); | |
241 returnValue = FALSE; | |
242 } | |
243 } | |
244 | |
245 return_only: | |
246 DEBUG_EXIT("format_raw_test_canon_cr2"); | |
247 | |
248 return returnValue; | |
249 } | |
250 | |
251 | |
252 gint format_raw_test_canon(const void *data, const guint len, | |
253 guint *image_offset, guint *exif_offset) | |
254 { | |
255 | |
256 | |
257 /* There are at least 2 types of Canon raw files. CRW and CR2 | |
258 | |
259 CRW files have a proprietary format. | |
260 | |
261 HEADER | |
262 Heap | |
263 RAW data | |
264 JPEG data | |
265 PHoto data | |
266 | |
267 HEADER_LENGTH 32 bytes | |
268 int2 byteOrder; Always II (MM Motorola ---big endian, II Intel --little endian) | |
269 int4 length; Should be 26 | |
270 char identifier[8];type HEAP, subtype heap CCDR | |
271 int2 version; | |
272 int2 subversion; | |
273 char unused[14]; | |
274 */ | |
275 | |
276 int returnValue = FALSE; | |
277 int heapHeaderOffset = 0; | |
278 int heapRecordsCount = 0; | |
279 #if 0 | |
280 guint32 rawInt4; | |
281 guint16 rawInt2; | |
282 #endif | |
283 int i; | |
284 unsigned int currentOffset; | |
285 /* File has to be little endian, first two bytes II */ | |
286 | |
287 if (len < 100) | |
288 return FALSE; | |
289 | |
290 if (format_raw_test_canon_cr2((void *)data, len, image_offset, exif_offset)) { | |
291 return TRUE; | |
292 } | |
293 | |
294 if (memcmp("II", data, 2) != 0) { | |
295 return FALSE; | |
296 } | |
297 /* NO DEBUG BEFORE THIS POINT, we want to debug only Canon */ | |
298 | |
299 DEBUG_ENTRY("format_raw_test_canon"); | |
300 | |
301 DEBUG_2("Length of buffer read %u", len); | |
302 | |
303 DEBUG_2("CRW header length Data %d", GUINT32_FROM_LE(*(guint32*)(data + 2))); | |
304 | |
305 /* the length has to be CANON_HEADER_SIZE */ | |
306 if (GUINT32_FROM_LE(*(guint32*)(data + 2)) != CANON_HEADER_SIZE) { | |
307 DEBUG_1("It is not the right size"); | |
308 goto return_only; | |
309 } | |
310 | |
311 if (!memcmp("HEAPCCDR", data+6, 8) == 0) { | |
312 DEBUG_1("This file is not a Canon CRW raw photo"); | |
313 goto return_only; | |
314 | |
315 } | |
316 | |
317 /* Ok, so now we know that this is a CRW file */ | |
318 | |
319 /* The heap is a strange data structure. It is recursive, so a record | |
320 can contain a heap itself. That is indeed the case for the photo information | |
321 reecord. Luckily the first heap contains the jpeg, so we don't need to do | |
322 any recursive processing. | |
323 | |
324 Its "header" is a the end. The header is a sequence of records, | |
325 and the data of each record is at the beginning of the heap | |
326 | |
327 +-----------------+ | |
328 | data raw | | |
329 +-----------------+ | |
330 | data jpeg | | |
331 +-----------------+ | |
332 | data photo info | | |
333 +-----------------+ | |
334 |header of heap | | |
335 | # records | it should be 3 | |
336 | raw info | | |
337 | jpeg info | | |
338 | photo info | | |
339 +-----------------+ | |
340 | |
341 The header contains | |
342 number of records: 2 bytes | |
343 for each record (10 bytes long) | |
344 type: 2 bytes | |
345 length: 4 bytes | |
346 offset: 4 bytes | |
347 | |
348 In some records the length and offset are actually data, | |
349 but none for the ones in the first heap. | |
350 | |
351 the offset is with respect to the beginning of the heap, not the | |
352 beginning of the file. That allows heaps to be "movable" | |
353 | |
354 For the purpose of finding the JPEG, all we need is to scan the fist heap, | |
355 which contains the following record types: | |
356 | |
357 0x2005 Record RAW data | |
358 0x2007 Record JPEG data | |
359 0x300a Record with photo info | |
360 | |
361 */ | |
362 | |
363 | |
364 if (len < 0x10000) { | |
365 DEBUG_2("We have a problem, the length is too small %d ", len); | |
366 goto return_only; | |
367 } | |
368 currentOffset = len-4; | |
369 | |
370 | |
371 /* The last 4 bytes have the offset of the header of the heap */ | |
372 if (!canon_read_int(¤tOffset, data, 4, &heapHeaderOffset)) | |
373 goto return_only; | |
374 | |
375 /* The heapoffset has to be adjusted to the actual file size, the header is CANON_HEADER_SIZE bytes long */ | |
376 heapHeaderOffset += CANON_HEADER_SIZE; | |
377 DEBUG_2("heap header Offset %d ", heapHeaderOffset); | |
378 | |
379 /* Just check, it does not hurt, we don't want to crash */ | |
380 if (heapHeaderOffset > len) | |
381 goto return_only; | |
382 | |
383 currentOffset = heapHeaderOffset; | |
384 /* Let us read the number of records in the heap */ | |
385 if (!canon_read_int(¤tOffset, data, 2, &heapRecordsCount)) | |
386 goto return_only; | |
387 | |
388 DEBUG_2("heap record count %d ", heapRecordsCount); | |
389 | |
390 if (heapRecordsCount != 3) { | |
391 /* In all the cameras I have seen, this is always 3 | |
392 if not, something is wrong, so just quit */ | |
393 goto return_only; | |
394 } | |
395 | |
396 for (i=0;i<3;i++) { | |
397 int recordType; | |
398 int recordOffset; | |
399 int recordLength; | |
400 const void *jpgInDataOffset; | |
401 /* Read each record, to find jpg, it should be second */ | |
402 | |
403 if (!canon_read_int(¤tOffset, data, 2, &recordType)) | |
404 goto return_only; | |
405 | |
406 DEBUG_2("record type 0x%x ", recordType); | |
407 | |
408 if (recordType != 0x2007) { | |
409 /* Go to the next record, don't waste time, | |
410 but first, eat 8 bytes from header */ | |
411 currentOffset += 8; | |
412 continue; /* Nah, wrong record, go to next */ | |
413 } | |
414 /* Bingo, we are at the JPEG record */ | |
415 | |
416 /* Read length */ | |
417 if (!canon_read_int(¤tOffset, data, 4, &recordLength)) | |
418 goto return_only; | |
419 | |
420 DEBUG_2("record length %d ", recordLength); | |
421 | |
422 /* Read offset */ | |
423 | |
424 if (!canon_read_int(¤tOffset, data, 4, &recordOffset)) | |
425 goto return_only; | |
426 | |
427 DEBUG_2("record offset 0x%d ", recordOffset); | |
428 | |
429 /* Great, we now know where the JPEG is! | |
430 it is CANON_HEADER_SIZE (size of CRW header) + recordOffset | |
431 */ | |
432 | |
433 *image_offset = CANON_HEADER_SIZE + recordOffset; | |
434 DEBUG_2("image offset %d ", *image_offset); | |
435 | |
436 /* keep checking for potential errors */ | |
437 if (*image_offset > len) { | |
438 goto return_only; | |
439 } | |
440 /* Get the JPEG is */ | |
441 | |
442 jpgInDataOffset = data + *image_offset; | |
443 | |
444 if (memcmp(jpgInDataOffset, "\xff\xd8\xff\xdb",4) != 0) { | |
445 /* It is not at the JPEG! */ | |
446 DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset); | |
447 goto return_only; | |
448 } | |
449 returnValue = TRUE; | |
450 goto return_only; | |
451 } | |
452 /* undo whatever we need in case of an error*/ | |
453 DEBUG_1("We scan all records, but nothing was found!!!!!!!!!!!!!!!!!!"); | |
454 | |
455 | |
456 /* At this point we are returning */ | |
457 return_only: | |
458 if (returnValue) { | |
459 DEBUG_1("****We got an embedded JPEG for a canon CRW"); | |
460 | |
461 } | |
462 | |
463 DEBUG_EXIT("format_raw_test_canon"); | |
464 return returnValue; | |
465 | |
466 #undef DEBUG_2 | |
467 #undef DEBUG | |
468 #undef DEBUG_ENTRY | |
469 #undef DEBUG_EXIT | |
470 | |
471 } | |
472 | |
473 |