📄 dcraw.c
字号:
/* dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2008 by Dave Coffin, dcoffin a cybercom o net This is a command-line ANSI C program to convert raw photos from any digital camera on any computer running any operating system. No license is required to download and use dcraw.c. However, to lawfully redistribute dcraw, you must either (a) offer, at no extra charge, full source code* for all executable files containing RESTRICTED functions, (b) distribute this code under the GPL Version 2 or later, (c) remove all RESTRICTED functions, re-implement them, or copy them from an earlier, unrestricted Revision of dcraw.c, or (d) purchase a license from the author. The functions that process Foveon images have been RESTRICTED since Revision 1.237. All other code remains free for all uses. *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". $Revision: 1.402 $ $Date: 2008/04/20 08:09:37 $ */#define VERSION "8.86"#define _GNU_SOURCE#define _USE_MATH_DEFINES#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <float.h>#include <limits.h>#include <math.h>#include <setjmp.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <sys/types.h>/* NO_JPEG disables decoding of compressed Kodak DC120 files. NO_LCMS disables the "-p" option. */#ifndef NO_JPEG#include <jpeglib.h>#endif#ifndef NO_LCMS#include <lcms.h>#endif#ifdef LOCALEDIR#include <libintl.h>#define _(String) gettext(String)#else#define _(String) (String)#endif#ifdef DJGPP#define fseeko fseek#define ftello ftell#else#define fgetc getc_unlocked#endif#ifdef __CYGWIN__#include <io.h>#endif#ifdef WIN32#include <sys/utime.h>#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")#define snprintf _snprintf#define strcasecmp stricmp#define strncasecmp strnicmptypedef __int64 INT64;typedef unsigned __int64 UINT64;#else#include <unistd.h>#include <utime.h>#include <netinet/in.h>typedef long long INT64;typedef unsigned long long UINT64;#endif#ifdef LJPEG_DECODE#error Please compile dcraw.c by itself.#error Do not link it with ljpeg_decode.#endif#ifndef LONG_BIT#define LONG_BIT (8 * sizeof (long))#endif#define ushort UshORttypedef unsigned char uchar;typedef unsigned short ushort;/* All global variables are defined here, and all functions that access them are prefixed with "CLASS". Note that a thread-safe C++ class cannot have non-const static local variables. */FILE *ifp;short order;char *ifname, *meta_data;char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;time_t timestamp;unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id;off_t strip_offset, data_offset;off_t thumb_offset, meta_offset, profile_offset;unsigned thumb_length, meta_length, profile_length;unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;unsigned black, maximum, mix_green, raw_color, use_gamma, zero_is_bad;unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;unsigned tile_width, tile_length, gpsdata[32];ushort raw_height, raw_width, height, width, top_margin, left_margin;ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;int flip, tiff_flip, colors;double pixel_aspect, aber[4]={1,1,1,1};ushort (*image)[4], white[8][8], curve[0x4001], cr2_slice[3], sraw_mul[4];float bright=1, user_mul[4]={0,0,0,0}, threshold=0;int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1;int output_color=1, output_bps=8, output_tiff=0, med_passes=0;int no_auto_bright=0;unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];const double xyz_rgb[3][3] = { /* XYZ from RGB */ { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } };const float d65_white[3] = { 0.950456, 1, 1.088754 };int histogram[4][0x2000];void (*write_thumb)(FILE *), (*write_fun)(FILE *);void (*load_raw)(), (*thumb_load_raw)();jmp_buf failure;struct decode { struct decode *branch[2]; int leaf;} first_decode[2048], *second_decode, *free_decode;struct { int width, height, bps, comp, phint, offset, flip, samples, bytes;} tiff_ifd[10];struct { int format, key_off, black, black_off, split_col, tag_21a; float tag_210;} ph1;#define CLASS#define FORC(cnt) for (c=0; c < cnt; c++)#define FORC3 FORC(3)#define FORC4 FORC(4)#define FORCC FORC(colors)#define SQR(x) ((x)*(x))#define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31))#define MIN(a,b) ((a) < (b) ? (a) : (b))#define MAX(a,b) ((a) > (b) ? (a) : (b))#define LIM(x,min,max) MAX(min,MIN(x,max))#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y))#define CLIP(x) LIM(x,0,65535)#define SWAP(a,b) { a ^= b; a ^= (b ^= a); }/* In order to inline this calculation, I make the risky assumption that all filter patterns can be described by a repeating pattern of eight rows and two columns Do not use the FC or BAYER macros with the Leaf CatchLight, because its pattern is 16x16, not 2x8. Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M 4 C Y C Y C Y 4 Y C Y C Y C PowerShot A5 5 G M G M G M 5 G M G M G M 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y 7 M G M G M G 7 M G M G M G 0 1 2 3 4 5 0 C Y C Y C Y 1 G M G M G M 2 C Y C Y C Y 3 M G M G M G All RGB cameras use one of these Bayer grids: 0x16161616: 0x61616161: 0x49494949: 0x94949494: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B */#define FC(row,col) \ (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)#define BAYER(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)]#define BAYER2(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][fc(row,col)]int CLASS fc (int row, int col){ static const char filter[16][16] = { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; if (filters != 1) return FC(row,col); return filter[(row+top_margin) & 15][(col+left_margin) & 15];}#ifndef __GLIBC__char *my_memmem (char *haystack, size_t haystacklen, char *needle, size_t needlelen){ char *c; for (c = haystack; c <= haystack + haystacklen - needlelen; c++) if (!memcmp (c, needle, needlelen)) return c; return 0;}#define memmem my_memmem#endifvoid CLASS merror (void *ptr, char *where){ if (ptr) return; fprintf (stderr,_("%s: Out of memory in %s\n"), ifname, where); longjmp (failure, 1);}void CLASS derror(){ if (!data_error) { fprintf (stderr, "%s: ", ifname); if (feof(ifp)) fprintf (stderr,_("Unexpected end of file\n")); else fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } data_error = 1;}ushort CLASS sget2 (uchar *s){ if (order == 0x4949) /* "II" means little-endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian */ return s[0] << 8 | s[1];}ushort CLASS get2(){ uchar str[2] = { 0xff,0xff }; fread (str, 1, 2, ifp); return sget2(str);}unsigned CLASS sget4 (uchar *s){ if (order == 0x4949) return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; else return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];}#define sget4(s) sget4((uchar *)s)unsigned CLASS get4(){ uchar str[4] = { 0xff,0xff,0xff,0xff }; fread (str, 1, 4, ifp); return sget4(str);}unsigned CLASS getint (int type){ return type == 3 ? get2() : get4();}float CLASS int_to_float (int i){ union { int i; float f; } u; u.i = i; return u.f;}double CLASS getreal (int type){ union { char c[8]; double d; } u; int i, rev; switch (type) { case 3: return (unsigned short) get2(); case 4: return (unsigned int) get4(); case 5: u.d = (unsigned int) get4(); return u.d / (unsigned int) get4(); case 8: return (signed short) get2(); case 9: return (signed int) get4(); case 10: u.d = (signed int) get4(); return u.d / (signed int) get4(); case 11: return int_to_float (get4()); case 12: rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); for (i=0; i < 8; i++) u.c[i ^ rev] = fgetc(ifp); return u.d; default: return fgetc(ifp); }}void CLASS read_shorts (ushort *pixel, int count){ if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) swab (pixel, pixel, count*2);}void CLASS canon_600_fixed_wb (int temp){ static const short mul[4][5] = { { 667, 358,397,565,452 }, { 731, 390,367,499,517 }, { 1119, 396,348,448,537 }, { 1399, 485,431,508,688 } }; int lo, hi, i; float frac=0; for (lo=4; --lo; ) if (*mul[lo] <= temp) break; for (hi=0; hi < 3; hi++) if (*mul[hi] >= temp) break; if (lo != hi) frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); for (i=1; i < 5; i++) pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]);}/* Return values: 0 = white 1 = near white 2 = not white */int CLASS canon_600_color (int ratio[2], int mar){ int clipped=0, target, miss; if (flash_used) { if (ratio[1] < -104) { ratio[1] = -104; clipped = 1; } if (ratio[1] > 12) { ratio[1] = 12; clipped = 1; } } else { if (ratio[1] < -264 || ratio[1] > 461) return 2; if (ratio[1] < -50) { ratio[1] = -50; clipped = 1; } if (ratio[1] > 307) { ratio[1] = 307; clipped = 1; } } target = flash_used || ratio[1] < 197 ? -38 - (398 * ratio[1] >> 10) : -123 + (48 * ratio[1] >> 10); if (target - mar <= ratio[0] && target + 20 >= ratio[0] && !clipped) return 0; miss = target - ratio[0]; if (abs(miss) >= mar*4) return 2; if (miss < -20) miss = -20; if (miss > mar) miss = mar; ratio[0] = target - miss; return 1;}void CLASS canon_600_auto_wb(){ int mar, row, col, i, j, st, count[] = { 0,0 }; int test[8], total[2][8], ratio[2][2], stat[2]; memset (&total, 0, sizeof total); i = canon_ev + 0.5; if (i < 10) mar = 150; else if (i > 12) mar = 20; else mar = 280 - 20 * i; if (flash_used) mar = 80; for (row=14; row < height-14; row+=4) for (col=10; col < width; col+=2) { for (i=0; i < 8; i++) test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = BAYER(row+(i >> 1),col+(i & 1)); for (i=0; i < 8; i++) if (test[i] < 150 || test[i] > 1500) goto next; for (i=0; i < 4; i++) if (abs(test[i] - test[i+4]) > 50) goto next; for (i=0; i < 2; i++) { for (j=0; j < 4; j+=2) ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; stat[i] = canon_600_color (ratio[i], mar); } if ((st = stat[0] | stat[1]) > 1) goto next; for (i=0; i < 2; i++) if (stat[i]) for (j=0; j < 2; j++) test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; for (i=0; i < 8; i++) total[st][i] += test[i]; count[st]++;next: ; } if (count[0] | count[1]) { st = count[0]*200 < count[1]; for (i=0; i < 4; i++) pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); }}void CLASS canon_600_coeff(){ static const short table[6][12] = { { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; int t=0, i, c; float mc, yc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -