# HG changeset patch # User gqview # Date 1117131052 0 # Node ID 7cfa60beda765458e04592a8ed7a0949434dcb28 # Parent 458e396d3f35c4bba239664d0c52b8186d39223e Thu May 26 13:57:19 2005 John Ellis * 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. ##### diff -r 458e396d3f35 -r 7cfa60beda76 ChangeLog --- a/ChangeLog Wed May 18 23:52:16 2005 +0000 +++ b/ChangeLog Thu May 26 18:10:52 2005 +0000 @@ -1,3 +1,19 @@ +Thu May 26 13:57:19 2005 John Ellis + + * 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. + Wed May 18 19:36:49 2005 John Ellis * utilops.[ch] (file_util_rename_dir): New utility to rename a folder, diff -r 458e396d3f35 -r 7cfa60beda76 THIS_CVS_IS_NOT_UP_TO_DATE --- a/THIS_CVS_IS_NOT_UP_TO_DATE Wed May 18 23:52:16 2005 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -The CVS on sourceforge is far behind the latest version, -this CVS is not used for GQview development. - -There is no public CVS! - -(This CVS was set up as a test, and is here in the event GQview development CVS does go public) diff -r 458e396d3f35 -r 7cfa60beda76 src/Makefile.am --- a/src/Makefile.am Wed May 18 23:52:16 2005 +0000 +++ b/src/Makefile.am Thu May 26 18:10:52 2005 +0000 @@ -84,6 +84,10 @@ exif.h \ filelist.c \ filelist.h \ + format_canon.c \ + format_canon.h \ + format_fuji.c \ + format_fuji.h \ format_raw.c \ format_raw.h \ fullscreen.c \ diff -r 458e396d3f35 -r 7cfa60beda76 src/exif.c --- a/src/exif.c Wed May 18 23:52:16 2005 +0000 +++ b/src/exif.c Thu May 26 18:10:52 2005 +0000 @@ -1088,7 +1088,7 @@ { guint32 offset = 0; - if (format_raw_img_exif_offsets(-1, f, size, NULL, &offset)) + if (format_raw_img_exif_offsets(f, size, NULL, &offset)) { res = parse_TIFF(exif, (unsigned char*)f + offset, size - offset); } diff -r 458e396d3f35 -r 7cfa60beda76 src/filelist.c --- a/src/filelist.c Wed May 18 23:52:16 2005 +0000 +++ b/src/filelist.c Thu May 26 18:10:52 2005 +0000 @@ -211,7 +211,8 @@ /* These are the raw camera formats with embedded jpeg/exif. * (see format_raw.c) */ - filter_add_if_missing("raf", "Fujifilm raw camera format", ".raf", TRUE); + filter_add_if_missing("raf", "Fujifilm raw format", ".raf", TRUE); + filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", TRUE); } static GList *filter_to_list(const gchar *extensions) diff -r 458e396d3f35 -r 7cfa60beda76 src/format_canon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_canon.c Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,473 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + * + * + * Code to add support for Canon CR2 and CRW files, version 0.2 + * + * Developed by Daniel M. German, dmgerman at uvic.ca + * + * you can find the sources for this patch at http://turingmachine.org/~dmg/libdcraw/gqview/ + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include +#include +#include + +#include + +#include "intl.h" + +#include "format_canon.h" +#include "format_raw.h" + + +#if 0 + #define CANON_DEBUG +#endif + +#ifdef CANON_DEBUG +int canonEnableDebug = 0; +/* This should be really a stack, but I am too lazy to implement */ +#define DEBUG_ENABLE (canonEnableDebug = 0) +#define DEBUG_DISABLE (canonEnableDebug = 1) +/* It would be nice if these functions indented according to depth in the stack, but I am too lazy to implement */ + +#define DEBUG_ENTRY(a) (canonEnableDebug || fprintf(stderr, "Entering function: %s [%s:%d]\n", a, __FILE__, __LINE__)) +#define DEBUG_EXIT(a) (canonEnableDebug || fprintf(stderr, "Exiting function: %s [%s:%d]\n", a, __FILE__, __LINE__)) +#define DEBUG_1(a) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n", __FILE__, __LINE__)) +#define DEBUG_2(a,b) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, __FILE__, __LINE__)) +#define DEBUG_3(a,b,c) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, c, __FILE__, __LINE__)) + +#else +#define DEBUG_ENABLE +#define DEBUG_DISABLE +#define DEBUG_ENTRY(a) +#define DEBUG_EXIT(a) + +#define DEBUG_1(a) +#define DEBUG_2(a,b) +#define DEBUG_3(a,b,c) +#endif + + +/* canon_read_int4 + + +The problem with gqview is that sometimes the data is to be read from +a file, and sometimes it is in memory. This function tries to isolate +the rest of the code from having to deal with both cases + +This function reads a 4 byte unsigned integer, and fixes its endianism. + +If fd >= 0 then the value is read from the corresponding file descriptor + + in that case, if offset is > 0, then the value is read from that offset + + otherwise it is read from the current file pointer + +if fd < 0 then the value is read from the memory pointed by data + offset + + +offset is a pointer to the actual offset of the file. + +sizeInt can be 2 or 4 (it is the number of bytes to read) + +RETURNS true is no error, false if it can't read the value + + +*/ +static int canon_read_int(unsigned int *offset, const void *data, int sizeInt, unsigned int *value ) +{ + DEBUG_DISABLE; + + DEBUG_ENTRY("canon_read_int"); + /* Verify values before we do anything */ + if (sizeInt != 2 && sizeInt != 4) return FALSE; + if (offset == NULL) return FALSE; + if (*offset <= 0) return FALSE; + if (data == NULL) return FALSE; + if (value == NULL) return FALSE; + + if (sizeInt == 4) { + *value = GUINT32_FROM_LE(*(guint32*)(data + *offset)); + *offset +=4; + DEBUG_3("Read 4 bytes %d %x", *value, *value); + } else { + *value = GUINT16_FROM_LE(*(guint32*)(data + *offset)); + *offset +=2; + DEBUG_3("Read 2 bytes %d %x", *value, *value); + } + + DEBUG_EXIT("canon_read_int"); + + DEBUG_ENABLE; + return TRUE; +} + +#define CANON_HEADER_SIZE 26 + +/* + + The CR2 format is really a TIFF format. It is nicely documented in the TIFF V 6.0 document available from adobe. + + The CR2 file contains two thumbnails, one tiny and one decent sized. The record Id of the latter is 0x0111. + + The photo info is also available, in EXIF, and it looks like I don't need to do anything! Yeah! + +*/ + +static int canon_cr2_process_directory(void *data, int offsetIFD, guint *jpegLocation, guint *exifLocation) +{ + unsigned int offset; + int returnValue = FALSE; + + DEBUG_ENTRY("canon_cr2_process_directory"); + + /* The directory is a link list, after an array of records, the next 4 byptes point to the offset of the next directory. + + All offsets are absolution within the file (in CRWs the offsets are relative ). + + */ + + while (offsetIFD != 0 && offsetIFD != 0xFFFF) { + int countEntries=0; + int i; + /* Read directory, we start by reading number of entries in the directory */ + + offset = offsetIFD; + if (!canon_read_int(&offset, data, 2, &countEntries)) { + goto return_only; + } + DEBUG_2("Number of entries: %d\n", countEntries); + + for (i=0;i len) + goto return_only; + + currentOffset = heapHeaderOffset; + /* Let us read the number of records in the heap */ + if (!canon_read_int(¤tOffset, data, 2, &heapRecordsCount)) + goto return_only; + + DEBUG_2("heap record count %d ", heapRecordsCount); + + if (heapRecordsCount != 3) { + /* In all the cameras I have seen, this is always 3 + if not, something is wrong, so just quit */ + goto return_only; + } + + for (i=0;i<3;i++) { + int recordType; + int recordOffset; + int recordLength; + const void *jpgInDataOffset; + /* Read each record, to find jpg, it should be second */ + + if (!canon_read_int(¤tOffset, data, 2, &recordType)) + goto return_only; + + DEBUG_2("record type 0x%x ", recordType); + + if (recordType != 0x2007) { + /* Go to the next record, don't waste time, + but first, eat 8 bytes from header */ + currentOffset += 8; + continue; /* Nah, wrong record, go to next */ + } + /* Bingo, we are at the JPEG record */ + + /* Read length */ + if (!canon_read_int(¤tOffset, data, 4, &recordLength)) + goto return_only; + + DEBUG_2("record length %d ", recordLength); + + /* Read offset */ + + if (!canon_read_int(¤tOffset, data, 4, &recordOffset)) + goto return_only; + + DEBUG_2("record offset 0x%d ", recordOffset); + + /* Great, we now know where the JPEG is! + it is CANON_HEADER_SIZE (size of CRW header) + recordOffset + */ + + *image_offset = CANON_HEADER_SIZE + recordOffset; + DEBUG_2("image offset %d ", *image_offset); + + /* keep checking for potential errors */ + if (*image_offset > len) { + goto return_only; + } + /* Get the JPEG is */ + + jpgInDataOffset = data + *image_offset; + + if (memcmp(jpgInDataOffset, "\xff\xd8\xff\xdb",4) != 0) { + /* It is not at the JPEG! */ + DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset); + goto return_only; + } + returnValue = TRUE; + goto return_only; + } + /* undo whatever we need in case of an error*/ + DEBUG_1("We scan all records, but nothing was found!!!!!!!!!!!!!!!!!!"); + + + /* At this point we are returning */ +return_only: + if (returnValue) { + DEBUG_1("****We got an embedded JPEG for a canon CRW"); + + } + + DEBUG_EXIT("format_raw_test_canon"); + return returnValue; + +#undef DEBUG_2 +#undef DEBUG +#undef DEBUG_ENTRY +#undef DEBUG_EXIT + +} + + diff -r 458e396d3f35 -r 7cfa60beda76 src/format_canon.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_canon.h Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,31 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + * + * + * Code to add support for Canon CR2 and CRW files, version 0.2 + * + * Developed by Daniel M. German, dmgerman at uvic.ca + * + * you can find the sources for this patch at http://turingmachine.org/~dmg/libdcraw/gqview/ + * + */ + +#ifndef __FORMAT_RAW_CANON_H +#define __FORMAT_RAW_CANON_H + + +gint format_raw_test_canon(const void *data, const guint len, + guint *image_offset, guint *exif_offset); + + +#define FORMAT_RAW_CANON { "II", 2, "Canon crw format", format_raw_test_canon }, \ + { "\x49\x49\x2a\00", 4, "Canon cr2 format", format_raw_test_canon } + + +#endif + diff -r 458e396d3f35 -r 7cfa60beda76 src/format_fuji.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_fuji.c Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,59 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * Authors: + * Original version 2005 Lars Ellenberg, base on dcraw by David coffin. + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include +#include +#include + +#include + +#include "intl.h" + +#include "format_fuji.h" +#include "format_raw.h" + + +gint format_raw_test_fuji(const void *data, const guint len, + guint *image_offset, guint *exif_offset) +{ + guint io; + guint eo; + + if (len < 128 || + memcmp(data, "FUJIFILM", 8) != 0) + { + return FALSE; + } + + io = GUINT32_FROM_BE(*(guint32*)(data + 84)); + eo = *image_offset + 12; + + /* verify jpeg marker */ + if (memcmp(data + io, "\xff\xd8\xff\xe1", 4) != 0) + { + return FALSE; + } + + if (image_offset) *image_offset = io; + if (exif_offset) *exif_offset = eo; + + printf("raw Fuji format file\n"); + + return TRUE; +} + + diff -r 458e396d3f35 -r 7cfa60beda76 src/format_fuji.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_fuji.h Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,25 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * Authors: + * Original version 2005 Lars Ellenberg, base on dcraw by David coffin. + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + */ + +#ifndef __FORMAT_RAW_FUJI_H +#define __FORMAT_RAW_FUJI_H + + +gint format_raw_test_fuji(const void *data, const guint len, + guint *image_offset, guint *exif_offset); + + +#define FORMAT_RAW_FUJI { "FUJIFILM", 8, "Fuji raw format", format_raw_test_fuji } + + +#endif + diff -r 458e396d3f35 -r 7cfa60beda76 src/format_raw.c --- a/src/format_raw.c Wed May 18 23:52:16 2005 +0000 +++ b/src/format_raw.c Thu May 26 18:10:52 2005 +0000 @@ -14,9 +14,13 @@ # include "config.h" #endif + #include #include #include +#include +#include +#include #include @@ -24,54 +28,59 @@ #include "format_raw.h" -static gint format_raw_test_canon(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) -{ - return FALSE; -} +#include "format_canon.h" +#include "format_fuji.h" + + +typedef struct _FormatEntry FormatEntry; +struct _FormatEntry { + const void *header_pattern; + const guint header_length; + const gchar *description; + FormatRawParseFunc func_parse; +}; + -static gint format_raw_test_fuji(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) +static FormatEntry format_list[] = { + FORMAT_RAW_CANON, + FORMAT_RAW_FUJI, + { NULL, 0, NULL, NULL } +}; + + +static FormatEntry *format_raw_find(const void *data, const guint len) { - if (len < 128 || - memcmp(data, "FUJIFILM", 8) != 0) + gint n; + + n = 0; + while (format_list[n].header_pattern) { - return FALSE; + if (format_list[n].header_length <= len && + memcmp(data, format_list[n].header_pattern, format_list[n].header_length) == 0) + { + return &format_list[n]; + } + n++; } - *image_offset = GUINT32_FROM_BE(*(guint32*)(data + 84)); - *exif_offset = *image_offset + 12; -printf("found a raw fuji file!\n"); - return TRUE; + return NULL; } -static gint format_raw_test_nikon(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) +static gint format_raw_parse(FormatEntry *entry, + const void *data, const guint len, + guint *image_offset, guint *exif_offset) { - return FALSE; -} - - -gint format_raw_img_exif_offsets(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) -{ - guint32 io = 0; - guint32 eo = 0; + gint io = 0; + gint eo = 0; gint found; - if (fd < 0 && !data) return FALSE; -#if 0 - if (len < 512) return FALSE; -#endif + if (!entry || !entry->func_parse) return FALSE; - found = format_raw_test_canon(fd, data, len, &io, &eo) || - format_raw_test_fuji (fd, data, len, &io, &eo) || - format_raw_test_nikon(fd, data, len, &io, &eo); + found = entry->func_parse(data, len, &io, &eo); if (!found || io >= len - 4 || - eo >= len || - memcmp(data + io, "\xff\xd8\xff\xe1", 4) != 0) /* jpeg marker */ + eo >= len) { return FALSE; } @@ -82,5 +91,69 @@ return TRUE; } +gint format_raw_img_exif_offsets(const void *data, const guint len, + guint *image_offset, guint *exif_offset) +{ + FormatEntry *entry; + + if (!data || len < 1) return FALSE; + + entry = format_raw_find(data, len); + + if (!entry || !entry->func_parse) return FALSE; + + return format_raw_parse(entry, data, len, image_offset, exif_offset); +} +gint format_raw_img_exif_offsets_fd(int fd, const void *header_data, const guint header_len, + guint *image_offset, guint *exif_offset) +{ + FormatEntry *entry; + void *map_data = NULL; + size_t map_len = 0; + struct stat st; + gint success; + + if (!header_data || fd < 0) return FALSE; + + entry = format_raw_find(header_data, header_len); + + if (!entry || !entry->func_parse) return FALSE; + + if (fstat(fd, &st) == -1) + { + printf("Failed to stat file %d\n", fd); + return FALSE; + } + map_len = st.st_size; + map_data = mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0); + if (map_data == MAP_FAILED) + { + printf("Failed to mmap of file %d\n", fd); + return FALSE; + } + + success = format_raw_parse(entry, map_data, map_len, image_offset, exif_offset); + + if (munmap(map_data, map_len) == -1) + { + printf("Failed to unmap file %d\n", fd); + } + + if (success && image_offset) + { + if (lseek(fd, *image_offset, SEEK_SET) != *image_offset) + { + printf("Failed to seek to embedded image\n"); + + *image_offset = 0; + if (*exif_offset) *exif_offset = 0; + success = FALSE; + } + } + + return success; +} + + diff -r 458e396d3f35 -r 7cfa60beda76 src/format_raw.h --- a/src/format_raw.h Wed May 18 23:52:16 2005 +0000 +++ b/src/format_raw.h Thu May 26 18:10:52 2005 +0000 @@ -13,8 +13,16 @@ #ifndef __FORMAT_RAW_H #define __FORMAT_RAW_H -gint format_raw_img_exif_offsets(int fd, const void *data, const guint len, + +typedef gint (* FormatRawParseFunc)(const void *data, const guint len, + guint *image_offset, guint *exif_offset); + + +gint format_raw_img_exif_offsets(const void *data, const guint len, guint *image_offset, guint *exif_offset); +gint format_raw_img_exif_offsets_fd(int fd, const void *header_data, const guint header_len, + guint *image_offset, guint *exif_offset); + #endif diff -r 458e396d3f35 -r 7cfa60beda76 src/image-load.c --- a/src/image-load.c Wed May 18 23:52:16 2005 +0000 +++ b/src/image-load.c Thu May 26 18:10:52 2005 +0000 @@ -217,17 +217,23 @@ b = read(il->load_fd, &buf, sizeof(buf)); + if (b > 1 && + format_raw_img_exif_offsets_fd(il->load_fd, buf, b, &offset, NULL)) + { + if (debug) printf("Raw file %s contains embedded image\n", il->path); + + b = read(il->load_fd, &buf, sizeof(buf)); + } + if (b < 1) { image_loader_stop(il); return FALSE; } - format_raw_img_exif_offsets(il->load_fd, buf, b, &offset, NULL); - - if (gdk_pixbuf_loader_write(il->loader, buf + offset, b - offset, NULL)) + if (gdk_pixbuf_loader_write(il->loader, buf, b, NULL)) { - il->bytes_read += b; + il->bytes_read += b + offset; if (b < sizeof(buf)) {