📄 format_canon.c
字号:
/* * 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 <stdio.h>#include <string.h>#include <unistd.h>#include <glib.h>#include "intl.h"#include "format_canon.h"#include "format_raw.h"#include "exif.h"/* *----------------------------------------------------------------------------- * Raw (CR2, CRW) embedded jpeg extraction for Canon *----------------------------------------------------------------------------- */static gint canon_cr2_tiff_entry(unsigned char *data, const guint len, guint offset, ExifByteOrder bo, guint *image_offset, gint *jpeg_encoding){ guint tag; guint type; guint count; guint jpeg_start; /* the two (tiff compliant) tags we want are: * 0x0103 image compression type (must be type 6 for jpeg) * 0x0111 jpeg start offset * only use the first segment that contains an actual jpeg - as there * is a another that contains the raw data. */ tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo); type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo); count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo); /* tag 0x0103 contains the compression type for this segment's image data */ if (tag == 0x0103) { if (ExifFormatList[type].size * count == 2 && exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_DATA, bo) == 6) { *jpeg_encoding = TRUE; } return FALSE; } /* find and verify jpeg offset */ if (tag != 0x0111 || !jpeg_encoding) return FALSE; /* make sure data segment contains 4 bytes */ if (ExifFormatList[type].size * count != 4) return FALSE; jpeg_start = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo); /* verify this is jpeg data */ if (len < jpeg_start + 4 || memcmp(data + jpeg_start, "\xff\xd8", 2) != 0) { return FALSE; } *image_offset = jpeg_start; return TRUE;}static gint canon_cr2_tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder bo, guint *image_offset){ gint jpeg_encoding = FALSE; guint count; guint i; if (len < offset + 2) return 0; count = exif_byte_get_int16(data + offset, bo); offset += 2; if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0; for (i = 0; i < count; i++) { if (canon_cr2_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, image_offset, &jpeg_encoding)) { return 0; } } return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);}gint format_canon_raw_cr2(unsigned char *data, const guint len, guint *image_offset, guint *exif_offset){ guint jpeg_offset = 0; ExifByteOrder bo; guint offset; gint level; /* cr2 files are tiff files with a few canon specific directory tags * they are (always ?) in little endian format */ if (!exif_tiff_directory_offset(data, len, &offset, &bo)) return FALSE; level = 0; while (offset && level < EXIF_TIFF_MAX_LEVELS) { offset = canon_cr2_tiff_table(data, len, offset, bo, &jpeg_offset); level++; if (jpeg_offset != 0) { if (image_offset) *image_offset = jpeg_offset; return TRUE; } } return FALSE;}#define CRW_BYTE_ORDER EXIF_BYTE_ORDER_INTEL#define CRW_HEADER_SIZE 26#define CRW_DIR_ENTRY_SIZE 10gint format_canon_raw_crw(unsigned char *data, const guint len, guint *image_offset, guint *exif_offset){ guint block_offset; guint data_length; guint offset; guint count; guint i; /* CRW header starts with 2 bytes for byte order (always "II", little endian), * 4 bytes for start of root block, * and 8 bytes of magic for file type and format "HEAPCCDR" * (also 4 bytes for file version, and 8 bytes reserved) * * CIFF specification in pdf format is available on some websites, * search for "CIFFspecV1R03.pdf" or "CIFFspecV1R04.pdf" */ if (len < CRW_HEADER_SIZE || memcmp(data, "II", 2) != 0 || memcmp(data + 6, "HEAPCCDR", 8) != 0) { return FALSE; } block_offset = exif_byte_get_int32(data + 2, CRW_BYTE_ORDER); /* the end of the root block equals end of file, * the last 4 bytes of the root block contain the block's data size */ offset = len - 4; data_length = exif_byte_get_int32(data + offset, CRW_BYTE_ORDER); offset = block_offset + data_length; if (len < offset + 2) return FALSE; /* number of directory entries for this block is in * the next two bytes after the data for this block. */ count = exif_byte_get_int16(data + offset, CRW_BYTE_ORDER); offset += 2; if (len < offset + count * CRW_DIR_ENTRY_SIZE + 4) return FALSE; /* walk the directory entries looking for type jpeg (tag 0x2007), * for reference, other tags are 0x2005 for raw and 0x300a for photo info: */ for (i = 0; i < count ; i++) { guint entry_offset; guint record_type; guint record_offset; guint record_length; entry_offset = offset + i * CRW_DIR_ENTRY_SIZE; /* entry is 10 bytes (in order): * 2 for type * 4 for length of data * 4 for offset into data segment of this block */ record_type = exif_byte_get_int16(data + entry_offset, CRW_BYTE_ORDER); record_length = exif_byte_get_int32(data + entry_offset + 2, CRW_BYTE_ORDER); record_offset = exif_byte_get_int32(data + entry_offset + 6, CRW_BYTE_ORDER); /* tag we want for jpeg data */ if (record_type == 0x2007) { guint jpeg_offset; jpeg_offset = block_offset + record_offset; if (len < jpeg_offset + record_length || record_length < 4 || memcmp(data + jpeg_offset, "\xff\xd8\xff\xdb", 4) != 0) { return FALSE; } /* we now know offset and verified jpeg */ *image_offset = jpeg_offset; return TRUE; } } return FALSE;}/* *----------------------------------------------------------------------------- * EXIF Makernote for Canon *----------------------------------------------------------------------------- */static ExifTextList CanonSet1MacroMode[] = { { 1, "macro" }, { 2, "normal" }, EXIF_TEXT_LIST_END};static ExifTextList CanonSet1Quality[] = { { 2, "normal" }, { 3, "fine" }, { 4, "raw" }, { 5, "superfine" }, EXIF_TEXT_LIST_END};static ExifTextList CanonSet1FlashMode[] = { { 0, "flash not fired" }, { 1, "auto" }, { 2, "on" }, { 3, "red-eye reduction" }, { 4, "slow sync" }, { 5, "auto + red-eye reduction" }, { 6, "on + red-eye reduction" }, { 16, "external flash" }, EXIF_TEXT_LIST_END};static ExifTextList CanonSet1DriveMode[] = { { 0, "single or timer" }, { 1, "continuous" }, EXIF_TEXT_LIST_END};static ExifTextList CanonSet1FocusMode[] = { { 0, "one-shot AF" }, { 1, "AI servo AF" }, { 2, "AI focus AF" }, { 3, "manual" }, { 4, "single" }, { 5, "continuous" }, { 6, "manual" }, EXIF_TEXT_LIST_END};static ExifTextList CanonSet1ImageSize[] = { { 0, "large" }, { 1, "medium" }, { 2, "small" }, /* where (or) does Medium 1/2 fit in here ? */ EXIF_TEXT_LIST_END};static ExifTextList CanonSet1ShootingMode[] = { { 0, "auto" }, { 1, "manual" }, { 2, "landscape" }, { 3, "fast shutter" }, { 4, "slow shutter" }, { 5, "night" }, { 6, "black and white" }, { 7, "sepia" }, { 8, "portrait" }, { 9, "sports" }, { 10, "macro" }, { 11, "pan focus" }, EXIF_TEXT_LIST_END};/* Don't think this is interpreted correctly/completely, A60 at 2.5x Digital sets value of 3 */static ExifTextList CanonSet1DigitalZoom[] = { { 0, "none" }, { 1, "2x" }, { 2, "4x" }, { 3, "other" }, EXIF_TEXT_LIST_END};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -