summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-18 20:37:27 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-18 20:37:27 +0000
commit3f38a0b873dd92aed82ca1c47cc9af5417ae68f5 (patch)
tree8725d04c261a0c02398103c7118b5a459acefd67
parent080528894f0f3ac6940d70065ae078d195ca8c6d (diff)
downloadlibkdcraw-3f38a0b873dd92aed82ca1c47cc9af5417ae68f5.tar.gz
libkdcraw-3f38a0b873dd92aed82ca1c47cc9af5417ae68f5.zip
Added missing libraw files
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/libkdcraw@1076753 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
-rw-r--r--libkdcraw/libraw/Makefile.am14
-rw-r--r--libkdcraw/libraw/internal/dcraw_common.cpp8284
-rw-r--r--libkdcraw/libraw/internal/dcraw_fileio.cpp211
-rw-r--r--libkdcraw/libraw/internal/defines.h129
-rw-r--r--libkdcraw/libraw/internal/foveon.cpp812
-rw-r--r--libkdcraw/libraw/internal/libraw_internal_funcs.h201
-rw-r--r--libkdcraw/libraw/internal/var_defines.h181
-rw-r--r--libkdcraw/libraw/libraw/libraw.h229
-rw-r--r--libkdcraw/libraw/libraw/libraw_alloc.h98
-rw-r--r--libkdcraw/libraw/libraw/libraw_const.h160
-rw-r--r--libkdcraw/libraw/libraw/libraw_datastream.h303
-rw-r--r--libkdcraw/libraw/libraw/libraw_internal.h241
-rw-r--r--libkdcraw/libraw/libraw/libraw_types.h293
-rw-r--r--libkdcraw/libraw/libraw/libraw_version.h47
-rw-r--r--libkdcraw/libraw/samples/4channels.cpp187
-rw-r--r--libkdcraw/libraw/samples/dcraw_emu.cpp281
-rw-r--r--libkdcraw/libraw/samples/dcraw_half.c83
-rw-r--r--libkdcraw/libraw/samples/half_mt.c178
-rw-r--r--libkdcraw/libraw/samples/half_mt_win32.c212
-rw-r--r--libkdcraw/libraw/samples/identify.cpp147
-rw-r--r--libkdcraw/libraw/samples/mem_image.cpp198
-rw-r--r--libkdcraw/libraw/samples/simple_dcraw.cpp213
-rw-r--r--libkdcraw/libraw/samples/unprocessed_raw.cpp156
-rw-r--r--libkdcraw/libraw/src/libraw_c_api.cpp143
-rw-r--r--libkdcraw/libraw/src/libraw_cxx.cpp1940
-rw-r--r--libkdcraw/test/Makefile.am51
-rw-r--r--libkdcraw/test/raw2png.cpp123
-rw-r--r--po/pt_BR/Makefile.am3
-rw-r--r--po/pt_BR/libkdcraw.po413
29 files changed, 15531 insertions, 0 deletions
diff --git a/libkdcraw/libraw/Makefile.am b/libkdcraw/libraw/Makefile.am
new file mode 100644
index 0000000..77ed085
--- /dev/null
+++ b/libkdcraw/libraw/Makefile.am
@@ -0,0 +1,14 @@
+
+# LibRaw definitions
+KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DDCRAW_VERBOSE -DUSE_LCMS
+
+INCLUDES = $(all_includes)
+
+# Requires by dcraw implementation from libraw.
+KDE_OPTIONS = nofinal
+
+noinst_LTLIBRARIES = libraw.la
+
+libraw_la_CXXFLAGS = -w
+libraw_la_SOURCES = src/libraw_cxx.cpp src/libraw_c_api.cpp internal/dcraw_common.cpp internal/dcraw_fileio.cpp internal/foveon.cpp
+libraw_la_LDFLAGS = $(LIBJPEG) $(LCMS_LIBS)
diff --git a/libkdcraw/libraw/internal/dcraw_common.cpp b/libkdcraw/libraw/internal/dcraw_common.cpp
new file mode 100644
index 0000000..2a79d50
--- /dev/null
+++ b/libkdcraw/libraw/internal/dcraw_common.cpp
@@ -0,0 +1,8284 @@
+/*
+ GENERATED FILE, DO NOT EDIT
+ Generated from dcraw/dcraw.c at Tue Apr 7 15:14:48 2009
+ Look into original file (probably http://cybercom.net/~dcoffin/dcraw/dcraw.c)
+ for copyright information.
+*/
+
+#define CLASS LibRaw::
+#include "libraw/libraw_types.h"
+#define LIBRAW_LIBRARY_BUILD
+#define LIBRAW_IO_REDEFINED
+#include "libraw/libraw.h"
+#include "internal/defines.h"
+#include "internal/var_defines.h"
+
+
+#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
+#endif
+
+
+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 ((char*)pixel, (char*)pixel, count*2);
+}
+void CLASS canon_black (double dark[2])
+{
+ int c, diff, row, col;
+
+ if (raw_width < width+4) return;
+ FORC(2) dark[c] /= (raw_width-width-2) * height >> 1;
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(!( filtering_mode & LIBRAW_FILTERING_NOBLACKS) )
+ {
+#endif
+ if ((diff = dark[0] - dark[1]))
+ for (row=0; row < height; row++)
+ for (col=1; col < width; col+=2)
+ BAYER(row,col) += diff;
+#ifdef LIBRAW_LIBRARY_BUILD
+ }
+#endif
+ dark[1] += diff;
+ black = (dark[0] + dark[1] + 1) / 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]);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+}
+
+/* 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]);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CALCULATED;
+#endif
+ }
+}
+
+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;
+
+ mc = pre_mul[1] / pre_mul[2];
+ yc = pre_mul[3] / pre_mul[2];
+ if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1;
+ if (mc > 1.28 && mc <= 2) {
+ if (yc < 0.8789) t=3;
+ else if (yc <= 2) t=4;
+ }
+ if (flash_used) t=5;
+ for (raw_color = i=0; i < 3; i++)
+ FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.rgb_cam_state = LIBRAW_COLORSTATE_CALCULATED;
+#endif
+}
+
+void CLASS canon_600_load_raw()
+{
+ uchar data[1120], *dp;
+ ushort pixel[896], *pix;
+ int irow, row, col, val;
+ static const short mul[4][2] =
+ { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } };
+
+ for (irow=row=0; irow < height; irow++) {
+ if (fread (data, 1, raw_width*5/4, ifp) < raw_width*5/4) derror();
+ for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8) {
+ pix[0] = (dp[0] << 2) + (dp[1] >> 6 );
+ pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3);
+ pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3);
+ pix[3] = (dp[4] << 2) + (dp[1] & 3);
+ pix[4] = (dp[5] << 2) + (dp[9] & 3);
+ pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3);
+ pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3);
+ pix[7] = (dp[8] << 2) + (dp[9] >> 6 );
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = pixel[col];
+ for (col=width; col < raw_width; col++)
+ {
+ black += pixel[col];
+#ifdef LIBRAW_LIBRARY_BUILD
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = pixel[col];
+#endif
+ }
+ if ((row+=2) > height) row = 1;
+ }
+ if (raw_width > width)
+ black = black / ((raw_width - width) * height) - 4;
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+#ifdef LIBRAW_LIBRARY_BUILD
+ if( filtering_mode & LIBRAW_FILTERING_NOBLACKS)
+ val = BAYER(row,col);
+ else
+#endif
+ if ((val = BAYER(row,col) - black) < 0) val = 0;
+ val = val * mul[row & 3][col & 1] >> 9;
+ BAYER(row,col) = val;
+ }
+ canon_600_fixed_wb(1311);
+ canon_600_auto_wb();
+ canon_600_coeff();
+ maximum = (0x3ff - black) * 1109 >> 9;
+ black = 0;
+}
+
+void CLASS remove_zeroes()
+{
+ unsigned row, col, tot, n, r, c;
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,0,2);
+#endif
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++)
+ if (BAYER(row,col) == 0) {
+ tot = n = 0;
+ for (r = row-2; r <= row+2; r++)
+ for (c = col-2; c <= col+2; c++)
+ if (r < height && c < width &&
+ FC(r,c) == FC(row,col) && BAYER(r,c))
+ tot += (n++,BAYER(r,c));
+ if (n) BAYER(row,col) = tot/n;
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,1,2);
+#endif
+}
+
+int CLASS canon_s2is()
+{
+ unsigned row;
+
+ for (row=0; row < 100; row++) {
+ fseek (ifp, row*3340 + 3284, SEEK_SET);
+ if (getc(ifp) > 15) return 1;
+ }
+ return 0;
+}
+
+void CLASS canon_a5_load_raw()
+{
+ ushort data[2565], *dp, pixel;
+ int vbits=0, buf=0, row, col, bc=0;
+
+ order = 0x4949;
+ for (row=-top_margin; row < raw_height-top_margin; row++) {
+ read_shorts (dp=data, raw_width * 10 / 16);
+ for (col=-left_margin; col < raw_width-left_margin; col++) {
+ if ((vbits -= 10) < 0)
+ buf = (vbits += 16, (buf << 16) + *dp++);
+ pixel = buf >> vbits & 0x3ff;
+#ifdef LIBRAW_LIBRARY_BUILD
+ ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin);
+ if(dfp) *dfp = pixel;
+#endif
+ if ((unsigned) row < height && (unsigned) col < width)
+ BAYER(row,col) = pixel;
+ else if (col > 1-left_margin && col != width)
+ black += (bc++,pixel);
+ }
+ }
+ if (bc) black /= bc;
+ maximum = 0x3ff;
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(!(filtering_mode & LIBRAW_FILTERING_NOZEROES))
+#endif
+ if (raw_width > 1600) remove_zeroes();
+}
+
+/*
+ getbits(-1) initializes the buffer
+ getbits(n) where 0 <= n <= 25 returns an n-bit integer
+ */
+unsigned CLASS getbits (int nbits)
+{
+#ifdef LIBRAW_NOTHREADS
+ static unsigned bitbuf=0;
+ static int vbits=0, reset=0;
+#else
+#define bitbuf tls->getbits.bitbuf
+#define vbits tls->getbits.vbits
+#define reset tls->getbits.reset
+#endif
+ unsigned c;
+
+ if (nbits == -1)
+ return bitbuf = vbits = reset = 0;
+ if (nbits == 0 || reset) return 0;
+ while (vbits < nbits) {
+ if ((c = fgetc(ifp)) == EOF) derror();
+ if ((reset = zero_after_ff && c == 0xff && fgetc(ifp))) return 0;
+ bitbuf = (bitbuf << 8) + (uchar) c;
+ vbits += 8;
+ }
+ vbits -= nbits;
+ return bitbuf << (32-nbits-vbits) >> (32-nbits);
+#ifndef LIBRAW_NOTHREADS
+#undef bitbuf
+#undef vbits
+#undef reset
+#endif
+}
+
+void CLASS init_decoder()
+{
+ memset (first_decode, 0, sizeof first_decode);
+ free_decode = first_decode;
+}
+
+/*
+ Construct a decode tree according to the specification in *source.
+ The first 16 bytes specify how many codes should be 1-bit, 2-bit
+ 3-bit, etc. Bytes after that are the leaf values.
+
+ For example, if the source is
+
+ { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0,
+ 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff },
+
+ then the code is
+
+ 00 0x04
+ 010 0x03
+ 011 0x05
+ 100 0x06
+ 101 0x02
+ 1100 0x07
+ 1101 0x01
+ 11100 0x08
+ 11101 0x09
+ 11110 0x00
+ 111110 0x0a
+ 1111110 0x0b
+ 1111111 0xff
+ */
+uchar * CLASS make_decoder (const uchar *source, int level)
+{
+ struct decode *cur;
+#ifndef LIBRAW_NOTHREADS
+#define t_leaf tls->make_decoder_leaf
+#else
+ static int t_leaf;
+#endif
+ int i, next;
+
+ if (level==0) t_leaf=0;
+ cur = free_decode++;
+ if (free_decode > first_decode+2048) {
+#ifdef LIBRAW_LIBRARY_BUILD
+ throw LIBRAW_EXCEPTION_DECODE_RAW;
+#else
+ fprintf (stderr,_("%s: decoder table overflow\n"), ifname);
+ longjmp (failure, 2);
+#endif
+ }
+ for (i=next=0; i <= t_leaf && next < 16; )
+ i += source[next++];
+ if (i > t_leaf) {
+ if (level < next) {
+ cur->branch[0] = free_decode;
+ make_decoder (source, level+1);
+ cur->branch[1] = free_decode;
+ make_decoder (source, level+1);
+ } else
+ cur->leaf = source[16 + t_leaf++];
+ }
+ return (uchar *) source + 16 + t_leaf;
+#ifndef LIBRAW_NOTHREADS
+#undef t_leaf
+#endif
+}
+
+void CLASS crw_init_tables (unsigned table)
+{
+ static const uchar first_tree[3][29] = {
+ { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0,
+ 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff },
+ { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0,
+ 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff },
+ { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0,
+ 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff },
+ };
+ static const uchar second_tree[3][180] = {
+ { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139,
+ 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08,
+ 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0,
+ 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42,
+ 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57,
+ 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9,
+ 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98,
+ 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6,
+ 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4,
+ 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7,
+ 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1,
+ 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64,
+ 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba,
+ 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4,
+ 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff },
+ { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140,
+ 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06,
+ 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32,
+ 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51,
+ 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26,
+ 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59,
+ 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9,
+ 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99,
+ 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85,
+ 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8,
+ 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a,
+ 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9,
+ 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8,
+ 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8,
+ 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff },
+ { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117,
+ 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08,
+ 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22,
+ 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34,
+ 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41,
+ 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48,
+ 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69,
+ 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8,
+ 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94,
+ 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a,
+ 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6,
+ 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62,
+ 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5,
+ 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3,
+ 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff }
+ };
+ if (table > 2) table = 2;
+ init_decoder();
+ make_decoder ( first_tree[table], 0);
+ second_decode = free_decode;
+ make_decoder (second_tree[table], 0);
+}
+
+/*
+ Return 0 if the image starts with compressed data,
+ 1 if it starts with uncompressed low-order bits.
+
+ In Canon compressed data, 0xff is always followed by 0x00.
+ */
+int CLASS canon_has_lowbits()
+{
+ uchar test[0x4000];
+ int ret=1, i;
+
+ fseek (ifp, 0, SEEK_SET);
+ fread (test, 1, sizeof test, ifp);
+ for (i=540; i < sizeof test - 1; i++)
+ if (test[i] == 0xff) {
+ if (test[i+1]) return 1;
+ ret=0;
+ }
+ return ret;
+}
+
+void CLASS canon_compressed_load_raw()
+{
+ ushort *pixel, *prow;
+ int nblocks, lowbits, i, row, r, col, save, val;
+ unsigned irow, icol;
+ struct decode *decode, *dindex;
+ int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2];
+ double dark[2] = { 0,0 };
+ uchar c;
+
+ crw_init_tables (tiff_compress);
+ pixel = (ushort *) calloc (raw_width*8, sizeof *pixel);
+ merror (pixel, "canon_compressed_load_raw()");
+ lowbits = canon_has_lowbits();
+ if (!lowbits) maximum = 0x3ff;
+ fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET);
+ zero_after_ff = 1;
+ getbits(-1);
+ for (row=0; row < raw_height; row+=8) {
+ nblocks = MIN (8, raw_height-row) * raw_width >> 6;
+ for (block=0; block < nblocks; block++) {
+ memset (diffbuf, 0, sizeof diffbuf);
+ decode = first_decode;
+ for (i=0; i < 64; i++ ) {
+ for (dindex=decode; dindex->branch[0]; )
+ dindex = dindex->branch[getbits(1)];
+ leaf = dindex->leaf;
+ decode = second_decode;
+ if (leaf == 0 && i) break;
+ if (leaf == 0xff) continue;
+ i += leaf >> 4;
+ len = leaf & 15;
+ if (len == 0) continue;
+ diff = getbits(len);
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ if (i < 64) diffbuf[i] = diff;
+ }
+ diffbuf[0] += carry;
+ carry = diffbuf[0];
+ for (i=0; i < 64; i++ ) {
+ if (pnum++ % raw_width == 0)
+ base[0] = base[1] = 512;
+ if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10)
+ derror();
+ }
+ }
+ if (lowbits) {
+ save = ftell(ifp);
+ fseek (ifp, 26 + row*raw_width/4, SEEK_SET);
+ for (prow=pixel, i=0; i < raw_width*2; i++) {
+ c = fgetc(ifp);
+ for (r=0; r < 8; r+=2, prow++) {
+ val = (*prow << 2) + ((c >> r) & 3);
+ if (raw_width == 2672 && val < 512) val += 2;
+ *prow = val;
+ }
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ for (r=0; r < 8; r++) {
+ irow = row - top_margin + r;
+#ifndef LIBRAW_LIBRARY_BUILD
+ if (irow >= height) continue;
+#endif
+ for (col=0; col < raw_width; col++) {
+#ifdef LIBRAW_LIBRARY_BUILD
+ ushort *dfp = get_masked_pointer(row+r,col);
+ if(dfp) *dfp = pixel[r*raw_width+col];
+ if (irow >= height) continue; // skip for top/bottom rows
+#endif
+ icol = col - left_margin;
+ if (icol < width)
+ BAYER(irow,icol) = pixel[r*raw_width+col];
+ else if (col > 1)
+ dark[icol & 1] += pixel[r*raw_width+col];
+ }
+ }
+ }
+ free (pixel);
+ canon_black (dark);
+}
+
+int CLASS ljpeg_start (struct jhead *jh, int info_only)
+{
+ int c, tag, len;
+ uchar data[0x10000], *dp;
+
+ if (!info_only) init_decoder();
+ memset (jh, 0, sizeof *jh);
+ FORC(6) jh->huff[c] = free_decode;
+ jh->restart = INT_MAX;
+ fread (data, 2, 1, ifp);
+ if (data[1] != 0xd8) return 0;
+ do {
+ fread (data, 2, 2, ifp);
+ tag = data[0] << 8 | data[1];
+ len = (data[2] << 8 | data[3]) - 2;
+ if (tag <= 0xff00) return 0;
+ fread (data, 1, len, ifp);
+ switch (tag) {
+ case 0xffc3:
+ jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3;
+ case 0xffc0:
+ jh->bits = data[0];
+ jh->high = data[1] << 8 | data[2];
+ jh->wide = data[3] << 8 | data[4];
+ jh->clrs = data[5] + jh->sraw;
+ if (len == 9 && !dng_version) getc(ifp);
+ break;
+ case 0xffc4:
+ if (info_only) break;
+ for (dp = data; dp < data+len && *dp < 4; ) {
+ jh->huff[*dp] = free_decode;
+ dp = make_decoder (++dp, 0);
+ }
+ break;
+ case 0xffda:
+ jh->psv = data[1+data[0]*2];
+ jh->bits -= data[3+data[0]*2] & 15;
+ break;
+ case 0xffdd:
+ jh->restart = data[0] << 8 | data[1];
+ }
+ } while (tag != 0xffda);
+ if (info_only) return 1;
+ if (jh->sraw) {
+ FORC(4) jh->huff[2+c] = jh->huff[1];
+ FORC(jh->sraw) jh->huff[1+c] = jh->huff[0];
+ }
+ jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4);
+ merror (jh->row, "ljpeg_start()");
+ return zero_after_ff = 1;
+}
+
+int CLASS ljpeg_diff (struct decode *dindex)
+{
+ int len, diff;
+
+ while (dindex->branch[0])
+ dindex = dindex->branch[getbits(1)];
+ len = dindex->leaf;
+ if (len == 16 && (!dng_version || dng_version >= 0x1010000))
+ return -32768;
+ diff = getbits(len);
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ return diff;
+}
+
+ushort * CLASS ljpeg_row (int jrow, struct jhead *jh)
+{
+ int col, c, diff, pred, spred=0;
+ ushort mark=0, *row[3];
+
+ if (jrow * jh->wide % jh->restart == 0) {
+ FORC(6) jh->vpred[c] = 1 << (jh->bits-1);
+ if (jrow)
+ do mark = (mark << 8) + (c = fgetc(ifp));
+ while (c != EOF && mark >> 4 != 0xffd);
+ getbits(-1);
+ }
+ FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1);
+ for (col=0; col < jh->wide; col++)
+ FORC(jh->clrs) {
+ diff = ljpeg_diff (jh->huff[c]);
+ if (jh->sraw && c <= jh->sraw && (col | c))
+ pred = spred;
+ else if (col) pred = row[0][-jh->clrs];
+ else pred = (jh->vpred[c] += diff) - diff;
+ if (jrow && col) switch (jh->psv) {
+ case 1: break;
+ case 2: pred = row[1][0]; break;
+ case 3: pred = row[1][-jh->clrs]; break;
+ case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break;
+ case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break;
+ case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break;
+ case 7: pred = (pred + row[1][0]) >> 1; break;
+ default: pred = 0;
+ }
+ if ((**row = pred + diff) >> jh->bits) derror();
+ if (c <= jh->sraw) spred = **row;
+ row[0]++; row[1]++;
+ }
+ return row[2];
+}
+
+void CLASS lossless_jpeg_load_raw()
+{
+ int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0;
+ double dark[2] = { 0,0 };
+ struct jhead jh;
+ int min=INT_MAX;
+ ushort *rp;
+
+ if (!ljpeg_start (&jh, 0)) return;
+ jwide = jh.wide * jh.clrs;
+
+ for (jrow=0; jrow < jh.high; jrow++) {
+ rp = ljpeg_row (jrow, &jh);
+ for (jcol=0; jcol < jwide; jcol++) {
+ val = *rp++;
+ if (jh.bits <= 12)
+#ifdef LIBRAW_LIBRARY_BUILD
+ if( !(filtering_mode & LIBRAW_FILTERING_NORAWCURVE))
+#endif
+ val = curve[val & 0xfff];
+ if (cr2_slice[0]) {
+ jidx = jrow*jwide + jcol;
+ i = jidx / (cr2_slice[1]*jh.high);
+ if ((j = i >= cr2_slice[0]))
+ i = cr2_slice[0];
+ jidx -= i * (cr2_slice[1]*jh.high);
+ row = jidx / cr2_slice[1+j];
+ col = jidx % cr2_slice[1+j] + i*cr2_slice[1];
+ }
+ if (raw_width == 3984 && (col -= 2) < 0)
+ col += (row--,raw_width);
+#ifdef LIBRAW_LIBRARY_BUILD
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = val;
+#endif
+ if ((unsigned) (row-top_margin) < height) {
+ if ((unsigned) (col-left_margin) < width) {
+ BAYER(row-top_margin,col-left_margin) = val;
+ if (min > val) min = val;
+ } else if (col > 1)
+ dark[(col-left_margin) & 1] += val;
+ }
+ if (++col >= raw_width)
+ col = (row++,0);
+ }
+ }
+ free (jh.row);
+ canon_black (dark);
+ if (!strcasecmp(make,"KODAK"))
+ black = min;
+}
+
+void CLASS canon_sraw_load_raw()
+{
+ struct jhead jh;
+ short *rp=0, (*ip)[4];
+ int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c;
+ int v[3]={0,0,0}, ver, hue;
+ char *cp;
+
+ if (!ljpeg_start (&jh, 0)) return;
+ jwide = (jh.wide >>= 1) * jh.clrs;
+
+ for (ecol=slice=0; slice <= cr2_slice[0]; slice++) {
+ scol = ecol;
+ ecol += cr2_slice[1] * 2 / jh.clrs;
+ if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2;
+ for (row=0; row < height; row += (jh.clrs >> 1) - 1) {
+ ip = (short (*)[4]) image + row*width;
+ for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) {
+ if ((jcol %= jwide) == 0)
+ rp = (short *) ljpeg_row (jrow++, &jh);
+ if (col >= width) continue;
+ FORC (jh.clrs-2)
+ ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c];
+ ip[col][1] = rp[jcol+jh.clrs-2] - 16384;
+ ip[col][2] = rp[jcol+jh.clrs-1] - 16384;
+ }
+ }
+ }
+ for (cp=model2; *cp && !isdigit(*cp); cp++);
+ sscanf (cp, "%d.%d.%d", v, v+1, v+2);
+ ver = (v[0]*1000 + v[1])*1000 + v[2];
+ hue = (jh.sraw+1) << 2;
+ if (unique_id == 0x80000218 && ver > 1000006 && ver < 3000000)
+ hue = jh.sraw << 1;
+ ip = (short (*)[4]) image;
+ rp = ip[0];
+ for (row=0; row < height; row++, ip+=width) {
+ if (row & (jh.sraw >> 1))
+ for (col=0; col < width; col+=2)
+ for (c=1; c < 3; c++)
+ if (row == height-1)
+ ip[col][c] = ip[col-width][c];
+ else ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1;
+ for (col=1; col < width; col+=2)
+ for (c=1; c < 3; c++)
+ if (col == width-1)
+ ip[col][c] = ip[col-1][c];
+ else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1;
+ }
+ for ( ; rp < ip[0]; rp+=4) {
+ if (unique_id < 0x80000200) {
+ pix[0] = rp[0] + rp[2] - 512;
+ pix[2] = rp[0] + rp[1] - 512;
+ pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12) - 512;
+ } else {
+ rp[1] = (rp[1] << 2) + hue;
+ rp[2] = (rp[2] << 2) + hue;
+ pix[0] = rp[0] + (( 200*rp[1] + 22929*rp[2]) >> 14);
+ pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14);
+ pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14);
+ }
+ FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10);
+ }
+ free (jh.row);
+ maximum = 0x3fff;
+}
+
+void CLASS adobe_copy_pixel (int row, int col, ushort **rp)
+{
+ unsigned r, c;
+
+ r = row -= top_margin;
+ c = col -= left_margin;
+ if (is_raw == 2 && shot_select) (*rp)++;
+ if (filters) {
+#ifndef LIBRAW_LIBRARY_BUILD
+ if (fuji_width) {
+ r = row + fuji_width - 1 - (col >> 1);
+ c = row + ((col+1) >> 1);
+ }
+#endif
+#ifdef LIBRAW_LIBRARY_BUILD
+ ushort val = **rp;
+ if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE))
+ val = **rp < 0x1000 ? curve[**rp] : **rp;
+ if (r < height && c < width)
+ BAYER(r,c) = val;
+ else
+ {
+ ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin);
+ if(dfp) *dfp = val;
+ }
+#else
+ if (r < height && c < width)
+ BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp;
+#endif
+ *rp += is_raw;
+ } else {
+ if (r < height && c < width)
+ FORC(tiff_samples)
+ image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c];
+ *rp += tiff_samples;
+ }
+ if (is_raw == 2 && shot_select) (*rp)--;
+}
+
+void CLASS adobe_dng_load_raw_lj()
+{
+ unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col;
+ struct jhead jh;
+ ushort *rp;
+
+ while (trow < raw_height) {
+ save = ftell(ifp);
+ if (tile_length < INT_MAX)
+ fseek (ifp, get4(), SEEK_SET);
+ if (!ljpeg_start (&jh, 0)) break;
+ jwide = jh.wide;
+ if (filters) jwide *= jh.clrs;
+ jwide /= is_raw;
+ for (row=col=jrow=0; jrow < jh.high; jrow++) {
+ rp = ljpeg_row (jrow, &jh);
+ for (jcol=0; jcol < jwide; jcol++) {
+ adobe_copy_pixel (trow+row, tcol+col, &rp);
+ if (++col >= tile_width || col >= raw_width)
+ row += 1 + (col = 0);
+ }
+ }
+ fseek (ifp, save+4, SEEK_SET);
+ if ((tcol += tile_width) >= raw_width)
+ trow += tile_length + (tcol = 0);
+ free (jh.row);
+ }
+}
+
+void CLASS adobe_dng_load_raw_nc()
+{
+ ushort *pixel, *rp;
+ int row, col;
+
+ pixel = (ushort *) calloc (raw_width * tiff_samples, sizeof *pixel);
+ merror (pixel, "adobe_dng_load_raw_nc()");
+ for (row=0; row < raw_height; row++) {
+ if (tiff_bps == 16)
+ read_shorts (pixel, raw_width * tiff_samples);
+ else {
+ getbits(-1);
+ for (col=0; col < raw_width * tiff_samples; col++)
+ pixel[col] = getbits(tiff_bps);
+ }
+ for (rp=pixel, col=0; col < raw_width; col++)
+ adobe_copy_pixel (row, col, &rp);
+ }
+ free (pixel);
+}
+
+void CLASS pentax_tree()
+{
+ ushort bit[2][13];
+ struct decode *cur;
+ int c, i, j;
+
+ init_decoder();
+ FORC(13) bit[0][c] = get2();
+ FORC(13) bit[1][c] = fgetc(ifp) & 15;
+ FORC(13) {
+ cur = first_decode;
+ for (i=0; i < bit[1][c]; i++) {
+ j = bit[0][c] >> (11-i) & 1;
+ if (!cur->branch[j]) cur->branch[j] = ++free_decode;
+ cur = cur->branch[j];
+ }
+ cur->leaf = c;
+ }
+}
+
+void CLASS pentax_k10_load_raw()
+{
+ int row, col, diff;
+ ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2];
+
+ getbits(-1);
+ for (row=0; row < raw_height; row++)
+ {
+#ifndef LIBRAW_LIBRARY_BUILD
+ if(row >= height) break;
+#endif
+ for (col=0; col < raw_width; col++) {
+ diff = ljpeg_diff (first_decode);
+ if (col < 2) hpred[col] = vpred[row & 1][col] += diff;
+ else hpred[col & 1] += diff;
+ if (col < width && row < height)
+ BAYER(row,col) = hpred[col & 1];
+#ifdef LIBRAW_LIBRARY_BUILD
+ else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = hpred[col & 1];
+ }
+
+ if (col < width && row < height)
+#endif
+ if (hpred[col & 1] >> 12) derror();
+ }
+ }
+}
+
+void CLASS nikon_compressed_load_raw()
+{
+ static const uchar nikon_tree[][32] = {
+ { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */
+ 5,4,3,6,2,7,1,0,8,9,11,10,12 },
+ { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */
+ 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 },
+ { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */
+ 5,4,6,3,7,2,8,1,9,0,10,11,12 },
+ { 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */
+ 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 },
+ { 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */
+ 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 },
+ { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */
+ 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } };
+ struct decode *dindex;
+ ushort ver0, ver1, vpred[2][2], hpred[2], csize;
+ int i, min, max, step=0, huff=0, split=0, row, col, len, shl, diff;
+
+ fseek (ifp, meta_offset, SEEK_SET);
+ ver0 = fgetc(ifp);
+ ver1 = fgetc(ifp);
+ if (ver0 == 0x49 || ver1 == 0x58)
+ fseek (ifp, 2110, SEEK_CUR);
+ if (ver0 == 0x46) huff = 2;
+ if (tiff_bps == 14) huff += 3;
+ read_shorts (vpred[0], 4);
+ max = 1 << tiff_bps & 0x7fff;
+ if ((csize = get2()) > 1)
+ step = max / (csize-1);
+ if (ver0 == 0x44 && ver1 == 0x20 && step > 0) {
+ for (i=0; i < csize; i++)
+ curve[i*step] = get2();
+ for (i=0; i < max; i++)
+ curve[i] = ( curve[i-i%step]*(step-i%step) +
+ curve[i-i%step+step]*(i%step) ) / step;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.curve_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ fseek (ifp, meta_offset+562, SEEK_SET);
+ split = get2();
+ } else if (ver0 != 0x46 && csize <= 0x4001)
+ {
+ read_shorts (curve, max=csize);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.curve_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ while (curve[max-2] == curve[max-1]) max--;
+ init_decoder();
+ make_decoder (nikon_tree[huff], 0);
+ fseek (ifp, data_offset, SEEK_SET);
+ getbits(-1);
+ for (min=row=0; row < height; row++) {
+ if (split && row == split) {
+ init_decoder();
+ make_decoder (nikon_tree[huff+1], 0);
+ max += (min = 16) << 1;
+ }
+ for (col=0; col < raw_width; col++) {
+ for (dindex=first_decode; dindex->branch[0]; )
+ dindex = dindex->branch[getbits(1)];
+ len = dindex->leaf & 15;
+ shl = dindex->leaf >> 4;
+ diff = ((getbits(len-shl) << 1) + 1) << shl >> 1;
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - !shl;
+ if (col < 2) hpred[col] = vpred[row & 1][col] += diff;
+ else hpred[col & 1] += diff;
+ if ((ushort)(hpred[col & 1] + min) >= max) derror();
+#ifndef LIBRAW_LIBRARY_BUILD
+ if ((unsigned) (col-left_margin) < width)
+ BAYER(row,col-left_margin) = curve[LIM((short)hpred[col & 1],0,0x3fff)];
+#else
+ ushort xval = hpred[col & 1];
+ if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE))
+ xval = curve[LIM((short)xval,0,0x3fff)];
+ if ((unsigned) (col-left_margin) < width)
+ {
+ BAYER(row,col-left_margin) = xval;
+ }
+ else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = xval;
+ }
+#endif
+
+ }
+ }
+}
+
+/*
+ Figure out if a NEF file is compressed. These fancy heuristics
+ are only needed for the D100, thanks to a bug in some cameras
+ that tags all images as "compressed".
+ */
+int CLASS nikon_is_compressed()
+{
+ uchar test[256];
+ int i;
+
+ fseek (ifp, data_offset, SEEK_SET);
+ fread (test, 1, 256, ifp);
+ for (i=15; i < 256; i+=16)
+ if (test[i]) return 1;
+ return 0;
+}
+
+/*
+ Returns 1 for a Coolpix 995, 0 for anything else.
+ */
+int CLASS nikon_e995()
+{
+ int i, histo[256];
+ const uchar often[] = { 0x00, 0x55, 0xaa, 0xff };
+
+ memset (histo, 0, sizeof histo);
+ fseek (ifp, -2000, SEEK_END);
+ for (i=0; i < 2000; i++)
+ histo[fgetc(ifp)]++;
+ for (i=0; i < 4; i++)
+ if (histo[often[i]] < 200)
+ return 0;
+ return 1;
+}
+
+/*
+ Returns 1 for a Coolpix 2100, 0 for anything else.
+ */
+int CLASS nikon_e2100()
+{
+ uchar t[12];
+ int i;
+
+ fseek (ifp, 0, SEEK_SET);
+ for (i=0; i < 1024; i++) {
+ fread (t, 1, 12, ifp);
+ if (((t[2] & t[4] & t[7] & t[9]) >> 4
+ & t[1] & t[6] & t[8] & t[11] & 3) != 3)
+ return 0;
+ }
+ return 1;
+}
+
+void CLASS nikon_3700()
+{
+ int bits, i;
+ uchar dp[24];
+ static const struct {
+ int bits;
+ char t_make[12], t_model[15];
+ } table[] = {
+ { 0x00, "PENTAX", "Optio 33WR" },
+ { 0x03, "NIKON", "E3200" },
+ { 0x32, "NIKON", "E3700" },
+ { 0x33, "OLYMPUS", "C740UZ" } };
+
+ fseek (ifp, 3072, SEEK_SET);
+ fread (dp, 1, 24, ifp);
+ bits = (dp[8] & 3) << 4 | (dp[20] & 3);
+ for (i=0; i < sizeof table / sizeof *table; i++)
+ if (bits == table[i].bits) {
+ strcpy (make, table[i].t_make );
+ strcpy (model, table[i].t_model);
+ }
+}
+
+/*
+ Separates a Minolta DiMAGE Z2 from a Nikon E4300.
+ */
+int CLASS minolta_z2()
+{
+ int i, nz;
+ char tail[424];
+
+ fseek (ifp, -sizeof tail, SEEK_END);
+ fread (tail, 1, sizeof tail, ifp);
+ for (nz=i=0; i < sizeof tail; i++)
+ if (tail[i]) nz++;
+ return nz > 20;
+}
+
+/* Here raw_width is in bytes, not pixels. */
+void CLASS nikon_e900_load_raw()
+{
+ int offset=0, irow, row, col;
+
+ for (irow=0; irow < height; irow++) {
+ row = irow * 2 % height;
+ if (row == 1)
+ offset = - (-offset & -4096);
+ fseek (ifp, offset, SEEK_SET);
+ offset += raw_width;
+ getbits(-1);
+ for (col=0; col < width; col++)
+ BAYER(row,col) = getbits(10);
+ }
+}
+
+/*
+ The Fuji Super CCD is just a Bayer grid rotated 45 degrees.
+ */
+void CLASS fuji_load_raw()
+{
+ ushort *pixel;
+#ifndef LIBRAW_LIBRARY_BUILD
+ int wide, row, col, r, c;
+
+ fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR);
+ wide = fuji_width << !fuji_layout;
+ pixel = (ushort *) calloc (wide, sizeof *pixel);
+ merror (pixel, "fuji_load_raw()");
+ for (row=0; row < raw_height; row++) {
+ read_shorts (pixel, wide);
+ fseek (ifp, 2*(raw_width - wide), SEEK_CUR);
+ for (col=0; col < wide; col++) {
+ if (fuji_layout) {
+ r = fuji_width - 1 - col + (row >> 1);
+ c = col + ((row+1) >> 1);
+ } else {
+ r = fuji_width - 1 + row - (col >> 1);
+ c = row + ((col+1) >> 1);
+ }
+ BAYER(r,c) = pixel[col];
+ }
+ }
+ free (pixel);
+#else
+ int row,col;
+ int wide, r, c;
+ pixel = (ushort *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "fuji_load_raw()");
+ for (row=0; row < raw_height; row++) {
+ read_shorts (pixel, raw_width);
+ for (col=0; col < raw_width; col++) {
+ if(col >= left_margin && col < width+left_margin
+ && row >= top_margin && row < height+top_margin)
+ {
+ int rrow = row-top_margin;
+ int ccol = col-left_margin;
+ if (fuji_layout) {
+ r = fuji_width - 1 - ccol + (rrow >> 1);
+ c = ccol + ((rrow+1) >> 1);
+ } else {
+ r = fuji_width - 1 + rrow - (ccol >> 1);
+ c = rrow + ((ccol+1) >> 1);
+ }
+
+ image[((row-top_margin) >> shrink)*iwidth + ((col-left_margin) >> shrink)][FC(r,c)] = pixel[col];
+ }
+ else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = pixel[col];
+ }
+ }
+ }
+ free (pixel);
+#endif
+}
+void CLASS ppm_thumb (FILE *tfp)
+{
+ char *thumb;
+ thumb_length = thumb_width*thumb_height*3;
+ thumb = (char *) malloc (thumb_length);
+ merror (thumb, "ppm_thumb()");
+ fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height);
+ fread (thumb, 1, thumb_length, ifp);
+ fwrite (thumb, 1, thumb_length, tfp);
+ free (thumb);
+}
+
+void CLASS layer_thumb (FILE *tfp)
+{
+ int i, c;
+ char *thumb, map[][4] = { "012","102" };
+
+ colors = thumb_misc >> 5 & 7;
+ thumb_length = thumb_width*thumb_height;
+ thumb = (char *) calloc (colors, thumb_length);
+ merror (thumb, "layer_thumb()");
+ fprintf (tfp, "P%d\n%d %d\n255\n",
+ 5 + (colors >> 1), thumb_width, thumb_height);
+ fread (thumb, thumb_length, colors, ifp);
+ for (i=0; i < thumb_length; i++)
+ FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], tfp);
+ free (thumb);
+}
+
+void CLASS rollei_thumb (FILE *tfp)
+{
+ unsigned i;
+ ushort *thumb;
+
+ thumb_length = thumb_width * thumb_height;
+ thumb = (ushort *) calloc (thumb_length, 2);
+ merror (thumb, "rollei_thumb()");
+ fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height);
+ read_shorts (thumb, thumb_length);
+ for (i=0; i < thumb_length; i++) {
+ putc (thumb[i] << 3, tfp);
+ putc (thumb[i] >> 5 << 2, tfp);
+ putc (thumb[i] >> 11 << 3, tfp);
+ }
+ free (thumb);
+}
+
+void CLASS rollei_load_raw()
+{
+ uchar pixel[10];
+ unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
+
+ isix = raw_width * raw_height * 5 / 8;
+ while (fread (pixel, 1, 10, ifp) == 10) {
+ for (i=0; i < 10; i+=2) {
+ todo[i] = iten++;
+ todo[i+1] = pixel[i] << 8 | pixel[i+1];
+ buffer = pixel[i] >> 2 | buffer << 6;
+ }
+ for ( ; i < 16; i+=2) {
+ todo[i] = isix++;
+ todo[i+1] = buffer >> (14-i)*5;
+ }
+ for (i=0; i < 16; i+=2) {
+ row = todo[i] / raw_width - top_margin;
+ col = todo[i] % raw_width - left_margin;
+ if (row < height && col < width)
+ BAYER(row,col) = (todo[i+1] & 0x3ff);
+#ifdef LIBRAW_LIBRARY_BUILD
+ else
+ {
+ ushort *dfp = get_masked_pointer(todo[i] / raw_width,todo[i] % raw_width);
+ if(dfp) *dfp = (todo[i+1] & 0x3ff);
+ }
+#endif
+ }
+ }
+ maximum = 0x3ff;
+}
+
+int CLASS bayer (unsigned row, unsigned col)
+{
+ return (row < height && col < width) ? BAYER(row,col) : 0;
+}
+
+void CLASS phase_one_flat_field (int is_float, int nc)
+{
+ ushort head[8];
+ unsigned wide, y, x, c, rend, cend, row, col;
+ float *mrow, num, mult[4];
+
+ read_shorts (head, 8);
+ wide = head[2] / head[4];
+ mrow = (float *) calloc (nc*wide, sizeof *mrow);
+ merror (mrow, "phase_one_flat_field()");
+ for (y=0; y < head[3] / head[5]; y++) {
+ for (x=0; x < wide; x++)
+ for (c=0; c < nc; c+=2) {
+ num = is_float ? getreal(11) : get2()/32768.0;
+ if (y==0) mrow[c*wide+x] = num;
+ else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5];
+ }
+ if (y==0) continue;
+ rend = head[1]-top_margin + y*head[5];
+ for (row = rend-head[5]; row < height && row < rend; row++) {
+ for (x=1; x < wide; x++) {
+ for (c=0; c < nc; c+=2) {
+ mult[c] = mrow[c*wide+x-1];
+ mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4];
+ }
+ cend = head[0]-left_margin + x*head[4];
+ for (col = cend-head[4]; col < width && col < cend; col++) {
+ c = nc > 2 ? FC(row,col) : 0;
+ if (!(c & 1)) {
+ c = BAYER(row,col) * mult[c];
+ BAYER(row,col) = LIM(c,0,65535);
+ }
+ for (c=0; c < nc; c+=2)
+ mult[c] += mult[c+1];
+ }
+ }
+ for (x=0; x < wide; x++)
+ for (c=0; c < nc; c+=2)
+ mrow[c*wide+x] += mrow[(c+1)*wide+x];
+ }
+ }
+ free (mrow);
+}
+
+void CLASS phase_one_correct()
+{
+ unsigned entries, tag, data, save, col, row, type;
+ int len, i, j, k, cip, val[4], dev[4], sum, max;
+ int head[9], diff, mindiff=INT_MAX, off_412=0;
+ static const signed char dir[12][2] =
+ { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0},
+ {-2,-2}, {-2,2}, {2,-2}, {2,2} };
+ float poly[8], num, cfrac, frac, mult[2], *yval[2];
+ ushort t_curve[0x10000], *xval[2];
+
+ if (half_size || !meta_length) return;
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("Phase One correction...\n"));
+#endif
+ fseek (ifp, meta_offset, SEEK_SET);
+ order = get2();
+ fseek (ifp, 6, SEEK_CUR);
+ fseek (ifp, meta_offset+get4(), SEEK_SET);
+ entries = get4(); get4();
+ while (entries--) {
+ tag = get4();
+ len = get4();
+ data = get4();
+ save = ftell(ifp);
+ fseek (ifp, meta_offset+data, SEEK_SET);
+ if (tag == 0x419) { /* Polynomial curve */
+ for (get4(), i=0; i < 8; i++)
+ poly[i] = getreal(11);
+ poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1;
+ for (i=0; i < 0x10000; i++) {
+ num = (poly[5]*i + poly[3])*i + poly[1];
+ t_curve[i] = LIM(num,0,65535);
+ } goto apply; /* apply to right half */
+ } else if (tag == 0x41a) { /* Polynomial curve */
+ for (i=0; i < 4; i++)
+ poly[i] = getreal(11);
+ for (i=0; i < 0x10000; i++) {
+ for (num=0, j=4; j--; )
+ num = num * i + poly[j];
+ t_curve[i] = LIM(num+i,0,65535);
+ } apply: /* apply to whole image */
+ for (row=0; row < height; row++)
+ for (col = (tag & 1)*ph1.split_col; col < width; col++)
+ BAYER(row,col) = t_curve[BAYER(row,col)];
+ } else if (tag == 0x400) { /* Sensor defects */
+ while ((len -= 8) >= 0) {
+ col = get2() - left_margin;
+ row = get2() - top_margin;
+ type = get2(); get2();
+ if (col >= width) continue;
+ if (type == 131) /* Bad column */
+ for (row=0; row < height; row++)
+ if (FC(row,col) == 1) {
+ for (sum=i=0; i < 4; i++)
+ sum += val[i] = bayer (row+dir[i][0], col+dir[i][1]);
+ for (max=i=0; i < 4; i++) {
+ dev[i] = abs((val[i] << 2) - sum);
+ if (dev[max] < dev[i]) max = i;
+ }
+ BAYER(row,col) = (sum - val[max])/3.0 + 0.5;
+ } else {
+ for (sum=0, i=8; i < 12; i++)
+ sum += bayer (row+dir[i][0], col+dir[i][1]);
+ BAYER(row,col) = 0.5 + sum * 0.0732233 +
+ (bayer(row,col-2) + bayer(row,col+2)) * 0.3535534;
+ }
+ else if (type == 129) { /* Bad pixel */
+ if (row >= height) continue;
+ j = (FC(row,col) != 1) * 4;
+ for (sum=0, i=j; i < j+8; i++)
+ sum += bayer (row+dir[i][0], col+dir[i][1]);
+ BAYER(row,col) = (sum + 4) >> 3;
+ }
+ }
+ } else if (tag == 0x401) { /* All-color flat fields */
+ phase_one_flat_field (1, 2);
+ } else if (tag == 0x416 || tag == 0x410) {
+ phase_one_flat_field (0, 2);
+ } else if (tag == 0x40b) { /* Red+blue flat field */
+ phase_one_flat_field (0, 4);
+ } else if (tag == 0x412) {
+ fseek (ifp, 36, SEEK_CUR);
+ diff = abs (get2() - ph1.tag_21a);
+ if (mindiff > diff) {
+ mindiff = diff;
+ off_412 = ftell(ifp) - 38;
+ }
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ if (off_412) {
+ fseek (ifp, off_412, SEEK_SET);
+ for (i=0; i < 9; i++) head[i] = get4() & 0x7fff;
+ yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6);
+ merror (yval[0], "phase_one_correct()");
+ yval[1] = (float *) (yval[0] + head[1]*head[3]);
+ xval[0] = (ushort *) (yval[1] + head[2]*head[4]);
+ xval[1] = (ushort *) (xval[0] + head[1]*head[3]);
+ get2();
+ for (i=0; i < 2; i++)
+ for (j=0; j < head[i+1]*head[i+3]; j++)
+ yval[i][j] = getreal(11);
+ for (i=0; i < 2; i++)
+ for (j=0; j < head[i+1]*head[i+3]; j++)
+ xval[i][j] = get2();
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ cfrac = (float) col * head[3] / raw_width;
+ cfrac -= cip = cfrac;
+ num = BAYER(row,col) * 0.5;
+ for (i=cip; i < cip+2; i++) {
+ for (k=j=0; j < head[1]; j++)
+ if (num < xval[0][k = head[1]*i+j]) break;
+ frac = (j == 0 || j == head[1]) ? 0 :
+ (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]);
+ mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac);
+ }
+ i = ((mult[0] * (1-cfrac) + mult[1] * cfrac)
+ * (row + top_margin) + num) * 2;
+ BAYER(row,col) = LIM(i,0,65535);
+ }
+ free (yval[0]);
+ }
+}
+
+void CLASS phase_one_load_raw()
+{
+ int row, col, a, b;
+ ushort *pixel, akey, bkey, mask;
+
+ fseek (ifp, ph1.key_off, SEEK_SET);
+ akey = get2();
+ bkey = get2();
+ mask = ph1.format == 1 ? 0x5555:0x1354;
+#ifndef LIBRAW_LIBRARY_BUILD
+ fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET);
+ pixel = (ushort *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "phase_one_load_raw()");
+ for (row=0; row < height; row++) {
+ read_shorts (pixel, raw_width);
+ for (col=0; col < raw_width; col+=2) {
+ a = pixel[col+0] ^ akey;
+ b = pixel[col+1] ^ bkey;
+ pixel[col+0] = (a & mask) | (b & ~mask);
+ pixel[col+1] = (b & mask) | (a & ~mask);
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = pixel[col+left_margin];
+ }
+ free (pixel);
+#else
+ fseek (ifp, data_offset, SEEK_SET);
+ pixel = (ushort *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "phase_one_load_raw()");
+ for (row=0; row < raw_height; row++) {
+ read_shorts (pixel, raw_width);
+ for (col=0; col < raw_width; col+=2) {
+ a = pixel[col+0] ^ akey;
+ b = pixel[col+1] ^ bkey;
+ pixel[col+0] = (a & mask) | (b & ~mask);
+ pixel[col+1] = (b & mask) | (a & ~mask);
+ }
+ for (col=0; col < raw_width; col++)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp)
+ *dfp = pixel[col];
+ else
+ BAYER(row,col-left_margin) = pixel[col];
+ }
+ }
+ free (pixel);
+ if(!( filtering_mode & LIBRAW_FILTERING_NORAWCURVE) )
+#endif
+ phase_one_correct();
+}
+
+unsigned CLASS ph1_bits (int nbits)
+{
+#ifndef LIBRAW_NOTHREADS
+#define bitbuf tls->ph1_bits.bitbuf
+#define vbits tls->ph1_bits.vbits
+#else
+ static UINT64 bitbuf=0;
+ static int vbits=0;
+#endif
+ if (nbits == -1)
+ return bitbuf = vbits = 0;
+ if (nbits == 0) return 0;
+ if ((vbits -= nbits) < 0) {
+ bitbuf = bitbuf << 32 | get4();
+ vbits += 32;
+ }
+ return bitbuf << (64-nbits-vbits) >> (64-nbits);
+#ifndef LIBRAW_NOTHREADS
+#undef bitbuf
+#undef vbits
+#endif
+}
+
+void CLASS phase_one_load_raw_c()
+{
+ static const int length[] = { 8,7,6,9,11,10,5,12,14,13 };
+ int *offset, len[2], pred[2], row, col, i, j;
+ ushort *pixel;
+ short (*t_black)[2];
+
+ pixel = (ushort *) calloc (raw_width + raw_height*4, 2);
+ merror (pixel, "phase_one_load_raw_c()");
+ offset = (int *) (pixel + raw_width);
+ fseek (ifp, strip_offset, SEEK_SET);
+ for (row=0; row < raw_height; row++)
+ offset[row] = get4();
+ t_black = (short (*)[2]) offset + raw_height;
+ fseek (ifp, ph1.black_off, SEEK_SET);
+ if (ph1.black_off)
+ {
+ read_shorts ((ushort *) t_black[0], raw_height*2);
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.masked_pixels.ph1_black = (ushort (*)[2])calloc(raw_height*2,sizeof(ushort));
+ merror (imgdata.masked_pixels.ph1_black, "phase_one_load_raw_c()");
+ memmove(imgdata.masked_pixels.ph1_black,(ushort *) t_black[0],raw_height*2*sizeof(ushort));
+#endif
+ }
+ for (i=0; i < 256; i++)
+ curve[i] = i*i / 3.969 + 0.5;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.curve_state = LIBRAW_COLORSTATE_CALCULATED;
+#endif
+ for (row=0; row < raw_height; row++) {
+ fseek (ifp, data_offset + offset[row], SEEK_SET);
+ ph1_bits(-1);
+ pred[0] = pred[1] = 0;
+ for (col=0; col < raw_width; col++) {
+ if (col >= (raw_width & -8))
+ len[0] = len[1] = 14;
+ else if ((col & 7) == 0)
+ for (i=0; i < 2; i++) {
+ for (j=0; j < 5 && !ph1_bits(1); j++);
+ if (j--) len[i] = length[j*2 + ph1_bits(1)];
+ }
+ if ((i = len[col & 1]) == 14)
+ pixel[col] = pred[col & 1] = ph1_bits(16);
+ else
+ pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1));
+ if (pred[col & 1] >> 16) derror();
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(!( filtering_mode & LIBRAW_FILTERING_NORAWCURVE) )
+#endif
+ if (ph1.format == 5 && pixel[col] < 256)
+ pixel[col] = curve[pixel[col]];
+ }
+ if ((unsigned) (row-top_margin) < height)
+#ifndef LIBRAW_LIBRARY_BUILD
+ for (col=0; col < width; col++) {
+ i = (pixel[col+left_margin] << 2)
+ - ph1.t_black + t_black[row][col >= ph1.split_col];
+ if (i > 0) BAYER(row-top_margin,col) = i;
+ }
+#else
+ {
+ for (col=0; col < raw_width; col++) {
+ if( filtering_mode & LIBRAW_FILTERING_NOBLACKS)
+ i = (pixel[col] << 2);
+ else
+ i = (pixel[col] << 2)
+ - ph1.t_black + t_black[row][(col /* - left_margin */) >= ph1.split_col]; // changed to fix Coffin's bug!
+ if(col >= left_margin && col < width+left_margin)
+ {
+ if (i > 0) BAYER(row-top_margin,col-left_margin) = i;
+ }
+ else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(i>0 && dfp) *dfp = i;
+ }
+ }
+ }
+ else
+ {
+ // top-bottom fields
+ for (col=0; col < raw_width; col++) {
+ i = (pixel[col] << 2)
+ - ph1.t_black + t_black[row][(col+left_margin) >= ph1.split_col];
+ if (i > 0)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = i;
+ }
+ }
+ }
+#endif
+ }
+ free (pixel);
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(!( filtering_mode & LIBRAW_FILTERING_NORAWCURVE) )
+#endif
+ phase_one_correct();
+ maximum = 0xfffc - ph1.t_black;
+}
+
+void CLASS hasselblad_load_raw()
+{
+ struct jhead jh;
+ struct decode *dindex;
+ int row, col, pred[2], len[2], diff, i;
+
+ if (!ljpeg_start (&jh, 0)) return;
+ free (jh.row);
+ order = 0x4949;
+ ph1_bits(-1);
+ for (row=-top_margin; row < raw_height-top_margin; row++) {
+ pred[0] = pred[1] = 0x8000;
+ for (col=-left_margin; col < raw_width-left_margin; col+=2) {
+ for (i=0; i < 2; i++) {
+ for (dindex=jh.huff[0]; dindex->branch[0]; )
+ dindex = dindex->branch[ph1_bits(1)];
+ len[i] = dindex->leaf;
+ }
+ for (i=0; i < 2; i++) {
+ diff = ph1_bits(len[i]);
+ if ((diff & (1 << (len[i]-1))) == 0)
+ diff -= (1 << len[i]) - 1;
+ if (diff == 65535) diff = -32768;
+ pred[i] += diff;
+ if (row >= 0 && row < height && (unsigned)(col+i) < width)
+ BAYER(row,col+i) = pred[i];
+#ifdef LIBRAW_LIBRARY_BUILD
+ else
+ {
+ ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin);
+ if(dfp) *dfp = pred[i];
+ }
+#endif
+ }
+ }
+ }
+ maximum = 0xffff;
+}
+
+void CLASS leaf_hdr_load_raw()
+{
+ ushort *pixel;
+ unsigned tile=0, r, c, row, col;
+
+ pixel = (ushort *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "leaf_hdr_load_raw()");
+ FORC(tiff_samples)
+ for (r=0; r < raw_height; r++) {
+ if (r % tile_length == 0) {
+ fseek (ifp, data_offset + 4*tile++, SEEK_SET);
+ fseek (ifp, get4() + 2*left_margin, SEEK_SET);
+ }
+ if (filters && c != shot_select) continue;
+ read_shorts (pixel, raw_width);
+ if ((row = r - top_margin) >= height) continue;
+ for (col=0; col < width; col++)
+ if (filters) BAYER(row,col) = pixel[col];
+ else image[row*width+col][c] = pixel[col];
+ }
+ free (pixel);
+ if (!filters) {
+ maximum = 0xffff;
+ raw_color = 1;
+ }
+}
+
+void CLASS sinar_4shot_load_raw()
+{
+ ushort *pixel;
+ unsigned shot, row, col, r, c;
+
+ if ((shot = shot_select) || half_size) {
+ if (shot) shot--;
+ if (shot > 3) shot = 3;
+ fseek (ifp, data_offset + shot*4, SEEK_SET);
+ fseek (ifp, get4(), SEEK_SET);
+ unpacked_load_raw();
+ return;
+ }
+ free (image);
+ image = (ushort (*)[4])
+ calloc ((iheight=height)*(iwidth=width), sizeof *image);
+ merror (image, "sinar_4shot_load_raw()");
+ pixel = (ushort *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "sinar_4shot_load_raw()");
+ for (shot=0; shot < 4; shot++) {
+ fseek (ifp, data_offset + shot*4, SEEK_SET);
+ fseek (ifp, get4(), SEEK_SET);
+ for (row=0; row < raw_height; row++) {
+ read_shorts (pixel, raw_width);
+ if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue;
+ for (col=0; col < raw_width; col++) {
+ if ((c = col-left_margin - (shot & 1)) >= width) continue;
+ image[r*width+c][FC(row,col)] = pixel[col];
+ }
+ }
+ }
+ free (pixel);
+ shrink = filters = 0;
+}
+
+void CLASS imacon_full_load_raw()
+{
+ int row, col;
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++)
+ read_shorts (image[row*width+col], 3);
+}
+
+void CLASS packed_12_load_raw()
+{
+ int vbits=0, rbits=0, irow, row, col;
+ UINT64 bitbuf=0;
+
+ if (raw_width * 2 >= width * 3) { /* If raw_width is in bytes, */
+ rbits = raw_width * 8;
+ raw_width = raw_width * 2 / 3; /* convert it to pixels and */
+ rbits -= raw_width * 12; /* save the remainder. */
+ }
+ order = load_flags & 1 ? 0x4949 : 0x4d4d;
+ for (irow=0; irow < height; irow++) {
+ row = irow;
+ if (load_flags & 2 &&
+ (row = irow * 2 % height + irow / (height/2)) == 1 &&
+ load_flags & 4) {
+ if (vbits=0, tiff_compress)
+ fseek (ifp, data_offset - (-width*height*3/4 & -2048), SEEK_SET);
+ else {
+ fseek (ifp, 0, SEEK_END);
+ fseek (ifp, ftell(ifp)/2, SEEK_SET);
+ }
+ }
+ for (col=0; col < raw_width; col++) {
+ if ((vbits -= 12) < 0) {
+ bitbuf = bitbuf << 32 | get4();
+ vbits += 32;
+ }
+ if ((unsigned) (col-left_margin) < width)
+ BAYER(row,col-left_margin) = bitbuf << (52-vbits) >> 52;
+#ifdef LIBRAW_LIBRARY_BUILD
+ else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = bitbuf << (52-vbits) >> 52;
+ }
+#endif
+ if (load_flags & 8 && (col % 10) == 9)
+ if (vbits=0, bitbuf & 255) derror();
+ }
+ vbits -= rbits;
+ }
+ if (!strcmp(make,"OLYMPUS")) black >>= 4;
+}
+
+void CLASS unpacked_load_raw()
+{
+ ushort *pixel;
+ int row, col, bits=0;
+
+ while (1 << ++bits < maximum);
+#ifndef LIBRAW_LIBRARY_BUILD
+ fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR);
+ pixel = (ushort *) calloc (width, sizeof *pixel);
+ merror (pixel, "unpacked_load_raw()");
+ for (row=0; row < height; row++) {
+ read_shorts (pixel, width);
+ fseek (ifp, 2*(raw_width - width), SEEK_CUR);
+ for (col=0; col < width; col++)
+ if ((BAYER2(row,col) = pixel[col]) >> bits) derror();
+ }
+ free (pixel);
+#else
+ // fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR);
+ pixel = (ushort *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "unpacked_load_raw()");
+ for (row=0; row < raw_height; row++) {
+ read_shorts (pixel, raw_width);
+ //fseek (ifp, 2*(raw_width - width), SEEK_CUR);
+ for (col=0; col < raw_width; col++)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp)
+ *dfp = pixel[col];
+ else
+ {
+ if ((BAYER2(row-top_margin,col-left_margin) = pixel[col]) >> bits) derror();
+ }
+ }
+ }
+ free (pixel);
+#endif
+}
+
+void CLASS nokia_load_raw()
+{
+ uchar *data, *dp;
+ ushort *pixel, *pix;
+ int dwide, row, c;
+
+ dwide = raw_width * 5 / 4;
+ data = (uchar *) malloc (dwide + raw_width*2);
+ merror (data, "nokia_load_raw()");
+ pixel = (ushort *) (data + dwide);
+ for (row=0; row < raw_height; row++) {
+ if (fread (data, 1, dwide, ifp) < dwide) derror();
+ for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=5, pix+=4)
+ FORC4 pix[c] = (dp[c] << 2) | (dp[4] >> (c << 1) & 3);
+ if (row < top_margin)
+#ifdef LIBRAW_LIBRARY_BUILD
+ {
+ int col;
+ for(col=0;col<width;col++)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp)
+ *dfp = pixel[col];
+ }
+ FORC(width) black += pixel[c];
+ }
+#else
+ FORC(width) black += pixel[c];
+#endif
+ else
+ FORC(width) BAYER(row-top_margin,c) = pixel[c];
+ }
+ free (data);
+ if (top_margin) black /= top_margin * width;
+ maximum = 0x3ff;
+}
+
+unsigned CLASS pana_bits (int nbits)
+{
+#ifndef LIBRAW_NOTHREADS
+#define buf tls->pana_bits.buf
+#define vbits tls->pana_bits.vbits
+#else
+ static uchar buf[0x4000];
+ static int vbits;
+#endif
+ int byte;
+
+ if (!nbits) return vbits=0;
+ if (!vbits) {
+ fread (buf+load_flags, 1, 0x4000-load_flags, ifp);
+ fread (buf, 1, load_flags, ifp);
+ }
+ vbits = (vbits - nbits) & 0x1ffff;
+ byte = vbits >> 3 ^ 0x3ff0;
+ return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits);
+#ifndef LIBRAW_NOTHREADS
+#undef buf
+#undef vbits
+#endif
+}
+
+void CLASS panasonic_load_raw()
+{
+ int row, col, i, j, sh=0, pred[2], nonz[2];
+
+ pana_bits(0);
+ for (row=0; row < height; row++)
+ for (col=0; col < raw_width; col++) {
+ if ((i = col % 14) == 0)
+ pred[0] = pred[1] = nonz[0] = nonz[1] = 0;
+ if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2));
+ if (nonz[i & 1]) {
+ if ((j = pana_bits(8))) {
+ if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4)
+ pred[i & 1] &= ~(-1 << sh);
+ pred[i & 1] += j << sh;
+ }
+ } else if ((nonz[i & 1] = pana_bits(8)) || i > 11)
+ pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4);
+ if (col < width)
+ if ((BAYER(row,col) = pred[col & 1]) > 4098) derror();
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(col>=width)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp)*dfp = pred[col & 1];
+ }
+#endif
+ }
+}
+
+void CLASS olympus_e300_load_raw()
+{
+ uchar *data, *dp;
+ ushort *pixel, *pix;
+ int dwide, row, col;
+
+ dwide = raw_width * 16 / 10;
+#ifndef LIBRAW_LIBRARY_BUILD
+ fseek (ifp, dwide*top_margin, SEEK_CUR);
+#endif
+ data = (uchar *) malloc (dwide + raw_width*2);
+ merror (data, "olympus_e300_load_raw()");
+ pixel = (ushort *) (data + dwide);
+#ifndef LIBRAW_LIBRARY_BUILD
+ for (row=0; row < height; row++)
+#else
+ for (row=0; row < raw_height; row++)
+#endif
+ {
+ if (fread (data, 1, dwide, ifp) < dwide) derror();
+ for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) {
+ if (((dp-data) & 15) == 15)
+ if (*dp++ && pix < pixel+width+left_margin) derror();
+ pix[0] = dp[1] << 8 | dp[0];
+ pix[1] = dp[2] << 4 | dp[1] >> 4;
+ }
+#ifndef LIBRAW_LIBRARY_BUILD
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (pixel[col+left_margin] & 0xfff);
+#else
+ for (col=0; col < raw_width; col++)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp)
+ *dfp = (pixel[col] & 0xfff);
+ else
+ BAYER(row-top_margin,col-left_margin) = (pixel[col] & 0xfff);
+ }
+
+#endif
+ }
+ free (data);
+ maximum >>= 4;
+ black >>= 4;
+}
+
+void CLASS olympus_e410_load_raw()
+{
+ int row, col, nbits, sign, low, high, i, w, n, nw;
+ int acarry[2][3], *carry, pred, diff;
+
+ fseek (ifp, 7, SEEK_CUR);
+ getbits(-1);
+ for (row=0; row < height; row++) {
+ memset (acarry, 0, sizeof acarry);
+ for (col=0; col < width; col++) {
+ carry = acarry[col & 1];
+ i = 2 * (carry[2] < 3);
+ for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++);
+ sign = getbits(1) * -1;
+ low = getbits(2);
+ for (high=0; high < 12; high++)
+ if (getbits(1)) break;
+ if (high == 12)
+ high = getbits(16-nbits) >> 1;
+ carry[0] = (high << nbits) | getbits(nbits);
+ diff = (carry[0] ^ sign) + carry[1];
+ carry[1] = (diff*3 + carry[1]) >> 5;
+ carry[2] = carry[0] > 16 ? 0 : carry[2]+1;
+ if (row < 2 && col < 2) pred = 0;
+ else if (row < 2) pred = BAYER(row,col-2);
+ else if (col < 2) pred = BAYER(row-2,col);
+ else {
+ w = BAYER(row,col-2);
+ n = BAYER(row-2,col);
+ nw = BAYER(row-2,col-2);
+ if ((w < nw && nw < n) || (n < nw && nw < w)) {
+ if (ABS(w-nw) > 32 || ABS(n-nw) > 32)
+ pred = w + n - nw;
+ else pred = (w + n) >> 1;
+ } else pred = ABS(w-nw) > ABS(n-nw) ? w : n;
+ }
+ if ((BAYER(row,col) = pred + ((diff << 2) | low)) >> 12) derror();
+ }
+ }
+}
+
+void CLASS minolta_rd175_load_raw()
+{
+ uchar pixel[768];
+ unsigned irow, box, row, col;
+
+ for (irow=0; irow < 1481; irow++) {
+ if (fread (pixel, 1, 768, ifp) < 768) derror();
+ box = irow / 82;
+ row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2);
+ switch (irow) {
+ case 1477: case 1479: continue;
+ case 1476: row = 984; break;
+ case 1480: row = 985; break;
+ case 1478: row = 985; box = 1;
+ }
+ if ((box < 12) && (box & 1)) {
+ for (col=0; col < 1533; col++, row ^= 1)
+ if (col != 1) BAYER(row,col) = (col+1) & 2 ?
+ pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1;
+ BAYER(row,1) = pixel[1] << 1;
+ BAYER(row,1533) = pixel[765] << 1;
+ } else
+ for (col=row & 1; col < 1534; col+=2)
+ BAYER(row,col) = pixel[col/2] << 1;
+ }
+ maximum = 0xff << 1;
+}
+
+void CLASS casio_qv5700_load_raw()
+{
+ uchar data[3232], *dp;
+ ushort pixel[2576], *pix;
+ int row, col;
+
+ for (row=0; row < height; row++) {
+ fread (data, 1, 3232, ifp);
+ for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) {
+ pix[0] = (dp[0] << 2) + (dp[1] >> 6);
+ pix[1] = (dp[1] << 4) + (dp[2] >> 4);
+ pix[2] = (dp[2] << 6) + (dp[3] >> 2);
+ pix[3] = (dp[3] << 8) + (dp[4] );
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (pixel[col] & 0x3ff);
+ }
+ maximum = 0x3fc;
+}
+
+void CLASS quicktake_100_load_raw()
+{
+ uchar pixel[484][644];
+ static const short gstep[16] =
+ { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 };
+ static const short rstep[6][4] =
+ { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 },
+ { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } };
+ static const short t_curve[256] =
+ { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,
+ 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53,
+ 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78,
+ 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116,
+ 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155,
+ 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195,
+ 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244,
+ 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322,
+ 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400,
+ 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479,
+ 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643,
+ 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844,
+ 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 };
+ int rb, row, col, sharp, val=0;
+
+ getbits(-1);
+ memset (pixel, 0x80, sizeof pixel);
+ for (row=2; row < height+2; row++) {
+ for (col=2+(row & 1); col < width+2; col+=2) {
+ val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] +
+ pixel[row][col-2]) >> 2) + gstep[getbits(4)];
+ pixel[row][col] = val = LIM(val,0,255);
+ if (col < 4)
+ pixel[row][col-2] = pixel[row+1][~row & 1] = val;
+ if (row == 2)
+ pixel[row-1][col+1] = pixel[row-1][col+3] = val;
+ }
+ pixel[row][col] = val;
+ }
+ for (rb=0; rb < 2; rb++)
+ for (row=2+rb; row < height+2; row+=2)
+ for (col=3-(row & 1); col < width+2; col+=2) {
+ if (row < 4 || col < 4) sharp = 2;
+ else {
+ val = ABS(pixel[row-2][col] - pixel[row][col-2])
+ + ABS(pixel[row-2][col] - pixel[row-2][col-2])
+ + ABS(pixel[row][col-2] - pixel[row-2][col-2]);
+ sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 :
+ val < 32 ? 3 : val < 48 ? 4 : 5;
+ }
+ val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1)
+ + rstep[sharp][getbits(2)];
+ pixel[row][col] = val = LIM(val,0,255);
+ if (row < 4) pixel[row-2][col+2] = val;
+ if (col < 4) pixel[row+2][col-2] = val;
+ }
+ for (row=2; row < height+2; row++)
+ for (col=3-(row & 1); col < width+2; col+=2) {
+ val = ((pixel[row][col-1] + (pixel[row][col] << 2) +
+ pixel[row][col+1]) >> 1) - 0x100;
+ pixel[row][col] = LIM(val,0,255);
+ }
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++)
+ BAYER(row,col) = t_curve[pixel[row+2][col+2]];
+ maximum = 0x3ff;
+}
+
+const int * CLASS make_decoder_int (const int *source, int level)
+{
+ struct decode *cur;
+
+ cur = free_decode++;
+ if (level < source[0]) {
+ cur->branch[0] = free_decode;
+ source = make_decoder_int (source, level+1);
+ cur->branch[1] = free_decode;
+ source = make_decoder_int (source, level+1);
+ } else {
+ cur->leaf = source[1];
+ source += 2;
+ }
+ return source;
+}
+
+int CLASS radc_token (int tree)
+{
+ int t;
+#ifndef LIBRAW_NOTHREADS
+#define dstart tls->radc_token.dstart
+#define dindex tls->radc_token.dindex
+#define s tls->radc_token.s
+
+ static const int source[] = {
+#else
+ static struct decode *dstart[18], *dindex;
+ static const int *s, source[] = {
+#endif
+ 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8,
+ 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8,
+ 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8,
+ 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8,
+ 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8,
+ 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8,
+ 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8,
+ 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8,
+ 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4,
+ 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8,
+ 1,0, 2,2, 2,-2,
+ 1,-3, 1,3,
+ 2,-17, 2,-5, 2,5, 2,17,
+ 2,-7, 2,2, 2,9, 2,18,
+ 2,-18, 2,-9, 2,-2, 2,7,
+ 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79,
+ 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76,
+ 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37
+ };
+
+ if (free_decode == first_decode)
+ for (s=source, t=0; t < 18; t++) {
+ dstart[t] = free_decode;
+ s = make_decoder_int (s, 0);
+ }
+ if (tree == 18) {
+ if (kodak_cbpp == 243)
+ return (getbits(6) << 2) + 2; /* most DC50 photos */
+ else
+ return (getbits(5) << 3) + 4; /* DC40, Fotoman Pixtura */
+ }
+ for (dindex = dstart[tree]; dindex->branch[0]; )
+ dindex = dindex->branch[getbits(1)];
+ return dindex->leaf;
+
+#ifndef LIBRAW_NOTHREADS
+#undef dstart
+#undef dindex
+#undef s
+#endif
+}
+
+#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--)
+
+#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \
+: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4)
+
+void CLASS kodak_radc_load_raw()
+{
+ int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val;
+ short last[3] = { 16,16,16 }, mul[3], buf[3][3][386];
+
+ init_decoder();
+ getbits(-1);
+ for (i=0; i < sizeof(buf)/sizeof(short); i++)
+ buf[0][0][i] = 2048;
+ for (row=0; row < height; row+=4) {
+ FORC3 mul[c] = getbits(6);
+ FORC3 {
+ val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c];
+ s = val > 65564 ? 10:12;
+ x = ~(-1 << (s-1));
+ val <<= 12-s;
+ for (i=0; i < sizeof(buf[0])/sizeof(short); i++)
+ buf[c][0][i] = (buf[c][0][i] * val + x) >> s;
+ last[c] = mul[c];
+ for (r=0; r <= !c; r++) {
+ buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7;
+ for (tree=1, col=width/2; col > 0; ) {
+ if ((tree = radc_token(tree))) {
+ col -= 2;
+ if (tree == 8)
+ FORYX buf[c][y][x] = radc_token(tree+10) * mul[c];
+ else
+ FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR;
+ } else
+ do {
+ nreps = (col > 2) ? radc_token(9) + 1 : 1;
+ for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) {
+ col -= 2;
+ FORYX buf[c][y][x] = PREDICTOR;
+ if (rep & 1) {
+ step = radc_token(10) << 4;
+ FORYX buf[c][y][x] += step;
+ }
+ }
+ } while (nreps == 9);
+ }
+ for (y=0; y < 2; y++)
+ for (x=0; x < width/2; x++) {
+ val = (buf[c][y+1][x] << 4) / mul[c];
+ if (val < 0) val = 0;
+ if (c) BAYER(row+y*2+c-1,x*2+2-c) = val;
+ else BAYER(row+r*2+y,x*2+y) = val;
+ }
+ memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c);
+ }
+ }
+ for (y=row; y < row+4; y++)
+ for (x=0; x < width; x++)
+ if ((x+y) & 1) {
+ r = x ? x-1 : x+1;
+ s = x+1 < width ? x+1 : x-1;
+ val = (BAYER(y,x)-2048)*2 + (BAYER(y,r)+BAYER(y,s))/2;
+ if (val < 0) val = 0;
+ BAYER(y,x) = val;
+ }
+ }
+ maximum = 0xfff;
+ use_gamma = 0;
+}
+
+#undef FORYX
+#undef PREDICTOR
+
+#ifdef NO_JPEG
+void CLASS kodak_jpeg_load_raw() {}
+#else
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+#ifndef LIBRAW_NOTHREADS
+#define jpeg_buffer tls->jpeg_buffer
+#else
+ static uchar jpeg_buffer[4096];
+#endif
+ size_t nbytes;
+
+ nbytes = fread (jpeg_buffer, 1, 4096, ifp);
+ swab (jpeg_buffer, jpeg_buffer, nbytes);
+ cinfo->src->next_input_byte = jpeg_buffer;
+ cinfo->src->bytes_in_buffer = nbytes;
+ return TRUE;
+#ifndef LIBRAW_NOTHREADS
+#undef jpeg_buffer
+#endif
+}
+
+void CLASS kodak_jpeg_load_raw()
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPARRAY buf;
+ JSAMPLE (*pixel)[3];
+ int row, col;
+
+ cinfo.err = jpeg_std_error (&jerr);
+ jpeg_create_decompress (&cinfo);
+ jpeg_stdio_src (&cinfo, ifp);
+ cinfo.src->fill_input_buffer = fill_input_buffer;
+ jpeg_read_header (&cinfo, TRUE);
+ jpeg_start_decompress (&cinfo);
+ if ((cinfo.output_width != width ) ||
+ (cinfo.output_height*2 != height ) ||
+ (cinfo.output_components != 3 )) {
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname);
+#endif
+ jpeg_destroy_decompress (&cinfo);
+#ifdef LIBRAW_LIBRARY_BUILD
+ throw LIBRAW_EXCEPTION_DECODE_JPEG;
+#else
+ longjmp (failure, 3);
+#endif
+ }
+ buf = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1);
+
+ while (cinfo.output_scanline < cinfo.output_height) {
+ row = cinfo.output_scanline * 2;
+ jpeg_read_scanlines (&cinfo, buf, 1);
+ pixel = (JSAMPLE (*)[3]) buf[0];
+ for (col=0; col < width; col+=2) {
+ BAYER(row+0,col+0) = pixel[col+0][1] << 1;
+ BAYER(row+1,col+1) = pixel[col+1][1] << 1;
+ BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0];
+ BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2];
+ }
+ }
+ jpeg_finish_decompress (&cinfo);
+ jpeg_destroy_decompress (&cinfo);
+ maximum = 0xff << 1;
+}
+#endif
+
+void CLASS kodak_dc120_load_raw()
+{
+ static const int mul[4] = { 162, 192, 187, 92 };
+ static const int add[4] = { 0, 636, 424, 212 };
+ uchar pixel[848];
+ int row, shift, col;
+
+ for (row=0; row < height; row++) {
+ if (fread (pixel, 1, 848, ifp) < 848) derror();
+ shift = row * mul[row & 3] + add[row & 3];
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (ushort) pixel[(col + shift) % 848];
+ }
+ maximum = 0xff;
+}
+
+void CLASS eight_bit_load_raw()
+{
+ uchar *pixel;
+ unsigned row, col, val, lblack=0;
+
+ pixel = (uchar *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "eight_bit_load_raw()");
+#ifndef LIBRAW_LIBRARY_BUILD
+ fseek (ifp, top_margin*raw_width, SEEK_CUR);
+ for (row=0; row < height; row++) {
+ if (fread (pixel, 1, raw_width, ifp) < raw_width) derror();
+ for (col=0; col < raw_width; col++) {
+ val = curve[pixel[col]];
+ if ((unsigned) (col-left_margin) < width)
+ BAYER(row,col-left_margin) = val;
+ else lblack += val;
+ }
+ }
+#else
+ for (row=0; row < raw_height; row++) {
+ if (fread (pixel, 1, raw_width, ifp) < raw_width) derror();
+ for (col=0; col < raw_width; col++) {
+ if(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)
+ {
+ val = pixel[col];
+ if(val>maximum) maximum = val;
+ }
+ else
+ val = curve[pixel[col]];
+ if((unsigned) (row-top_margin)< height)
+ {
+ if ((unsigned) (col-left_margin) < width)
+ BAYER(row,col-left_margin) = val;
+ else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = val;
+ lblack += val;
+ }
+ }
+ else // top/bottom margins
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = val;
+ }
+ }
+ }
+#endif
+
+ free (pixel);
+ if (raw_width > width+1)
+ black = lblack / ((raw_width - width) * height);
+ if (!strncmp(model,"DC2",3))
+ black = 0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE))
+#endif
+ maximum = curve[0xff];
+}
+
+void CLASS kodak_yrgb_load_raw()
+{
+ uchar *pixel;
+ int row, col, y, cb, cr, rgb[3], c;
+
+ pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel);
+ merror (pixel, "kodak_yrgb_load_raw()");
+ for (row=0; row < height; row++) {
+ if (~row & 1)
+ if (fread (pixel, raw_width, 3, ifp) < 3) derror();
+ for (col=0; col < raw_width; col++) {
+ y = pixel[width*2*(row & 1) + col];
+ cb = pixel[width + (col & -2)] - 128;
+ cr = pixel[width + (col & -2)+1] - 128;
+ rgb[1] = y-((cb + cr + 2) >> 2);
+ rgb[2] = rgb[1] + cb;
+ rgb[0] = rgb[1] + cr;
+ FORC3 image[row*width+col][c] = LIM(rgb[c],0,255);
+ }
+ }
+ free (pixel);
+ use_gamma = 0;
+}
+
+void CLASS kodak_262_load_raw()
+{
+ static const uchar kodak_tree[2][26] =
+ { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 },
+ { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } };
+ struct decode *decode[2];
+ uchar *pixel;
+ int *strip, ns, i, row, col, chess, pi=0, pi1, pi2, pred, val;
+
+ init_decoder();
+ for (i=0; i < 2; i++) {
+ decode[i] = free_decode;
+ make_decoder (kodak_tree[i], 0);
+ }
+ ns = (raw_height+63) >> 5;
+ pixel = (uchar *) malloc (raw_width*32 + ns*4);
+ merror (pixel, "kodak_262_load_raw()");
+ strip = (int *) (pixel + raw_width*32);
+ order = 0x4d4d;
+ for (i=0; i < ns; i++)
+ strip[i] = get4();
+ for (row=0; row < raw_height; row++) {
+ if ((row & 31) == 0) {
+ fseek (ifp, strip[row >> 5], SEEK_SET);
+ getbits(-1);
+ pi = 0;
+ }
+ for (col=0; col < raw_width; col++) {
+ chess = (row + col) & 1;
+ pi1 = chess ? pi-2 : pi-raw_width-1;
+ pi2 = chess ? pi-2*raw_width : pi-raw_width+1;
+ if (col <= chess) pi1 = -1;
+ if (pi1 < 0) pi1 = pi2;
+ if (pi2 < 0) pi2 = pi1;
+ if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2;
+ pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1;
+ pixel[pi] = val = pred + ljpeg_diff (decode[chess]);
+ if (val >> 8) derror();
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)
+ val = pixel[pi++];
+ else
+ val = curve[pixel[pi++]];
+#else
+ val = curve[pixel[pi++]];
+#endif
+ if ((unsigned) (col-left_margin) < width)
+ BAYER(row,col-left_margin) = val;
+ else
+#ifndef LIBRAW_LIBRARY_BUILD
+ black += val;
+#else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = val;
+ black += val;
+ }
+#endif
+ }
+ }
+ free (pixel);
+ if (raw_width > width)
+ black /= (raw_width - width) * height;
+}
+
+int CLASS kodak_65000_decode (short *out, int bsize)
+{
+ uchar c, blen[768];
+ ushort raw[6];
+ INT64 bitbuf=0;
+ int save, bits=0, i, j, len, diff;
+
+ save = ftell(ifp);
+ bsize = (bsize + 3) & -4;
+ for (i=0; i < bsize; i+=2) {
+ c = fgetc(ifp);
+ if ((blen[i ] = c & 15) > 12 ||
+ (blen[i+1] = c >> 4) > 12 ) {
+ fseek (ifp, save, SEEK_SET);
+ for (i=0; i < bsize; i+=8) {
+ read_shorts (raw, 6);
+ out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12;
+ out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12;
+ for (j=0; j < 6; j++)
+ out[i+2+j] = raw[j] & 0xfff;
+ }
+ return 1;
+ }
+ }
+ if ((bsize & 7) == 4) {
+ bitbuf = fgetc(ifp) << 8;
+ bitbuf += fgetc(ifp);
+ bits = 16;
+ }
+ for (i=0; i < bsize; i++) {
+ len = blen[i];
+ if (bits < len) {
+ for (j=0; j < 32; j+=8)
+ bitbuf += (INT64) fgetc(ifp) << (bits+(j^8));
+ bits += 32;
+ }
+ diff = bitbuf & (0xffff >> (16-len));
+ bitbuf >>= len;
+ bits -= len;
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ out[i] = diff;
+ }
+ return 0;
+}
+
+void CLASS kodak_65000_load_raw()
+{
+ short buf[256];
+ int row, col, len, pred[2], ret, i;
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col+=256) {
+ pred[0] = pred[1] = 0;
+ len = MIN (256, width-col);
+ ret = kodak_65000_decode (buf, len);
+ for (i=0; i < len; i++)
+#ifndef LIBRAW_LIBRARY_BUILD
+ if ((BAYER(row,col+i) = curve[ret ? buf[i] :
+ (pred[i & 1] += buf[i])]) >> 12) derror();
+#else
+ {
+ ushort val = ret ? buf[i] : (pred[i & 1] += buf[i]);
+ if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE))
+ val = curve[val];
+ BAYER(row,col+i)=val;
+ if(curve[val]>>12) derror();
+ }
+#endif
+ }
+}
+
+void CLASS kodak_ycbcr_load_raw()
+{
+ short buf[384], *bp;
+ int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3];
+ ushort *ip;
+
+ for (row=0; row < height; row+=2)
+ for (col=0; col < width; col+=128) {
+ len = MIN (128, width-col);
+ kodak_65000_decode (buf, len*3);
+ y[0][1] = y[1][1] = cb = cr = 0;
+ for (bp=buf, i=0; i < len; i+=2, bp+=2) {
+ cb += bp[4];
+ cr += bp[5];
+ rgb[1] = -((cb + cr + 2) >> 2);
+ rgb[2] = rgb[1] + cb;
+ rgb[0] = rgb[1] + cr;
+ for (j=0; j < 2; j++)
+ for (k=0; k < 2; k++) {
+ if ((y[j][k] = y[j][k^1] + *bp++) >> 10) derror();
+ ip = image[(row+j)*width + col+i+k];
+#ifndef LIBRAW_LIBRARY_BUILD
+ FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)];
+#else
+ if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE))
+ FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)];
+ else
+ FORC3 ip[c] = y[j][k]+rgb[c];;
+#endif
+ }
+ }
+ }
+}
+
+void CLASS kodak_rgb_load_raw()
+{
+ short buf[768], *bp;
+ int row, col, len, c, i, rgb[3];
+ ushort *ip=image[0];
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col+=256) {
+ len = MIN (256, width-col);
+ kodak_65000_decode (buf, len*3);
+ memset (rgb, 0, sizeof rgb);
+ for (bp=buf, i=0; i < len; i++, ip+=4)
+ FORC3 if ((ip[c] = rgb[c] += *bp++) >> 12) derror();
+ }
+}
+
+void CLASS kodak_thumb_load_raw()
+{
+ int row, col;
+ colors = thumb_misc >> 5;
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++)
+ read_shorts (image[row*width+col], colors);
+ maximum = (1 << (thumb_misc & 31)) - 1;
+}
+
+void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
+{
+#ifndef LIBRAW_NOTHREADS
+#define pad tls->sony_decrypt.pad
+#define p tls->sony_decrypt.p
+#else
+ static unsigned pad[128], p;
+#endif
+
+ if (start) {
+ for (p=0; p < 4; p++)
+ pad[p] = key = key * 48828125 + 1;
+ pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31;
+ for (p=4; p < 127; p++)
+ pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31;
+ for (p=0; p < 127; p++)
+ pad[p] = htonl(pad[p]);
+ }
+ while (len--)
+ *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127];
+#ifndef LIBRAW_NOTHREADS
+#undef pad
+#undef p
+#endif
+}
+
+void CLASS sony_load_raw()
+{
+ uchar head[40];
+ ushort *pixel;
+ unsigned i, key, row, col;
+
+ fseek (ifp, 200896, SEEK_SET);
+ fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR);
+ order = 0x4d4d;
+ key = get4();
+ fseek (ifp, 164600, SEEK_SET);
+ fread (head, 1, 40, ifp);
+ sony_decrypt ((unsigned int *) head, 10, 1, key);
+ for (i=26; i-- > 22; )
+ key = key << 8 | head[i];
+ fseek (ifp, data_offset, SEEK_SET);
+ pixel = (ushort *) calloc (raw_width, sizeof *pixel);
+ merror (pixel, "sony_load_raw()");
+ for (row=0; row < height; row++) {
+ if (fread (pixel, 2, raw_width, ifp) < raw_width) derror();
+ sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key);
+#ifdef LIBRAW_LIBRARY_BUILD
+ for (col=0; col < left_margin; col++)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = ntohs(pixel[col]);
+ }
+ for (col=left_margin+width; col < raw_width; col++)
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = ntohs(pixel[col]);
+ }
+#endif
+ for (col=9; col < left_margin; col++)
+ black += ntohs(pixel[col]);
+ for (col=0; col < width; col++)
+ if ((BAYER(row,col) = ntohs(pixel[col+left_margin])) >> 14)
+ derror();
+ }
+ free (pixel);
+ if (left_margin > 9)
+ black /= (left_margin-9) * height;
+ maximum = 0x3ff0;
+}
+
+void CLASS sony_arw_load_raw()
+{
+ int col, row, len, diff, sum=0;
+
+ getbits(-1);
+ for (col = raw_width; col--; )
+ for (row=0; row < raw_height+1; row+=2) {
+ if (row == raw_height) row = 1;
+ len = 4 - getbits(2);
+ if (len == 3 && getbits(1)) len = 0;
+ if (len == 4)
+ while (len < 17 && !getbits(1)) len++;
+ diff = getbits(len);
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ if ((sum += diff) >> 12) derror();
+ if (row < height) BAYER(row,col) = sum;
+#ifdef LIBRAW_LIBRARY_BUILD
+ else
+ {
+ ushort *dfp = get_masked_pointer(row,col);
+ if(dfp) *dfp = sum;
+ }
+#endif
+ }
+}
+
+void CLASS sony_arw2_load_raw()
+{
+ uchar *data, *dp;
+ ushort pix[16];
+ int row, col, val, max, min, imax, imin, sh, bit, i;
+
+ data = (uchar *) malloc (raw_width*tiff_bps >> 3);
+ merror (data, "sony_arw2_load_raw()");
+ for (row=0; row < height; row++) {
+ fread (data, 1, raw_width*tiff_bps >> 3, ifp);
+ if (tiff_bps == 8) {
+ for (dp=data, col=0; col < width-30; dp+=16) {
+ max = 0x7ff & (val = sget4(dp));
+ min = 0x7ff & val >> 11;
+ imax = 0x0f & val >> 22;
+ imin = 0x0f & val >> 26;
+ for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++);
+ for (bit=30, i=0; i < 16; i++)
+ if (i == imax) pix[i] = max;
+ else if (i == imin) pix[i] = min;
+ else {
+ pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min;
+ if (pix[i] > 0x7ff) pix[i] = 0x7ff;
+ bit += 7;
+ }
+ for (i=0; i < 16; i++, col+=2)
+#ifndef LIBRAW_LIBRARY_BUILD
+ BAYER(row,col) = curve[pix[i] << 1] >> 1;
+#else
+ {
+ ushort val = pix[i];
+ if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE))
+ val = curve[val<<1]>>1;
+ BAYER(row,col)=val;
+ }
+#endif
+ col -= col & 1 ? 1:31;
+ }
+ } else if (tiff_bps == 12)
+ for (dp=data, col=0; col < width; dp+=3, col+=2) {
+ BAYER(row,col) = ((dp[1] << 8 | dp[0]) & 0xfff) << 1;
+ BAYER(row,col+1) = (dp[2] << 4 | dp[1] >> 4) << 1;
+ }
+ }
+ free (data);
+}
+
+#define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1)
+
+/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */
+void CLASS smal_decode_segment (unsigned seg[2][2], int holes)
+{
+ uchar hist[3][13] = {
+ { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 },
+ { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 },
+ { 3, 3, 0, 0, 63, 47, 31, 15, 0 } };
+ int low, high=0xff, carry=0, nbits=8;
+ int s, count, bin, next, i, sym[3];
+ uchar diff, pred[]={0,0};
+ ushort data=0, range=0;
+ unsigned pix, row, col;
+
+ fseek (ifp, seg[0][1]+1, SEEK_SET);
+ getbits(-1);
+ for (pix=seg[0][0]; pix < seg[1][0]; pix++) {
+ for (s=0; s < 3; s++) {
+ data = data << nbits | getbits(nbits);
+ if (carry < 0)
+ carry = (nbits += carry+1) < 1 ? nbits-1 : 0;
+ while (--nbits >= 0)
+ if ((data >> nbits & 0xff) == 0xff) break;
+ if (nbits > 0)
+ data = ((data & ((1 << (nbits-1)) - 1)) << 1) |
+ ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits));
+ if (nbits >= 0) {
+ data += getbits(1);
+ carry = nbits - 8;
+ }
+ count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4);
+ for (bin=0; hist[s][bin+5] > count; bin++);
+ low = hist[s][bin+5] * (high >> 4) >> 2;
+ if (bin) high = hist[s][bin+4] * (high >> 4) >> 2;
+ high -= low;
+ for (nbits=0; high << nbits < 128; nbits++);
+ range = (range+low) << nbits;
+ high <<= nbits;
+ next = hist[s][1];
+ if (++hist[s][2] > hist[s][3]) {
+ next = (next+1) & hist[s][0];
+ hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2;
+ hist[s][2] = 1;
+ }
+ if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) {
+ if (bin < hist[s][1])
+ for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--;
+ else if (next <= bin)
+ for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++;
+ }
+ hist[s][1] = next;
+ sym[s] = bin;
+ }
+ diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3);
+ if (sym[0] & 4)
+ diff = diff ? -diff : 0x80;
+ if (ftell(ifp) + 12 >= seg[1][1])
+ diff = 0;
+ pred[pix & 1] += diff;
+ row = pix / raw_width - top_margin;
+ col = pix % raw_width - left_margin;
+ if (row < height && col < width)
+ BAYER(row,col) = pred[pix & 1];
+#ifdef LIBRAW_LIBRARY_BUILD
+ else
+ {
+ ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin);
+ if(dfp) *dfp = pred[pix &1];
+ }
+#endif
+ if (!(pix & 1) && HOLE(row)) pix += 2;
+ }
+ maximum = 0xff;
+}
+
+void CLASS smal_v6_load_raw()
+{
+ unsigned seg[2][2];
+
+ fseek (ifp, 16, SEEK_SET);
+ seg[0][0] = 0;
+ seg[0][1] = get2();
+ seg[1][0] = raw_width * raw_height;
+ seg[1][1] = INT_MAX;
+ smal_decode_segment (seg, 0);
+ use_gamma = 0;
+}
+
+int CLASS median4 (int *p)
+{
+ int min, max, sum, i;
+
+ min = max = sum = p[0];
+ for (i=1; i < 4; i++) {
+ sum += p[i];
+ if (min > p[i]) min = p[i];
+ if (max < p[i]) max = p[i];
+ }
+ return (sum - min - max) >> 1;
+}
+
+void CLASS fill_holes (int holes)
+{
+ int row, col, val[4];
+
+ for (row=2; row < height-2; row++) {
+ if (!HOLE(row)) continue;
+ for (col=1; col < width-1; col+=4) {
+ val[0] = BAYER(row-1,col-1);
+ val[1] = BAYER(row-1,col+1);
+ val[2] = BAYER(row+1,col-1);
+ val[3] = BAYER(row+1,col+1);
+ BAYER(row,col) = median4(val);
+ }
+ for (col=2; col < width-2; col+=4)
+ if (HOLE(row-2) || HOLE(row+2))
+ BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1;
+ else {
+ val[0] = BAYER(row,col-2);
+ val[1] = BAYER(row,col+2);
+ val[2] = BAYER(row-2,col);
+ val[3] = BAYER(row+2,col);
+ BAYER(row,col) = median4(val);
+ }
+ }
+}
+
+void CLASS smal_v9_load_raw()
+{
+ unsigned seg[256][2], offset, nseg, holes, i;
+
+ fseek (ifp, 67, SEEK_SET);
+ offset = get4();
+ nseg = fgetc(ifp);
+ fseek (ifp, offset, SEEK_SET);
+ for (i=0; i < nseg*2; i++)
+ seg[0][i] = get4() + data_offset*(i & 1);
+ fseek (ifp, 78, SEEK_SET);
+ holes = fgetc(ifp);
+ fseek (ifp, 88, SEEK_SET);
+ seg[nseg][0] = raw_height * raw_width;
+ seg[nseg][1] = get4() + data_offset;
+ for (i=0; i < nseg; i++)
+ smal_decode_segment (seg+i, holes);
+ if (holes) fill_holes (holes);
+}
+
+void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size)
+{
+ double work[3][6], num;
+ int i, j, k;
+
+ for (i=0; i < 3; i++) {
+ for (j=0; j < 6; j++)
+ work[i][j] = j == i+3;
+ for (j=0; j < 3; j++)
+ for (k=0; k < size; k++)
+ work[i][j] += in[k][i] * in[k][j];
+ }
+ for (i=0; i < 3; i++) {
+ num = work[i][i];
+ for (j=0; j < 6; j++)
+ work[i][j] /= num;
+ for (k=0; k < 3; k++) {
+ if (k==i) continue;
+ num = work[k][i];
+ for (j=0; j < 6; j++)
+ work[k][j] -= work[i][j] * num;
+ }
+ }
+ for (i=0; i < size; i++)
+ for (j=0; j < 3; j++)
+ for (out[i][j]=k=0; k < 3; k++)
+ out[i][j] += work[j][k+3] * in[i][k];
+}
+
+void CLASS cam_xyz_coeff (double cam_xyz[4][3])
+{
+ double cam_rgb[4][3], inverse[4][3], num;
+ int i, j, k;
+
+ for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */
+ for (j=0; j < 3; j++)
+ for (cam_rgb[i][j] = k=0; k < 3; k++)
+ cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j];
+
+ for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */
+ for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */
+ num += cam_rgb[i][j];
+ for (j=0; j < 3; j++)
+ cam_rgb[i][j] /= num;
+ pre_mul[i] = 1 / num;
+ }
+ pseudoinverse (cam_rgb, inverse, colors);
+ for (raw_color = i=0; i < 3; i++)
+ for (j=0; j < colors; j++)
+ rgb_cam[i][j] = inverse[j][i];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+ color_flags.rgb_cam_state = LIBRAW_COLORSTATE_CONST;
+#endif
+}
+
+#ifdef COLORCHECK
+void CLASS colorcheck()
+{
+#define NSQ 24
+// Coordinates of the GretagMacbeth ColorChecker squares
+// width, height, 1st_column, 1st_row
+ static const int cut[NSQ][4] = {
+ { 241, 231, 234, 274 },
+ { 251, 235, 534, 274 },
+ { 255, 239, 838, 272 },
+ { 255, 240, 1146, 274 },
+ { 251, 237, 1452, 278 },
+ { 243, 238, 1758, 288 },
+ { 253, 253, 218, 558 },
+ { 255, 249, 524, 562 },
+ { 261, 253, 830, 562 },
+ { 260, 255, 1144, 564 },
+ { 261, 255, 1450, 566 },
+ { 247, 247, 1764, 576 },
+ { 255, 251, 212, 862 },
+ { 259, 259, 518, 862 },
+ { 263, 261, 826, 864 },
+ { 265, 263, 1138, 866 },
+ { 265, 257, 1450, 872 },
+ { 257, 255, 1762, 874 },
+ { 257, 253, 212, 1164 },
+ { 262, 251, 516, 1172 },
+ { 263, 257, 826, 1172 },
+ { 263, 255, 1136, 1176 },
+ { 255, 252, 1452, 1182 },
+ { 257, 253, 1760, 1180 } };
+// ColorChecker Chart under 6500-kelvin illumination
+ static const double gmb_xyY[NSQ][3] = {
+ { 0.400, 0.350, 10.1 }, // Dark Skin
+ { 0.377, 0.345, 35.8 }, // Light Skin
+ { 0.247, 0.251, 19.3 }, // Blue Sky
+ { 0.337, 0.422, 13.3 }, // Foliage
+ { 0.265, 0.240, 24.3 }, // Blue Flower
+ { 0.261, 0.343, 43.1 }, // Bluish Green
+ { 0.506, 0.407, 30.1 }, // Orange
+ { 0.211, 0.175, 12.0 }, // Purplish Blue
+ { 0.453, 0.306, 19.8 }, // Moderate Red
+ { 0.285, 0.202, 6.6 }, // Purple
+ { 0.380, 0.489, 44.3 }, // Yellow Green
+ { 0.473, 0.438, 43.1 }, // Orange Yellow
+ { 0.187, 0.129, 6.1 }, // Blue
+ { 0.305, 0.478, 23.4 }, // Green
+ { 0.539, 0.313, 12.0 }, // Red
+ { 0.448, 0.470, 59.1 }, // Yellow
+ { 0.364, 0.233, 19.8 }, // Magenta
+ { 0.196, 0.252, 19.8 }, // Cyan
+ { 0.310, 0.316, 90.0 }, // White
+ { 0.310, 0.316, 59.1 }, // Neutral 8
+ { 0.310, 0.316, 36.2 }, // Neutral 6.5
+ { 0.310, 0.316, 19.8 }, // Neutral 5
+ { 0.310, 0.316, 9.0 }, // Neutral 3.5
+ { 0.310, 0.316, 3.1 } }; // Black
+ double gmb_cam[NSQ][4], gmb_xyz[NSQ][3];
+ double inverse[NSQ][3], cam_xyz[4][3], num;
+ int c, i, j, k, sq, row, col, count[4];
+
+ memset (gmb_cam, 0, sizeof gmb_cam);
+ for (sq=0; sq < NSQ; sq++) {
+ FORCC count[c] = 0;
+ for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++)
+ for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) {
+ c = FC(row,col);
+ if (c >= colors) c -= 2;
+ gmb_cam[sq][c] += BAYER(row,col);
+ count[c]++;
+ }
+ FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black;
+ gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1];
+ gmb_xyz[sq][1] = gmb_xyY[sq][2];
+ gmb_xyz[sq][2] = gmb_xyY[sq][2] *
+ (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1];
+ }
+ pseudoinverse (gmb_xyz, inverse, NSQ);
+ for (i=0; i < colors; i++)
+ for (j=0; j < 3; j++)
+ for (cam_xyz[i][j] = k=0; k < NSQ; k++)
+ cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j];
+ cam_xyz_coeff (cam_xyz);
+#ifdef DCRAW_VERBOSE
+ if (verbose) {
+ printf (" { \"%s %s\", %d,\n\t{", make, model, black);
+ num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]);
+ FORCC for (j=0; j < 3; j++)
+ printf ("%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5));
+ puts (" } },");
+ }
+#endif
+#undef NSQ
+}
+#endif
+
+void CLASS hat_transform (float *temp, float *base, int st, int size, int sc)
+{
+ int i;
+ for (i=0; i < sc; i++)
+ temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)];
+ for (; i+sc < size; i++)
+ temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)];
+ for (; i < size; i++)
+ temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))];
+}
+
+#ifndef _OPENMP
+void CLASS wavelet_denoise()
+{
+ float *fimg=0, *temp, thold, mul[2], avg, diff;
+ int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast;
+ ushort *window[4];
+ static const float noise[] =
+ { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 };
+
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("Wavelet denoising...\n"));
+#endif
+
+ while (maximum << scale < 0x10000) scale++;
+ maximum <<= --scale;
+ black <<= scale;
+ if ((size = iheight*iwidth) < 0x15550000)
+ fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg);
+ merror (fimg, "wavelet_denoise()");
+ temp = fimg + size*3;
+ if ((nc = colors) == 3 && filters) nc++;
+ FORC(nc) { /* denoise R,G1,B,G3 individually */
+ for (i=0; i < size; i++)
+ fimg[i] = 256 * sqrt((double)(image[i][c] << scale));
+ for (hpass=lev=0; lev < 5; lev++) {
+ lpass = size*((lev & 1)+1);
+ for (row=0; row < iheight; row++) {
+ hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev);
+ for (col=0; col < iwidth; col++)
+ fimg[lpass + row*iwidth + col] = temp[col] * 0.25;
+ }
+ for (col=0; col < iwidth; col++) {
+ hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev);
+ for (row=0; row < iheight; row++)
+ fimg[lpass + row*iwidth + col] = temp[row] * 0.25;
+ }
+ thold = threshold * noise[lev];
+ for (i=0; i < size; i++) {
+ fimg[hpass+i] -= fimg[lpass+i];
+ if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold;
+ else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold;
+ else fimg[hpass+i] = 0;
+ if (hpass) fimg[i] += fimg[hpass+i];
+ }
+ hpass = lpass;
+ }
+ for (i=0; i < size; i++)
+ image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000);
+ }
+ if (filters && colors == 3) { /* pull G1 and G3 closer together */
+ for (row=0; row < 2; row++)
+ mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1];
+ for (i=0; i < 4; i++)
+ window[i] = (ushort *) fimg + width*i;
+ for (wlast=-1, row=1; row < height-1; row++) {
+ while (wlast < row+1) {
+ for (wlast++, i=0; i < 4; i++)
+ window[(i+3) & 3] = window[i];
+ for (col = FC(wlast,1) & 1; col < width; col+=2)
+ window[2][col] = BAYER(wlast,col);
+ }
+ thold = threshold/512;
+ for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) {
+ avg = ( window[0][col-1] + window[0][col+1] +
+ window[2][col-1] + window[2][col+1] - black*4 )
+ * mul[row & 1] + (window[1][col] - black) * 0.5 + black;
+ avg = avg < 0 ? 0 : sqrt(avg);
+ diff = sqrt((double)(BAYER(row,col))) - avg;
+ if (diff < -thold) diff += thold;
+ else if (diff > thold) diff -= thold;
+ else diff = 0;
+ BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5);
+ }
+ }
+ }
+ free (fimg);
+}
+#else
+void CLASS wavelet_denoise()
+{
+ float *fimg=0, *temp, thold, mul[2], avg, diff;
+ int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast;
+ ushort *window[4];
+ static const float noise[] =
+ { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 };
+
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("Wavelet denoising...\n"));
+#endif
+
+ while (maximum << scale < 0x10000) scale++;
+ maximum <<= --scale;
+ black <<= scale;
+ if ((size = iheight*iwidth) < 0x15550000)
+ fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg);
+ merror (fimg, "wavelet_denoise()");
+ temp = fimg + size*3;
+ if ((nc = colors) == 3 && filters) nc++;
+#ifdef LIBRAW_LIBRARY_BUILD
+#pragma omp parallel default(shared) private(i,col,row,thold,lev,lpass,hpass,temp) firstprivate(c,scale,size)
+#endif
+ {
+ temp = (float*)malloc( (iheight + iwidth) * sizeof *fimg);
+ FORC(nc) { /* denoise R,G1,B,G3 individually */
+#ifdef LIBRAW_LIBRARY_BUILD
+#pragma omp for
+#endif
+ for (i=0; i < size; i++)
+ fimg[i] = 256 * sqrt((double)(image[i][c] << scale));
+ for (hpass=lev=0; lev < 5; lev++) {
+ lpass = size*((lev & 1)+1);
+#ifdef LIBRAW_LIBRARY_BUILD
+#pragma omp for
+#endif
+ for (row=0; row < iheight; row++) {
+ hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev);
+ for (col=0; col < iwidth; col++)
+ fimg[lpass + row*iwidth + col] = temp[col] * 0.25;
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+#pragma omp for
+#endif
+ for (col=0; col < iwidth; col++) {
+ hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev);
+ for (row=0; row < iheight; row++)
+ fimg[lpass + row*iwidth + col] = temp[row] * 0.25;
+ }
+ thold = threshold * noise[lev];
+#ifdef LIBRAW_LIBRARY_BUILD
+#pragma omp for
+#endif
+ for (i=0; i < size; i++) {
+ fimg[hpass+i] -= fimg[lpass+i];
+ if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold;
+ else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold;
+ else fimg[hpass+i] = 0;
+ if (hpass) fimg[i] += fimg[hpass+i];
+ }
+ hpass = lpass;
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+#pragma omp for
+#endif
+ for (i=0; i < size; i++)
+ image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000);
+ }
+ free(temp);
+ } /* end omp parallel */
+/* the following loops are hard to parallize, no idea yes,
+ * problem is wlast which is carrying dependency
+ * second part should be easyer, but did not yet get it right.
+ */
+ if (filters && colors == 3) { /* pull G1 and G3 closer together */
+ for (row=0; row < 2; row++)
+ mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1];
+ for (i=0; i < 4; i++)
+ window[i] = (ushort *) fimg + width*i;
+ for (wlast=-1, row=1; row < height-1; row++) {
+ while (wlast < row+1) {
+ for (wlast++, i=0; i < 4; i++)
+ window[(i+3) & 3] = window[i];
+ for (col = FC(wlast,1) & 1; col < width; col+=2)
+ window[2][col] = BAYER(wlast,col);
+ }
+ thold = threshold/512;
+ for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) {
+ avg = ( window[0][col-1] + window[0][col+1] +
+ window[2][col-1] + window[2][col+1] - black*4 )
+ * mul[row & 1] + (window[1][col] - black) * 0.5 + black;
+ avg = avg < 0 ? 0 : sqrt(avg);
+ diff = sqrt(BAYER(row,col)) - avg;
+ if (diff < -thold) diff += thold;
+ else if (diff > thold) diff -= thold;
+ else diff = 0;
+ BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5);
+ }
+ }
+ }
+ free (fimg);
+}
+
+#endif
+
+void CLASS scale_colors()
+{
+ unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8];
+ int val, dark, sat;
+ double dsum[8], dmin, dmax;
+ float scale_mul[4], fr, fc;
+ ushort *img=0, *pix;
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,0,2);
+#endif
+
+ if (user_mul[0])
+ memcpy (pre_mul, user_mul, sizeof pre_mul);
+ if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) {
+ memset (dsum, 0, sizeof dsum);
+ bottom = MIN (greybox[1]+greybox[3], height);
+ right = MIN (greybox[0]+greybox[2], width);
+ for (row=greybox[1]; row < bottom; row += 8)
+ for (col=greybox[0]; col < right; col += 8) {
+ memset (sum, 0, sizeof sum);
+ for (y=row; y < row+8 && y < bottom; y++)
+ for (x=col; x < col+8 && x < right; x++)
+ FORC4 {
+ if (filters) {
+ c = FC(y,x);
+ val = BAYER(y,x);
+ } else
+ val = image[y*width+x][c];
+ if (val > maximum-25) goto skip_block;
+ if ((val -= black) < 0) val = 0;
+ sum[c] += val;
+ sum[c+4]++;
+ if (filters) break;
+ }
+ FORC(8) dsum[c] += sum[c];
+skip_block: ;
+ }
+ FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CALCULATED;
+#endif
+ }
+ if (use_camera_wb && cam_mul[0] != -1) {
+ memset (sum, 0, sizeof sum);
+ for (row=0; row < 8; row++)
+ for (col=0; col < 8; col++) {
+ c = FC(row,col);
+ if ((val = white[row][col] - black) > 0)
+ sum[c] += val;
+ sum[c+4]++;
+ }
+ if (sum[0] && sum[1] && sum[2] && sum[3])
+ {
+ FORC4 pre_mul[c] = (float) sum[c+4] / sum[c];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CALCULATED;
+#endif
+ }
+ else if (cam_mul[0] && cam_mul[2])
+ {
+ memcpy (pre_mul, cam_mul, sizeof pre_mul);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state =color_flags.pre_mul_state;
+#endif
+ }
+ else
+ {
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB;
+#endif
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname);
+#endif
+ }
+ }
+ if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1;
+ dark = black;
+ sat = maximum;
+ if (threshold) wavelet_denoise();
+ maximum -= black;
+ for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) {
+ if (dmin > pre_mul[c])
+ dmin = pre_mul[c];
+ if (dmax < pre_mul[c])
+ dmax = pre_mul[c];
+ }
+ if (!highlight) dmax = dmin;
+ FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum;
+#ifdef DCRAW_VERBOSE
+ if (verbose) {
+ fprintf (stderr,
+ _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat);
+ FORC4 fprintf (stderr, " %f", pre_mul[c]);
+ fputc ('\n', stderr);
+ }
+#endif
+ size = iheight*iwidth;
+ for (i=0; i < size*4; i++) {
+ val = image[0][i];
+ if (!val) continue;
+ val -= black;
+ val *= scale_mul[i & 3];
+ image[0][i] = CLIP(val);
+ }
+ if ((aber[0] != 1 || aber[2] != 1) && colors == 3) {
+#ifdef DCRAW_VERBOSE
+ if (verbose)
+ fprintf (stderr,_("Correcting chromatic aberration...\n"));
+#endif
+ for (c=0; c < 4; c+=2) {
+ if (aber[c] == 1) continue;
+ img = (ushort *) malloc (size * sizeof *img);
+ merror (img, "scale_colors()");
+ for (i=0; i < size; i++)
+ img[i] = image[i][c];
+ for (row=0; row < iheight; row++) {
+ ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5;
+ if (ur > iheight-2) continue;
+ fr -= ur;
+ for (col=0; col < iwidth; col++) {
+ uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5;
+ if (uc > iwidth-2) continue;
+ fc -= uc;
+ pix = img + ur*iwidth + uc;
+ image[row*iwidth+col][c] =
+ (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) +
+ (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr;
+ }
+ }
+ free(img);
+ }
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,1,2);
+#endif
+}
+
+void CLASS pre_interpolate()
+{
+ ushort (*img)[4];
+ int row, col, c;
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,0,2);
+#endif
+ if (shrink) {
+ if (half_size) {
+ height = iheight;
+ width = iwidth;
+ } else {
+ img = (ushort (*)[4]) calloc (height*width, sizeof *img);
+ merror (img, "pre_interpolate()");
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ c = fc(row,col);
+ img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c];
+ }
+ free (image);
+ image = img;
+ shrink = 0;
+ }
+ }
+ if (filters && colors == 3) {
+ if ((mix_green = four_color_rgb)) colors++;
+ else {
+ for (row = FC(1,0) >> 1; row < height; row+=2)
+ for (col = FC(row,1) & 1; col < width; col+=2)
+ image[row*width+col][1] = image[row*width+col][3];
+ filters &= ~((filters & 0x55555555) << 1);
+ }
+ }
+ if (half_size) filters = 0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,1,2);
+#endif
+}
+
+void CLASS border_interpolate (int border)
+{
+ unsigned row, col, y, x, f, c, sum[8];
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ if (col==border && row >= border && row < height-border)
+ col = width-border;
+ memset (sum, 0, sizeof sum);
+ for (y=row-1; y != row+2; y++)
+ for (x=col-1; x != col+2; x++)
+ if (y < height && x < width) {
+ f = fc(y,x);
+ sum[f] += image[y*width+x][f];
+ sum[f+4]++;
+ }
+ f = fc(row,col);
+ FORCC if (c != f && sum[c+4])
+ image[row*width+col][c] = sum[c] / sum[c+4];
+ }
+}
+
+void CLASS lin_interpolate()
+{
+ int code[16][16][32], *ip, sum[4];
+ int c, i, x, y, row, col, shift, color;
+ ushort *pix;
+
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("Bilinear interpolation...\n"));
+#endif
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3);
+#endif
+ border_interpolate(1);
+ for (row=0; row < 16; row++)
+ for (col=0; col < 16; col++) {
+ ip = code[row][col];
+ memset (sum, 0, sizeof sum);
+ for (y=-1; y <= 1; y++)
+ for (x=-1; x <= 1; x++) {
+ shift = (y==0) + (x==0);
+ if (shift == 2) continue;
+ color = fc(row+y,col+x);
+ *ip++ = (width*y + x)*4 + color;
+ *ip++ = shift;
+ *ip++ = color;
+ sum[color] += 1 << shift;
+ }
+ FORCC
+ if (c != fc(row,col)) {
+ *ip++ = c;
+ *ip++ = 256 / sum[c];
+ }
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3);
+#endif
+ for (row=1; row < height-1; row++)
+ for (col=1; col < width-1; col++) {
+ pix = image[row*width+col];
+ ip = code[row & 15][col & 15];
+ memset (sum, 0, sizeof sum);
+ for (i=8; i--; ip+=3)
+ sum[ip[2]] += pix[ip[0]] << ip[1];
+ for (i=colors; --i; ip+=2)
+ pix[ip[0]] = sum[ip[0]] * ip[1] >> 8;
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3);
+#endif
+}
+
+/*
+ This algorithm is officially called:
+
+ "Interpolation using a Threshold-based variable number of gradients"
+
+ described in http://scien.stanford.edu/class/psych221/projects/99/tingchen/algodep/vargra.html
+
+ I've extended the basic idea to work with non-Bayer filter arrays.
+ Gradients are numbered clockwise from NW=0 to W=7.
+ */
+void CLASS vng_interpolate()
+{
+ static const signed char *cp, terms[] = {
+ -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01,
+ -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01,
+ -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03,
+ -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06,
+ -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04,
+ -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01,
+ -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40,
+ -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11,
+ -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11,
+ -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22,
+ -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44,
+ -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10,
+ -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04,
+ +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40,
+ +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20,
+ +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08,
+ +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20,
+ +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44,
+ +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60,
+ +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80,
+ +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40,
+ +1,+0,+2,+1,0,0x10
+ }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
+ ushort (*brow[5])[4], *pix;
+ int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4];
+ int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
+ int g, diff, thold, num, c;
+ lin_interpolate();
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("VNG interpolation...\n"));
+#endif
+
+ if (filters == 1) prow = pcol = 15;
+ ip = (int *) calloc ((prow+1)*(pcol+1), 1280);
+ merror (ip, "vng_interpolate()");
+ for (row=0; row <= prow; row++) /* Precalculate for VNG */
+ for (col=0; col <= pcol; col++) {
+ code[row][col] = ip;
+ for (cp=terms, t=0; t < 64; t++) {
+ y1 = *cp++; x1 = *cp++;
+ y2 = *cp++; x2 = *cp++;
+ weight = *cp++;
+ grads = *cp++;
+ color = fc(row+y1,col+x1);
+ if (fc(row+y2,col+x2) != color) continue;
+ diag = (fc(row,col+1) == color && fc(row+1,col) == color) ? 2:1;
+ if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue;
+ *ip++ = (y1*width + x1)*4 + color;
+ *ip++ = (y2*width + x2)*4 + color;
+ *ip++ = weight;
+ for (g=0; g < 8; g++)
+ if (grads & 1<<g) *ip++ = g;
+ *ip++ = -1;
+ }
+ *ip++ = INT_MAX;
+ for (cp=chood, g=0; g < 8; g++) {
+ y = *cp++; x = *cp++;
+ *ip++ = (y*width + x) * 4;
+ color = fc(row,col);
+ if (fc(row+y,col+x) != color && fc(row+y*2,col+x*2) == color)
+ *ip++ = (y*width + x) * 8 + color;
+ else
+ *ip++ = 0;
+ }
+ }
+ brow[4] = (ushort (*)[4]) calloc (width*3, sizeof **brow);
+ merror (brow[4], "vng_interpolate()");
+ for (row=0; row < 3; row++)
+ brow[row] = brow[4] + row*width;
+ for (row=2; row < height-2; row++) { /* Do VNG interpolation */
+#ifdef LIBRAW_LIBRARY_BUILD
+ if(!((row-2)%256))RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,(row-2)/256+1,((height-3)/256)+1);
+#endif
+ for (col=2; col < width-2; col++) {
+ pix = image[row*width+col];
+ ip = code[row & prow][col & pcol];
+ memset (gval, 0, sizeof gval);
+ while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */
+ diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
+ gval[ip[3]] += diff;
+ ip += 5;
+ if ((g = ip[-1]) == -1) continue;
+ gval[g] += diff;
+ while ((g = *ip++) != -1)
+ gval[g] += diff;
+ }
+ ip++;
+ gmin = gmax = gval[0]; /* Choose a threshold */
+ for (g=1; g < 8; g++) {
+ if (gmin > gval[g]) gmin = gval[g];
+ if (gmax < gval[g]) gmax = gval[g];
+ }
+ if (gmax == 0) {
+ memcpy (brow[2][col], pix, sizeof *image);
+ continue;
+ }
+ thold = gmin + (gmax >> 1);
+ memset (sum, 0, sizeof sum);
+ color = fc(row,col);
+ for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */
+ if (gval[g] <= thold) {
+ FORCC
+ if (c == color && ip[1])
+ sum[c] += (pix[c] + pix[ip[1]]) >> 1;
+ else
+ sum[c] += pix[ip[0] + c];
+ num++;
+ }
+ }
+ FORCC { /* Save to buffer */
+ t = pix[color];
+ if (c != color)
+ t += (sum[c] - sum[color]) / num;
+ brow[2][col][c] = CLIP(t);
+ }
+ }
+ if (row > 3) /* Write buffer to image */
+ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+ for (g=0; g < 4; g++)
+ brow[(g-1) & 3] = brow[g];
+ }
+ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+ memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
+ free (brow[4]);
+ free (code[0][0]);
+}
+
+/*
+ Patterned Pixel Grouping Interpolation by Alain Desbiolles
+*/
+void CLASS ppg_interpolate()
+{
+ int dir[5] = { 1, width, -1, -width, 1 };
+ int row, col, diff[2], guess[2], c, d, i;
+ ushort (*pix)[4];
+
+ border_interpolate(3);
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("PPG interpolation...\n"));
+#endif
+
+/* Fill in the green layer with gradients and pattern recognition: */
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3);
+#endif
+ for (row=3; row < height-3; row++)
+ for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) {
+ pix = image + row*width+col;
+ for (i=0; (d=dir[i]) > 0; i++) {
+ guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2
+ - pix[-2*d][c] - pix[2*d][c];
+ diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) +
+ ABS(pix[ 2*d][c] - pix[ 0][c]) +
+ ABS(pix[ -d][1] - pix[ d][1]) ) * 3 +
+ ( ABS(pix[ 3*d][1] - pix[ d][1]) +
+ ABS(pix[-3*d][1] - pix[-d][1]) ) * 2;
+ }
+ d = dir[i = diff[0] > diff[1]];
+ pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]);
+ }
+/* Calculate red and blue for each green pixel: */
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3);
+#endif
+ for (row=1; row < height-1; row++)
+ for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) {
+ pix = image + row*width+col;
+ for (i=0; (d=dir[i]) > 0; c=2-c, i++)
+ pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1]
+ - pix[-d][1] - pix[d][1]) >> 1);
+ }
+/* Calculate blue for red pixels and vice versa: */
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3);
+#endif
+ for (row=1; row < height-1; row++)
+ for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) {
+ pix = image + row*width+col;
+ for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) {
+ diff[i] = ABS(pix[-d][c] - pix[d][c]) +
+ ABS(pix[-d][1] - pix[0][1]) +
+ ABS(pix[ d][1] - pix[0][1]);
+ guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1]
+ - pix[-d][1] - pix[d][1];
+ }
+ if (diff[0] != diff[1])
+ pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1);
+ else
+ pix[0][c] = CLIP((guess[0]+guess[1]) >> 2);
+ }
+}
+
+/*
+ Adaptive Homogeneity-Directed interpolation is based on
+ the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
+ */
+#define TS 256 /* Tile Size */
+#ifndef _OPENMP
+void CLASS ahd_interpolate()
+{
+ int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2];
+ ushort (*pix)[4], (*rix)[3];
+ static const int dir[4] = { -1, 1, -TS, TS };
+ unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
+ float r, cbrt[0x10000], xyz[3], xyz_cam[3][4];
+ ushort (*rgb)[TS][TS][3];
+ short (*lab)[TS][TS][3], (*lix)[3];
+ char (*homo)[TS][TS], *buffer;
+
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("AHD interpolation...\n"));
+#endif
+
+ for (i=0; i < 0x10000; i++) {
+ r = i / 65535.0;
+ cbrt[i] = r > 0.008856 ? pow((double)r,1/3.0) : 7.787*r + 16/116.0;
+ }
+ for (i=0; i < 3; i++)
+ for (j=0; j < colors; j++)
+ for (xyz_cam[i][j] = k=0; k < 3; k++)
+ xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i];
+
+ border_interpolate(5);
+ buffer = (char *) malloc (26*TS*TS); /* 1664 kB */
+ merror (buffer, "ahd_interpolate()");
+ rgb = (ushort(*)[TS][TS][3]) buffer;
+ lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS);
+ homo = (char (*)[TS][TS]) (buffer + 24*TS*TS);
+
+ for (top=2; top < height-5; top += TS-6)
+ {
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,(top-2)/(TS-6),(height-7)/(TS-6)+1);
+#endif
+ for (left=2; left < width-5; left += TS-6) {
+
+/* Interpolate green horizontally and vertically: */
+ for (row = top; row < top+TS && row < height-2; row++) {
+ col = left + (FC(row,left) & 1);
+ for (c = FC(row,col); col < left+TS && col < width-2; col+=2) {
+ pix = image + row*width+col;
+ val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2
+ - pix[-2][c] - pix[2][c]) >> 2;
+ rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]);
+ val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2
+ - pix[-2*width][c] - pix[2*width][c]) >> 2;
+ rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]);
+ }
+ }
+/* Interpolate red and blue, and convert to CIELab: */
+ for (d=0; d < 2; d++)
+ for (row=top+1; row < top+TS-1 && row < height-3; row++)
+ for (col=left+1; col < left+TS-1 && col < width-3; col++) {
+ pix = image + row*width+col;
+ rix = &rgb[d][row-top][col-left];
+ lix = &lab[d][row-top][col-left];
+ if ((c = 2 - FC(row,col)) == 1) {
+ c = FC(row+1,col);
+ val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c]
+ - rix[-1][1] - rix[1][1] ) >> 1);
+ rix[0][2-c] = CLIP(val);
+ val = pix[0][1] + (( pix[-width][c] + pix[width][c]
+ - rix[-TS][1] - rix[TS][1] ) >> 1);
+ } else
+ val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c]
+ + pix[+width-1][c] + pix[+width+1][c]
+ - rix[-TS-1][1] - rix[-TS+1][1]
+ - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2);
+ rix[0][c] = CLIP(val);
+ c = FC(row,col);
+ rix[0][c] = pix[0][c];
+ xyz[0] = xyz[1] = xyz[2] = 0.5;
+ FORCC {
+ xyz[0] += xyz_cam[0][c] * rix[0][c];
+ xyz[1] += xyz_cam[1][c] * rix[0][c];
+ xyz[2] += xyz_cam[2][c] * rix[0][c];
+ }
+ xyz[0] = cbrt[CLIP((int) xyz[0])];
+ xyz[1] = cbrt[CLIP((int) xyz[1])];
+ xyz[2] = cbrt[CLIP((int) xyz[2])];
+ lix[0][0] = 64 * (116 * xyz[1] - 16);
+ lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]);
+ lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]);
+ }
+/* Build homogeneity maps from the CIELab images: */
+ memset (homo, 0, 2*TS*TS);
+ for (row=top+2; row < top+TS-2 && row < height-4; row++) {
+ tr = row-top;
+ for (col=left+2; col < left+TS-2 && col < width-4; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++) {
+ lix = &lab[d][tr][tc];
+ for (i=0; i < 4; i++) {
+ ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]);
+ abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1])
+ + SQR(lix[0][2]-lix[dir[i]][2]);
+ }
+ }
+ leps = MIN(MAX(ldiff[0][0],ldiff[0][1]),
+ MAX(ldiff[1][2],ldiff[1][3]));
+ abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]),
+ MAX(abdiff[1][2],abdiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
+ homo[d][tr][tc]++;
+ }
+ }
+/* Combine the most homogenous pixels for the final result: */
+ for (row=top+3; row < top+TS-3 && row < height-5; row++) {
+ tr = row-top;
+ for (col=left+3; col < left+TS-3 && col < width-5; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (hm[d]=0, i=tr-1; i <= tr+1; i++)
+ for (j=tc-1; j <= tc+1; j++)
+ hm[d] += homo[d][i][j];
+ if (hm[0] != hm[1])
+ FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c];
+ else
+ FORC3 image[row*width+col][c] =
+ (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1;
+ }
+ }
+ }
+ }
+ free (buffer);
+}
+#else
+void CLASS ahd_interpolate()
+{
+ int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2];
+ ushort (*pix)[4], (*rix)[3];
+ static const int dir[4] = { -1, 1, -TS, TS };
+ unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
+ float r, cbrt[0x10000], xyz[3], xyz_cam[3][4];
+ ushort (*rgb)[TS][TS][3];
+ short (*lab)[TS][TS][3], (*lix)[3];
+ char (*homo)[TS][TS], *buffer;
+
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("AHD interpolation...\n"));
+#endif
+
+ for (i=0; i < 0x10000; i++) {
+ r = i / 65535.0;
+ cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0;
+ }
+ for (i=0; i < 3; i++)
+ for (j=0; j < colors; j++)
+ for (xyz_cam[i][j] = k=0; k < 3; k++)
+ xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i];
+
+ border_interpolate(5);
+
+#ifdef LIBRAW_LIBRARY_BUILD
+#pragma omp parallel private(buffer,rgb,lab,homo,top,left,row,c,col,pix,val,d,rix,xyz,lix,tc,tr,ldiff,abdiff,leps,abeps,hm,i,j) firstprivate(cbrt) shared(xyz_cam)
+#endif
+ {
+ buffer = (char *) malloc (26*TS*TS); /* 1664 kB */
+ merror (buffer, "ahd_interpolate()");
+ rgb = (ushort(*)[TS][TS][3]) buffer;
+ lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS);
+ homo = (char (*)[TS][TS]) (buffer + 24*TS*TS);
+
+#pragma omp for schedule(dynamic)
+ for (top=2; top < height-5; top += TS-6){
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,(top-2)/(TS-6)+1,(height-7)/(TS-6)+1);
+#endif
+ for (left=2; left < width-5; left += TS-6) {
+
+ /* Interpolate green horizontally and vertically: */
+ for (row = top; row < top+TS && row < height-2; row++) {
+ col = left + (FC(row,left) & 1);
+ for (c = FC(row,col); col < left+TS && col < width-2; col+=2) {
+ pix = image + row*width+col;
+ val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2
+ - pix[-2][c] - pix[2][c]) >> 2;
+ rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]);
+ val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2
+ - pix[-2*width][c] - pix[2*width][c]) >> 2;
+ rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]);
+ }
+ }
+ /* Interpolate red and blue, and convert to CIELab: */
+ for (d=0; d < 2; d++)
+ for (row=top+1; row < top+TS-1 && row < height-3; row++)
+ for (col=left+1; col < left+TS-1 && col < width-3; col++) {
+ pix = image + row*width+col;
+ rix = &rgb[d][row-top][col-left];
+ lix = &lab[d][row-top][col-left];
+ if ((c = 2 - FC(row,col)) == 1) {
+ c = FC(row+1,col);
+ val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c]
+ - rix[-1][1] - rix[1][1] ) >> 1);
+ rix[0][2-c] = CLIP(val);
+ val = pix[0][1] + (( pix[-width][c] + pix[width][c]
+ - rix[-TS][1] - rix[TS][1] ) >> 1);
+ } else
+ val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c]
+ + pix[+width-1][c] + pix[+width+1][c]
+ - rix[-TS-1][1] - rix[-TS+1][1]
+ - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2);
+ rix[0][c] = CLIP(val);
+ c = FC(row,col);
+ rix[0][c] = pix[0][c];
+ xyz[0] = xyz[1] = xyz[2] = 0.5;
+ FORCC {
+ xyz[0] += xyz_cam[0][c] * rix[0][c];
+ xyz[1] += xyz_cam[1][c] * rix[0][c];
+ xyz[2] += xyz_cam[2][c] * rix[0][c];
+ }
+ xyz[0] = cbrt[CLIP((int) xyz[0])];
+ xyz[1] = cbrt[CLIP((int) xyz[1])];
+ xyz[2] = cbrt[CLIP((int) xyz[2])];
+ lix[0][0] = 64 * (116 * xyz[1] - 16);
+ lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]);
+ lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]);
+ }
+ /* Build homogeneity maps from the CIELab images: */
+ memset (homo, 0, 2*TS*TS);
+ for (row=top+2; row < top+TS-2 && row < height-4; row++) {
+ tr = row-top;
+ for (col=left+2; col < left+TS-2 && col < width-4; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++) {
+ lix = &lab[d][tr][tc];
+ for (i=0; i < 4; i++) {
+ ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]);
+ abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1])
+ + SQR(lix[0][2]-lix[dir[i]][2]);
+ }
+ }
+ leps = MIN(MAX(ldiff[0][0],ldiff[0][1]),
+ MAX(ldiff[1][2],ldiff[1][3]));
+ abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]),
+ MAX(abdiff[1][2],abdiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
+ homo[d][tr][tc]++;
+ }
+ }
+ /* Combine the most homogenous pixels for the final result: */
+ for (row=top+3; row < top+TS-3 && row < height-5; row++) {
+ tr = row-top;
+ for (col=left+3; col < left+TS-3 && col < width-5; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (hm[d]=0, i=tr-1; i <= tr+1; i++)
+ for (j=tc-1; j <= tc+1; j++)
+ hm[d] += homo[d][i][j];
+ if (hm[0] != hm[1])
+ FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c];
+ else
+ FORC3 image[row*width+col][c] =
+ (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1;
+ }
+ }
+ }
+ }
+ free (buffer);
+ }
+}
+
+#endif
+#undef TS
+
+void CLASS median_filter()
+{
+ ushort (*pix)[4];
+ int pass, c, i, j, k, med[9];
+ static const uchar opt[] = /* Optimal 9-element median search */
+ { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8,
+ 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 };
+
+ for (pass=1; pass <= med_passes; pass++) {
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_MEDIAN_FILTER,pass-1,med_passes);
+#endif
+#ifdef DCRAW_VERBOSE
+ if (verbose)
+ fprintf (stderr,_("Median filter pass %d...\n"), pass);
+#endif
+ for (c=0; c < 3; c+=2) {
+ for (pix = image; pix < image+width*height; pix++)
+ pix[0][3] = pix[0][c];
+ for (pix = image+width; pix < image+width*(height-1); pix++) {
+ if ((pix-image+1) % width < 2) continue;
+ for (k=0, i = -width; i <= width; i += width)
+ for (j = i-1; j <= i+1; j++)
+ med[k++] = pix[j][3] - pix[j][1];
+ for (i=0; i < sizeof opt; i+=2)
+ if (med[opt[i]] > med[opt[i+1]])
+ SWAP (med[opt[i]] , med[opt[i+1]]);
+ pix[0][c] = CLIP(med[4] + pix[0][1]);
+ }
+ }
+ }
+}
+
+void CLASS blend_highlights()
+{
+ int clip=INT_MAX, row, col, c, i, j;
+ static const float trans[2][4][4] =
+ { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } },
+ { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } };
+ static const float itrans[2][4][4] =
+ { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } },
+ { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } };
+ float cam[2][4], lab[2][4], sum[2], chratio;
+
+ if ((unsigned) (colors-3) > 1) return;
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("Blending highlights...\n"));
+#endif
+ FORCC if (clip > (i = 65535*pre_mul[c])) clip = i;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,0,2);
+#endif
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ FORCC if (image[row*width+col][c] > clip) break;
+ if (c == colors) continue;
+ FORCC {
+ cam[0][c] = image[row*width+col][c];
+ cam[1][c] = MIN(cam[0][c],clip);
+ }
+ for (i=0; i < 2; i++) {
+ FORCC for (lab[i][c]=j=0; j < colors; j++)
+ lab[i][c] += trans[colors-3][c][j] * cam[i][j];
+ for (sum[i]=0,c=1; c < colors; c++)
+ sum[i] += SQR(lab[i][c]);
+ }
+ chratio = sqrt(sum[1]/sum[0]);
+ for (c=1; c < colors; c++)
+ lab[0][c] *= chratio;
+ FORCC for (cam[0][c]=j=0; j < colors; j++)
+ cam[0][c] += itrans[colors-3][c][j] * lab[0][j];
+ FORCC image[row*width+col][c] = cam[0][c] / colors;
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,1,2);
+#endif
+}
+
+#define SCALE (4 >> shrink)
+void CLASS recover_highlights()
+{
+ float *map, sum, wgt, grow;
+ int hsat[4], count, spread, change, val, i;
+ unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x;
+ ushort *pixel;
+ static const signed char dir[8][2] =
+ { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} };
+
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("Rebuilding highlights...\n"));
+#endif
+
+ grow = pow (2.0, 4.0-highlight);
+ FORCC hsat[c] = 32000 * pre_mul[c];
+ for (kc=0, c=1; c < colors; c++)
+ if (pre_mul[kc] < pre_mul[c]) kc = c;
+ high = height / SCALE;
+ wide = width / SCALE;
+ map = (float *) calloc (high*wide, sizeof *map);
+ merror (map, "recover_highlights()");
+ FORCC if (c != kc) {
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,c-1,colors-1);
+#endif
+ memset (map, 0, high*wide*sizeof *map);
+ for (mrow=0; mrow < high; mrow++)
+ for (mcol=0; mcol < wide; mcol++) {
+ sum = wgt = count = 0;
+ for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++)
+ for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) {
+ pixel = image[row*width+col];
+ if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) {
+ sum += pixel[c];
+ wgt += pixel[kc];
+ count++;
+ }
+ }
+ if (count == SCALE*SCALE)
+ map[mrow*wide+mcol] = sum / wgt;
+ }
+ for (spread = 32/grow; spread--; ) {
+ for (mrow=0; mrow < high; mrow++)
+ for (mcol=0; mcol < wide; mcol++) {
+ if (map[mrow*wide+mcol]) continue;
+ sum = count = 0;
+ for (d=0; d < 8; d++) {
+ y = mrow + dir[d][0];
+ x = mcol + dir[d][1];
+ if (y < high && x < wide && map[y*wide+x] > 0) {
+ sum += (1 + (d & 1)) * map[y*wide+x];
+ count += 1 + (d & 1);
+ }
+ }
+ if (count > 3)
+ map[mrow*wide+mcol] = - (sum+grow) / (count+grow);
+ }
+ for (change=i=0; i < high*wide; i++)
+ if (map[i] < 0) {
+ map[i] = -map[i];
+ change = 1;
+ }
+ if (!change) break;
+ }
+ for (i=0; i < high*wide; i++)
+ if (map[i] == 0) map[i] = 1;
+ for (mrow=0; mrow < high; mrow++)
+ for (mcol=0; mcol < wide; mcol++) {
+ for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++)
+ for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) {
+ pixel = image[row*width+col];
+ if (pixel[c] / hsat[c] > 1) {
+ val = pixel[kc] * map[mrow*wide+mcol];
+ if (pixel[c] < val) pixel[c] = CLIP(val);
+ }
+ }
+ }
+ }
+ free (map);
+}
+#undef SCALE
+
+void CLASS tiff_get (unsigned base,
+ unsigned *tag, unsigned *type, unsigned *len, unsigned *save)
+{
+ *tag = get2();
+ *type = get2();
+ *len = get4();
+ *save = ftell(ifp) + 4;
+ if (*len * ("11124811248488"[*type < 14 ? *type:0]-'0') > 4)
+ fseek (ifp, get4()+base, SEEK_SET);
+}
+
+void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen)
+{
+ unsigned entries, tag, type, len, save;
+
+ entries = get2();
+ while (entries--) {
+ tiff_get (base, &tag, &type, &len, &save);
+ if (tag == toff) thumb_offset = get4()+base;
+ if (tag == tlen) thumb_length = get4();
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+void CLASS parse_makernote (int base, int uptag)
+{
+ static const uchar xlat[2][256] = {
+ { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d,
+ 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d,
+ 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f,
+ 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f,
+ 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1,
+ 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17,
+ 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89,
+ 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f,
+ 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b,
+ 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb,
+ 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3,
+ 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f,
+ 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35,
+ 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43,
+ 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5,
+ 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 },
+ { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c,
+ 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34,
+ 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad,
+ 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05,
+ 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee,
+ 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d,
+ 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b,
+ 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b,
+ 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc,
+ 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33,
+ 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8,
+ 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6,
+ 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c,
+ 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49,
+ 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb,
+ 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } };
+ unsigned offset=0, entries, tag, type, len, save, c;
+ unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0};
+ uchar buf97[324], ci, cj, ck;
+ short sorder=order;
+ char buf[10];
+/*
+ The MakerNote might have its own TIFF header (possibly with
+ its own byte-order!), or it might just be a table.
+ */
+ fread (buf, 1, 10, ifp);
+ if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */
+ !strncmp (buf,"VER" ,3) ||
+ !strncmp (buf,"IIII",4) ||
+ !strncmp (buf,"MMMM",4)) return;
+ if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */
+ !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */
+ order = 0x4d4d;
+ while ((i=ftell(ifp)) < data_offset && i < 16384) {
+ wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3];
+ wb[3] = get2();
+ if (wb[1] == 256 && wb[3] == 256 &&
+ wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640)
+ FORC4 cam_mul[c] = wb[c];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ goto quit;
+ }
+ if (!strcmp (buf,"Nikon")) {
+ base = ftell(ifp);
+ order = get2();
+ if (get2() != 42) goto quit;
+ offset = get4();
+ fseek (ifp, offset-8, SEEK_CUR);
+ } else if (!strcmp (buf,"OLYMPUS")) {
+ base = ftell(ifp)-10;
+ fseek (ifp, -2, SEEK_CUR);
+ order = get2(); get2();
+ } else if (!strncmp (buf,"FUJIFILM",8) ||
+ !strncmp (buf,"SONY",4) ||
+ !strcmp (buf,"Panasonic")) {
+ order = 0x4949;
+ fseek (ifp, 2, SEEK_CUR);
+ } else if (!strcmp (buf,"OLYMP") ||
+ !strcmp (buf,"LEICA") ||
+ !strcmp (buf,"Ricoh") ||
+ !strcmp (buf,"EPSON"))
+ fseek (ifp, -2, SEEK_CUR);
+ else if (!strcmp (buf,"AOC") ||
+ !strcmp (buf,"QVC"))
+ fseek (ifp, -4, SEEK_CUR);
+ else fseek (ifp, -10, SEEK_CUR);
+
+ entries = get2();
+ if (entries > 1000) return;
+ while (entries--) {
+ tiff_get (base, &tag, &type, &len, &save);
+ tag |= uptag << 16;
+ if (tag == 2 && strstr(make,"NIKON"))
+ iso_speed = (get2(),get2());
+ if (tag == 4 && len > 26 && len < 35) {
+ if ((i=(get4(),get2())) != 0x7fff && !iso_speed)
+ iso_speed = 50 * pow (2, i/32.0 - 4);
+ if ((i=(get2(),get2())) != 0x7fff && !aperture)
+ aperture = pow (2, i/64.0);
+ if ((i=get2()) != 0xffff && !shutter)
+ shutter = pow (2, (short) i/-32.0);
+ wbi = (get2(),get2());
+ shot_order = (get2(),get2());
+ }
+ if (tag == 7 && type == 2 && len > 20)
+ fgets (model2, 64, ifp);
+ if (tag == 8 && type == 4)
+ shot_order = get4();
+ if (tag == 9 && !strcmp(make,"Canon"))
+ fread (artist, 64, 1, ifp);
+ if (tag == 0xc && len == 4) {
+ cam_mul[0] = getreal(type);
+ cam_mul[2] = getreal(type);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (tag == 0x10 && type == 4)
+ unique_id = get4();
+ if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) {
+ fseek (ifp, get4()+base, SEEK_SET);
+ parse_tiff_ifd (base);
+ }
+ if (tag == 0x14 && len == 2560 && type == 7) {
+ fseek (ifp, 1248, SEEK_CUR);
+ goto get2_256;
+ }
+ if (tag == 0x15 && type == 2 && is_raw)
+ fread (model, 64, 1, ifp);
+ if (strstr(make,"PENTAX")) {
+ if (tag == 0x1b) tag = 0x1018;
+ if (tag == 0x1c) tag = 0x1017;
+ }
+ if (tag == 0x1d)
+ while ((c = fgetc(ifp)) && c != EOF)
+ serial = serial*10 + (isdigit(c) ? c - '0' : c % 10);
+ if (tag == 0x81 && type == 4) {
+ data_offset = get4();
+ fseek (ifp, data_offset + 41, SEEK_SET);
+ raw_height = get2() * 2;
+ raw_width = get2();
+ filters = 0x61616161;
+ }
+ if (tag == 0x29 && type == 1) {
+ c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0;
+ fseek (ifp, 8 + c*32, SEEK_CUR);
+ FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if ((tag == 0x81 && type == 7) ||
+ (tag == 0x100 && type == 7) ||
+ (tag == 0x280 && type == 1)) {
+ thumb_offset = ftell(ifp);
+ thumb_length = len;
+ }
+ if (tag == 0x88 && type == 4 && (thumb_offset = get4()))
+ thumb_offset += base;
+ if (tag == 0x89 && type == 4)
+ thumb_length = get4();
+ if (tag == 0x8c || tag == 0x96)
+ meta_offset = ftell(ifp);
+ if (tag == 0x97) {
+ for (i=0; i < 4; i++)
+ ver97 = ver97 * 10 + fgetc(ifp)-'0';
+ switch (ver97) {
+ case 100:
+ fseek (ifp, 68, SEEK_CUR);
+ FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 102:
+ fseek (ifp, 6, SEEK_CUR);
+ goto get2_rggb;
+ case 103:
+ fseek (ifp, 16, SEEK_CUR);
+ FORC4 cam_mul[c] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (ver97 >= 200) {
+ if (ver97 != 205) fseek (ifp, 280, SEEK_CUR);
+ fread (buf97, 324, 1, ifp);
+ }
+ }
+ if (tag == 0xa4 && type == 3) {
+ fseek (ifp, wbi*48, SEEK_CUR);
+ FORC3 cam_mul[c] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (tag == 0xa7 && (unsigned) (ver97-200) < 12 && !cam_mul[0]) {
+ ci = xlat[0][serial & 0xff];
+ cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)];
+ ck = 0x60;
+ for (i=0; i < 324; i++)
+ buf97[i] ^= (cj += ci * ck++);
+ i = "66666>666;6A"[ver97-200] - '0';
+ FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] =
+ sget2 (buf97 + (i & -2) + c*2);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (tag == 0x200 && len == 3)
+ shot_order = (get4(),get4());
+ if (tag == 0x200 && len == 4)
+ black = (get2()+get2()+get2()+get2())/4;
+ if (tag == 0x201 && len == 4)
+ goto get2_rggb;
+ if (tag == 0x220 && len == 53) {
+ fseek (ifp, 14, SEEK_CUR);
+ pentax_tree();
+ }
+ if (tag == 0x401 && len == 4) {
+ black = (get4()+get4()+get4()+get4())/4;
+ }
+ if (tag == 0xe01) { /* Nikon Capture Note */
+ type = order;
+ order = 0x4949;
+ fseek (ifp, 22, SEEK_CUR);
+ for (offset=22; offset+22 < len; offset += 22+i) {
+ tag = get4();
+ fseek (ifp, 14, SEEK_CUR);
+ i = get4()-4;
+ if (tag == 0x76a43207) flip = get2();
+ else fseek (ifp, i, SEEK_CUR);
+ }
+ order = type;
+ }
+ if (tag == 0xe80 && len == 256 && type == 7) {
+ fseek (ifp, 48, SEEK_CUR);
+ cam_mul[0] = get2() * 508 * 1.078 / 0x10000;
+ cam_mul[2] = get2() * 382 * 1.173 / 0x10000;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (tag == 0xf00 && type == 7) {
+ if (len == 614)
+ fseek (ifp, 176, SEEK_CUR);
+ else if (len == 734 || len == 1502)
+ fseek (ifp, 148, SEEK_CUR);
+ else goto next;
+ goto get2_256;
+ }
+ if ((tag == 0x1011 && len == 9) || tag == 0x20400200)
+ {
+ for (i=0; i < 3; i++)
+ FORC3 cmatrix[i][c] = ((short) get2()) / 256.0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cmatrix_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if ((tag == 0x1012 || tag == 0x20400600) && len == 4)
+ for (black = i=0; i < 4; i++)
+ black += get2() << 2;
+ if (tag == 0x1017 || tag == 0x20400100)
+ {
+ cam_mul[0] = get2() / 256.0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (tag == 0x1018 || tag == 0x20400100)
+ {
+ cam_mul[2] = get2() / 256.0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (tag == 0x2011 && len == 2) {
+get2_256:
+ order = 0x4d4d;
+ cam_mul[0] = get2() / 256.0;
+ cam_mul[2] = get2() / 256.0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if ((tag | 0x70) == 0x2070 && type == 4)
+ fseek (ifp, get4()+base, SEEK_SET);
+ if (tag == 0x2010 && type != 7)
+ load_raw = &CLASS olympus_e410_load_raw;
+ if (tag == 0x2020)
+ parse_thumb_note (base, 257, 258);
+ if (tag == 0x2040)
+ parse_makernote (base, 0x2040);
+ if (tag == 0xb028) {
+ fseek (ifp, get4(), SEEK_SET);
+ parse_thumb_note (base, 136, 137);
+ }
+ if (tag == 0x4001 && len > 500) {
+ i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126;
+ fseek (ifp, i, SEEK_CUR);
+get2_rggb:
+ FORC4 cam_mul[c ^ (c >> 1)] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ fseek (ifp, 22, SEEK_CUR);
+ FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+ }
+next:
+ fseek (ifp, save, SEEK_SET);
+ }
+quit:
+ order = sorder;
+}
+
+/*
+ Since the TIFF DateTime string has no timezone information,
+ assume that the camera's clock was set to Universal Time.
+ */
+void CLASS get_timestamp (int reversed)
+{
+ struct tm t;
+ char str[20];
+ int i;
+
+ str[19] = 0;
+ if (reversed)
+ for (i=19; i--; ) str[i] = fgetc(ifp);
+ else
+ fread (str, 19, 1, ifp);
+ memset (&t, 0, sizeof t);
+ if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon,
+ &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
+ return;
+ t.tm_year -= 1900;
+ t.tm_mon -= 1;
+ if (mktime(&t) > 0)
+ timestamp = mktime(&t);
+}
+
+void CLASS parse_exif (int base)
+{
+ unsigned kodak, entries, tag, type, len, save, c;
+ double expo;
+
+ kodak = !strncmp(make,"EASTMAN",7);
+ entries = get2();
+ while (entries--) {
+ tiff_get (base, &tag, &type, &len, &save);
+ switch (tag) {
+ case 33434: shutter = getreal(type); break;
+ case 33437: aperture = getreal(type); break;
+ case 34855: iso_speed = get2(); break;
+ case 36867:
+ case 36868: get_timestamp(0); break;
+ case 37377: if ((expo = -getreal(type)) < 128)
+ shutter = pow (2, expo); break;
+ case 37378: aperture = pow (2, getreal(type)/2); break;
+ case 37386: focal_len = getreal(type); break;
+ case 37500: parse_makernote (base, 0); break;
+ case 40962: if (kodak) raw_width = get4(); break;
+ case 40963: if (kodak) raw_height = get4(); break;
+ case 41730:
+ if (get4() == 0x20002)
+ for (exif_cfa=c=0; c < 8; c+=2)
+ exif_cfa |= fgetc(ifp) * 0x01010101 << c;
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+void CLASS parse_gps (int base)
+{
+ unsigned entries, tag, type, len, save, c;
+
+ entries = get2();
+ while (entries--) {
+ tiff_get (base, &tag, &type, &len, &save);
+ switch (tag) {
+ case 1: case 3: case 5:
+ gpsdata[29+tag/2] = getc(ifp); break;
+ case 2: case 4: case 7:
+ FORC(6) gpsdata[tag/3*6+c] = get4(); break;
+ case 6:
+ FORC(2) gpsdata[18+c] = get4(); break;
+ case 18: case 29:
+ fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp);
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+void CLASS romm_coeff (float romm_cam[3][3])
+{
+ static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */
+ { { 2.034193, -0.727420, -0.306766 },
+ { -0.228811, 1.231729, -0.002922 },
+ { -0.008565, -0.153273, 1.161839 } };
+ int i, j, k;
+
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ for (cmatrix[i][j] = k=0; k < 3; k++)
+ cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cmatrix_state = LIBRAW_COLORSTATE_CALCULATED;
+#endif
+}
+
+void CLASS parse_mos (int offset)
+{
+ char data[40];
+ int skip, from, i, c, neut[4], planes=0, frot=0;
+ static const char *mod[] =
+ { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22",
+ "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65",
+ "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7" };
+ float romm_cam[3][3];
+
+ fseek (ifp, offset, SEEK_SET);
+ while (1) {
+ if (get4() != 0x504b5453) break;
+ get4();
+ fread (data, 1, 40, ifp);
+ skip = get4();
+ from = ftell(ifp);
+ if (!strcmp(data,"JPEG_preview_data")) {
+ thumb_offset = from;
+ thumb_length = skip;
+ }
+ if (!strcmp(data,"icc_camera_profile")) {
+ profile_offset = from;
+ profile_length = skip;
+ }
+ if (!strcmp(data,"ShootObj_back_type")) {
+ fscanf (ifp, "%d", &i);
+ if ((unsigned) i < sizeof mod / sizeof (*mod))
+ strcpy (model, mod[i]);
+ }
+ if (!strcmp(data,"icc_camera_to_tone_matrix")) {
+ for (i=0; i < 9; i++)
+ romm_cam[0][i] = int_to_float(get4());
+ romm_coeff (romm_cam);
+ }
+ if (!strcmp(data,"CaptProf_color_matrix")) {
+ for (i=0; i < 9; i++)
+ fscanf (ifp, "%f", &romm_cam[0][i]);
+ romm_coeff (romm_cam);
+ }
+ if (!strcmp(data,"CaptProf_number_of_planes"))
+ fscanf (ifp, "%d", &planes);
+ if (!strcmp(data,"CaptProf_raw_data_rotation"))
+ fscanf (ifp, "%d", &flip);
+ if (!strcmp(data,"CaptProf_mosaic_pattern"))
+ FORC4 {
+ fscanf (ifp, "%d", &i);
+ if (i == 1) frot = c ^ (c >> 1);
+ }
+ if (!strcmp(data,"ImgProf_rotation_angle")) {
+ fscanf (ifp, "%d", &i);
+ flip = i - flip;
+ }
+ if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) {
+ FORC4 fscanf (ifp, "%d", neut+c);
+ FORC3 cam_mul[c] = (float) neut[0] / neut[c+1];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ parse_mos (from);
+ fseek (ifp, skip+from, SEEK_SET);
+ }
+ if (planes)
+ filters = (planes == 1) * 0x01010101 *
+ (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3];
+}
+
+void CLASS linear_table (unsigned len)
+{
+ int i;
+ if (len > 0x1000) len = 0x1000;
+ read_shorts (curve, len);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.curve_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ for (i=len; i < 0x1000; i++)
+ curve[i] = curve[i-1];
+ maximum = curve[0xfff];
+}
+
+void CLASS parse_kodak_ifd (int base)
+{
+ unsigned entries, tag, type, len, save;
+ int i, c, wbi=-2, wbtemp=6500;
+ float mul[3], num;
+
+ entries = get2();
+ if (entries > 1024) return;
+ while (entries--) {
+ tiff_get (base, &tag, &type, &len, &save);
+ if (tag == 1020) wbi = getint(type);
+ if (tag == 1021 && len == 72) { /* WB set in software */
+ fseek (ifp, 40, SEEK_CUR);
+ FORC3 cam_mul[c] = 2048.0 / get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ wbi = -2;
+ }
+ if (tag == 2118) wbtemp = getint(type);
+ if (tag == 2130 + wbi)
+ FORC3 mul[c] = getreal(type);
+ if (tag == 2140 + wbi && wbi >= 0)
+ {
+ FORC3 {
+ for (num=i=0; i < 4; i++)
+ num += getreal(type) * pow (wbtemp/100.0, i);
+ cam_mul[c] = 2048 / (num * mul[c]);
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (tag == 2317) linear_table (len);
+ if (tag == 6020) iso_speed = getint(type);
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+int CLASS parse_tiff_ifd (int base)
+{
+ unsigned entries, tag, type, len, plen=16, save;
+ int ifd, use_cm=0, cfa, i, j, c, ima_len=0;
+ char software[64], *cbuf, *cp;
+ uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256];
+ double dblack, cc[4][4], cm[4][3], cam_xyz[4][3], num;
+ double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 };
+ unsigned sony_curve[] = { 0,0,0,0,0,4095 };
+ unsigned *buf, sony_offset=0, sony_length=0, sony_key=0;
+ struct jhead jh;
+ FILE *sfp;
+
+ if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0])
+ return 1;
+ ifd = tiff_nifds++;
+ for (j=0; j < 4; j++)
+ for (i=0; i < 4; i++)
+ cc[j][i] = i == j;
+ entries = get2();
+ if (entries > 512) return 1;
+ while (entries--) {
+ tiff_get (base, &tag, &type, &len, &save);
+ switch (tag) {
+ case 17: case 18:
+ if (type == 3 && len == 1)
+ {
+ cam_mul[(tag-17)*2] = get2() / 256.0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ break;
+ case 23:
+ if (type == 3) iso_speed = get2();
+ break;
+ case 36: case 37: case 38:
+ cam_mul[tag-0x24] = get2();
+ break;
+ case 39:
+ if (len < 50 || cam_mul[0]) break;
+ fseek (ifp, 12, SEEK_CUR);
+ FORC3 cam_mul[c] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 46:
+ if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break;
+ thumb_offset = ftell(ifp) - 2;
+ thumb_length = len;
+ break;
+ case 2: case 256: /* ImageWidth */
+ tiff_ifd[ifd].t_width = getint(type);
+ break;
+ case 3: case 257: /* ImageHeight */
+ tiff_ifd[ifd].t_height = getint(type);
+ break;
+ case 258: /* BitsPerSample */
+ tiff_ifd[ifd].samples = len & 7;
+ tiff_ifd[ifd].bps = get2();
+ break;
+ case 259: /* Compression */
+ tiff_ifd[ifd].comp = get2();
+ break;
+ case 262: /* PhotometricInterpretation */
+ tiff_ifd[ifd].phint = get2();
+ break;
+ case 270: /* ImageDescription */
+ fread (desc, 512, 1, ifp);
+ break;
+ case 271: /* Make */
+ fgets (make, 64, ifp);
+ break;
+ case 272: /* Model */
+ fgets (model, 64, ifp);
+ break;
+ case 280: /* Panasonic RW2 offset */
+ if (type != 4) break;
+ load_raw = &CLASS panasonic_load_raw;
+ load_flags = 0x2008;
+ case 273: /* StripOffset */
+ case 513:
+ tiff_ifd[ifd].offset = get4()+base;
+ if (!tiff_ifd[ifd].bps) {
+ fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET);
+ if (ljpeg_start (&jh, 1)) {
+ tiff_ifd[ifd].comp = 6;
+ tiff_ifd[ifd].t_width = jh.wide << (jh.clrs == 2);
+ tiff_ifd[ifd].t_height = jh.high;
+ tiff_ifd[ifd].bps = jh.bits;
+ tiff_ifd[ifd].samples = jh.clrs;
+ }
+ }
+ break;
+ case 274: /* Orientation */
+ tiff_ifd[ifd].t_flip = "50132467"[get2() & 7]-'0';
+ break;
+ case 277: /* SamplesPerPixel */
+ tiff_ifd[ifd].samples = getint(type) & 7;
+ break;
+ case 279: /* StripByteCounts */
+ case 514:
+ tiff_ifd[ifd].bytes = get4();
+ break;
+ case 305: case 11: /* Software */
+ fgets (software, 64, ifp);
+ if (!strncmp(software,"Adobe",5) ||
+ !strncmp(software,"dcraw",5) ||
+ !strncmp(software,"UFRaw",5) ||
+ !strncmp(software,"Bibble",6) ||
+ !strncmp(software,"Nikon Scan",10) ||
+ !strcmp (software,"Digital Photo Professional"))
+ is_raw = 0;
+ break;
+ case 306: /* DateTime */
+ get_timestamp(0);
+ break;
+ case 315: /* Artist */
+ fread (artist, 64, 1, ifp);
+ break;
+ case 322: /* TileWidth */
+ tile_width = getint(type);
+ break;
+ case 323: /* TileLength */
+ tile_length = getint(type);
+ break;
+ case 324: /* TileOffsets */
+ tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4();
+ if (len == 4) {
+ load_raw = &CLASS sinar_4shot_load_raw;
+ is_raw = 5;
+ }
+ break;
+ case 330: /* SubIFDs */
+ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].t_width == 3872) {
+ load_raw = &CLASS sony_arw_load_raw;
+ data_offset = get4()+base;
+ ifd++; break;
+ }
+ while (len--) {
+ i = ftell(ifp);
+ fseek (ifp, get4()+base, SEEK_SET);
+ if (parse_tiff_ifd (base)) break;
+ fseek (ifp, i+4, SEEK_SET);
+ }
+ break;
+ case 400:
+ strcpy (make, "Sarnoff");
+ maximum = 0xfff;
+ break;
+ case 28688:
+ FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff;
+ for (i=0; i < 5; i++)
+ for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++)
+ curve[j] = curve[j-1] + (1 << i);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.curve_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 29184: sony_offset = get4(); break;
+ case 29185: sony_length = get4(); break;
+ case 29217: sony_key = get4(); break;
+ case 29264:
+ parse_minolta (ftell(ifp));
+ raw_width = 0;
+ break;
+ case 29443:
+ FORC4 cam_mul[c ^ (c < 2)] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 29459:
+ FORC4 cam_mul[c ^ (c >> 1)] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 33405: /* Model2 */
+ fgets (model2, 64, ifp);
+ break;
+ case 33422: /* CFAPattern */
+ case 64777: /* Kodak P-series */
+ if ((plen=len) > 16) plen = 16;
+ fread (cfa_pat, 1, plen, ifp);
+ for (colors=cfa=i=0; i < plen; i++) {
+ colors += !(cfa & (1 << cfa_pat[i]));
+ cfa |= 1 << cfa_pat[i];
+ }
+ if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */
+ if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */
+ goto guess_cfa_pc;
+ case 33424:
+ fseek (ifp, get4()+base, SEEK_SET);
+ parse_kodak_ifd (base);
+ break;
+ case 33434: /* ExposureTime */
+ shutter = getreal(type);
+ break;
+ case 33437: /* FNumber */
+ aperture = getreal(type);
+ break;
+ case 34306: /* Leaf white balance */
+ FORC4 cam_mul[c ^ 1] = 4096.0 / get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 34307: /* Leaf CatchLight color matrix */
+ fread (software, 1, 7, ifp);
+ if (strncmp(software,"MATRIX",6)) break;
+ colors = 4;
+ for (raw_color = i=0; i < 3; i++) {
+ FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]);
+ if (!use_camera_wb) continue;
+ num = 0;
+ FORC4 num += rgb_cam[i][c];
+ FORC4 rgb_cam[i][c] /= num;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.rgb_cam_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ break;
+ case 34310: /* Leaf metadata */
+ parse_mos (ftell(ifp));
+ case 34303:
+ strcpy (make, "Leaf");
+ break;
+ case 34665: /* EXIF tag */
+ fseek (ifp, get4()+base, SEEK_SET);
+ parse_exif (base);
+ break;
+ case 34853: /* GPSInfo tag */
+ fseek (ifp, get4()+base, SEEK_SET);
+ parse_gps (base);
+ break;
+ case 34675: /* InterColorProfile */
+ case 50831: /* AsShotICCProfile */
+ profile_offset = ftell(ifp);
+ profile_length = len;
+ break;
+ case 37122: /* CompressedBitsPerPixel */
+ kodak_cbpp = get4();
+ break;
+ case 37386: /* FocalLength */
+ focal_len = getreal(type);
+ break;
+ case 37393: /* ImageNumber */
+ shot_order = getint(type);
+ break;
+ case 37400: /* old Kodak KDC tag */
+ for (raw_color = i=0; i < 3; i++) {
+ getreal(type);
+ FORC3 rgb_cam[i][c] = getreal(type);
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.rgb_cam_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 46275: /* Imacon tags */
+ strcpy (make, "Imacon");
+ data_offset = ftell(ifp);
+ ima_len = len;
+ break;
+ case 46279:
+ if (!ima_len) break;
+ fseek (ifp, 78, SEEK_CUR);
+ raw_width = get4();
+ raw_height = get4();
+ left_margin = get4() & 7;
+ width = raw_width - left_margin - (get4() & 7);
+ top_margin = get4() & 7;
+ height = raw_height - top_margin - (get4() & 7);
+ if (raw_width == 7262) {
+ height = 5444;
+ width = 7244;
+ left_margin = 7;
+ }
+ fseek (ifp, 52, SEEK_CUR);
+ FORC3 cam_mul[c] = getreal(11);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ fseek (ifp, 114, SEEK_CUR);
+ flip = (get2() >> 7) * 90;
+ if (width * height * 6 == ima_len) {
+ if (flip % 180 == 90) SWAP(width,height);
+ filters = flip = 0;
+ }
+ sprintf (model, "Ixpress %d-Mp", height*width/1000000);
+ load_raw = &CLASS imacon_full_load_raw;
+ if (filters) {
+ if (left_margin & 1) filters = 0x61616161;
+ load_raw = &CLASS unpacked_load_raw;
+ }
+ maximum = 0xffff;
+ break;
+ case 50454: /* Sinar tag */
+ case 50455:
+ if (!(cbuf = (char *) malloc(len))) break;
+ fread (cbuf, 1, len, ifp);
+ for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n'))
+ if (!strncmp (++cp,"Neutral ",8))
+ {
+ sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ free (cbuf);
+ break;
+ case 50458:
+ if (!make[0]) strcpy (make, "Hasselblad");
+ break;
+ case 50459: /* Hasselblad tag */
+ i = order;
+ j = ftell(ifp);
+ c = tiff_nifds;
+ order = get2();
+ fseek (ifp, j+(get2(),get4()), SEEK_SET);
+ parse_tiff_ifd (j);
+ maximum = 0xffff;
+ tiff_nifds = c;
+ order = i;
+ break;
+ case 50706: /* DNGVersion */
+ FORC4 dng_version = (dng_version << 8) + fgetc(ifp);
+ if (!make[0]) strcpy (make, "DNG");
+ is_raw = 1;
+ break;
+ case 50710: /* CFAPlaneColor */
+ if (len > 4) len = 4;
+ colors = len;
+ fread (cfa_pc, 1, colors, ifp);
+guess_cfa_pc:
+ FORCC tab[cfa_pc[c]] = c;
+ cdesc[c] = 0;
+ for (i=16; i--; )
+ filters = filters << 2 | tab[cfa_pat[i % plen]];
+ break;
+ case 50711: /* CFALayout */
+ if (get2() == 2) {
+ fuji_width = 1;
+ filters = 0x49494949;
+ }
+ break;
+ case 291:
+ case 50712: /* LinearizationTable */
+ linear_table (len);
+ break;
+ case 50714: /* BlackLevel */
+ case 50715: /* BlackLevelDeltaH */
+ case 50716: /* BlackLevelDeltaV */
+ for (dblack=i=0; i < len; i++)
+ dblack += getreal(type);
+ black += dblack/len + 0.5;
+ break;
+ case 50717: /* WhiteLevel */
+ maximum = getint(type);
+ break;
+ case 50718: /* DefaultScale */
+ pixel_aspect = getreal(type);
+ pixel_aspect /= getreal(type);
+ break;
+ case 50721: /* ColorMatrix1 */
+ case 50722: /* ColorMatrix2 */
+ FORCC for (j=0; j < 3; j++)
+ cm[c][j] = getreal(type);
+ use_cm = 1;
+ break;
+ case 50723: /* CameraCalibration1 */
+ case 50724: /* CameraCalibration2 */
+ for (i=0; i < colors; i++)
+ FORCC cc[i][c] = getreal(type);
+ case 50727: /* AnalogBalance */
+ FORCC ab[c] = getreal(type);
+ break;
+ case 50728: /* AsShotNeutral */
+ FORCC asn[c] = getreal(type);
+ break;
+ case 50729: /* AsShotWhiteXY */
+ xyz[0] = getreal(type);
+ xyz[1] = getreal(type);
+ xyz[2] = 1 - xyz[0] - xyz[1];
+ FORC3 xyz[c] /= d65_white[c];
+ break;
+ case 50740: /* DNGPrivateData */
+ if (dng_version) break;
+ parse_minolta (j = get4()+base);
+ fseek (ifp, j, SEEK_SET);
+ parse_tiff_ifd (base);
+ break;
+ case 50752:
+ read_shorts (cr2_slice, 3);
+ break;
+ case 50829: /* ActiveArea */
+ top_margin = getint(type);
+ left_margin = getint(type);
+ height = getint(type) - top_margin;
+ width = getint(type) - left_margin;
+ break;
+ case 64772: /* Kodak P-series */
+ fseek (ifp, 16, SEEK_CUR);
+ data_offset = get4();
+ fseek (ifp, 28, SEEK_CUR);
+ data_offset += get4();
+ load_raw = &CLASS packed_12_load_raw;
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ if (sony_length && (buf = (unsigned *) malloc(sony_length))) {
+ fseek (ifp, sony_offset, SEEK_SET);
+ fread (buf, sony_length, 1, ifp);
+ sony_decrypt (buf, sony_length/4, 1, sony_key);
+#ifndef LIBRAW_LIBRARY_BUILD
+ sfp = ifp;
+ if ((ifp = tmpfile())) {
+ fwrite (buf, sony_length, 1, ifp);
+ fseek (ifp, 0, SEEK_SET);
+ parse_tiff_ifd (-sony_offset);
+ fclose (ifp);
+ }
+ ifp = sfp;
+#else
+ if( !ifp->tempbuffer_open(buf,sony_length))
+ {
+ parse_tiff_ifd(-sony_offset);
+ ifp->tempbuffer_close();
+ }
+#endif
+ free (buf);
+ }
+ for (i=0; i < colors; i++)
+ FORCC cc[i][c] *= ab[i];
+ if (use_cm) {
+ FORCC for (i=0; i < 3; i++)
+ for (cam_xyz[c][i]=j=0; j < colors; j++)
+ cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i];
+ cam_xyz_coeff (cam_xyz);
+ }
+ if (asn[0]) {
+ cam_mul[3] = 0;
+ FORCC cam_mul[c] = 1 / asn[c];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (!use_cm)
+ {
+ FORCC pre_mul[c] /= cc[c][c];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+
+ return 0;
+}
+
+void CLASS parse_tiff (int base)
+{
+ int doff, max_samp=0, raw=-1, thm=-1, i;
+ struct jhead jh;
+
+ fseek (ifp, base, SEEK_SET);
+ order = get2();
+ if (order != 0x4949 && order != 0x4d4d) return;
+ get2();
+ memset (tiff_ifd, 0, sizeof tiff_ifd);
+ tiff_nifds = 0;
+ while ((doff = get4())) {
+ fseek (ifp, doff+base, SEEK_SET);
+ if (parse_tiff_ifd (base)) break;
+ }
+ thumb_misc = 16;
+ if (thumb_offset) {
+ fseek (ifp, thumb_offset, SEEK_SET);
+ if (ljpeg_start (&jh, 1)) {
+ thumb_misc = jh.bits;
+ thumb_width = jh.wide;
+ thumb_height = jh.high;
+ }
+ }
+ for (i=0; i < tiff_nifds; i++) {
+ if (max_samp < tiff_ifd[i].samples)
+ max_samp = tiff_ifd[i].samples;
+ if (max_samp > 3) max_samp = 3;
+ if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) &&
+ tiff_ifd[i].t_width*tiff_ifd[i].t_height > raw_width*raw_height) {
+ raw_width = tiff_ifd[i].t_width;
+ raw_height = tiff_ifd[i].t_height;
+ tiff_bps = tiff_ifd[i].bps;
+ tiff_compress = tiff_ifd[i].comp;
+ data_offset = tiff_ifd[i].offset;
+ tiff_flip = tiff_ifd[i].t_flip;
+ tiff_samples = tiff_ifd[i].samples;
+ raw = i;
+ }
+ }
+ fuji_width *= (raw_width+1)/2;
+ if (tiff_ifd[0].t_flip) tiff_flip = tiff_ifd[0].t_flip;
+ if (raw >= 0 && !load_raw)
+ switch (tiff_compress) {
+ case 0: case 1:
+ switch (tiff_bps) {
+ case 8: load_raw = &CLASS eight_bit_load_raw; break;
+ case 12: load_raw = &CLASS packed_12_load_raw;
+ if (tiff_ifd[raw].phint == 2)
+ load_flags = 6;
+ if (strncmp(make,"PENTAX",6)) break;
+ case 14:
+ case 16: load_raw = &CLASS unpacked_load_raw; break;
+ }
+ if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8)
+ load_raw = &CLASS olympus_e300_load_raw;
+ break;
+ case 6: case 7: case 99:
+ load_raw = &CLASS lossless_jpeg_load_raw; break;
+ case 262:
+ load_raw = &CLASS kodak_262_load_raw; break;
+ case 32767:
+ load_raw = &CLASS sony_arw2_load_raw;
+ if (tiff_ifd[raw].bytes*8 == raw_width*raw_height*tiff_bps)
+ break;
+ raw_height += 8;
+ load_raw = &CLASS sony_arw_load_raw; break;
+ case 32769:
+ load_flags = 8;
+ case 32773:
+ load_raw = &CLASS packed_12_load_raw; break;
+ case 34713:
+ load_raw = &CLASS nikon_compressed_load_raw; break;
+ case 65535:
+ load_raw = &CLASS pentax_k10_load_raw; break;
+ case 65000:
+ switch (tiff_ifd[raw].phint) {
+ case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break;
+ case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break;
+ case 32803: load_raw = &CLASS kodak_65000_load_raw;
+ }
+ case 32867: break;
+ default: is_raw = 0;
+ }
+ if (!dng_version && tiff_samples == 3)
+ if (tiff_ifd[raw].bytes && tiff_bps != 14 && tiff_bps != 2048)
+ is_raw = 0;
+ if (!dng_version && tiff_bps == 8 && tiff_compress == 1 &&
+ tiff_ifd[raw].phint == 1) is_raw = 0;
+ if (tiff_bps == 8 && tiff_samples == 4) is_raw = 0;
+ for (i=0; i < tiff_nifds; i++)
+ if (i != raw && tiff_ifd[i].samples == max_samp &&
+ tiff_ifd[i].t_width * tiff_ifd[i].t_height / SQR(tiff_ifd[i].bps+1) >
+ thumb_width * thumb_height / SQR(thumb_misc+1)) {
+ thumb_width = tiff_ifd[i].t_width;
+ thumb_height = tiff_ifd[i].t_height;
+ thumb_offset = tiff_ifd[i].offset;
+ thumb_length = tiff_ifd[i].bytes;
+ thumb_misc = tiff_ifd[i].bps;
+ thm = i;
+ }
+ if (thm >= 0) {
+ thumb_misc |= tiff_ifd[thm].samples << 5;
+ switch (tiff_ifd[thm].comp) {
+ case 0:
+ write_thumb = &CLASS layer_thumb;
+ break;
+ case 1:
+ if (tiff_ifd[thm].bps > 8)
+ thumb_load_raw = &CLASS kodak_thumb_load_raw;
+ else
+ write_thumb = &CLASS ppm_thumb;
+ break;
+ case 65000:
+ thumb_load_raw = tiff_ifd[thm].phint == 6 ?
+ &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw;
+ }
+ }
+}
+
+void CLASS parse_minolta (int base)
+{
+ int save, tag, len, offset, high=0, wide=0, i, c;
+ short sorder=order;
+
+ fseek (ifp, base, SEEK_SET);
+ if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return;
+ order = fgetc(ifp) * 0x101;
+ offset = base + get4() + 8;
+ while ((save=ftell(ifp)) < offset) {
+ for (tag=i=0; i < 4; i++)
+ tag = tag << 8 | fgetc(ifp);
+ len = get4();
+ switch (tag) {
+ case 0x505244: /* PRD */
+ fseek (ifp, 8, SEEK_CUR);
+ high = get2();
+ wide = get2();
+ break;
+ case 0x574247: /* WBG */
+ get4();
+ i = strcmp(model,"DiMAGE A200") ? 0:3;
+ FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 0x545457: /* TTW */
+ parse_tiff (ftell(ifp));
+ data_offset = offset;
+ }
+ fseek (ifp, save+len+8, SEEK_SET);
+ }
+ raw_height = high;
+ raw_width = wide;
+ order = sorder;
+}
+
+/*
+ Many cameras have a "debug mode" that writes JPEG and raw
+ at the same time. The raw file has no header, so try to
+ to open the matching JPEG file and read its metadata.
+ */
+void CLASS parse_external_jpeg()
+{
+ char *file, *ext, *jname, *jfile, *jext;
+#ifndef LIBRAW_LIBRARY_BUILD
+ FILE *save=ifp;
+#else
+ if(!ifp->fname())
+ {
+ imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ;
+ return;
+ }
+#endif
+
+ ext = strrchr (ifname, '.');
+ file = strrchr (ifname, '/');
+ if (!file) file = strrchr (ifname, '\\');
+#ifndef LIBRAW_LIBRARY_BUILD
+ if (!file) file = ifname-1;
+#else
+ if (!file) file = (char*)ifname-1;
+#endif
+ file++;
+ if (!ext || strlen(ext) != 4 || ext-file != 8) return;
+ jname = (char *) malloc (strlen(ifname) + 1);
+ merror (jname, "parse_external_jpeg()");
+ strcpy (jname, ifname);
+ jfile = file - ifname + jname;
+ jext = ext - ifname + jname;
+ if (strcasecmp (ext, ".jpg")) {
+ strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg");
+ if (isdigit(*file)) {
+ memcpy (jfile, file+4, 4);
+ memcpy (jfile+4, file, 4);
+ }
+ } else
+ while (isdigit(*--jext)) {
+ if (*jext != '9') {
+ (*jext)++;
+ break;
+ }
+ *jext = '0';
+ }
+#ifndef LIBRAW_LIBRARY_BUILD
+ if (strcmp (jname, ifname)) {
+ if ((ifp = fopen (jname, "rb"))) {
+#ifdef DCRAW_VERBOSE
+ if (verbose)
+ fprintf (stderr,_("Reading metadata from %s ...\n"), jname);
+#endif
+ parse_tiff (12);
+ thumb_offset = 0;
+ is_raw = 1;
+ fclose (ifp);
+ }
+ }
+#else
+ if (strcmp (jname, ifname))
+ {
+ if(!ifp->subfile_open(jname))
+ {
+ parse_tiff (12);
+ thumb_offset = 0;
+ is_raw = 1;
+ ifp->subfile_close();
+ }
+ else
+ imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ;
+ }
+#endif
+ if (!timestamp)
+ {
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ;
+#endif
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("Failed to read metadata from %s\n"), jname);
+#endif
+ }
+ free (jname);
+#ifndef LIBRAW_LIBRARY_BUILD
+ ifp = save;
+#endif
+}
+
+/*
+ CIFF block 0x1030 contains an 8x8 white sample.
+ Load this into white[][] for use in scale_colors().
+ */
+void CLASS ciff_block_1030()
+{
+ static const ushort key[] = { 0x410, 0x45f3 };
+ int i, bpp, row, col, vbits=0;
+ unsigned long bitbuf=0;
+
+ if ((get2(),get4()) != 0x80008 || !get4()) return;
+ bpp = get2();
+ if (bpp != 10 && bpp != 12) return;
+ for (i=row=0; row < 8; row++)
+ for (col=0; col < 8; col++) {
+ if (vbits < bpp) {
+ bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]);
+ vbits += 16;
+ }
+ white[row][col] =
+ bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp);
+ vbits -= bpp;
+ }
+}
+
+/*
+ Parse a CIFF file, better known as Canon CRW format.
+ */
+void CLASS parse_ciff (int offset, int length)
+{
+ int tboff, nrecs, c, type, len, save, wbi=-1;
+ ushort key[] = { 0x410, 0x45f3 };
+
+ fseek (ifp, offset+length-4, SEEK_SET);
+ tboff = get4() + offset;
+ fseek (ifp, tboff, SEEK_SET);
+ nrecs = get2();
+ if (nrecs > 100) return;
+ while (nrecs--) {
+ type = get2();
+ len = get4();
+ save = ftell(ifp) + 4;
+ fseek (ifp, offset+get4(), SEEK_SET);
+ if ((((type >> 8) + 8) | 8) == 0x38)
+ parse_ciff (ftell(ifp), len); /* Parse a sub-table */
+
+ if (type == 0x0810)
+ fread (artist, 64, 1, ifp);
+ if (type == 0x080a) {
+ fread (make, 64, 1, ifp);
+ fseek (ifp, strlen(make) - 63, SEEK_CUR);
+ fread (model, 64, 1, ifp);
+ }
+ if (type == 0x1810) {
+ fseek (ifp, 12, SEEK_CUR);
+ flip = get4();
+ }
+ if (type == 0x1835) /* Get the decoder table */
+ tiff_compress = get4();
+ if (type == 0x2007) {
+ thumb_offset = ftell(ifp);
+ thumb_length = len;
+ }
+ if (type == 0x1818) {
+ shutter = pow (2.0f, -int_to_float((get4(),get4())));
+ aperture = pow (2.0f, int_to_float(get4())/2);
+ }
+ if (type == 0x102a) {
+ iso_speed = pow (2, (get4(),get2())/32.0 - 4) * 50;
+ aperture = pow (2, (get2(),(short)get2())/64.0);
+ shutter = pow (2,-((short)get2())/32.0);
+ wbi = (get2(),get2());
+ if (wbi > 17) wbi = 0;
+ fseek (ifp, 32, SEEK_CUR);
+ if (shutter > 1e6) shutter = get2()/10.0;
+ }
+ if (type == 0x102c) {
+ if (get2() > 512) { /* Pro90, G1 */
+ fseek (ifp, 118, SEEK_CUR);
+ FORC4 cam_mul[c ^ 2] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ } else { /* G2, S30, S40 */
+ fseek (ifp, 98, SEEK_CUR);
+ FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ }
+ if (type == 0x0032) {
+ if (len == 768) { /* EOS D30 */
+ fseek (ifp, 72, SEEK_CUR);
+ FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ if (!wbi) cam_mul[0] = -1; /* use my auto white balance */
+ } else if (!cam_mul[0]) {
+ if (get2() == key[0]) /* Pro1, G6, S60, S70 */
+ c = (strstr(model,"Pro1") ?
+ "012346000000000000":"01345:000000006008")[wbi]-'0'+ 2;
+ else { /* G3, G5, S45, S50 */
+ c = "023457000000006000"[wbi]-'0';
+ key[0] = key[1] = 0;
+ }
+ fseek (ifp, 78 + c*8, SEEK_CUR);
+ FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ if (!wbi) cam_mul[0] = -1;
+ }
+ }
+ if (type == 0x10a9) { /* D60, 10D, 300D, and clones */
+ if (len > 66) wbi = "0134567028"[wbi]-'0';
+ fseek (ifp, 2 + wbi*8, SEEK_CUR);
+ FORC4 cam_mul[c ^ (c >> 1)] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ if (type == 0x1030 && (0x18040 >> wbi & 1))
+ ciff_block_1030(); /* all that don't have 0x10a9 */
+ if (type == 0x1031) {
+ raw_width = (get2(),get2());
+ raw_height = get2();
+ }
+ if (type == 0x5029) {
+ focal_len = len >> 16;
+ if ((len & 0xffff) == 2) focal_len /= 32;
+ }
+ if (type == 0x5813) flash_used = int_to_float(len);
+ if (type == 0x5814) canon_ev = int_to_float(len);
+ if (type == 0x5817) shot_order = len;
+ if (type == 0x5834) unique_id = len;
+ if (type == 0x580e) timestamp = len;
+ if (type == 0x180e) timestamp = get4();
+#ifdef LOCALTIME
+ if ((type | 0x4000) == 0x580e)
+ timestamp = mktime (gmtime (&timestamp));
+#endif
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+void CLASS parse_rollei()
+{
+ char line[128], *val;
+ struct tm t;
+
+ fseek (ifp, 0, SEEK_SET);
+ memset (&t, 0, sizeof t);
+ do {
+ fgets (line, 128, ifp);
+ if ((val = strchr(line,'=')))
+ *val++ = 0;
+ else
+ val = line + strlen(line);
+ if (!strcmp(line,"DAT"))
+ sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year);
+ if (!strcmp(line,"TIM"))
+ sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
+ if (!strcmp(line,"HDR"))
+ thumb_offset = atoi(val);
+ if (!strcmp(line,"X "))
+ raw_width = atoi(val);
+ if (!strcmp(line,"Y "))
+ raw_height = atoi(val);
+ if (!strcmp(line,"TX "))
+ thumb_width = atoi(val);
+ if (!strcmp(line,"TY "))
+ thumb_height = atoi(val);
+ } while (strncmp(line,"EOHD",4));
+ data_offset = thumb_offset + thumb_width * thumb_height * 2;
+ t.tm_year -= 1900;
+ t.tm_mon -= 1;
+ if (mktime(&t) > 0)
+ timestamp = mktime(&t);
+ strcpy (make, "Rollei");
+ strcpy (model,"d530flex");
+ write_thumb = &CLASS rollei_thumb;
+}
+
+void CLASS parse_sinar_ia()
+{
+ int entries, off;
+ char str[8], *cp;
+
+ order = 0x4949;
+ fseek (ifp, 4, SEEK_SET);
+ entries = get4();
+ fseek (ifp, get4(), SEEK_SET);
+ while (entries--) {
+ off = get4(); get4();
+ fread (str, 8, 1, ifp);
+ if (!strcmp(str,"META")) meta_offset = off;
+ if (!strcmp(str,"THUMB")) thumb_offset = off;
+ if (!strcmp(str,"RAW0")) data_offset = off;
+ }
+ fseek (ifp, meta_offset+20, SEEK_SET);
+ fread (make, 64, 1, ifp);
+ make[63] = 0;
+ if ((cp = strchr(make,' '))) {
+ strcpy (model, cp+1);
+ *cp = 0;
+ }
+ raw_width = get2();
+ raw_height = get2();
+ load_raw = &CLASS unpacked_load_raw;
+ thumb_width = (get4(),get2());
+ thumb_height = get2();
+ write_thumb = &CLASS ppm_thumb;
+ maximum = 0x3fff;
+}
+
+void CLASS parse_phase_one (int base)
+{
+ unsigned entries, tag, type, len, data, save, i, c;
+ float romm_cam[3][3];
+ char *cp;
+
+ memset (&ph1, 0, sizeof ph1);
+ fseek (ifp, base, SEEK_SET);
+ order = get4() & 0xffff;
+ if (get4() >> 8 != 0x526177) return; /* "Raw" */
+ fseek (ifp, get4()+base, SEEK_SET);
+ entries = get4();
+ get4();
+ while (entries--) {
+ tag = get4();
+ type = get4();
+ len = get4();
+ data = get4();
+ save = ftell(ifp);
+ fseek (ifp, base+data, SEEK_SET);
+ switch (tag) {
+ case 0x100: flip = "0653"[data & 3]-'0'; break;
+ case 0x106:
+ for (i=0; i < 9; i++)
+ romm_cam[0][i] = getreal(11);
+ romm_coeff (romm_cam);
+ break;
+ case 0x107:
+ FORC3 cam_mul[c] = getreal(11);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ break;
+ case 0x108: raw_width = data; break;
+ case 0x109: raw_height = data; break;
+ case 0x10a: left_margin = data; break;
+ case 0x10b: top_margin = data; break;
+ case 0x10c: width = data; break;
+ case 0x10d: height = data; break;
+ case 0x10e: ph1.format = data; break;
+ case 0x10f: data_offset = data+base; break;
+ case 0x110: meta_offset = data+base;
+ meta_length = len; break;
+ case 0x112: ph1.key_off = save - 4; break;
+ case 0x210: ph1.tag_210 = int_to_float(data); break;
+ case 0x21a: ph1.tag_21a = data; break;
+ case 0x21c: strip_offset = data+base; break;
+ case 0x21d: ph1.t_black = data; break;
+ case 0x222: ph1.split_col = data - left_margin; break;
+ case 0x223: ph1.black_off = data+base; break;
+ case 0x301:
+ model[63] = 0;
+ fread (model, 1, 63, ifp);
+ if ((cp = strstr(model," camera"))) *cp = 0;
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ load_raw = ph1.format < 3 ?
+ &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c;
+ maximum = 0xffff;
+ strcpy (make, "Phase One");
+ if (model[0]) return;
+ switch (raw_height) {
+ case 2060: strcpy (model,"LightPhase"); break;
+ case 2682: strcpy (model,"H 10"); break;
+ case 4128: strcpy (model,"H 20"); break;
+ case 5488: strcpy (model,"H 25"); break;
+ }
+}
+
+void CLASS parse_fuji (int offset)
+{
+ unsigned entries, tag, len, save, c;
+
+ fseek (ifp, offset, SEEK_SET);
+ entries = get4();
+ if (entries > 255) return;
+ while (entries--) {
+ tag = get2();
+ len = get2();
+ save = ftell(ifp);
+ if (tag == 0x100) {
+ raw_height = get2();
+ raw_width = get2();
+ } else if (tag == 0x121) {
+ height = get2();
+ if ((width = get2()) == 4284) width += 3;
+ } else if (tag == 0x130)
+ fuji_layout = fgetc(ifp) >> 7;
+ if (tag == 0x2ff0)
+ {
+ FORC4 cam_mul[c ^ 1] = get2();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ }
+ fseek (ifp, save+len, SEEK_SET);
+ }
+ height <<= fuji_layout;
+ width >>= fuji_layout;
+}
+
+int CLASS parse_jpeg (int offset)
+{
+ int len, save, hlen, mark;
+
+ fseek (ifp, offset, SEEK_SET);
+ if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0;
+
+ while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) {
+ order = 0x4d4d;
+ len = get2() - 2;
+ save = ftell(ifp);
+ if (mark == 0xc0 || mark == 0xc3) {
+ fgetc(ifp);
+ raw_height = get2();
+ raw_width = get2();
+ }
+ order = get2();
+ hlen = get4();
+ if (get4() == 0x48454150) /* "HEAP" */
+ parse_ciff (save+hlen, len-hlen);
+ parse_tiff (save+6);
+ fseek (ifp, save+len, SEEK_SET);
+ }
+ return 1;
+}
+
+void CLASS parse_riff()
+{
+ unsigned i, size, end;
+ char tag[4], date[64], month[64];
+ static const char mon[12][4] =
+ { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
+ struct tm t;
+
+ order = 0x4949;
+ fread (tag, 4, 1, ifp);
+ size = get4();
+ end = ftell(ifp) + size;
+ if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) {
+ get4();
+ while (ftell(ifp)+7 < end)
+ parse_riff();
+ } else if (!memcmp(tag,"nctg",4)) {
+ while (ftell(ifp)+7 < end) {
+ i = get2();
+ size = get2();
+ if ((i+1) >> 1 == 10 && size == 20)
+ get_timestamp(0);
+ else fseek (ifp, size, SEEK_CUR);
+ }
+ } else if (!memcmp(tag,"IDIT",4) && size < 64) {
+ fread (date, 64, 1, ifp);
+ date[size] = 0;
+ memset (&t, 0, sizeof t);
+ if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday,
+ &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) {
+ for (i=0; i < 12 && strcasecmp(mon[i],month); i++);
+ t.tm_mon = i;
+ t.tm_year -= 1900;
+ if (mktime(&t) > 0)
+ timestamp = mktime(&t);
+ }
+ } else
+ fseek (ifp, size, SEEK_CUR);
+}
+
+void CLASS parse_smal (int offset, int fsize)
+{
+ int ver;
+
+ fseek (ifp, offset+2, SEEK_SET);
+ order = 0x4949;
+ ver = fgetc(ifp);
+ if (ver == 6)
+ fseek (ifp, 5, SEEK_CUR);
+ if (get4() != fsize) return;
+ if (ver > 6) data_offset = get4();
+ raw_height = height = get2();
+ raw_width = width = get2();
+ strcpy (make, "SMaL");
+ sprintf (model, "v%d %dx%d", ver, width, height);
+ if (ver == 6) load_raw = &CLASS smal_v6_load_raw;
+ if (ver == 9) load_raw = &CLASS smal_v9_load_raw;
+}
+
+void CLASS parse_cine()
+{
+ unsigned off_head, off_setup, off_image, i;
+
+ order = 0x4949;
+ fseek (ifp, 4, SEEK_SET);
+ is_raw = get2() == 2;
+ fseek (ifp, 14, SEEK_CUR);
+ is_raw *= get4();
+ off_head = get4();
+ off_setup = get4();
+ off_image = get4();
+ timestamp = get4();
+ if ((i = get4())) timestamp = i;
+ fseek (ifp, off_head+4, SEEK_SET);
+ raw_width = get4();
+ raw_height = get4();
+ switch (get2(),get2()) {
+ case 8: load_raw = &CLASS eight_bit_load_raw; break;
+ case 16: load_raw = &CLASS unpacked_load_raw;
+ }
+ fseek (ifp, off_setup+792, SEEK_SET);
+ strcpy (make, "CINE");
+ sprintf (model, "%d", get4());
+ fseek (ifp, 12, SEEK_CUR);
+ switch ((i=get4()) & 0xffffff) {
+ case 3: filters = 0x94949494; break;
+ case 4: filters = 0x49494949; break;
+ default: is_raw = 0;
+ }
+ fseek (ifp, 72, SEEK_CUR);
+ switch ((get4()+3600) % 360) {
+ case 270: flip = 4; break;
+ case 180: flip = 1; break;
+ case 90: flip = 7; break;
+ case 0: flip = 2;
+ }
+ cam_mul[0] = getreal(11);
+ cam_mul[2] = getreal(11);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ maximum = ~(-1 << get4());
+ fseek (ifp, 668, SEEK_CUR);
+ shutter = get4()/1000000000.0;
+ fseek (ifp, off_image, SEEK_SET);
+ if (shot_select < is_raw)
+ fseek (ifp, shot_select*8, SEEK_CUR);
+ data_offset = (INT64) get4() + 8;
+ data_offset += (INT64) get4() << 32;
+}
+#ifdef LIBRAW_LIBRARY_BUILD
+void CLASS adobe_coeff (const char *p_make, const char *p_model)
+#else
+void CLASS adobe_coeff (char *p_make, char *p_model)
+#endif
+{
+ static const struct {
+ const char *prefix;
+ short t_black, t_maximum, trans[12];
+ } table[] = {
+ { "Apple QuickTake", 0, 0, /* DJC */
+ { 17576,-3191,-3318,5210,6733,-1942,9031,1280,-124 } },
+ { "Canon EOS D2000", 0, 0,
+ { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+ { "Canon EOS D6000", 0, 0,
+ { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
+ { "Canon EOS D30", 0, 0,
+ { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
+ { "Canon EOS D60", 0, 0xfa0,
+ { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
+ { "Canon EOS 5D Mark II", 0, 0x3cf0,
+ { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } },
+ { "Canon EOS 5D", 0, 0xe6c,
+ { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } },
+ { "Canon EOS 10D", 0, 0xfa0,
+ { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+ { "Canon EOS 20Da", 0, 0,
+ { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } },
+ { "Canon EOS 20D", 0, 0xfff,
+ { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } },
+ { "Canon EOS 30D", 0, 0,
+ { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } },
+ { "Canon EOS 40D", 0, 0x3f60,
+ { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } },
+ { "Canon EOS 50D", 0, 0x3d93,
+ { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } },
+ { "Canon EOS 300D", 0, 0xfa0,
+ { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+ { "Canon EOS 350D", 0, 0xfff,
+ { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } },
+ { "Canon EOS 400D", 0, 0xe8e,
+ { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } },
+ { "Canon EOS 450D", 0, 0x390d,
+ { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } },
+ { "Canon EOS 1000D", 0, 0xe43,
+ { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } },
+ { "Canon EOS-1Ds Mark III", 0, 0x3bb0,
+ { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } },
+ { "Canon EOS-1Ds Mark II", 0, 0xe80,
+ { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } },
+ { "Canon EOS-1D Mark II N", 0, 0xe80,
+ { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } },
+ { "Canon EOS-1D Mark III", 0, 0x3bb0,
+ { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } },
+ { "Canon EOS-1D Mark II", 0, 0xe80,
+ { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } },
+ { "Canon EOS-1DS", 0, 0xe20,
+ { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } },
+ { "Canon EOS-1D", 0, 0xe20,
+ { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } },
+ { "Canon EOS", 0, 0,
+ { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+ { "Canon PowerShot A50", 0, 0,
+ { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } },
+ { "Canon PowerShot A5", 0, 0,
+ { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } },
+ { "Canon PowerShot G10", 0, 0,
+ { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } },
+ { "Canon PowerShot G1", 0, 0,
+ { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } },
+ { "Canon PowerShot G2", 0, 0,
+ { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
+ { "Canon PowerShot G3", 0, 0,
+ { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
+ { "Canon PowerShot G5", 0, 0,
+ { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
+ { "Canon PowerShot G6", 0, 0,
+ { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
+ { "Canon PowerShot G9", 0, 0,
+ { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } },
+ { "Canon PowerShot Pro1", 0, 0,
+ { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
+ { "Canon PowerShot Pro70", 34, 0,
+ { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } },
+ { "Canon PowerShot Pro90", 0, 0,
+ { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } },
+ { "Canon PowerShot S30", 0, 0,
+ { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } },
+ { "Canon PowerShot S40", 0, 0,
+ { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } },
+ { "Canon PowerShot S45", 0, 0,
+ { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } },
+ { "Canon PowerShot S50", 0, 0,
+ { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } },
+ { "Canon PowerShot S60", 0, 0,
+ { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } },
+ { "Canon PowerShot S70", 0, 0,
+ { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } },
+ { "Canon PowerShot A610", 0, 0, /* DJC */
+ { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } },
+ { "Canon PowerShot A620", 0, 0, /* DJC */
+ { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } },
+ { "Canon PowerShot A630", 0, 0, /* DJC */
+ { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } },
+ { "Canon PowerShot A640", 0, 0, /* DJC */
+ { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } },
+ { "Canon PowerShot A650", 0, 0, /* DJC */
+ { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } },
+ { "Canon PowerShot A720", 0, 0, /* DJC */
+ { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } },
+ { "Canon PowerShot S3 IS", 0, 0, /* DJC */
+ { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } },
+ { "CINE 650", 0, 0,
+ { 3390,480,-500,-800,3610,340,-550,2336,1192 } },
+ { "CINE 660", 0, 0,
+ { 3390,480,-500,-800,3610,340,-550,2336,1192 } },
+ { "CINE", 0, 0,
+ { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } },
+ { "Contax N Digital", 0, 0xf1e,
+ { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } },
+ { "EPSON R-D1", 0, 0,
+ { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } },
+ { "FUJIFILM FinePix E550", 0, 0,
+ { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
+ { "FUJIFILM FinePix E900", 0, 0,
+ { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } },
+ { "FUJIFILM FinePix F8", 0, 0,
+ { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
+ { "FUJIFILM FinePix F7", 0, 0,
+ { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+ { "FUJIFILM FinePix S100FS", 514, 0,
+ { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } },
+ { "FUJIFILM FinePix S20Pro", 0, 0,
+ { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+ { "FUJIFILM FinePix S2Pro", 128, 0,
+ { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } },
+ { "FUJIFILM FinePix S3Pro", 0, 0,
+ { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } },
+ { "FUJIFILM FinePix S5Pro", 0, 0,
+ { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } },
+ { "FUJIFILM FinePix S5000", 0, 0,
+ { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } },
+ { "FUJIFILM FinePix S5100", 0, 0x3e00,
+ { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
+ { "FUJIFILM FinePix S5500", 0, 0x3e00,
+ { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
+ { "FUJIFILM FinePix S5200", 0, 0,
+ { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } },
+ { "FUJIFILM FinePix S5600", 0, 0,
+ { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } },
+ { "FUJIFILM FinePix S6", 0, 0,
+ { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } },
+ { "FUJIFILM FinePix S7000", 0, 0,
+ { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
+ { "FUJIFILM FinePix S9000", 0, 0,
+ { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } },
+ { "FUJIFILM FinePix S9500", 0, 0,
+ { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } },
+ { "FUJIFILM FinePix S9100", 0, 0,
+ { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } },
+ { "FUJIFILM FinePix S9600", 0, 0,
+ { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } },
+ { "FUJIFILM IS-1", 0, 0,
+ { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } },
+ { "FUJIFILM IS Pro", 0, 0,
+ { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } },
+ { "Imacon Ixpress", 0, 0, /* DJC */
+ { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } },
+ { "KODAK NC2000", 0, 0,
+ { 13891,-6055,-803,-465,9919,642,2121,82,1291 } },
+ { "Kodak DCS315C", 8, 0,
+ { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } },
+ { "Kodak DCS330C", 8, 0,
+ { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } },
+ { "KODAK DCS420", 0, 0,
+ { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } },
+ { "KODAK DCS460", 0, 0,
+ { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+ { "KODAK EOSDCS1", 0, 0,
+ { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+ { "KODAK EOSDCS3B", 0, 0,
+ { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } },
+ { "Kodak DCS520C", 180, 0,
+ { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+ { "Kodak DCS560C", 188, 0,
+ { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
+ { "Kodak DCS620C", 180, 0,
+ { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } },
+ { "Kodak DCS620X", 185, 0,
+ { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } },
+ { "Kodak DCS660C", 214, 0,
+ { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } },
+ { "Kodak DCS720X", 0, 0,
+ { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } },
+ { "Kodak DCS760C", 0, 0,
+ { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } },
+ { "Kodak DCS Pro SLR", 0, 0,
+ { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+ { "Kodak DCS Pro 14nx", 0, 0,
+ { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+ { "Kodak DCS Pro 14", 0, 0,
+ { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } },
+ { "Kodak ProBack645", 0, 0,
+ { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } },
+ { "Kodak ProBack", 0, 0,
+ { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } },
+ { "KODAK P712", 0, 0,
+ { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } },
+ { "KODAK P850", 0, 0xf7c,
+ { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } },
+ { "KODAK P880", 0, 0xfff,
+ { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } },
+ { "Leaf CMost", 0, 0,
+ { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } },
+ { "Leaf Valeo 6", 0, 0,
+ { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } },
+ { "Leaf Aptus 54S", 0, 0,
+ { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } },
+ { "Leaf Aptus 65", 0, 0,
+ { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } },
+ { "Leaf Aptus 75", 0, 0,
+ { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } },
+ { "Leaf", 0, 0,
+ { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } },
+ { "Mamiya ZD", 0, 0,
+ { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } },
+ { "Micron 2010", 110, 0, /* DJC */
+ { 16695,-3761,-2151,155,9682,163,3433,951,4904 } },
+ { "Minolta DiMAGE 5", 0, 0xf7d,
+ { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } },
+ { "Minolta DiMAGE 7Hi", 0, 0xf7d,
+ { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } },
+ { "Minolta DiMAGE 7", 0, 0xf7d,
+ { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
+ { "Minolta DiMAGE A1", 0, 0xf8b,
+ { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
+ { "MINOLTA DiMAGE A200", 0, 0,
+ { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
+ { "Minolta DiMAGE A2", 0, 0xf8f,
+ { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
+ { "Minolta DiMAGE Z2", 0, 0, /* DJC */
+ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } },
+ { "MINOLTA DYNAX 5", 0, 0xffb,
+ { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } },
+ { "MINOLTA DYNAX 7", 0, 0xffb,
+ { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
+ { "NIKON D100", 0, 0,
+ { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } },
+ { "NIKON D1H", 0, 0,
+ { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } },
+ { "NIKON D1X", 0, 0,
+ { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } },
+ { "NIKON D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */
+ { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } },
+ { "NIKON D2H", 0, 0,
+ { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } },
+ { "NIKON D2X", 0, 0,
+ { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } },
+ { "NIKON D40X", 0, 0,
+ { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } },
+ { "NIKON D40", 0, 0,
+ { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } },
+ { "NIKON D50", 0, 0,
+ { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
+ { "NIKON D60", 0, 0,
+ { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } },
+ { "NIKON D700", 0, 0,
+ { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } },
+ { "NIKON D70", 0, 0,
+ { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
+ { "NIKON D80", 0, 0,
+ { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } },
+ { "NIKON D90", 0, 0xf00,
+ { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } },
+ { "NIKON D200", 0, 0xfbc,
+ { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } },
+ { "NIKON D300", 0, 0,
+ { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } },
+ { "NIKON D3", 0, 0,
+ { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } },
+ { "NIKON E950", 0, 0x3dd, /* DJC */
+ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } },
+ { "NIKON E995", 0, 0, /* copied from E5000 */
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E2100", 0, 0, /* copied from Z2, new white balance */
+ { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} },
+ { "NIKON E2500", 0, 0,
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */
+ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } },
+ { "NIKON E4500", 0, 0,
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E5000", 0, 0,
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E5400", 0, 0,
+ { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } },
+ { "NIKON E5700", 0, 0,
+ { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } },
+ { "NIKON E8400", 0, 0,
+ { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } },
+ { "NIKON E8700", 0, 0,
+ { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } },
+ { "NIKON E8800", 0, 0,
+ { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } },
+ { "NIKON COOLPIX P6000", 0, 0,
+ { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } },
+ { "OLYMPUS C5050", 0, 0,
+ { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } },
+ { "OLYMPUS C5060", 0, 0,
+ { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } },
+ { "OLYMPUS C7070", 0, 0,
+ { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } },
+ { "OLYMPUS C70", 0, 0,
+ { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } },
+ { "OLYMPUS C80", 0, 0,
+ { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } },
+ { "OLYMPUS E-10", 0, 0xffc0,
+ { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } },
+ { "OLYMPUS E-1", 0, 0xfff0,
+ { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } },
+ { "OLYMPUS E-20", 0, 0xffc0,
+ { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } },
+ { "OLYMPUS E-300", 0, 0,
+ { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
+ { "OLYMPUS E-330", 0, 0,
+ { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } },
+ { "OLYMPUS E-3", 0, 0xf99,
+ { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } },
+ { "OLYMPUS E-400", 0, 0xfff0,
+ { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } },
+ { "OLYMPUS E-410", 0, 0xf6a,
+ { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } },
+ { "OLYMPUS E-420", 0, 0xfd7,
+ { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } },
+ { "OLYMPUS E-500", 0, 0,
+ { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } },
+ { "OLYMPUS E-510", 0, 0xf6a,
+ { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } },
+ { "OLYMPUS E-520", 0, 0xfd2,
+ { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } },
+ { "OLYMPUS SP350", 0, 0,
+ { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } },
+ { "OLYMPUS SP3", 0, 0,
+ { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } },
+ { "OLYMPUS SP500UZ", 0, 0xfff,
+ { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } },
+ { "OLYMPUS SP510UZ", 0, 0xffe,
+ { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } },
+ { "OLYMPUS SP550UZ", 0, 0xffe,
+ { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } },
+ { "OLYMPUS SP560UZ", 0, 0xff9,
+ { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } },
+ { "OLYMPUS SP570UZ", 0, 0,
+ { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } },
+ { "PENTAX *ist DL2", 0, 0,
+ { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } },
+ { "PENTAX *ist DL", 0, 0,
+ { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } },
+ { "PENTAX *ist DS2", 0, 0,
+ { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } },
+ { "PENTAX *ist DS", 0, 0,
+ { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } },
+ { "PENTAX *ist D", 0, 0,
+ { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } },
+ { "PENTAX K10D", 0, 0,
+ { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } },
+ { "PENTAX K1", 0, 0,
+ { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } },
+ { "PENTAX K20D", 0, 0,
+ { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } },
+ { "PENTAX K200D", 0, 0,
+ { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } },
+ { "PENTAX K2000", 0, 0,
+ { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } },
+ { "PENTAX K-m", 0, 0,
+ { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } },
+ { "Panasonic DMC-FZ8", 0, 0xf7f0,
+ { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } },
+ { "Panasonic DMC-FZ18", 0, 0,
+ { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } },
+ { "Panasonic DMC-FZ28", 15, 0xfff,
+ { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } },
+ { "Panasonic DMC-FZ30", 0, 0xf94c,
+ { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } },
+ { "Panasonic DMC-FZ50", 0, 0xfff0, /* aka "LEICA V-LUX1" */
+ { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } },
+ { "Panasonic DMC-L10", 15, 0xf96,
+ { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } },
+ { "Panasonic DMC-L1", 0, 0xf7fc, /* aka "LEICA DIGILUX 3" */
+ { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } },
+ { "Panasonic DMC-LC1", 0, 0, /* aka "LEICA DIGILUX 2" */
+ { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+ { "Panasonic DMC-LX1", 0, 0xf7f0, /* aka "LEICA D-LUX2" */
+ { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } },
+ { "Panasonic DMC-LX2", 0, 0, /* aka "LEICA D-LUX3" */
+ { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } },
+ { "Panasonic DMC-LX3", 15, 0xfff, /* aka "LEICA D-LUX4" */
+ { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } },
+ { "Panasonic DMC-FX150", 15, 0xfff,
+ { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } },
+ { "Panasonic DMC-G1", 15, 0xfff,
+ { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } },
+ { "Phase One H 20", 0, 0, /* DJC */
+ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } },
+ { "Phase One P 2", 0, 0,
+ { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } },
+ { "Phase One P 30", 0, 0,
+ { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } },
+ { "Phase One P 45", 0, 0,
+ { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } },
+ { "SAMSUNG GX-1", 0, 0,
+ { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } },
+ { "Sinar", 0, 0, /* DJC */
+ { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } },
+ { "SONY DSC-F828", 491, 0,
+ { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } },
+ { "SONY DSC-R1", 512, 0,
+ { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } },
+ { "SONY DSC-V3", 0, 0,
+ { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } },
+ { "SONY DSLR-A100", 0, 0xfeb,
+ { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } },
+ { "SONY DSLR-A200", 0, 0,
+ { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } },
+ { "SONY DSLR-A300", 0, 0,
+ { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } },
+ { "SONY DSLR-A350", 0, 0xffc,
+ { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } },
+ { "SONY DSLR-A700", 254, 0x1ffe,
+ { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } },
+ { "SONY DSLR-A900", 254, 0x1ffe,
+ { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }
+ };
+ double cam_xyz[4][3];
+ char name[130];
+ int i, j;
+
+ sprintf (name, "%s %s", p_make, p_model);
+ for (i=0; i < sizeof table / sizeof *table; i++)
+ if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) {
+ if (table[i].t_black) black = (ushort) table[i].t_black;
+ if (table[i].t_maximum) maximum = (ushort) table[i].t_maximum;
+ for (j=0; j < 12; j++)
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.color.cam_xyz[0][j] =
+#endif
+ cam_xyz[0][j] = table[i].trans[j] / 10000.0;
+ cam_xyz_coeff (cam_xyz);
+ break;
+ }
+}
+
+void CLASS simple_coeff (int index)
+{
+ static const float table[][12] = {
+ /* index 0 -- all Foveon cameras */
+ { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 },
+ /* index 1 -- Kodak DC20 and DC25 */
+ { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 },
+ /* index 2 -- Logitech Fotoman Pixtura */
+ { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 },
+ /* index 3 -- Nikon E880, E900, and E990 */
+ { -1.936280, 1.800443, -1.448486, 2.584324,
+ 1.405365, -0.524955, -0.289090, 0.408680,
+ -1.204965, 1.082304, 2.941367, -1.818705 }
+ };
+ int i, c;
+
+ for (raw_color = i=0; i < 3; i++)
+ FORCC rgb_cam[i][c] = table[index][i*colors+c];
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.rgb_cam_state = LIBRAW_COLORSTATE_CALCULATED;
+#endif
+}
+
+short CLASS guess_byte_order (int words)
+{
+ uchar test[4][2];
+ int t=2, msb;
+ double diff, sum[2] = {0,0};
+
+ fread (test[0], 2, 2, ifp);
+ for (words-=2; words--; ) {
+ fread (test[t], 2, 1, ifp);
+ for (msb=0; msb < 2; msb++) {
+ diff = (test[t^2][msb] << 8 | test[t^2][!msb])
+ - (test[t ][msb] << 8 | test[t ][!msb]);
+ sum[msb] += diff*diff;
+ }
+ t = (t+1) & 3;
+ }
+ return sum[0] < sum[1] ? 0x4d4d : 0x4949;
+}
+
+/*
+ Identify which camera created this file, and set global variables
+ accordingly.
+ */
+void CLASS identify()
+{
+ char head[32], *cp;
+ unsigned hlen, fsize, i, c, is_canon;
+ struct jhead jh;
+ static const struct {
+ int fsize;
+ char t_make[12], t_model[19], withjpeg;
+ } table[] = {
+ { 62464, "Kodak", "DC20" ,0 },
+ { 124928, "Kodak", "DC20" ,0 },
+ { 1652736, "Kodak", "DCS200" ,0 },
+ { 4159302, "Kodak", "C330" ,0 },
+ { 4162462, "Kodak", "C330" ,0 },
+ { 460800, "Kodak", "C603v" ,0 },
+ { 614400, "Kodak", "C603v" ,0 },
+ { 6163328, "Kodak", "C603" ,0 },
+ { 6166488, "Kodak", "C603" ,0 },
+ { 9116448, "Kodak", "C603y" ,0 },
+ { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */
+ { 614400, "Kodak", "KAI-0340" ,0 },
+ { 787456, "Creative", "PC-CAM 600" ,0 },
+ { 1138688, "Minolta", "RD175" ,0 },
+ { 3840000, "Foculus", "531C" ,0 },
+ { 786432, "AVT", "F-080C" ,0 },
+ { 1447680, "AVT", "F-145C" ,0 },
+ { 1920000, "AVT", "F-201C" ,0 },
+ { 5067304, "AVT", "F-510C" ,0 },
+ { 10134608, "AVT", "F-510C" ,0 },
+ { 16157136, "AVT", "F-810C" ,0 },
+ { 1409024, "Sony", "XCD-SX910CR" ,0 },
+ { 2818048, "Sony", "XCD-SX910CR" ,0 },
+ { 3884928, "Micron", "2010" ,0 },
+ { 6624000, "Pixelink", "A782" ,0 },
+ { 13248000, "Pixelink", "A782" ,0 },
+ { 6291456, "RoverShot","3320AF" ,0 },
+ { 6553440, "Canon", "PowerShot A460" ,0 },
+ { 6653280, "Canon", "PowerShot A530" ,0 },
+ { 6573120, "Canon", "PowerShot A610" ,0 },
+ { 9219600, "Canon", "PowerShot A620" ,0 },
+ { 10341600, "Canon", "PowerShot A720" ,0 },
+ { 10383120, "Canon", "PowerShot A630" ,0 },
+ { 12945240, "Canon", "PowerShot A640" ,0 },
+ { 15636240, "Canon", "PowerShot A650" ,0 },
+ { 5298000, "Canon", "PowerShot SD300" ,0 },
+ { 7710960, "Canon", "PowerShot S3 IS" ,0 },
+ { 5939200, "OLYMPUS", "C770UZ" ,0 },
+ { 1581060, "NIKON", "E900" ,1 }, /* or E900s,E910 */
+ { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */
+ { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */
+ { 4771840, "NIKON", "E990" ,1 }, /* or E995, Oly C3030Z */
+ { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */
+ { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */
+ { 5865472, "NIKON", "E4500" ,1 },
+ { 7438336, "NIKON", "E5000" ,1 }, /* or E5700 */
+ { 8998912, "NIKON", "COOLPIX S6" ,1 },
+ { 1976352, "CASIO", "QV-2000UX" ,1 },
+ { 3217760, "CASIO", "QV-3*00EX" ,1 },
+ { 6218368, "CASIO", "QV-5700" ,1 },
+ { 6054400, "CASIO", "QV-R41" ,1 },
+ { 7530816, "CASIO", "QV-R51" ,1 },
+ { 7684000, "CASIO", "QV-4000" ,1 },
+ { 4948608, "CASIO", "EX-S100" ,1 },
+ { 7542528, "CASIO", "EX-Z50" ,1 },
+ { 7753344, "CASIO", "EX-Z55" ,1 },
+ { 7426656, "CASIO", "EX-P505" ,1 },
+ { 9313536, "CASIO", "EX-P600" ,1 },
+ { 10979200, "CASIO", "EX-P700" ,1 },
+ { 3178560, "PENTAX", "Optio S" ,1 },
+ { 4841984, "PENTAX", "Optio S" ,1 },
+ { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i, CASIO EX-Z4 */
+ { 10702848, "PENTAX", "Optio 750Z" ,1 },
+ { 16098048, "SAMSUNG", "S85" ,1 },
+ { 16215552, "SAMSUNG", "S85" ,1 },
+ { 12582980, "Sinar", "" ,0 },
+ { 33292868, "Sinar", "" ,0 },
+ { 44390468, "Sinar", "" ,0 } };
+ static const char *corp[] =
+ { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX",
+ "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar", "Phase One",
+ "SAMSUNG", "Mamiya" };
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,0,2);
+#endif
+
+ tiff_flip = flip = filters = -1; /* 0 is valid, so -1 is unknown */
+ raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0;
+ maximum = height = width = top_margin = left_margin = 0;
+ cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0;
+ iso_speed = shutter = aperture = focal_len = unique_id = 0;
+ memset (gpsdata, 0, sizeof gpsdata);
+ memset (white, 0, sizeof white);
+ thumb_offset = thumb_length = thumb_width = thumb_height = 0;
+ load_raw = thumb_load_raw = 0;
+ write_thumb = &CLASS jpeg_thumb;
+ data_offset = meta_length = tiff_bps = tiff_compress = 0;
+ kodak_cbpp = zero_after_ff = dng_version = load_flags = 0;
+ timestamp = shot_order = tiff_samples = black = is_foveon = 0;
+ mix_green = profile_length = data_error = zero_is_bad = 0;
+ pixel_aspect = is_raw = raw_color = use_gamma = 1;
+ tile_width = tile_length = INT_MAX;
+ for (i=0; i < 4; i++) {
+ cam_mul[i] = i == 1;
+ pre_mul[i] = i < 3;
+ FORC3 cmatrix[c][i] = 0;
+ FORC3 rgb_cam[c][i] = c == i;
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cmatrix_state = LIBRAW_COLORSTATE_INIT;
+ color_flags.rgb_cam_state = LIBRAW_COLORSTATE_INIT;
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_INIT;
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_INIT;
+#endif
+ colors = 3;
+ tiff_bps = 12;
+ for (i=0; i < 0x4000; i++) curve[i] = i;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.curve_state = LIBRAW_COLORSTATE_INIT;
+#endif
+
+ order = get2();
+ hlen = get4();
+ fseek (ifp, 0, SEEK_SET);
+ fread (head, 1, 32, ifp);
+ fseek (ifp, 0, SEEK_END);
+ fsize = ftell(ifp);
+ if ((cp = (char *) memmem (head, 32, "MMMM", 4)) ||
+ (cp = (char *) memmem (head, 32, "IIII", 4))) {
+ parse_phase_one (cp-head);
+ if (cp-head) parse_tiff(0);
+ } else if (order == 0x4949 || order == 0x4d4d) {
+ if (!memcmp (head+6,"HEAPCCDR",8)) {
+ data_offset = hlen;
+ parse_ciff (hlen, fsize - hlen);
+ } else {
+ parse_tiff(0);
+ }
+ } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) &&
+ !memcmp (head+6,"Exif",4)) {
+ fseek (ifp, 4, SEEK_SET);
+ data_offset = 4 + get2();
+ fseek (ifp, data_offset, SEEK_SET);
+ if (fgetc(ifp) != 0xff)
+ parse_tiff(12);
+ thumb_offset = 0;
+ } else if (!memcmp (head+25,"ARECOYK",7)) {
+ strcpy (make, "Contax");
+ strcpy (model,"N Digital");
+ fseek (ifp, 33, SEEK_SET);
+ get_timestamp(1);
+ fseek (ifp, 60, SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = get4();
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ } else if (!strcmp (head, "PXN")) {
+ strcpy (make, "Logitech");
+ strcpy (model,"Fotoman Pixtura");
+ } else if (!strcmp (head, "qktk")) {
+ strcpy (make, "Apple");
+ strcpy (model,"QuickTake 100");
+ } else if (!strcmp (head, "qktn")) {
+ strcpy (make, "Apple");
+ strcpy (model,"QuickTake 150");
+ } else if (!memcmp (head,"FUJIFILM",8)) {
+ fseek (ifp, 84, SEEK_SET);
+ thumb_offset = get4();
+ thumb_length = get4();
+ fseek (ifp, 92, SEEK_SET);
+ parse_fuji (get4());
+ if (thumb_offset > 120) {
+ fseek (ifp, 120, SEEK_SET);
+ is_raw += (i = get4()) && 1;
+ if (is_raw == 2 && shot_select)
+ parse_fuji (i);
+ }
+ fseek (ifp, 100, SEEK_SET);
+ data_offset = get4();
+ parse_tiff (thumb_offset+12);
+ } else if (!memcmp (head,"RIFF",4)) {
+ fseek (ifp, 0, SEEK_SET);
+ parse_riff();
+ } else if (!memcmp (head,"\0\001\0\001\0@",6)) {
+ fseek (ifp, 6, SEEK_SET);
+ fread (make, 1, 8, ifp);
+ fread (model, 1, 8, ifp);
+ fread (model2, 1, 16, ifp);
+ data_offset = get2();
+ get2();
+ raw_width = get2();
+ raw_height = get2();
+ load_raw = &CLASS nokia_load_raw;
+ filters = 0x61616161;
+ } else if (!memcmp (head,"DSC-Image",9))
+ parse_rollei();
+ else if (!memcmp (head,"PWAD",4))
+ parse_sinar_ia();
+ else if (!memcmp (head,"\0MRM",4))
+ parse_minolta(0);
+ else if (!memcmp (head,"FOVb",4))
+ parse_foveon();
+ else if (!memcmp (head,"CI",2))
+ parse_cine();
+ else
+ for (i=0; i < sizeof table / sizeof *table; i++)
+ if (fsize == table[i].fsize) {
+ strcpy (make, table[i].t_make );
+ strcpy (model, table[i].t_model);
+ if (table[i].withjpeg)
+ parse_external_jpeg();
+ }
+ if (make[0] == 0) parse_smal (0, fsize);
+ if (make[0] == 0) parse_jpeg (is_raw = 0);
+
+ for (i=0; i < sizeof corp / sizeof *corp; i++)
+ if (strstr (make, corp[i])) /* Simplify company names */
+ strcpy (make, corp[i]);
+ if (!strncmp (make,"KODAK",5))
+ make[16] = model[16] = 0;
+ cp = make + strlen(make); /* Remove trailing spaces */
+ while (*--cp == ' ') *cp = 0;
+ cp = model + strlen(model);
+ while (*--cp == ' ') *cp = 0;
+ i = strlen(make); /* Remove make from model */
+ if (!strncasecmp (model, make, i) && model[i++] == ' ')
+ memmove (model, model+i, 64-i);
+ if (!strncmp (model,"Digital Camera ",15))
+ strcpy (model, model+15);
+ desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0;
+ if (!is_raw) goto notraw;
+
+ if (!maximum) maximum = (1 << tiff_bps) - 1;
+ if (!height) height = raw_height;
+ if (!width) width = raw_width;
+ if (fuji_width) {
+ width = height + fuji_width;
+ height = width - 1;
+ pixel_aspect = 1;
+ }
+ if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */
+ { height = 2616; width = 3896; }
+ if (height == 3136 && width == 4864) /* Pentax K20D */
+ { height = 3124; width = 4688; }
+ if (height == 3014 && width == 4096) /* Ricoh GX200 */
+ width = 4014;
+ if (dng_version) {
+ if (filters == UINT_MAX) filters = 0;
+ if (filters) is_raw = tiff_samples;
+ else colors = tiff_samples;
+ if (tiff_compress == 1)
+ load_raw = &CLASS adobe_dng_load_raw_nc;
+ if (tiff_compress == 7)
+ load_raw = &CLASS adobe_dng_load_raw_lj;
+ goto dng_skip;
+ }
+ if ((is_canon = !strcmp(make,"Canon")))
+ load_raw = memcmp (head+6,"HEAPCCDR",8) ?
+ &CLASS lossless_jpeg_load_raw : &CLASS canon_compressed_load_raw;
+ if (!strcmp(make,"NIKON")) {
+ if (!load_raw)
+ load_raw = &CLASS packed_12_load_raw;
+ if (model[0] == 'E')
+ load_flags |= !data_offset << 2 | 2;
+ }
+ if (!strcmp(make,"CASIO")) {
+ load_raw = &CLASS packed_12_load_raw;
+ maximum = 0xf7f;
+ }
+
+/* Set parameters based on camera name (for non-DNG files). */
+
+ if (is_foveon) {
+ if (height*2 < width) pixel_aspect = 0.5;
+ if (height > width) pixel_aspect = 2;
+ filters = 0;
+ load_raw = &CLASS foveon_load_raw;
+ simple_coeff(0);
+ } else if (is_canon && tiff_bps == 15) {
+ switch (width) {
+ case 3344: width -= 66;
+ case 3872: width -= 6;
+ }
+ filters = 0;
+ load_raw = &CLASS canon_sraw_load_raw;
+ } else if (!strcmp(model,"PowerShot 600")) {
+ height = 613;
+ width = 854;
+ raw_width = 896;
+ pixel_aspect = 607/628.0;
+ colors = 4;
+ filters = 0xe1e4e1e4;
+ load_raw = &CLASS canon_600_load_raw;
+ } else if (!strcmp(model,"PowerShot A5") ||
+ !strcmp(model,"PowerShot A5 Zoom")) {
+ height = 773;
+ width = 960;
+ raw_width = 992;
+ pixel_aspect = 256/235.0;
+ colors = 4;
+ filters = 0x1e4e1e4e;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A50")) {
+ height = 968;
+ width = 1290;
+ raw_width = 1320;
+ colors = 4;
+ filters = 0x1b4e4b1e;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot Pro70")) {
+ height = 1024;
+ width = 1552;
+ colors = 4;
+ filters = 0x1e4b4e1b;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot SD300")) {
+ height = 1752;
+ width = 2344;
+ raw_height = 1766;
+ raw_width = 2400;
+ top_margin = 12;
+ left_margin = 12;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A460")) {
+ height = 1960;
+ width = 2616;
+ raw_height = 1968;
+ raw_width = 2664;
+ top_margin = 4;
+ left_margin = 4;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A530")) {
+ height = 1984;
+ width = 2620;
+ raw_height = 1992;
+ raw_width = 2672;
+ top_margin = 6;
+ left_margin = 10;
+ load_raw = &CLASS canon_a5_load_raw;
+ raw_color = 0;
+ } else if (!strcmp(model,"PowerShot A610")) {
+ if (canon_s2is()) strcpy (model+10, "S2 IS");
+ height = 1960;
+ width = 2616;
+ raw_height = 1968;
+ raw_width = 2672;
+ top_margin = 8;
+ left_margin = 12;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A620")) {
+ height = 2328;
+ width = 3112;
+ raw_height = 2340;
+ raw_width = 3152;
+ top_margin = 12;
+ left_margin = 36;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A720")) {
+ height = 2472;
+ width = 3298;
+ raw_height = 2480;
+ raw_width = 3336;
+ top_margin = 5;
+ left_margin = 6;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A630")) {
+ height = 2472;
+ width = 3288;
+ raw_height = 2484;
+ raw_width = 3344;
+ top_margin = 6;
+ left_margin = 12;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A640")) {
+ height = 2760;
+ width = 3672;
+ raw_height = 2772;
+ raw_width = 3736;
+ top_margin = 6;
+ left_margin = 12;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A650")) {
+ height = 3024;
+ width = 4032;
+ raw_height = 3048;
+ raw_width = 4104;
+ top_margin = 12;
+ left_margin = 48;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot S3 IS")) {
+ height = 2128;
+ width = 2840;
+ raw_height = 2136;
+ raw_width = 2888;
+ top_margin = 8;
+ left_margin = 44;
+ load_raw = &CLASS canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot Pro90 IS")) {
+ width = 1896;
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ } else if (is_canon && raw_width == 2144) {
+ height = 1550;
+ width = 2088;
+ top_margin = 8;
+ left_margin = 4;
+ if (!strcmp(model,"PowerShot G1")) {
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ }
+ } else if (is_canon && raw_width == 2224) {
+ height = 1448;
+ width = 2176;
+ top_margin = 6;
+ left_margin = 48;
+ } else if (is_canon && raw_width == 2376) {
+ height = 1720;
+ width = 2312;
+ top_margin = 6;
+ left_margin = 12;
+ } else if (is_canon && raw_width == 2672) {
+ height = 1960;
+ width = 2616;
+ top_margin = 6;
+ left_margin = 12;
+ } else if (is_canon && raw_width == 3152) {
+ height = 2056;
+ width = 3088;
+ top_margin = 12;
+ left_margin = 64;
+ if (unique_id == 0x80000170)
+ adobe_coeff ("Canon","EOS 300D");
+ } else if (is_canon && raw_width == 3160) {
+ height = 2328;
+ width = 3112;
+ top_margin = 12;
+ left_margin = 44;
+ } else if (is_canon && raw_width == 3344) {
+ height = 2472;
+ width = 3288;
+ top_margin = 6;
+ left_margin = 4;
+ } else if (!strcmp(model,"EOS D2000C")) {
+ filters = 0x61616161;
+ black = curve[200];
+ } else if (is_canon && raw_width == 3516) {
+ top_margin = 14;
+ left_margin = 42;
+ if (unique_id == 0x80000189)
+ adobe_coeff ("Canon","EOS 350D");
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 3596) {
+ top_margin = 12;
+ left_margin = 74;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 3944) {
+ height = 2602;
+ width = 3908;
+ top_margin = 18;
+ left_margin = 30;
+ } else if (is_canon && raw_width == 3948) {
+ top_margin = 18;
+ left_margin = 42;
+ height -= 2;
+ if (unique_id == 0x80000236)
+ adobe_coeff ("Canon","EOS 400D");
+ if (unique_id == 0x80000254)
+ adobe_coeff ("Canon","EOS 1000D");
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 3984) {
+ top_margin = 20;
+ left_margin = 76;
+ height -= 2;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 4104) {
+ height = 3024;
+ width = 4032;
+ top_margin = 12;
+ left_margin = 48;
+ } else if (is_canon && raw_width == 4312) {
+ top_margin = 18;
+ left_margin = 22;
+ height -= 2;
+ if (unique_id == 0x80000176)
+ adobe_coeff ("Canon","EOS 450D");
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 4476) {
+ top_margin = 34;
+ left_margin = 90;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 4480) {
+ height = 3326;
+ width = 4432;
+ top_margin = 10;
+ left_margin = 12;
+ filters = 0x49494949;
+ } else if (is_canon && raw_width == 1208) {
+ top_margin = 51;
+ left_margin = 62;
+ raw_width = width *= 4;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 1448) {
+ top_margin = 51;
+ left_margin = 158;
+ raw_width = width *= 4;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 5108) {
+ top_margin = 13;
+ left_margin = 98;
+canon_cr2:
+ height -= top_margin;
+ width -= left_margin;
+ } else if (is_canon && raw_width == 5712) {
+ height = 3752;
+ width = 5640;
+ top_margin = 20;
+ left_margin = 62;
+ } else if (!strcmp(model,"D1")) {
+ cam_mul[0] *= 256/527.0;
+ cam_mul[2] *= 256/317.0;
+ } else if (!strcmp(model,"D1X")) {
+ width -= 4;
+ pixel_aspect = 0.5;
+ } else if (!strcmp(model,"D40X") ||
+ !strcmp(model,"D60") ||
+ !strcmp(model,"D80")) {
+ height -= 3;
+ width -= 4;
+ } else if (!strcmp(model,"D3") ||
+ !strcmp(model,"D700")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strncmp(model,"D40",3) ||
+ !strncmp(model,"D50",3) ||
+ !strncmp(model,"D70",3)) {
+ width--;
+ } else if (!strcmp(model,"D90")) {
+ width -= 42;
+ } else if (!strcmp(model,"D100")) {
+ if (tiff_compress == 34713 && !nikon_is_compressed()) {
+ load_raw = &CLASS packed_12_load_raw;
+ load_flags |= 8;
+ raw_width = (width += 3) + 3;
+ }
+ } else if (!strcmp(model,"D200")) {
+ left_margin = 1;
+ width -= 4;
+ filters = 0x94949494;
+ } else if (!strncmp(model,"D2H",3)) {
+ left_margin = 6;
+ width -= 14;
+ } else if (!strncmp(model,"D2X",3)) {
+ if (width == 3264) width -= 32;
+ else width -= 8;
+ } else if (!strcmp(model,"D300")) {
+ width -= 32;
+ } else if (!strcmp(model,"COOLPIX P6000")) {
+ load_flags = 1;
+ filters = 0x94949494;
+ } else if (fsize == 1581060) {
+ height = 963;
+ width = 1287;
+ raw_width = 1632;
+ load_raw = &CLASS nikon_e900_load_raw;
+ maximum = 0x3f4;
+ colors = 4;
+ filters = 0x1e1e1e1e;
+ simple_coeff(3);
+ pre_mul[0] = 1.2085;
+ pre_mul[1] = 1.0943;
+ pre_mul[3] = 1.1103;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (fsize == 2465792) {
+ height = 1203;
+ width = 1616;
+ raw_width = 2048;
+ load_raw = &CLASS nikon_e900_load_raw;
+ colors = 4;
+ filters = 0x4b4b4b4b;
+ adobe_coeff ("NIKON","E950");
+ } else if (fsize == 4771840) {
+ height = 1540;
+ width = 2064;
+ colors = 4;
+ filters = 0xe1e1e1e1;
+ load_raw = &CLASS packed_12_load_raw;
+ load_flags = 6;
+ if (!timestamp && nikon_e995())
+ strcpy (model, "E995");
+ if (strcmp(model,"E995")) {
+ filters = 0xb4b4b4b4;
+ simple_coeff(3);
+ pre_mul[0] = 1.196;
+ pre_mul[1] = 1.246;
+ pre_mul[2] = 1.018;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ }
+ } else if (!strcmp(model,"E2100")) {
+ if (!timestamp && !nikon_e2100()) goto cp_e2500;
+ height = 1206;
+ width = 1616;
+ load_flags = 7;
+ } else if (!strcmp(model,"E2500")) {
+cp_e2500:
+ strcpy (model, "E2500");
+ height = 1204;
+ width = 1616;
+ colors = 4;
+ filters = 0x4b4b4b4b;
+ } else if (fsize == 4775936) {
+ height = 1542;
+ width = 2064;
+ load_raw = &CLASS packed_12_load_raw;
+ load_flags = 7;
+ pre_mul[0] = 1.818;
+ pre_mul[2] = 1.618;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ if (!timestamp) nikon_3700();
+ if (model[0] == 'E' && atoi(model+1) < 3700)
+ filters = 0x49494949;
+ if (!strcmp(model,"Optio 33WR")) {
+ flip = 1;
+ filters = 0x16161616;
+ pre_mul[0] = 1.331;
+ pre_mul[2] = 1.820;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ }
+ } else if (fsize == 5869568) {
+ height = 1710;
+ width = 2288;
+ filters = 0x16161616;
+ if (!timestamp && minolta_z2()) {
+ strcpy (make, "Minolta");
+ strcpy (model,"DiMAGE Z2");
+ }
+ load_raw = &CLASS packed_12_load_raw;
+ load_flags = 6 + (make[0] == 'M');
+ } else if (!strcmp(model,"E4500")) {
+ height = 1708;
+ width = 2288;
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ } else if (fsize == 7438336) {
+ height = 1924;
+ width = 2576;
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ } else if (fsize == 8998912) {
+ height = 2118;
+ width = 2832;
+ maximum = 0xf83;
+ load_raw = &CLASS packed_12_load_raw;
+ load_flags = 7;
+ } else if (!strcmp(model,"FinePix S5100") ||
+ !strcmp(model,"FinePix S5500")) {
+ load_raw = &CLASS unpacked_load_raw;
+ } else if (!strcmp(make,"FUJIFILM")) {
+ if (!strcmp(model+7,"S2Pro")) {
+ strcpy (model+7," S2Pro");
+ height = 2144;
+ width = 2880;
+ flip = 6;
+ } else
+ maximum = 0x3e00;
+ if (is_raw == 2 && shot_select)
+ maximum = 0x2f00;
+ top_margin = (raw_height - height)/2;
+ left_margin = (raw_width - width )/2;
+ if (is_raw == 2)
+ data_offset += (shot_select > 0) * ( fuji_layout ?
+ (raw_width *= 2) : raw_height*raw_width*2 );
+ fuji_width = width >> !fuji_layout;
+ width = (height >> fuji_layout) + fuji_width;
+ raw_height = height;
+ height = width - 1;
+ load_raw = &CLASS fuji_load_raw;
+ if (!(fuji_width & 1)) filters = 0x49494949;
+ } else if (!strcmp(model,"RD175")) {
+ height = 986;
+ width = 1534;
+ data_offset = 513;
+ filters = 0x61616161;
+ load_raw = &CLASS minolta_rd175_load_raw;
+ } else if (!strcmp(model,"KD-400Z")) {
+ height = 1712;
+ width = 2312;
+ raw_width = 2336;
+ goto konica_400z;
+ } else if (!strcmp(model,"KD-510Z")) {
+ goto konica_510z;
+ } else if (!strcasecmp(make,"MINOLTA")) {
+ load_raw = &CLASS unpacked_load_raw;
+ maximum = 0xfff;
+ if (!strncmp(model,"DiMAGE A",8)) {
+ if (!strcmp(model,"DiMAGE A200"))
+ filters = 0x49494949;
+ load_raw = &CLASS packed_12_load_raw;
+ } else if (!strncmp(model,"ALPHA",5) ||
+ !strncmp(model,"DYNAX",5) ||
+ !strncmp(model,"MAXXUM",6)) {
+ sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M'));
+ adobe_coeff (make, model+20);
+ load_raw = &CLASS packed_12_load_raw;
+ } else if (!strncmp(model,"DiMAGE G",8)) {
+ if (model[8] == '4') {
+ height = 1716;
+ width = 2304;
+ } else if (model[8] == '5') {
+konica_510z:
+ height = 1956;
+ width = 2607;
+ raw_width = 2624;
+ } else if (model[8] == '6') {
+ height = 2136;
+ width = 2848;
+ }
+ data_offset += 14;
+ filters = 0x61616161;
+konica_400z:
+ load_raw = &CLASS unpacked_load_raw;
+ maximum = 0x3df;
+ order = 0x4d4d;
+ }
+ } else if (!strcmp(model,"*ist DS")) {
+ height -= 2;
+ } else if (!strcmp(model,"K20D")) {
+ filters = 0x16161616;
+ } else if (!strcmp(model,"Optio S")) {
+ if (fsize == 3178560) {
+ height = 1540;
+ width = 2064;
+ load_raw = &CLASS eight_bit_load_raw;
+ cam_mul[0] *= 4;
+ cam_mul[2] *= 4;
+ pre_mul[0] = 1.391;
+ pre_mul[2] = 1.188;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else {
+ height = 1544;
+ width = 2068;
+ raw_width = 3136;
+ load_raw = &CLASS packed_12_load_raw;
+ maximum = 0xf7c;
+ pre_mul[0] = 1.137;
+ pre_mul[2] = 1.453;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ }
+ } else if (fsize == 6114240) {
+ height = 1737;
+ width = 2324;
+ raw_width = 3520;
+ load_raw = &CLASS packed_12_load_raw;
+ maximum = 0xf7a;
+ pre_mul[0] = 1.980;
+ pre_mul[2] = 1.570;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"Optio 750Z")) {
+ height = 2302;
+ width = 3072;
+ load_raw = &CLASS packed_12_load_raw;
+ load_flags = 7;
+ } else if (!strcmp(model,"S85")) {
+ height = 2448;
+ width = 3264;
+ raw_width = fsize/height/2;
+ order = 0x4d4d;
+ load_raw = &CLASS unpacked_load_raw;
+ maximum = 0xffff;
+ } else if (!strcmp(model,"STV680 VGA")) {
+ height = 484;
+ width = 644;
+ load_raw = &CLASS eight_bit_load_raw;
+ flip = 2;
+ filters = 0x16161616;
+ black = 16;
+ pre_mul[0] = 1.097;
+ pre_mul[2] = 1.128;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"KAI-0340")) {
+ height = 477;
+ width = 640;
+ order = 0x4949;
+ data_offset = 3840;
+ load_raw = &CLASS unpacked_load_raw;
+ pre_mul[0] = 1.561;
+ pre_mul[2] = 2.454;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"N95")) {
+ height = raw_height - (top_margin = 2);
+ } else if (!strcmp(model,"531C")) {
+ height = 1200;
+ width = 1600;
+ load_raw = &CLASS unpacked_load_raw;
+ filters = 0x49494949;
+ pre_mul[1] = 1.218;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"F-080C")) {
+ height = 768;
+ width = 1024;
+ load_raw = &CLASS eight_bit_load_raw;
+ } else if (!strcmp(model,"F-145C")) {
+ height = 1040;
+ width = 1392;
+ load_raw = &CLASS eight_bit_load_raw;
+ } else if (!strcmp(model,"F-201C")) {
+ height = 1200;
+ width = 1600;
+ load_raw = &CLASS eight_bit_load_raw;
+ } else if (!strcmp(model,"F-510C")) {
+ height = 1958;
+ width = 2588;
+ load_raw = fsize < 7500000 ?
+ &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw;
+ maximum = 0xfff0;
+ } else if (!strcmp(model,"F-810C")) {
+ height = 2469;
+ width = 3272;
+ load_raw = &CLASS unpacked_load_raw;
+ maximum = 0xfff0;
+ } else if (!strcmp(model,"XCD-SX910CR")) {
+ height = 1024;
+ width = 1375;
+ raw_width = 1376;
+ filters = 0x49494949;
+ maximum = 0x3ff;
+ load_raw = fsize < 2000000 ?
+ &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw;
+ } else if (!strcmp(model,"2010")) {
+ height = 1207;
+ width = 1608;
+ order = 0x4949;
+ filters = 0x16161616;
+ data_offset = 3212;
+ maximum = 0x3ff;
+ load_raw = &CLASS unpacked_load_raw;
+ } else if (!strcmp(model,"A782")) {
+ height = 3000;
+ width = 2208;
+ filters = 0x61616161;
+ load_raw = fsize < 10000000 ?
+ &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw;
+ maximum = 0xffc0;
+ } else if (!strcmp(model,"3320AF")) {
+ height = 1536;
+ raw_width = width = 2048;
+ filters = 0x61616161;
+ load_raw = &CLASS unpacked_load_raw;
+ maximum = 0x3ff;
+ pre_mul[0] = 1.717;
+ pre_mul[2] = 1.138;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ fseek (ifp, 0x300000, SEEK_SET);
+ if ((order = guess_byte_order(0x10000)) == 0x4d4d) {
+ height -= (top_margin = 16);
+ width -= (left_margin = 28);
+ maximum = 0xf5c0;
+ strcpy (make, "ISG");
+ model[0] = 0;
+ }
+ } else if (!strcmp(make,"Hasselblad")) {
+ if (load_raw == &CLASS lossless_jpeg_load_raw)
+ load_raw = &CLASS hasselblad_load_raw;
+ if (raw_width == 7262) {
+ height = 5444;
+ width = 7248;
+ top_margin = 4;
+ left_margin = 7;
+ filters = 0x61616161;
+ } else if (raw_width == 4090) {
+ strcpy (model, "V96C");
+ height -= (top_margin = 6);
+ width -= (left_margin = 3) + 7;
+ filters = 0x61616161;
+ }
+ } else if (!strcmp(make,"Sinar")) {
+ if (!memcmp(head,"8BPS",4)) {
+ fseek (ifp, 14, SEEK_SET);
+ height = get4();
+ width = get4();
+ filters = 0x61616161;
+ data_offset = 68;
+ }
+ if (!load_raw) load_raw = &CLASS unpacked_load_raw;
+ maximum = 0x3fff;
+ } else if (!strcmp(make,"Leaf")) {
+ maximum = 0x3fff;
+ fseek (ifp, data_offset, SEEK_SET);
+ if (ljpeg_start (&jh, 1) && jh.bits == 15)
+ maximum = 0x1fff;
+ if (tiff_samples > 1) filters = 0;
+ if (tiff_samples > 1 || tile_length < raw_height)
+ load_raw = &CLASS leaf_hdr_load_raw;
+ if ((width | height) == 2048) {
+ if (tiff_samples == 1) {
+ filters = 1;
+ strcpy (cdesc, "RBTG");
+ strcpy (model, "CatchLight");
+ top_margin = 8; left_margin = 18; height = 2032; width = 2016;
+ } else {
+ strcpy (model, "DCB2");
+ top_margin = 10; left_margin = 16; height = 2028; width = 2022;
+ }
+ } else if (width+height == 3144+2060) {
+ if (!model[0]) strcpy (model, "Cantare");
+ if (width > height) {
+ top_margin = 6; left_margin = 32; height = 2048; width = 3072;
+ filters = 0x61616161;
+ } else {
+ left_margin = 6; top_margin = 32; width = 2048; height = 3072;
+ filters = 0x16161616;
+ }
+ if (!cam_mul[0] || model[0] == 'V') filters = 0;
+ else is_raw = tiff_samples;
+ } else if (width == 2116) {
+ strcpy (model, "Valeo 6");
+ height -= 2 * (top_margin = 30);
+ width -= 2 * (left_margin = 55);
+ filters = 0x49494949;
+ } else if (width == 3171) {
+ strcpy (model, "Valeo 6");
+ height -= 2 * (top_margin = 24);
+ width -= 2 * (left_margin = 24);
+ filters = 0x16161616;
+ }
+ } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) {
+ maximum = 0xfff0;
+ if ((fsize-data_offset) / (width*8/7) == height)
+ load_raw = &CLASS panasonic_load_raw;
+ if (!load_raw) load_raw = &CLASS unpacked_load_raw;
+ switch (width) {
+ case 2568:
+ adobe_coeff ("Panasonic","DMC-LC1"); break;
+ case 3130:
+ left_margin = -14;
+ case 3170:
+ left_margin += 18;
+ width = 3096;
+ if (height > 2326) {
+ height = 2326;
+ top_margin = 13;
+ filters = 0x49494949;
+ }
+ zero_is_bad = 1;
+ adobe_coeff ("Panasonic","DMC-FZ8"); break;
+ case 3213:
+ width -= 27;
+ case 3177:
+ width -= 10;
+ filters = 0x49494949;
+ zero_is_bad = 1;
+ adobe_coeff ("Panasonic","DMC-L1"); break;
+ case 3304:
+ width -= 17;
+ zero_is_bad = 1;
+ adobe_coeff ("Panasonic","DMC-FZ30"); break;
+ case 3330:
+ width += 43;
+ left_margin = -6;
+ maximum = 0xf7f0;
+ case 3370:
+ width -= 82;
+ left_margin += 15;
+ if (height > 2480)
+ height = 2480 - (top_margin = 10);
+ filters = 0x49494949;
+ zero_is_bad = 1;
+ adobe_coeff ("Panasonic","DMC-FZ18"); break;
+ case 3690:
+ height -= 2;
+ left_margin = -14;
+ maximum = 0xf7f0;
+ case 3770:
+ width = 3672;
+ if (--height == 2798 && (height = 2760))
+ top_margin = 15;
+ else filters = 0x49494949;
+ left_margin += 17;
+ zero_is_bad = 1;
+ adobe_coeff ("Panasonic","DMC-FZ50"); break;
+ case 3710:
+ width = 3682;
+ filters = 0x49494949;
+ adobe_coeff ("Panasonic","DMC-L10"); break;
+ case 3724:
+ width -= 14;
+ case 3836:
+ width -= 42;
+lx3: filters = 0x16161616;
+ if (make[0] != 'P')
+ adobe_coeff ("Panasonic","DMC-LX3");
+ break;
+ case 3880:
+ width -= 22;
+ left_margin = 6;
+ zero_is_bad = 1;
+ adobe_coeff ("Panasonic","DMC-LX1"); break;
+ case 4060:
+ width = 3982;
+ if (height == 2250) goto lx3;
+ width = 4018;
+ filters = 0x49494949;
+ zero_is_bad = 1;
+ adobe_coeff ("Panasonic","DMC-G1"); break;
+ case 4290:
+ height += 38;
+ left_margin = -14;
+ filters = 0x49494949;
+ case 4330:
+ width = 4248;
+ if ((height -= 39) == 2400)
+ top_margin = 15;
+ left_margin += 17;
+ adobe_coeff ("Panasonic","DMC-LX2"); break;
+ case 4508:
+ height -= 6;
+ width = 4429;
+ filters = 0x16161616;
+ adobe_coeff ("Panasonic","DMC-FX150"); break;
+ }
+ } else if (!strcmp(model,"C770UZ")) {
+ height = 1718;
+ width = 2304;
+ filters = 0x16161616;
+ load_raw = &CLASS packed_12_load_raw;
+ load_flags = 7;
+ } else if (!strcmp(make,"OLYMPUS")) {
+ height += height & 1;
+ filters = exif_cfa;
+ if (load_raw == &CLASS olympus_e410_load_raw) {
+ black >>= 4;
+ } else if (!strcmp(model,"E-10") ||
+ !strncmp(model,"E-20",4)) {
+ black <<= 2;
+ } else if (!strcmp(model,"E-300") ||
+ !strcmp(model,"E-500")) {
+ width -= 20;
+ if (load_raw == &CLASS unpacked_load_raw) {
+ maximum = 0xfc30;
+ black = 0;
+ }
+ } else if (!strcmp(model,"E-330")) {
+ width -= 30;
+ if (load_raw == &CLASS unpacked_load_raw)
+ maximum = 0xf790;
+ } else if (!strcmp(model,"SP550UZ")) {
+ thumb_length = fsize - (thumb_offset = 0xa39800);
+ thumb_height = 480;
+ thumb_width = 640;
+ }
+ } else if (!strcmp(model,"N Digital")) {
+ height = 2047;
+ width = 3072;
+ filters = 0x61616161;
+ data_offset = 0x1a00;
+ load_raw = &CLASS packed_12_load_raw;
+ } else if (!strcmp(model,"DSC-F828")) {
+ width = 3288;
+ left_margin = 5;
+ data_offset = 862144;
+ load_raw = &CLASS sony_load_raw;
+ filters = 0x9c9c9c9c;
+ colors = 4;
+ strcpy (cdesc, "RGBE");
+ } else if (!strcmp(model,"DSC-V3")) {
+ width = 3109;
+ left_margin = 59;
+ data_offset = 787392;
+ load_raw = &CLASS sony_load_raw;
+ } else if (!strcmp(make,"SONY") && raw_width == 3984) {
+ adobe_coeff ("SONY","DSC-R1");
+ width = 3925;
+ order = 0x4d4d;
+ } else if (!strcmp(model,"DSLR-A100")) {
+ height--;
+ } else if (!strcmp(model,"DSLR-A350")) {
+ height -= 4;
+ } else if (!strcmp(model,"C603v")) {
+ height = 480;
+ width = 640;
+ goto c603v;
+ } else if (!strcmp(model,"C603y")) {
+ height = 2134;
+ width = 2848;
+c603v:
+ filters = 0;
+ load_raw = &CLASS kodak_yrgb_load_raw;
+ } else if (!strcmp(model,"C603")) {
+ raw_height = height = 2152;
+ raw_width = width = 2864;
+ goto c603;
+ } else if (!strcmp(model,"C330")) {
+ height = 1744;
+ width = 2336;
+ raw_height = 1779;
+ raw_width = 2338;
+ top_margin = 33;
+ left_margin = 1;
+c603:
+ order = 0x4949;
+ if ((data_offset = fsize - raw_height*raw_width)) {
+ fseek (ifp, 168, SEEK_SET);
+ read_shorts (curve, 256);
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.curve_state = LIBRAW_COLORSTATE_LOADED;
+#endif
+ } else use_gamma = 0;
+ load_raw = &CLASS eight_bit_load_raw;
+ } else if (!strcasecmp(make,"KODAK")) {
+ if (filters == UINT_MAX) filters = 0x61616161;
+ if (!strncmp(model,"NC2000",6)) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"EOSDCS3B")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"EOSDCS1")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"DCS420")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"DCS460")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"DCS460A")) {
+ width -= 4;
+ left_margin = 2;
+ colors = 1;
+ filters = 0;
+ } else if (!strcmp(model,"DCS660M")) {
+ black = 214;
+ colors = 1;
+ filters = 0;
+ } else if (!strcmp(model,"DCS760M")) {
+ colors = 1;
+ filters = 0;
+ }
+ if (!strcmp(model+4,"20X"))
+ strcpy (cdesc, "MYCY");
+ if (strstr(model,"DC25")) {
+ strcpy (model, "DC25");
+ data_offset = 15424;
+ }
+ if (!strncmp(model,"DC2",3)) {
+ height = 242;
+ if (fsize < 100000) {
+ raw_width = 256; width = 249;
+ pixel_aspect = (4.0*height) / (3.0*width);
+ } else {
+ raw_width = 512; width = 501;
+ pixel_aspect = (493.0*height) / (373.0*width);
+ }
+ data_offset += raw_width + 1;
+ colors = 4;
+ filters = 0x8d8d8d8d;
+ simple_coeff(1);
+ pre_mul[1] = 1.179;
+ pre_mul[2] = 1.209;
+ pre_mul[3] = 1.036;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ load_raw = &CLASS eight_bit_load_raw;
+ } else if (!strcmp(model,"40")) {
+ strcpy (model, "DC40");
+ height = 512;
+ width = 768;
+ data_offset = 1152;
+ load_raw = &CLASS kodak_radc_load_raw;
+ } else if (strstr(model,"DC50")) {
+ strcpy (model, "DC50");
+ height = 512;
+ width = 768;
+ data_offset = 19712;
+ load_raw = &CLASS kodak_radc_load_raw;
+ } else if (strstr(model,"DC120")) {
+ strcpy (model, "DC120");
+ height = 976;
+ width = 848;
+ pixel_aspect = height/0.75/width;
+ load_raw = tiff_compress == 7 ?
+ &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw;
+ } else if (!strcmp(model,"DCS200")) {
+ thumb_height = 128;
+ thumb_width = 192;
+ thumb_offset = 6144;
+ thumb_misc = 360;
+ write_thumb = &CLASS layer_thumb;
+ height = 1024;
+ width = 1536;
+ data_offset = 79872;
+ load_raw = &CLASS eight_bit_load_raw;
+ black = 17;
+ }
+ } else if (!strcmp(model,"Fotoman Pixtura")) {
+ height = 512;
+ width = 768;
+ data_offset = 3632;
+ load_raw = &CLASS kodak_radc_load_raw;
+ filters = 0x61616161;
+ simple_coeff(2);
+ } else if (!strcmp(model,"QuickTake 100")) {
+ fseek (ifp, 544, SEEK_SET);
+ height = get2();
+ width = get2();
+ data_offset = (get4(),get2()) == 30 ? 738:736;
+ if (height > width) {
+ SWAP(height,width);
+ fseek (ifp, data_offset-6, SEEK_SET);
+ flip = ~get2() & 3 ? 5:6;
+ }
+ load_raw = &CLASS quicktake_100_load_raw;
+ filters = 0x61616161;
+ } else if (!strcmp(model,"QuickTake 150")) {
+ data_offset = 738 - head[5];
+ if (head[5]) strcpy (model+10, "200");
+ load_raw = &CLASS kodak_radc_load_raw;
+ height = 480;
+ width = 640;
+ filters = 0x61616161;
+ } else if (!strcmp(make,"Rollei") && !load_raw) {
+ switch (raw_width) {
+ case 1316:
+ height = 1030;
+ width = 1300;
+ top_margin = 1;
+ left_margin = 6;
+ break;
+ case 2568:
+ height = 1960;
+ width = 2560;
+ top_margin = 2;
+ left_margin = 8;
+ }
+ filters = 0x16161616;
+ load_raw = &CLASS rollei_load_raw;
+ pre_mul[0] = 1.8;
+ pre_mul[2] = 1.3;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"PC-CAM 600")) {
+ height = 768;
+ data_offset = width = 1024;
+ filters = 0x49494949;
+ load_raw = &CLASS eight_bit_load_raw;
+ pre_mul[0] = 1.14;
+ pre_mul[2] = 2.73;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"QV-2000UX")) {
+ height = 1208;
+ width = 1632;
+ data_offset = width * 2;
+ load_raw = &CLASS eight_bit_load_raw;
+ } else if (fsize == 3217760) {
+ height = 1546;
+ width = 2070;
+ raw_width = 2080;
+ load_raw = &CLASS eight_bit_load_raw;
+ } else if (!strcmp(model,"QV-4000")) {
+ height = 1700;
+ width = 2260;
+ load_raw = &CLASS unpacked_load_raw;
+ maximum = 0xffff;
+ } else if (!strcmp(model,"QV-5700")) {
+ height = 1924;
+ width = 2576;
+ load_raw = &CLASS casio_qv5700_load_raw;
+ } else if (!strcmp(model,"QV-R41")) {
+ height = 1720;
+ width = 2312;
+ raw_width = 3520;
+ left_margin = 2;
+ } else if (!strcmp(model,"QV-R51")) {
+ height = 1926;
+ width = 2580;
+ raw_width = 3904;
+ pre_mul[0] = 1.340;
+ pre_mul[2] = 1.672;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"EX-S100")) {
+ height = 1544;
+ width = 2058;
+ raw_width = 3136;
+ pre_mul[0] = 1.631;
+ pre_mul[2] = 1.106;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"EX-Z50")) {
+ height = 1931;
+ width = 2570;
+ raw_width = 3904;
+ pre_mul[0] = 2.529;
+ pre_mul[2] = 1.185;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"EX-Z55")) {
+ height = 1960;
+ width = 2570;
+ raw_width = 3904;
+ pre_mul[0] = 1.520;
+ pre_mul[2] = 1.316;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"EX-P505")) {
+ height = 1928;
+ width = 2568;
+ raw_width = 3852;
+ maximum = 0xfff;
+ pre_mul[0] = 2.07;
+ pre_mul[2] = 1.88;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (fsize == 9313536) { /* EX-P600 or QV-R61 */
+ height = 2142;
+ width = 2844;
+ raw_width = 4288;
+ pre_mul[0] = 1.797;
+ pre_mul[2] = 1.219;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ } else if (!strcmp(model,"EX-P700")) {
+ height = 2318;
+ width = 3082;
+ raw_width = 4672;
+ pre_mul[0] = 1.758;
+ pre_mul[2] = 1.504;
+#ifdef LIBRAW_LIBRARY_BUILD
+ color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST;
+#endif
+ }
+ if (!model[0])
+ sprintf (model, "%dx%d", width, height);
+ if (filters == UINT_MAX) filters = 0x94949494;
+ if (raw_color) adobe_coeff (make, model);
+ if (thumb_offset && !thumb_height) {
+ fseek (ifp, thumb_offset, SEEK_SET);
+ if (ljpeg_start (&jh, 1)) {
+ thumb_width = jh.wide;
+ thumb_height = jh.high;
+ }
+ }
+dng_skip:
+ if (!load_raw || height < 22) is_raw = 0;
+#ifdef NO_JPEG
+ if (load_raw == &CLASS kodak_jpeg_load_raw) {
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("%s: You must link dcraw with libjpeg!!\n"), ifname);
+#endif
+ is_raw = 0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_NO_JPEGLIB;
+#endif
+ }
+#endif
+ if (!cdesc[0])
+ strcpy (cdesc, colors == 3 ? "RGB":"GMCY");
+ if (!raw_height) raw_height = height;
+ if (!raw_width ) raw_width = width;
+ if (filters && colors == 3)
+ for (i=0; i < 32; i+=4) {
+ if ((filters >> i & 15) == 9)
+ filters |= 2 << i;
+ if ((filters >> i & 15) == 6)
+ filters |= 8 << i;
+ }
+notraw:
+ if (flip == -1) flip = tiff_flip;
+ if (flip == -1) flip = 0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2);
+#endif
+}
+void CLASS convert_to_rgb()
+{
+ int row, col, c, i, j, k;
+ ushort *img;
+ float out[3], out_cam[3][4];
+ double num, inverse[3][3], bnd[2]={0,0};
+ static const double xyzd50_srgb[3][3] =
+ { { 0.436083, 0.385083, 0.143055 },
+ { 0.222507, 0.716888, 0.060608 },
+ { 0.013930, 0.097097, 0.714022 } };
+ static const double rgb_rgb[3][3] =
+ { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } };
+ static const double adobe_rgb[3][3] =
+ { { 0.715146, 0.284856, 0.000000 },
+ { 0.000000, 1.000000, 0.000000 },
+ { 0.000000, 0.041166, 0.958839 } };
+ static const double wide_rgb[3][3] =
+ { { 0.593087, 0.404710, 0.002206 },
+ { 0.095413, 0.843149, 0.061439 },
+ { 0.011621, 0.069091, 0.919288 } };
+ static const double prophoto_rgb[3][3] =
+ { { 0.529317, 0.330092, 0.140588 },
+ { 0.098368, 0.873465, 0.028169 },
+ { 0.016879, 0.117663, 0.865457 } };
+ static const double (*out_rgb[])[3] =
+ { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb };
+ static const char *name[] =
+ { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" };
+ static const unsigned phead[] =
+ { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0,
+ 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d };
+ unsigned pbody[] =
+ { 10, 0x63707274, 0, 36, /* cprt */
+ 0x64657363, 0, 40, /* desc */
+ 0x77747074, 0, 20, /* wtpt */
+ 0x626b7074, 0, 20, /* bkpt */
+ 0x72545243, 0, 14, /* rTRC */
+ 0x67545243, 0, 14, /* gTRC */
+ 0x62545243, 0, 14, /* bTRC */
+ 0x7258595a, 0, 20, /* rXYZ */
+ 0x6758595a, 0, 20, /* gXYZ */
+ 0x6258595a, 0, 20 }; /* bXYZ */
+ static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc };
+ unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 };
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,0,2);
+#endif
+
+ bnd[gamm[1] >= 1] = 1;
+ if (gamm[1] && (gamm[1]-1)*(gamm[0]-1) <= 0) {
+ for (i=0; i < 36; i++) {
+ gamm[2] = (bnd[0] + bnd[1])/2;
+ bnd[(pow(gamm[2]/gamm[1],-gamm[0])-1)/gamm[0]-1/gamm[2] > -1] = gamm[2];
+ }
+ gamm[3] = gamm[2]*(1/gamm[0]-1);
+ gamm[2] /= gamm[1];
+ }
+ gamm[4] = 1 / (gamm[1]/2*SQR(gamm[2]) - gamm[3]*(1-gamm[2]) +
+ (1-pow(gamm[2],1+gamm[0]))*(1+gamm[3])/(1+gamm[0])) - 1;
+
+ memcpy (out_cam, rgb_cam, sizeof out_cam);
+ raw_color |= colors == 1 || document_mode ||
+ output_color < 1 || output_color > 5;
+ if (!raw_color) {
+ oprof = (unsigned *) calloc (phead[0], 1);
+ merror (oprof, "convert_to_rgb()");
+ memcpy (oprof, phead, sizeof phead);
+ if (output_color == 5) oprof[4] = oprof[5];
+ oprof[0] = 132 + 12*pbody[0];
+ for (i=0; i < pbody[0]; i++) {
+ oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874;
+ pbody[i*3+2] = oprof[0];
+ oprof[0] += (pbody[i*3+3] + 3) & -4;
+ }
+ memcpy (oprof+32, pbody, sizeof pbody);
+ oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1;
+ memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite);
+ if (output_bps == 8 | gamma_16bit)
+ pcurve[3] = (short)(256/gamm[4]+0.5) << 16;
+ for (i=4; i < 7; i++)
+ memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve);
+ pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3);
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++) {
+ for (num = k=0; k < 3; k++)
+ num += xyzd50_srgb[i][k] * inverse[j][k];
+ oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5;
+ }
+ for (i=0; i < phead[0]/4; i++)
+ oprof[i] = htonl(oprof[i]);
+ strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw");
+ strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]);
+ for (i=0; i < 3; i++)
+ for (j=0; j < colors; j++)
+ for (out_cam[i][j] = k=0; k < 3; k++)
+ out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j];
+ }
+#ifdef DCRAW_VERBOSE
+ if (verbose)
+ fprintf (stderr, raw_color ? _("Building histograms...\n") :
+ _("Converting to %s colorspace...\n"), name[output_color-1]);
+
+#endif
+#ifdef LIBRAW_LIBRARY_BUILD
+ memset(histogram,0,sizeof(int)*LIBRAW_HISTOGRAM_SIZE*4);
+#else
+ memset (histogram, 0, sizeof histogram);
+#endif
+ for (img=image[0], row=0; row < height; row++)
+ for (col=0; col < width; col++, img+=4) {
+ if (!raw_color) {
+ out[0] = out[1] = out[2] = 0;
+ FORCC {
+ out[0] += out_cam[0][c] * img[c];
+ out[1] += out_cam[1][c] * img[c];
+ out[2] += out_cam[2][c] * img[c];
+ }
+ FORC3 img[c] = CLIP((int) out[c]);
+ }
+ else if (document_mode)
+ img[0] = img[FC(row,col)];
+ FORCC histogram[c][img[c] >> 3]++;
+ }
+ if (colors == 4 && output_color) colors = 3;
+ if (document_mode && filters) colors = 1;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,1,2);
+#endif
+}
+
+void CLASS fuji_rotate()
+{
+ int i, row, col;
+ double step;
+ float r, c, fr, fc;
+ unsigned ur, uc;
+ ushort wide, high, (*img)[4], (*pix)[4];
+
+ if (!fuji_width) return;
+#ifdef DCRAW_VERBOSE
+ if (verbose)
+ fprintf (stderr,_("Rotating image 45 degrees...\n"));
+#endif
+ fuji_width = (fuji_width - 1 + shrink) >> shrink;
+ step = sqrt(0.5);
+ wide = fuji_width / step;
+ high = (height - fuji_width) / step;
+ img = (ushort (*)[4]) calloc (wide*high, sizeof *img);
+ merror (img, "fuji_rotate()");
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,0,2);
+#endif
+
+ for (row=0; row < high; row++)
+ for (col=0; col < wide; col++) {
+ ur = r = fuji_width + (row-col)*step;
+ uc = c = (row+col)*step;
+ if (ur > height-2 || uc > width-2) continue;
+ fr = r - ur;
+ fc = c - uc;
+ pix = image + ur*width + uc;
+ for (i=0; i < colors; i++)
+ img[row*wide+col][i] =
+ (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) +
+ (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr;
+ }
+ free (image);
+ width = wide;
+ height = high;
+ image = img;
+ fuji_width = 0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,1,2);
+#endif
+}
+
+void CLASS stretch()
+{
+ ushort newdim, (*img)[4], *pix0, *pix1;
+ int row, col, c;
+ double rc, frac;
+
+ if (pixel_aspect == 1) return;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,0,2);
+#endif
+#ifdef DCRAW_VERBOSE
+ if (verbose) fprintf (stderr,_("Stretching the image...\n"));
+#endif
+ if (pixel_aspect < 1) {
+ newdim = height / pixel_aspect + 0.5;
+ img = (ushort (*)[4]) calloc (width*newdim, sizeof *img);
+ merror (img, "stretch()");
+ for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) {
+ frac = rc - (c = rc);
+ pix0 = pix1 = image[c*width];
+ if (c+1 < height) pix1 += width*4;
+ for (col=0; col < width; col++, pix0+=4, pix1+=4)
+ FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5;
+ }
+ height = newdim;
+ } else {
+ newdim = width * pixel_aspect + 0.5;
+ img = (ushort (*)[4]) calloc (height*newdim, sizeof *img);
+ merror (img, "stretch()");
+ for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) {
+ frac = rc - (c = rc);
+ pix0 = pix1 = image[c];
+ if (c+1 < width) pix1 += 4;
+ for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4)
+ FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5;
+ }
+ width = newdim;
+ }
+ free (image);
+ image = img;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,1,2);
+#endif
+}
+
+int CLASS flip_index (int row, int col)
+{
+ if (flip & 4) SWAP(row,col);
+ if (flip & 2) row = iheight - 1 - row;
+ if (flip & 1) col = iwidth - 1 - col;
+ return row * iwidth + col;
+}
+
+void CLASS gamma_lut (ushort lut[0x10000])
+{
+ int perc, c, val, total, i;
+ float t_white=0, r;
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ perc = width * height * imgdata.params.auto_bright_thr;
+#else
+ perc = width * height * 0.01; /* 99th percentile white level */
+#endif
+ if (fuji_width) perc /= 2;
+ if ((highlight & ~2) || no_auto_bright) perc = -1;
+ FORCC {
+ for (val=0x2000, total=0; --val > 32; )
+ if ((total += histogram[c][val]) > perc) break;
+ if (t_white < val) t_white = val;
+ }
+ t_white *= 8 / bright;
+ for (i=0; i < 0x10000; i++) {
+ r = i / t_white;
+ val = 65535 * ( !use_gamma ? r :
+ r <= gamm[2] ? r*gamm[1] : pow((double)r,gamm[0])*(1+gamm[3])-gamm[3]);
+ if (val > 65535) val = 65535;
+ lut[i] = val;
+ }
+}
+
+
+void CLASS tiff_set (ushort *ntag,
+ ushort tag, ushort type, int count, int val)
+{
+ struct tiff_tag *tt;
+ int c;
+
+ tt = (struct tiff_tag *)(ntag+1) + (*ntag)++;
+ tt->tag = tag;
+ tt->type = type;
+ tt->count = count;
+ if (type < 3 && count <= 4)
+ FORC(4) tt->val.c[c] = val >> (c << 3);
+ else if (type == 3 && count <= 2)
+ FORC(2) tt->val.s[c] = val >> (c << 4);
+ else tt->val.i = val;
+}
+
+#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th)
+
+void CLASS tiff_head (struct tiff_hdr *th, int full)
+{
+ int c, psize=0;
+ struct tm *t;
+
+ memset (th, 0, sizeof *th);
+ th->t_order = htonl(0x4d4d4949) >> 16;
+ th->magic = 42;
+ th->ifd = 10;
+ if (full) {
+ tiff_set (&th->ntag, 254, 4, 1, 0);
+ tiff_set (&th->ntag, 256, 4, 1, width);
+ tiff_set (&th->ntag, 257, 4, 1, height);
+ tiff_set (&th->ntag, 258, 3, colors, output_bps);
+ if (colors > 2)
+ th->tag[th->ntag-1].val.i = TOFF(th->bps);
+ FORC4 th->bps[c] = output_bps;
+ tiff_set (&th->ntag, 259, 3, 1, 1);
+ tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1));
+ }
+ tiff_set (&th->ntag, 270, 2, 512, TOFF(th->t_desc));
+ tiff_set (&th->ntag, 271, 2, 64, TOFF(th->t_make));
+ tiff_set (&th->ntag, 272, 2, 64, TOFF(th->t_model));
+ if (full) {
+ if (oprof) psize = ntohl(oprof[0]);
+ tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize);
+ tiff_set (&th->ntag, 277, 3, 1, colors);
+ tiff_set (&th->ntag, 278, 4, 1, height);
+ tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8);
+ } else
+ tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0');
+ tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0]));
+ tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2]));
+ tiff_set (&th->ntag, 284, 3, 1, 1);
+ tiff_set (&th->ntag, 296, 3, 1, 2);
+ tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft));
+ tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date));
+ tiff_set (&th->ntag, 315, 2, 64, TOFF(th->t_artist));
+ tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif));
+ if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th);
+ tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4]));
+ tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6]));
+ tiff_set (&th->nexif, 34855, 3, 1, iso_speed);
+ tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8]));
+ if (gpsdata[1]) {
+ tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps));
+ tiff_set (&th->ngps, 0, 1, 4, 0x202);
+ tiff_set (&th->ngps, 1, 2, 2, gpsdata[29]);
+ tiff_set (&th->ngps, 2, 5, 3, TOFF(th->gps[0]));
+ tiff_set (&th->ngps, 3, 2, 2, gpsdata[30]);
+ tiff_set (&th->ngps, 4, 5, 3, TOFF(th->gps[6]));
+ tiff_set (&th->ngps, 5, 1, 1, gpsdata[31]);
+ tiff_set (&th->ngps, 6, 5, 1, TOFF(th->gps[18]));
+ tiff_set (&th->ngps, 7, 5, 3, TOFF(th->gps[12]));
+ tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20]));
+ tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23]));
+ memcpy (th->gps, gpsdata, sizeof th->gps);
+ }
+ th->rat[0] = th->rat[2] = 300;
+ th->rat[1] = th->rat[3] = 1;
+ FORC(6) th->rat[4+c] = 1000000;
+ th->rat[4] *= shutter;
+ th->rat[6] *= aperture;
+ th->rat[8] *= focal_len;
+ strncpy (th->t_desc, desc, 512);
+ strncpy (th->t_make, make, 64);
+ strncpy (th->t_model, model, 64);
+ strcpy (th->soft, "dcraw v"VERSION);
+ t = gmtime (&timestamp);
+ sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d",
+ t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
+ strncpy (th->t_artist, artist, 64);
+}
+
+void CLASS jpeg_thumb_writer (FILE *tfp,char *t_humb,int t_humb_length)
+{
+ ushort exif[5];
+ struct tiff_hdr th;
+ fputc (0xff, tfp);
+ fputc (0xd8, tfp);
+ if (strcmp (t_humb+6, "Exif")) {
+ memcpy (exif, "\xff\xe1 Exif\0\0", 10);
+ exif[1] = htons (8 + sizeof th);
+ fwrite (exif, 1, sizeof exif, tfp);
+ tiff_head (&th, 0);
+ fwrite (&th, 1, sizeof th, tfp);
+ }
+ fwrite (t_humb+2, 1, t_humb_length-2, tfp);
+}
+
+
+void CLASS jpeg_thumb (FILE *tfp)
+{
+ char *thumb;
+ ushort exif[5];
+ struct tiff_hdr th;
+
+ thumb = (char *) malloc (thumb_length);
+ merror (thumb, "jpeg_thumb()");
+ fread (thumb, 1, thumb_length, ifp);
+#if 0
+ fputc (0xff, tfp);
+ fputc (0xd8, tfp);
+ if (strcmp (thumb+6, "Exif")) {
+ memcpy (exif, "\xff\xe1 Exif\0\0", 10);
+ exif[1] = htons (8 + sizeof th);
+ fwrite (exif, 1, sizeof exif, tfp);
+ tiff_head (&th, 0);
+ fwrite (&th, 1, sizeof th, tfp);
+ }
+ fwrite (thumb+2, 1, thumb_length-2, tfp);
+#else
+ jpeg_thumb_writer(tfp,thumb,thumb_length);
+#endif
+ free (thumb);
+}
+
+void CLASS write_ppm_tiff (FILE *ofp)
+{
+ struct tiff_hdr th;
+ uchar *ppm;
+ ushort *ppm2,lut16[0x10000];
+ int c, row, col, soff, rstep, cstep;
+
+ iheight = height;
+ iwidth = width;
+ if (flip & 4) SWAP(height,width);
+ ppm = (uchar *) calloc (width, colors*output_bps/8);
+ ppm2 = (ushort *) ppm;
+ merror (ppm, "write_ppm_tiff()");
+ if (output_tiff) {
+ tiff_head (&th, 1);
+ fwrite (&th, sizeof th, 1, ofp);
+ if (oprof)
+ fwrite (oprof, ntohl(oprof[0]), 1, ofp);
+ } else if (colors > 3)
+ fprintf (ofp,
+ "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n",
+ width, height, colors, (1 << output_bps)-1, cdesc);
+ else
+ fprintf (ofp, "P%d\n%d %d\n%d\n",
+ colors/2+5, width, height, (1 << output_bps)-1);
+
+ if (output_bps == 8 || gamma_16bit ) gamma_lut (lut16);
+
+ soff = flip_index (0, 0);
+ cstep = flip_index (0, 1) - soff;
+ rstep = flip_index (1, 0) - flip_index (0, width);
+ for (row=0; row < height; row++, soff += rstep) {
+ for (col=0; col < width; col++, soff += cstep)
+ if (output_bps == 8)
+ FORCC ppm [col*colors+c] = lut16[image[soff][c]]/256;
+ else if(gamma_16bit) FORCC ppm2[col*colors+c] = lut16[image[soff][c]];
+ else FORCC ppm2[col*colors+c] = image[soff][c];
+ if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa)
+ swab ((char*)ppm2, (char*)ppm2, width*colors*2);
+ fwrite (ppm, colors*output_bps/8, width, ofp);
+ }
+ free (ppm);
+}
diff --git a/libkdcraw/libraw/internal/dcraw_fileio.cpp b/libkdcraw/libraw/internal/dcraw_fileio.cpp
new file mode 100644
index 0000000..926009a
--- /dev/null
+++ b/libkdcraw/libraw/internal/dcraw_fileio.cpp
@@ -0,0 +1,211 @@
+/*
+ GENERATED FILE, DO NOT EDIT
+ Generated from dcraw/dcraw.c at Tue Apr 7 15:14:50 2009
+ Look into original file (probably http://cybercom.net/~dcoffin/dcraw/dcraw.c)
+ for copyright information.
+*/
+
+#define CLASS LibRaw::
+#include "libraw/libraw_types.h"
+#define LIBRAW_LIBRARY_BUILD
+#include "libraw/libraw.h"
+#include "internal/defines.h"
+#include "internal/var_defines.h"
+
+/*
+ Seach from the current directory up to the root looking for
+ a ".badpixels" file, and fix those pixels now.
+ */
+void CLASS bad_pixels (char *fname)
+{
+ FILE *fp=0;
+ char *cp, line[128];
+ int len, time, row, col, r, c, rad, tot, n, fixed=0;
+
+ if (!filters) return;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,0,2);
+#endif
+ if (fname)
+ fp = fopen (fname, "r");
+ if (!fp)
+ {
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_NO_BADPIXELMAP;
+#endif
+ return;
+ }
+ while (fgets (line, 128, fp)) {
+ cp = strchr (line, '#');
+ if (cp) *cp = 0;
+ if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue;
+ if ((unsigned) col >= width || (unsigned) row >= height) continue;
+ if (time > timestamp) continue;
+ for (tot=n=0, rad=1; rad < 3 && n==0; rad++)
+ for (r = row-rad; r <= row+rad; r++)
+ for (c = col-rad; c <= col+rad; c++)
+ if ((unsigned) r < height && (unsigned) c < width &&
+ (r != row || c != col) && fc(r,c) == fc(row,col)) {
+ tot += BAYER2(r,c);
+ n++;
+ }
+ BAYER2(row,col) = tot/n;
+#ifdef DCRAW_VERBOSE
+ if (verbose) {
+ if (!fixed++)
+ fprintf (stderr,_("Fixed dead pixels at:"));
+ fprintf (stderr, " %d,%d", col, row);
+ }
+#endif
+ }
+#ifdef DCRAW_VERBOSE
+ if (fixed) fputc ('\n', stderr);
+#endif
+ fclose (fp);
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,1,2);
+#endif
+}
+
+void CLASS subtract (char *fname)
+{
+ FILE *fp;
+ int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col;
+ ushort *pixel;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,0,2);
+#endif
+
+ if (!(fp = fopen (fname, "rb"))) {
+#ifdef DCRAW_VERBOSE
+ perror (fname);
+#endif
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_FILE;
+#endif
+ return;
+ }
+ if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1;
+ while (!error && nd < 3 && (c = fgetc(fp)) != EOF) {
+ if (c == '#') comment = 1;
+ if (c == '\n') comment = 0;
+ if (comment) continue;
+ if (isdigit(c)) number = 1;
+ if (number) {
+ if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0';
+ else if (isspace(c)) {
+ number = 0; nd++;
+ } else error = 1;
+ }
+ }
+ if (error || nd < 3) {
+ fprintf (stderr,_("%s is not a valid PGM file!\n"), fname);
+ fclose (fp); return;
+ } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) {
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("%s has the wrong dimensions!\n"), fname);
+#endif
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_DIM;
+#endif
+ fclose (fp); return;
+ }
+ pixel = (ushort *) calloc (width, sizeof *pixel);
+ merror (pixel, "subtract()");
+ for (row=0; row < height; row++) {
+ fread (pixel, 2, width, fp);
+ for (col=0; col < width; col++)
+ BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0);
+ }
+ free (pixel);
+ black = 0;
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,1,2);
+#endif
+}
+
+#ifndef NO_LCMS
+void CLASS apply_profile (char *input, char *output)
+{
+ char *prof;
+ cmsHPROFILE hInProfile=0, hOutProfile=0;
+ cmsHTRANSFORM hTransform;
+ FILE *fp;
+ unsigned size;
+
+ cmsErrorAction (LCMS_ERROR_SHOW);
+ if (strcmp (input, "embed"))
+ hInProfile = cmsOpenProfileFromFile (input, "r");
+ else if (profile_length) {
+#ifndef LIBRAW_LIBRARY_BUILD
+ prof = (char *) malloc (profile_length);
+ merror (prof, "apply_profile()");
+ fseek (ifp, profile_offset, SEEK_SET);
+ fread (prof, 1, profile_length, ifp);
+ hInProfile = cmsOpenProfileFromMem (prof, profile_length);
+ free (prof);
+#else
+ hInProfile = cmsOpenProfileFromMem (imgdata.color.profile, profile_length);
+#endif
+ } else
+ {
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_NO_EMBEDDED_PROFILE;
+#endif
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("%s has no embedded profile.\n"), ifname);
+#endif
+ }
+ if (!hInProfile)
+ {
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_NO_INPUT_PROFILE;
+#endif
+ return;
+ }
+ if (!output)
+ hOutProfile = cmsCreate_sRGBProfile();
+ else if ((fp = fopen (output, "rb"))) {
+ fread (&size, 4, 1, fp);
+ fseek (fp, 0, SEEK_SET);
+ oprof = (unsigned *) malloc (size = ntohl(size));
+ merror (oprof, "apply_profile()");
+ fread (oprof, 1, size, fp);
+ fclose (fp);
+ if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) {
+ free (oprof);
+ oprof = 0;
+ }
+#ifdef DCRAW_VERBOSE
+ } else
+ fprintf (stderr,_("Cannot open file %s!\n"), output);
+#else
+}
+#endif
+ if (!hOutProfile)
+ {
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_BAD_OUTPUT_PROFILE;
+#endif
+ goto quit;
+ }
+#ifdef DCRAW_VERBOSE
+ if (verbose)
+ fprintf (stderr,_("Applying color profile...\n"));
+#endif
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,0,2);
+#endif
+ hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16,
+ hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0);
+ cmsDoTransform (hTransform, image, image, width*height);
+ raw_color = 1; /* Don't use rgb_cam with a profile */
+ cmsDeleteTransform (hTransform);
+ cmsCloseProfile (hOutProfile);
+quit:
+ cmsCloseProfile (hInProfile);
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,1,2);
+#endif
+}
+#endif
diff --git a/libkdcraw/libraw/internal/defines.h b/libkdcraw/libraw/internal/defines.h
new file mode 100644
index 0000000..ca5038e
--- /dev/null
+++ b/libkdcraw/libraw/internal/defines.h
@@ -0,0 +1,129 @@
+/*
+ GENERATED FILE, DO NOT EDIT
+ Generated from dcraw/dcraw.c at Tue Apr 7 15:14:48 2009
+ Look into original file (probably http://cybercom.net/~dcoffin/dcraw/dcraw.c)
+ for copyright information.
+*/
+
+#define NO_JPEG
+#define VERSION "8.93"
+
+#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>
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+/*
+ 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 __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 strnicmp
+typedef __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 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 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)]
diff --git a/libkdcraw/libraw/internal/foveon.cpp b/libkdcraw/libraw/internal/foveon.cpp
new file mode 100644
index 0000000..6080bb8
--- /dev/null
+++ b/libkdcraw/libraw/internal/foveon.cpp
@@ -0,0 +1,812 @@
+/*
+ GENERATED FILE, DO NOT EDIT
+ Generated from dcraw/dcraw.c at Tue Apr 7 15:14:48 2009
+ Look into original file (probably http://cybercom.net/~dcoffin/dcraw/dcraw.c)
+ for copyright information.
+*/
+
+#define CLASS LibRaw::
+#include "libraw/libraw_types.h"
+#define LIBRAW_IO_REDEFINED
+#define LIBRAW_LIBRARY_BUILD
+#include "libraw/libraw.h"
+#include "internal/defines.h"
+#define SRC_USES_SHRINK
+#define SRC_USES_BLACK
+#define SRC_USES_CURVE
+#include "internal/var_defines.h"
+#define sget4(s) sget4((uchar *)s)
+
+/* RESTRICTED code starts here */
+
+void CLASS foveon_decoder (unsigned size, unsigned code)
+{
+#ifndef LIBRAW_NOTHREADS
+#define huff tls->foveon_decoder_huff
+#else
+ static unsigned huff[1024];
+#endif
+ struct decode *cur;
+ int i, len;
+
+ if (!code) {
+ for (i=0; i < size; i++)
+ huff[i] = get4();
+ init_decoder();
+ }
+ cur = free_decode++;
+ if (free_decode > first_decode+2048) {
+#ifdef LIBRAW_LIBRARY_BUILD
+ throw LIBRAW_EXCEPTION_DECODE_RAW;
+#else
+ fprintf (stderr,_("%s: decoder table overflow\n"), ifname);
+ longjmp (failure, 2);
+#endif
+ }
+ if (code)
+ for (i=0; i < size; i++)
+ if (huff[i] == code) {
+ cur->leaf = i;
+ return;
+ }
+ if ((len = code >> 27) > 26) return;
+ code = (len+1) << 27 | (code & 0x3ffffff) << 1;
+
+ cur->branch[0] = free_decode;
+ foveon_decoder (size, code);
+ cur->branch[1] = free_decode;
+ foveon_decoder (size, code+1);
+#ifndef LIBRAW_NOTHREADS
+#undef huff
+#endif
+}
+
+void CLASS foveon_thumb (FILE *tfp)
+{
+ unsigned bwide, row, col, bitbuf=0, bit=1, c, i;
+ char *buf;
+ struct decode *dindex;
+ short pred[3];
+
+ bwide = get4();
+ fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height);
+ if (bwide > 0) {
+ if (bwide < thumb_width*3) return;
+ buf = (char *) malloc (bwide);
+ merror (buf, "foveon_thumb()");
+ for (row=0; row < thumb_height; row++) {
+ fread (buf, 1, bwide, ifp);
+ fwrite (buf, 3, thumb_width, tfp);
+ }
+ free (buf);
+ return;
+ }
+ foveon_decoder (256, 0);
+
+ for (row=0; row < thumb_height; row++) {
+ memset (pred, 0, sizeof pred);
+ if (!bit) get4();
+ for (bit=col=0; col < thumb_width; col++)
+ FORC3 {
+ for (dindex=first_decode; dindex->branch[0]; ) {
+ if ((bit = (bit-1) & 31) == 31)
+ for (i=0; i < 4; i++)
+ bitbuf = (bitbuf << 8) + fgetc(ifp);
+ dindex = dindex->branch[bitbuf >> bit & 1];
+ }
+ pred[c] += dindex->leaf;
+ fputc (pred[c], tfp);
+ }
+ }
+}
+
+void CLASS foveon_load_camf()
+{
+ unsigned key, i, val;
+
+ fseek (ifp, meta_offset, SEEK_SET);
+ key = get4();
+ fread (meta_data, 1, meta_length, ifp);
+ for (i=0; i < meta_length; i++) {
+ key = (key * 1597 + 51749) % 244944;
+ val = key * (INT64) 301593171 >> 24;
+ meta_data[i] ^= ((((key << 8) - val) >> 1) + val) >> 17;
+ }
+}
+
+void CLASS foveon_load_raw()
+{
+ struct decode *dindex;
+ short diff[1024];
+ unsigned bitbuf=0;
+ int pred[3], fixed, row, col, bit=-1, c, i;
+
+ fixed = get4();
+ read_shorts ((ushort *) diff, 1024);
+ if (!fixed) foveon_decoder (1024, 0);
+
+ for (row=0; row < height; row++) {
+ memset (pred, 0, sizeof pred);
+ if (!bit && !fixed && atoi(model+2) < 14) get4();
+ for (col=bit=0; col < width; col++) {
+ if (fixed) {
+ bitbuf = get4();
+ FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff];
+ }
+ else FORC3 {
+ for (dindex=first_decode; dindex->branch[0]; ) {
+ if ((bit = (bit-1) & 31) == 31)
+ for (i=0; i < 4; i++)
+ bitbuf = (bitbuf << 8) + fgetc(ifp);
+ dindex = dindex->branch[bitbuf >> bit & 1];
+ }
+ pred[c] += diff[dindex->leaf];
+ if (pred[c] >> 16 && ~pred[c] >> 16) derror();
+ }
+ FORC3 image[row*width+col][c] = pred[c];
+ }
+ }
+ if (document_mode)
+ for (i=0; i < height*width*4; i++)
+ if ((short) image[0][i] < 0) image[0][i] = 0;
+ foveon_load_camf();
+}
+
+const char * CLASS foveon_camf_param (const char *block, const char *param)
+{
+ unsigned idx, num;
+ char *pos, *cp, *dp;
+
+ for (idx=0; idx < meta_length; idx += sget4(pos+8)) {
+ pos = meta_data + idx;
+ if (strncmp (pos, "CMb", 3)) break;
+ if (pos[3] != 'P') continue;
+ if (strcmp (block, pos+sget4(pos+12))) continue;
+ cp = pos + sget4(pos+16);
+ num = sget4(cp);
+ dp = pos + sget4(cp+4);
+ while (num--) {
+ cp += 8;
+ if (!strcmp (param, dp+sget4(cp)))
+ return dp+sget4(cp+4);
+ }
+ }
+ return 0;
+}
+
+void * CLASS foveon_camf_matrix (unsigned dim[3], const char *name)
+{
+ unsigned i, idx, type, ndim, size, *mat;
+ char *pos, *cp, *dp;
+ double dsize;
+
+ for (idx=0; idx < meta_length; idx += sget4(pos+8)) {
+ pos = meta_data + idx;
+ if (strncmp (pos, "CMb", 3)) break;
+ if (pos[3] != 'M') continue;
+ if (strcmp (name, pos+sget4(pos+12))) continue;
+ dim[0] = dim[1] = dim[2] = 1;
+ cp = pos + sget4(pos+16);
+ type = sget4(cp);
+ if ((ndim = sget4(cp+4)) > 3) break;
+ dp = pos + sget4(cp+8);
+ for (i=ndim; i--; ) {
+ cp += 12;
+ dim[i] = sget4(cp);
+ }
+ if ((dsize = (double) dim[0]*dim[1]*dim[2]) > meta_length/4) break;
+ mat = (unsigned *) malloc ((size = dsize) * 4);
+ merror (mat, "foveon_camf_matrix()");
+ for (i=0; i < size; i++)
+ if (type && type != 6)
+ mat[i] = sget4(dp + i*4);
+ else
+ mat[i] = sget4(dp + i*2) & 0xffff;
+ return mat;
+ }
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_FOVEON_NOMATRIX;
+#endif
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("%s: \"%s\" matrix not found!\n"), ifname, name);
+#endif
+ return 0;
+}
+
+int CLASS foveon_fixed (void *ptr, int size, const char *name)
+{
+ void *dp;
+ unsigned dim[3];
+
+ dp = foveon_camf_matrix (dim, name);
+ if (!dp) return 0;
+ memcpy (ptr, dp, size*4);
+ free (dp);
+ return 1;
+}
+
+float CLASS foveon_avg (short *pix, int range[2], float cfilt)
+{
+ int i;
+ float val, min=FLT_MAX, max=-FLT_MAX, sum=0;
+
+ for (i=range[0]; i <= range[1]; i++) {
+ sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt;
+ if (min > val) min = val;
+ if (max < val) max = val;
+ }
+ if (range[1] - range[0] == 1) return sum/2;
+ return (sum - min - max) / (range[1] - range[0] - 1);
+}
+
+short * CLASS foveon_make_curve (double max, double mul, double filt)
+{
+ short *curve;
+ unsigned i, size;
+ double x;
+
+ if (!filt) filt = 0.8;
+ size = 4*M_PI*max / filt;
+ if (size == UINT_MAX) size--;
+ curve = (short *) calloc (size+1, sizeof *curve);
+ merror (curve, "foveon_make_curve()");
+ curve[0] = size;
+ for (i=0; i < size; i++) {
+ x = i*filt/max/4;
+ curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5;
+ }
+ return curve;
+}
+
+void CLASS foveon_make_curves
+ (short **curvep, float dq[3], float div[3], float filt)
+{
+ double mul[3], max=0;
+ int c;
+
+ FORC3 mul[c] = dq[c]/div[c];
+ FORC3 if (max < mul[c]) max = mul[c];
+ FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt);
+}
+
+int CLASS foveon_apply_curve (short *curve, int i)
+{
+ if (abs(i) >= curve[0]) return 0;
+ return i < 0 ? -curve[1-i] : curve[1+i];
+}
+
+#ifdef image
+#undef image
+#endif
+#define image ((short(*)[4]) imgdata.image)
+
+void CLASS foveon_interpolate()
+{
+ static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 };
+ short *pix, prev[3], *curve[8], (*shrink)[3];
+ float cfilt=0, ddft[3][3][2], ppm[3][3][3];
+ float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3];
+ float chroma_dq[3], color_dq[3], diag[3][3], div[3];
+ float (*black)[3], (*sgain)[3], (*sgrow)[3];
+ float fsum[3], val, frow, num;
+ int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit;
+ int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3];
+ int work[3][3], smlast, smred, smred_p=0, dev[3];
+ int satlev[3], keep[4], active[4];
+ unsigned dim[3], *badpix;
+ double dsum=0, trsum[3];
+ char str[128];
+ const char* cp;
+
+
+#ifdef DCRAW_VERBOSE
+ if (verbose)
+ fprintf(stderr,_("Foveon interpolation...\n"));
+#endif
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,0,9);
+#endif
+
+ foveon_fixed (dscr, 4, "DarkShieldColRange");
+ foveon_fixed (ppm[0][0], 27, "PostPolyMatrix");
+ foveon_fixed (satlev, 3, "SaturationLevel");
+ foveon_fixed (keep, 4, "KeepImageArea");
+ foveon_fixed (active, 4, "ActiveImageArea");
+ foveon_fixed (chroma_dq, 3, "ChromaDQ");
+ foveon_fixed (color_dq, 3,
+ foveon_camf_param ("IncludeBlocks", "ColorDQ") ?
+ "ColorDQ" : "ColorDQCamRGB");
+ if (foveon_camf_param ("IncludeBlocks", "ColumnFilter"))
+ foveon_fixed (&cfilt, 1, "ColumnFilter");
+
+ memset (ddft, 0, sizeof ddft);
+ if (!foveon_camf_param ("IncludeBlocks", "DarkDrift")
+ || !foveon_fixed (ddft[1][0], 12, "DarkDrift"))
+ for (i=0; i < 2; i++) {
+ foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop");
+ for (row = dstb[1]; row <= dstb[3]; row++)
+ for (col = dstb[0]; col <= dstb[2]; col++)
+ FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c];
+ FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1);
+ }
+
+ if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2)))
+ {
+#ifdef DCRAW_VERBOSE
+ fprintf (stderr,_("%s: Invalid white balance \"%s\"\n"), ifname, model2);
+#endif
+#ifdef LIBRAW_LIBRARY_BUILD
+ imgdata.process_warnings |= LIBRAW_WARN_FOVEON_INVALIDWB;
+#endif
+ return;
+ }
+ foveon_fixed (cam_xyz, 9, cp);
+ foveon_fixed (correct, 9,
+ foveon_camf_param ("WhiteBalanceCorrections", model2));
+ memset (last, 0, sizeof last);
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j];
+
+ #define LAST(x,y) last[(i+x)%3][(c+y)%3]
+ for (i=0; i < 3; i++)
+ FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1);
+ #undef LAST
+ FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583;
+ sprintf (str, "%sRGBNeutral", model2);
+ if (foveon_camf_param ("IncludeBlocks", str))
+ foveon_fixed (div, 3, str);
+ num = 0;
+ FORC3 if (num < div[c]) num = div[c];
+ FORC3 div[c] /= num;
+
+ memset (trans, 0, sizeof trans);
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j];
+ FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2];
+ dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20;
+ for (i=0; i < 3; i++)
+ FORC3 last[i][c] = trans[i][c] * dsum / trsum[i];
+ memset (trans, 0, sizeof trans);
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30;
+
+ foveon_make_curves (curve, color_dq, div, cfilt);
+ FORC3 chroma_dq[c] /= 3;
+ foveon_make_curves (curve+3, chroma_dq, div, cfilt);
+ FORC3 dsum += chroma_dq[c] / div[c];
+ curve[6] = foveon_make_curve (dsum, dsum, cfilt);
+ curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt);
+
+ sgain = (float (*)[3]) foveon_camf_matrix (dim, "SpatialGain");
+ if (!sgain) return;
+ sgrow = (float (*)[3]) calloc (dim[1], sizeof *sgrow);
+ sgx = (width + dim[1]-2) / (dim[1]-1);
+
+ black = (float (*)[3]) calloc (height, sizeof *black);
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,1,9);
+#endif
+ for (row=0; row < height; row++) {
+ for (i=0; i < 6; i++)
+ ddft[0][0][i] = ddft[1][0][i] +
+ row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+ FORC3 black[row][c] =
+ ( foveon_avg (image[row*width]+c, dscr[0], cfilt) +
+ foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3
+ - ddft[0][c][0] ) / 4 - ddft[0][c][1];
+ }
+ memcpy (black, black+8, sizeof *black*8);
+ memcpy (black+height-11, black+height-22, 11*sizeof *black);
+ memcpy (last, black, sizeof last);
+
+ for (row=1; row < height-1; row++) {
+ FORC3 if (last[1][c] > last[0][c]) {
+ if (last[1][c] > last[2][c])
+ black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c];
+ } else
+ if (last[1][c] < last[2][c])
+ black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c];
+ memmove (last, last+1, 2*sizeof last[0]);
+ memcpy (last[2], black[row+1], sizeof last[2]);
+ }
+ FORC3 black[row][c] = (last[0][c] + last[1][c])/2;
+ FORC3 black[0][c] = (black[1][c] + black[3][c])/2;
+
+ val = 1 - exp(-1/24.0);
+ memcpy (fsum, black, sizeof fsum);
+ for (row=1; row < height; row++)
+ FORC3 fsum[c] += black[row][c] =
+ (black[row][c] - black[row-1][c])*val + black[row-1][c];
+ memcpy (last[0], black[height-1], sizeof last[0]);
+ FORC3 fsum[c] /= height;
+ for (row = height; row--; )
+ FORC3 last[0][c] = black[row][c] =
+ (black[row][c] - fsum[c] - last[0][c])*val + last[0][c];
+
+ memset (total, 0, sizeof total);
+ for (row=2; row < height; row+=4)
+ for (col=2; col < width; col+=4) {
+ FORC3 total[c] += (short) image[row*width+col][c];
+ total[3]++;
+ }
+ for (row=0; row < height; row++)
+ FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0);
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,2,9);
+#endif
+ for (row=0; row < height; row++) {
+ for (i=0; i < 6; i++)
+ ddft[0][0][i] = ddft[1][0][i] +
+ row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+ pix = image[row*width];
+ memcpy (prev, pix, sizeof prev);
+ frow = row / (height-1.0) * (dim[2]-1);
+ if ((irow = frow) == dim[2]-1) irow--;
+ frow -= irow;
+ for (i=0; i < dim[1]; i++)
+ FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) +
+ sgain[(irow+1)*dim[1]+i][c] * frow;
+ for (col=0; col < width; col++) {
+ FORC3 {
+ diff = pix[c] - prev[c];
+ prev[c] = pix[c];
+ ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt
+ - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5)
+ - black[row][c] );
+ }
+ FORC3 {
+ work[0][c] = ipix[c] * ipix[c] >> 14;
+ work[2][c] = ipix[c] * work[0][c] >> 14;
+ work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14;
+ }
+ FORC3 {
+ for (val=i=0; i < 3; i++)
+ for ( j=0; j < 3; j++)
+ val += ppm[c][i][j] * work[i][j];
+ ipix[c] = floor ((ipix[c] + floor(val)) *
+ ( sgrow[col/sgx ][c] * (sgx - col%sgx) +
+ sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]);
+ if (ipix[c] > 32000) ipix[c] = 32000;
+ pix[c] = ipix[c];
+ }
+ pix += 4;
+ }
+ }
+ free (black);
+ free (sgrow);
+ free (sgain);
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,3,9);
+#endif
+ if ((badpix = (unsigned int *) foveon_camf_matrix (dim, "BadPixels"))) {
+ for (i=0; i < dim[0]; i++) {
+ col = (badpix[i] >> 8 & 0xfff) - keep[0];
+ row = (badpix[i] >> 20 ) - keep[1];
+ if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3)
+ continue;
+ memset (fsum, 0, sizeof fsum);
+ for (sum=j=0; j < 8; j++)
+ if (badpix[i] & (1 << j)) {
+ FORC3 fsum[c] += (short)
+ image[(row+hood[j*2])*width+col+hood[j*2+1]][c];
+ sum++;
+ }
+ if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum;
+ }
+ free (badpix);
+ }
+
+ /* Array for 5x5 Gaussian averaging of red values */
+ smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow);
+ merror (smrow[6], "foveon_interpolate()");
+ for (i=0; i < 5; i++)
+ smrow[i] = smrow[6] + i*width;
+
+ /* Sharpen the reds against these Gaussian averages */
+ for (smlast=-1, row=2; row < height-2; row++) {
+ while (smlast < row+2) {
+ for (i=0; i < 6; i++)
+ smrow[(i+5) % 6] = smrow[i];
+ pix = image[++smlast*width+2];
+ for (col=2; col < width-2; col++) {
+ smrow[4][col][0] =
+ (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4;
+ pix += 4;
+ }
+ }
+ pix = image[row*width+2];
+ for (col=2; col < width-2; col++) {
+ smred = ( 6 * smrow[2][col][0]
+ + 4 * (smrow[1][col][0] + smrow[3][col][0])
+ + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4;
+ if (col == 2)
+ smred_p = smred;
+ i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3);
+ if (i > 32000) i = 32000;
+ pix[0] = i;
+ smred_p = smred;
+ pix += 4;
+ }
+ }
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,4,9);
+#endif
+ /* Adjust the brighter pixels for better linearity */
+ min = 0xffff;
+ FORC3 {
+ i = satlev[c] / div[c];
+ if (min > i) min = i;
+ }
+ limit = min * 9 >> 4;
+ for (pix=image[0]; pix < image[height*width]; pix+=4) {
+ if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit)
+ continue;
+ min = max = pix[0];
+ for (c=1; c < 3; c++) {
+ if (min > pix[c]) min = pix[c];
+ if (max < pix[c]) max = pix[c];
+ }
+ if (min >= limit*2) {
+ pix[0] = pix[1] = pix[2] = max;
+ } else {
+ i = 0x4000 - ((min - limit) << 14) / limit;
+ i = 0x4000 - (i*i >> 14);
+ i = i*i >> 14;
+ FORC3 pix[c] += (max - pix[c]) * i >> 14;
+ }
+ }
+/*
+ Because photons that miss one detector often hit another,
+ the sum R+G+B is much less noisy than the individual colors.
+ So smooth the hues without smoothing the total.
+ */
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,5,9);
+#endif
+ for (smlast=-1, row=2; row < height-2; row++) {
+ while (smlast < row+2) {
+ for (i=0; i < 6; i++)
+ smrow[(i+5) % 6] = smrow[i];
+ pix = image[++smlast*width+2];
+ for (col=2; col < width-2; col++) {
+ FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2;
+ pix += 4;
+ }
+ }
+ pix = image[row*width+2];
+ for (col=2; col < width-2; col++) {
+ FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] -
+ ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2));
+ sum = (dev[0] + dev[1] + dev[2]) >> 3;
+ FORC3 pix[c] += dev[c] - sum;
+ pix += 4;
+ }
+ }
+ for (smlast=-1, row=2; row < height-2; row++) {
+ while (smlast < row+2) {
+ for (i=0; i < 6; i++)
+ smrow[(i+5) % 6] = smrow[i];
+ pix = image[++smlast*width+2];
+ for (col=2; col < width-2; col++) {
+ FORC3 smrow[4][col][c] =
+ (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2;
+ pix += 4;
+ }
+ }
+ pix = image[row*width+2];
+ for (col=2; col < width-2; col++) {
+ for (total[3]=375, sum=60, c=0; c < 3; c++) {
+ for (total[c]=i=0; i < 5; i++)
+ total[c] += smrow[i][col][c];
+ total[3] += total[c];
+ sum += pix[c];
+ }
+ if (sum < 0) sum = 0;
+ j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174;
+ FORC3 pix[c] += foveon_apply_curve (curve[6],
+ ((j*total[c] + 0x8000) >> 16) - pix[c]);
+ pix += 4;
+ }
+ }
+
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,6,9);
+#endif
+ /* Transform the image to a different colorspace */
+ for (pix=image[0]; pix < image[height*width]; pix+=4) {
+ FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]);
+ sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2;
+ FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum);
+ FORC3 {
+ for (dsum=i=0; i < 3; i++)
+ dsum += trans[c][i] * pix[i];
+ if (dsum < 0) dsum = 0;
+ if (dsum > 24000) dsum = 24000;
+ ipix[c] = dsum + 0.5;
+ }
+ FORC3 pix[c] = ipix[c];
+ }
+
+ /* Smooth the image bottom-to-top and save at 1/4 scale */
+ shrink = (short (*)[3]) calloc ((width/4) * (height/4), sizeof *shrink);
+ merror (shrink, "foveon_interpolate()");
+ for (row = height/4; row--; )
+ for (col=0; col < width/4; col++) {
+ ipix[0] = ipix[1] = ipix[2] = 0;
+ for (i=0; i < 4; i++)
+ for (j=0; j < 4; j++)
+ FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c];
+ FORC3
+ if (row+2 > height/4)
+ shrink[row*(width/4)+col][c] = ipix[c] >> 4;
+ else
+ shrink[row*(width/4)+col][c] =
+ (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12;
+ }
+ /* From the 1/4-scale image, smooth right-to-left */
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,7,9);
+#endif
+ for (row=0; row < (height & ~3); row++) {
+ ipix[0] = ipix[1] = ipix[2] = 0;
+ if ((row & 3) == 0)
+ for (col = width & ~3 ; col--; )
+ FORC3 smrow[0][col][c] = ipix[c] =
+ (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13;
+
+ /* Then smooth left-to-right */
+ ipix[0] = ipix[1] = ipix[2] = 0;
+ for (col=0; col < (width & ~3); col++)
+ FORC3 smrow[1][col][c] = ipix[c] =
+ (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13;
+
+ /* Smooth top-to-bottom */
+ if (row == 0)
+ memcpy (smrow[2], smrow[1], sizeof **smrow * width);
+ else
+ for (col=0; col < (width & ~3); col++)
+ FORC3 smrow[2][col][c] =
+ (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13;
+
+ /* Adjust the chroma toward the smooth values */
+ for (col=0; col < (width & ~3); col++) {
+ for (i=j=30, c=0; c < 3; c++) {
+ i += smrow[2][col][c];
+ j += image[row*width+col][c];
+ }
+ j = (j << 16) / i;
+ for (sum=c=0; c < 3; c++) {
+ ipix[c] = foveon_apply_curve (curve[c+3],
+ ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]);
+ sum += ipix[c];
+ }
+ sum >>= 3;
+ FORC3 {
+ i = image[row*width+col][c] + ipix[c] - sum;
+ if (i < 0) i = 0;
+ image[row*width+col][c] = i;
+ }
+ }
+ }
+ free (shrink);
+ free (smrow[6]);
+ for (i=0; i < 8; i++)
+ free (curve[i]);
+#ifdef LIBRAW_LIBRARY_BUILD
+ RUN_CALLBACK(LIBRAW_PROGRESS_FOVEON_INTERPOLATE,8,9);
+#endif
+
+ /* Trim off the black border */
+ active[1] -= keep[1];
+ active[3] -= 2;
+ i = active[2] - active[0];
+ for (row=0; row < active[3]-active[1]; row++)
+ memcpy (image[row*i], image[(row+active[1])*width+active[0]],
+ i * sizeof *image);
+ width = i;
+ height = row;
+}
+#undef image
+
+/* RESTRICTED code ends here */
+char * CLASS foveon_gets (int offset, char *str, int len)
+{
+ int i;
+ fseek (ifp, offset, SEEK_SET);
+ for (i=0; i < len-1; i++)
+ if ((str[i] = get2()) == 0) break;
+ str[i] = 0;
+ return str;
+}
+
+void CLASS parse_foveon()
+{
+ int entries, img=0, off, len, tag, save, i, wide, high, pent, poff[256][2];
+ char name[64], value[64];
+
+ order = 0x4949; /* Little-endian */
+ fseek (ifp, 36, SEEK_SET);
+ flip = get4();
+ fseek (ifp, -4, SEEK_END);
+ fseek (ifp, get4(), SEEK_SET);
+ if (get4() != 0x64434553) return; /* SECd */
+ entries = (get4(),get4());
+ while (entries--) {
+ off = get4();
+ len = get4();
+ tag = get4();
+ save = ftell(ifp);
+ fseek (ifp, off, SEEK_SET);
+ if (get4() != (0x20434553 | (tag << 24))) return;
+ switch (tag) {
+ case 0x47414d49: /* IMAG */
+ case 0x32414d49: /* IMA2 */
+ fseek (ifp, 12, SEEK_CUR);
+ wide = get4();
+ high = get4();
+ if (wide > raw_width && high > raw_height) {
+ raw_width = wide;
+ raw_height = high;
+ data_offset = off+24;
+ }
+ fseek (ifp, off+28, SEEK_SET);
+ if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8
+ && thumb_length < len-28) {
+ thumb_offset = off+28;
+ thumb_length = len-28;
+ write_thumb = &CLASS jpeg_thumb;
+ }
+ if (++img == 2 && !thumb_length) {
+ thumb_offset = off+24;
+ thumb_width = wide;
+ thumb_height = high;
+ write_thumb = &CLASS foveon_thumb;
+ }
+ break;
+ case 0x464d4143: /* CAMF */
+ meta_offset = off+24;
+ meta_length = len-28;
+ if (meta_length > 0x20000)
+ meta_length = 0x20000;
+ break;
+ case 0x504f5250: /* PROP */
+ pent = (get4(),get4());
+ fseek (ifp, 12, SEEK_CUR);
+ off += pent*8 + 24;
+ if ((unsigned) pent > 256) pent=256;
+ for (i=0; i < pent*2; i++)
+ poff[0][i] = off + get4()*2;
+ for (i=0; i < pent; i++) {
+ foveon_gets (poff[i][0], name, 64);
+ foveon_gets (poff[i][1], value, 64);
+ if (!strcmp (name, "ISO"))
+ iso_speed = atoi(value);
+ if (!strcmp (name, "CAMMANUF"))
+ strcpy (make, value);
+ if (!strcmp (name, "CAMMODEL"))
+ strcpy (model, value);
+ if (!strcmp (name, "WB_DESC"))
+ strcpy (model2, value);
+ if (!strcmp (name, "TIME"))
+ timestamp = atoi(value);
+ if (!strcmp (name, "EXPTIME"))
+ shutter = atoi(value) / 1000000.0;
+ if (!strcmp (name, "APERTURE"))
+ aperture = atof(value);
+ if (!strcmp (name, "FLENGTH"))
+ focal_len = atof(value);
+ }
+#ifdef LOCALTIME
+ timestamp = mktime (gmtime (&timestamp));
+#endif
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ is_foveon = 1;
+}
diff --git a/libkdcraw/libraw/internal/libraw_internal_funcs.h b/libkdcraw/libraw/internal/libraw_internal_funcs.h
new file mode 100644
index 0000000..03bd3e8
--- /dev/null
+++ b/libkdcraw/libraw/internal/libraw_internal_funcs.h
@@ -0,0 +1,201 @@
+/* -*- C++ -*-
+ * File: libraw_internal_funcs.h
+ * Copyright 2008 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 14, 2008
+ *
+ * LibRaw internal data structures (not visible outside)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIBRAW_INTERNAL_FUNCS_H
+#define _LIBRAW_INTERNAL_FUNCS_H
+
+#ifndef LIBRAW_LIBRARY_BUILD
+#error "This file should be used only for libraw library build"
+#else
+// inline functions
+ ushort sget2 (uchar *s);
+ ushort get2();
+ unsigned sget4 (uchar *s);
+ unsigned getint (int type);
+ float int_to_float (int i);
+ double getreal (int type);
+ void read_shorts (ushort *pixel, int count);
+
+// Canon P&S cameras
+ void canon_600_fixed_wb (int temp);
+ int canon_600_color (int ratio[2], int mar);
+ void canon_600_auto_wb();
+ void canon_600_coeff();
+ void canon_600_load_raw();
+ int canon_s2is();
+ void canon_a5_load_raw();
+ void parse_ciff (int offset, int length);
+ void ciff_block_1030();
+
+// LJPEG decoder
+ unsigned getbits (int nbits);
+ void init_decoder();
+ uchar * make_decoder (const uchar *source, int level);
+ int ljpeg_start (struct jhead *jh, int info_only);
+ int ljpeg_diff (struct decode *dindex);
+ ushort * ljpeg_row (int jrow, struct jhead *jh);
+
+// Canon DSLRs
+ void crw_init_tables (unsigned table);
+ int canon_has_lowbits();
+ void canon_compressed_load_raw();
+ void lossless_jpeg_load_raw();
+ void canon_sraw_load_raw();
+ void canon_black(double *);
+// Adobe DNG
+ void adobe_copy_pixel (int row, int col, ushort **rp);
+ void adobe_dng_load_raw_lj();
+ void adobe_dng_load_raw_nc();
+
+// Pentax
+ void pentax_k10_load_raw();
+ void pentax_tree();
+
+// Nikon (and Minolta Z2)
+ void nikon_compressed_load_raw();
+ void nikon_load_raw();
+ int nikon_is_compressed();
+ int nikon_e995();
+ int nikon_e2100();
+ void nikon_3700();
+ int minolta_z2();
+ void nikon_e900_load_raw();
+ void nikon_e2100_load_raw();
+
+// Fuji
+ void fuji_load_raw();
+ void parse_fuji (int offset);
+
+
+
+
+// Rollei
+ void rollei_load_raw();
+ void parse_rollei();
+
+// MF backs
+ int bayer (unsigned row, unsigned col);
+ void phase_one_flat_field (int is_float, int nc);
+ void phase_one_correct();
+ void phase_one_load_raw();
+ unsigned ph1_bits (int nbits);
+ void phase_one_load_raw_c();
+ void hasselblad_load_raw();
+ void leaf_hdr_load_raw();
+ void sinar_4shot_load_raw();
+ void imacon_full_load_raw();
+ void packed_12_load_raw();
+ void unpacked_load_raw();
+ void parse_sinar_ia();
+ void parse_phase_one (int base);
+
+// Misc P&S cameras
+ void nokia_load_raw();
+ unsigned pana_bits (int nbits);
+ void panasonic_load_raw();
+ void olympus_e300_load_raw();
+ void olympus_e410_load_raw();
+ void olympus_cseries_load_raw();
+ void minolta_rd175_load_raw();
+ void casio_qv5700_load_raw();
+ void quicktake_100_load_raw();
+ const int* make_decoder_int (const int *source, int level);
+ int radc_token (int tree);
+ void kodak_radc_load_raw();
+ void kodak_jpeg_load_raw();
+ void kodak_dc120_load_raw();
+ void eight_bit_load_raw();
+ void smal_decode_segment (unsigned seg[2][2], int holes);
+ void smal_v6_load_raw();
+ int median4 (int *p);
+ void fill_holes (int holes);
+ void smal_v9_load_raw();
+ void parse_riff();
+ void parse_cine();
+ void parse_smal (int offset, int fsize);
+ int parse_jpeg (int offset);
+
+// Kodak
+ void kodak_262_load_raw();
+ int kodak_65000_decode (short *out, int bsize);
+ void kodak_65000_load_raw();
+ void kodak_rgb_load_raw();
+ void kodak_yrgb_load_raw();
+
+// It's a Sony (and K&M)
+ void sony_decrypt (unsigned *data, int len, int start, int key);
+ void sony_load_raw();
+ void sony_arw_load_raw();
+ void sony_arw2_load_raw();
+ void parse_minolta (int base);
+
+#ifndef NO_FOVEON
+// Foveon/Sigma
+ void foveon_load_camf();
+ void foveon_load_raw();
+ const char* foveon_camf_param (const char *block, const char *param);
+ void * foveon_camf_matrix (unsigned dim[3], const char *name);
+ int foveon_fixed (void *ptr, int size, const char *name);
+ float foveon_avg (short *pix, int range[2], float cfilt);
+ short * foveon_make_curve (double max, double mul, double filt);
+ void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt);
+ int foveon_apply_curve (short *curve, int i);
+ void foveon_interpolate();
+ char * foveon_gets (int offset, char *str, int len);
+ void parse_foveon();
+#endif
+
+
+// CAM/RGB
+ void pseudoinverse (double (*in)[3], double (*out)[3], int size);
+ void cam_xyz_coeff (double cam_xyz[4][3]);
+ void adobe_coeff (const char *, const char *);
+ void simple_coeff (int index);
+
+
+// Tiff/Exif parsers
+ void tiff_get (unsigned base,unsigned *tag, unsigned *type, unsigned *len, unsigned *save);
+ void parse_thumb_note (int base, unsigned toff, unsigned tlen);
+ void parse_makernote (int base, int uptag);
+ void parse_exif (int base);
+ void linear_table (unsigned len);
+ void parse_kodak_ifd (int base);
+ int parse_tiff_ifd (int base);
+ void parse_tiff (int base);
+ void parse_gps (int base);
+ void romm_coeff (float romm_cam[3][3]);
+ void parse_mos (int offset);
+ void get_timestamp (int reversed);
+
+// External JPEGs, what cameras uses it ?
+ void parse_external_jpeg();
+
+// The identify
+ short guess_byte_order (int words);
+
+// Tiff writer
+ void tiff_set (ushort *ntag, ushort tag, ushort type, int count, int val);
+ void tiff_head (struct tiff_hdr *th, int full);
+#endif
+
+#endif
diff --git a/libkdcraw/libraw/internal/var_defines.h b/libkdcraw/libraw/internal/var_defines.h
new file mode 100644
index 0000000..99bb4fb
--- /dev/null
+++ b/libkdcraw/libraw/internal/var_defines.h
@@ -0,0 +1,181 @@
+/* -*- C++ -*-
+ * File: var_defines.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8, 2008
+ *
+ * LibRaw redefinitions of dcraw internal variables
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef VAR_DEFINES_H
+#define VAR_DEFINES_H
+
+// imgdata.idata
+#define make (imgdata.idata.make)
+#define model (imgdata.idata.model)
+#define is_raw (imgdata.idata.raw_count)
+#define dng_version (imgdata.idata.dng_version)
+#define is_foveon (imgdata.idata.is_foveon)
+#define colors (imgdata.idata.colors)
+#define cdesc (imgdata.idata.cdesc)
+#define filters (imgdata.idata.filters)
+
+//imgdata image
+#define image (imgdata.image)
+
+// imgdata.sizes
+#define raw_height (imgdata.sizes.raw_height)
+#define raw_width (imgdata.sizes.raw_width)
+#define height (imgdata.sizes.height)
+#define width (imgdata.sizes.width)
+#define top_margin (imgdata.sizes.top_margin)
+#define left_margin (imgdata.sizes.left_margin)
+#define bottom_margin (imgdata.sizes.bottom_margin)
+#define right_margin (imgdata.sizes.right_margin)
+#define iheight (imgdata.sizes.iheight)
+#define iwidth (imgdata.sizes.iwidth)
+#define pixel_aspect (imgdata.sizes.pixel_aspect)
+#define flip (imgdata.sizes.flip)
+
+//imgdata.color
+#define white (imgdata.color.white)
+#define cam_mul (imgdata.color.cam_mul)
+#define pre_mul (imgdata.color.pre_mul)
+#define cmatrix (imgdata.color.cmatrix)
+#define rgb_cam (imgdata.color.rgb_cam)
+#ifndef SRC_USES_CURVE
+#define curve (imgdata.color.curve)
+#endif
+#ifndef SRC_USES_BLACK
+#define black (imgdata.color.black)
+#endif
+#define maximum (imgdata.color.maximum)
+#define profile_length (imgdata.color.profile_length)
+#define color_flags (imgdata.color.color_flags)
+#define ph1 (imgdata.color.phase_one_data)
+#define flash_used (imgdata.color.flash_used)
+#define canon_ev (imgdata.color.canon_ev)
+#define model2 (imgdata.color.model2)
+
+//imgdata.thumbnail
+
+#define thumb_width (imgdata.thumbnail.twidth)
+#define thumb_height (imgdata.thumbnail.theight)
+#define thumb_length (imgdata.thumbnail.tlength)
+
+
+//imgdata.others
+#define iso_speed (imgdata.other.iso_speed)
+#define shutter (imgdata.other.shutter)
+#define aperture (imgdata.other.aperture)
+#define focal_len (imgdata.other.focal_len)
+#define timestamp (imgdata.other.timestamp)
+#define shot_order (imgdata.other.shot_order)
+#define gpsdata (imgdata.other.gpsdata)
+#define desc (imgdata.other.desc)
+#define artist (imgdata.other.artist)
+
+//imgdata.output
+#define greybox (imgdata.params.greybox)
+#define aber (imgdata.params.aber)
+#define gamm (imgdata.params.gamm)
+#define user_mul (imgdata.params.user_mul)
+#define shot_select (imgdata.params.shot_select)
+#define bright (imgdata.params.bright)
+#define threshold (imgdata.params.threshold)
+#define half_size (imgdata.params.half_size)
+#define four_color_rgb (imgdata.params.four_color_rgb)
+#define document_mode (imgdata.params.document_mode)
+#define highlight (imgdata.params.highlight)
+//#define verbose (imgdata.params.verbose)
+#define use_auto_wb (imgdata.params.use_auto_wb)
+#define use_camera_wb (imgdata.params.use_camera_wb)
+#define use_camera_matrix (imgdata.params.use_camera_matrix)
+#define output_color (imgdata.params.output_color)
+#define output_bps (imgdata.params.output_bps)
+#define gamma_16bit (imgdata.params.gamma_16bit)
+#define output_tiff (imgdata.params.output_tiff)
+#define med_passes (imgdata.params.med_passes)
+#define no_auto_bright (imgdata.params.no_auto_bright)
+#define use_fuji_rotate (imgdata.params.use_fuji_rotate)
+#define filtering_mode (imgdata.params.filtering_mode)
+
+//rgb_constants
+#define xyz_rgb (rgb_constants.xyz_rgb)
+#define d65_white (rgb_constants.d65_white)
+
+//libraw_internal_data.internal_data
+#define meta_data (libraw_internal_data.internal_data.meta_data)
+#define ifp libraw_internal_data.internal_data.input
+#define ifname ((char*)libraw_internal_data.internal_data.input->fname())
+#define profile_offset (libraw_internal_data.internal_data.profile_offset)
+#define thumb_offset (libraw_internal_data.internal_data.toffset)
+
+//libraw_internal_data.internal_output_params
+#define mix_green (libraw_internal_data.internal_output_params.mix_green)
+#define raw_color (libraw_internal_data.internal_output_params.raw_color)
+#define use_gamma (libraw_internal_data.internal_output_params.use_gamma)
+#define zero_is_bad (libraw_internal_data.internal_output_params.zero_is_bad)
+#ifndef SRC_USES_SHRINK
+#define shrink (libraw_internal_data.internal_output_params.shrink)
+#endif
+#define fuji_width (libraw_internal_data.internal_output_params.fuji_width)
+
+
+//libraw_internal_data.output_data
+#define histogram (libraw_internal_data.output_data.histogram)
+#define oprof (libraw_internal_data.output_data.oprof)
+
+//libraw_internal_data.identify_data
+#define exif_cfa (libraw_internal_data.identify_data.olympus_exif_cfa)
+#define unique_id (libraw_internal_data.identify_data.unique_id)
+#define tiff_nifds (libraw_internal_data.identify_data.tiff_nifds)
+#define tiff_flip (libraw_internal_data.identify_data.tiff_flip)
+
+//libraw_internal_data.unpacker_data
+#define order (libraw_internal_data.unpacker_data.order)
+#define data_error (libraw_internal_data.unpacker_data.data_error)
+#define cr2_slice (libraw_internal_data.unpacker_data.cr2_slice)
+#define sraw_mul (libraw_internal_data.unpacker_data.sraw_mul)
+#define kodak_cbpp (libraw_internal_data.unpacker_data.kodak_cbpp)
+#define strip_offset (libraw_internal_data.unpacker_data.strip_offset)
+#define data_offset (libraw_internal_data.unpacker_data.data_offset)
+#define meta_offset (libraw_internal_data.unpacker_data.meta_offset)
+#define meta_length (libraw_internal_data.unpacker_data.meta_length)
+#define thumb_misc (libraw_internal_data.unpacker_data.thumb_misc)
+#define fuji_layout (libraw_internal_data.unpacker_data.fuji_layout)
+#define tiff_samples (libraw_internal_data.unpacker_data.tiff_samples)
+#define tiff_bps (libraw_internal_data.unpacker_data.tiff_bps)
+#define tiff_compress (libraw_internal_data.unpacker_data.tiff_compress)
+#define zero_after_ff (libraw_internal_data.unpacker_data.zero_after_ff)
+#define tile_width (libraw_internal_data.unpacker_data.tile_width)
+#define tile_length (libraw_internal_data.unpacker_data.tile_length)
+#define load_flags (libraw_internal_data.unpacker_data.load_flags)
+
+#ifdef LIBRAW_IO_REDEFINED
+#define fread(ptr,size,n,stream) stream->read(ptr,size,n)
+#define fseek(stream,o,w) stream->seek(o,w)
+#define fseeko(stream,o,w) stream->seek(o,w)
+#define ftell(stream) stream->tell()
+#define ftello(stream) stream->tell()
+#define getc(stream) stream->get_char()
+#define fgetc(stream) stream->get_char()
+#define fgets(str,n,stream) stream->gets(str,n)
+#define fscanf(stream,fmt,ptr) stream->scanf_one(fmt,ptr)
+#endif
+
+#endif
diff --git a/libkdcraw/libraw/libraw/libraw.h b/libkdcraw/libraw/libraw/libraw.h
new file mode 100644
index 0000000..6bd12d6
--- /dev/null
+++ b/libkdcraw/libraw/libraw/libraw.h
@@ -0,0 +1,229 @@
+/* -*- C++ -*-
+ * File: libraw.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8, 2008
+ *
+ * LibRaw C++ interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIBRAW_CLASS_H
+#define _LIBRAW_CLASS_H
+
+#include <limits.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include "libraw_datastream.h"
+#include "libraw_types.h"
+#include "libraw_const.h"
+#include "libraw_internal.h"
+#include "libraw_alloc.h"
+
+//#define DCRAW_VERBOSE
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+DllDef const char *libraw_strerror(int errorcode);
+DllDef const char *libraw_strprogress(enum LibRaw_progress);
+ // LibRaw C API
+DllDef libraw_data_t *libraw_init(unsigned int flags);
+DllDef int libraw_open_file(libraw_data_t*, const char *);
+DllDef int libraw_open_buffer(libraw_data_t*, void * buffer, size_t size);
+DllDef int libraw_unpack(libraw_data_t*);
+DllDef int libraw_unpack_thumb(libraw_data_t*);
+DllDef void libraw_recycle(libraw_data_t*);
+DllDef void libraw_close(libraw_data_t*);
+ // version helpers
+DllDef const char* libraw_version();
+DllDef int libraw_versionNumber();
+ // Camera list
+DllDef const char** libraw_cameraList();
+DllDef int libraw_cameraCount();
+
+DllDef void libraw_set_memerror_handler(libraw_data_t*, memory_callback cb, void *datap);
+DllDef void libraw_set_dataerror_handler(libraw_data_t*,data_callback func,void *datap);
+DllDef void libraw_set_progress_handler(libraw_data_t*,progress_callback cb,void *datap);
+DllDef int libraw_add_masked_borders_to_bitmap(libraw_data_t* lr);
+DllDef const char * libraw_unpack_function_name(libraw_data_t* lr);
+DllDef int libraw_rotate_fuji_raw(libraw_data_t* lr);
+
+ // DCRAW compatibility
+DllDef int libraw_adjust_sizes_info_only(libraw_data_t*);
+DllDef int libraw_dcraw_document_mode_processing(libraw_data_t*);
+DllDef int libraw_dcraw_ppm_tiff_writer(libraw_data_t* lr,const char *filename);
+DllDef int libraw_dcraw_thumb_writer(libraw_data_t* lr,const char *fname);
+DllDef int libraw_dcraw_process(libraw_data_t* lr);
+DllDef libraw_processed_image_t* dcraw_make_mem_image(libraw_data_t* lr, int *errc);
+DllDef libraw_processed_image_t* dcraw_make_mem_thumb(libraw_data_t* lr, int *errc);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+
+class DllDef LibRaw
+{
+ public:
+ libraw_data_t imgdata;
+ int verbose;
+
+ LibRaw(unsigned int flags = LIBRAW_OPTIONS_NONE);
+
+ libraw_output_params_t* output_params_ptr() { return &imgdata.params;}
+ int open_file(const char *fname);
+ int open_buffer(void *buffer, size_t size);
+ int open_datastream(LibRaw_abstract_datastream *);
+ int unpack(void);
+ int unpack_thumb(void);
+
+ int adjust_sizes_info_only(void);
+ void set_memerror_handler( memory_callback cb,void *data) {callbacks.memcb_data = data; callbacks.mem_cb = cb; }
+ void set_dataerror_handler(data_callback func, void *data) { callbacks.datacb_data = data; callbacks.data_cb = func;}
+ void set_progress_handler(progress_callback pcb, void *data) { callbacks.progresscb_data = data; callbacks.progress_cb = pcb;}
+
+ // helpers
+ static const char* version() { return LIBRAW_VERSION_STR;}
+ static int versionNumber() { return LIBRAW_VERSION; }
+ static const char** cameraList();
+ static int cameraCount();
+ static const char* strprogress(enum LibRaw_progress);
+ static const char* strerror(int p) { return libraw_strerror(p);}
+ // dcraw emulation
+ int dcraw_document_mode_processing();
+ int dcraw_ppm_tiff_writer(const char *filename);
+ int dcraw_thumb_writer(const char *fname);
+ int dcraw_process(void);
+ // memory writers
+ libraw_processed_image_t* dcraw_make_mem_image(int *errcode=NULL);
+ libraw_processed_image_t* dcraw_make_mem_thumb(int *errcode=NULL);
+
+ // free all internal data structures
+ void recycle();
+ ~LibRaw(void) { recycle(); delete tls; }
+
+ int FC(int row,int col) { return (imgdata.idata.filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3);}
+ int fc (int row, int col);
+ int add_masked_borders_to_bitmap();
+
+ const char *unpack_function_name();
+ int rotate_fuji_raw();
+
+ private:
+ void* malloc(size_t t);
+ void* calloc(size_t n,size_t t);
+ void free(void *p);
+ void merror (void *ptr, const char *where);
+ void derror();
+
+// data
+
+ LibRaw_TLS *tls;
+ libraw_internal_data_t libraw_internal_data;
+ decode first_decode[2048], *second_decode, *free_decode;
+ tiff_ifd_t tiff_ifd[10];
+ libraw_memmgr memmgr;
+ libraw_callbacks_t callbacks;
+
+ LibRaw_constants rgb_constants;
+ void (LibRaw:: *write_thumb)(FILE *),
+ (LibRaw:: *write_fun)(FILE *);
+ void (LibRaw:: *load_raw)(),
+ (LibRaw:: *thumb_load_raw)();
+
+ void kodak_thumb_loader();
+ void write_thumb_ppm_tiff(FILE *); // kodak
+ void foveon_thumb_loader (void); //Sigma
+
+
+ // moved from implementation level to private: visibility
+ void init_masked_ptrs();
+ ushort *get_masked_pointer(int row, int col);
+
+ int own_filtering_supported(){ return 0;}
+ void identify();
+ void write_ppm_tiff (FILE *ofp);
+ void convert_to_rgb();
+ void kodak_ycbcr_load_raw();
+ void remove_zeroes();
+#ifndef NO_LCMS
+ void apply_profile(char*,char*);
+#endif
+// Iterpolators
+ void pre_interpolate();
+ void border_interpolate (int border);
+ void lin_interpolate();
+ void vng_interpolate();
+ void ppg_interpolate();
+ void ahd_interpolate();
+
+// Image filters
+ void bad_pixels(char*);
+ void subtract(char*);
+ void hat_transform (float *temp, float *base, int st, int size, int sc);
+ void wavelet_denoise();
+ void scale_colors();
+ void median_filter ();
+ void blend_highlights();
+ void recover_highlights();
+
+ void fuji_rotate();
+ void stretch();
+
+// Thmbnail functions
+ void foveon_thumb (FILE *tfp);
+ void jpeg_thumb_writer (FILE *tfp,char *thumb,int thumb_length);
+ void jpeg_thumb (FILE *tfp);
+ void ppm_thumb (FILE *tfp);
+ void layer_thumb (FILE *tfp);
+ void rollei_thumb (FILE *tfp);
+ void kodak_thumb_load_raw();
+
+ // utility for cut'n'pasted code
+ void foveon_decoder (unsigned size, unsigned code);
+ unsigned get4();
+
+ int flip_index (int row, int col);
+ void gamma_lut(ushort lut[0x10000]);
+
+
+// == internal functions
+
+#ifdef LIBRAW_LIBRARY_BUILD
+#include "internal/libraw_internal_funcs.h"
+#endif
+
+};
+
+#ifdef LIBRAW_LIBRARY_BUILD
+#define RUN_CALLBACK(stage,iter,expect) if(callbacks.progress_cb) { \
+ int rr = (*callbacks.progress_cb)(callbacks.progresscb_data,stage,iter,expect); \
+ if(rr!=0) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; \
+ }
+#endif
+
+
+#endif // __cplusplus
+
+
+#endif // _LIBRAW_CLASS_H
diff --git a/libkdcraw/libraw/libraw/libraw_alloc.h b/libkdcraw/libraw/libraw/libraw_alloc.h
new file mode 100644
index 0000000..84970d2
--- /dev/null
+++ b/libkdcraw/libraw/libraw/libraw_alloc.h
@@ -0,0 +1,98 @@
+/* -*- C++ -*-
+ * File: libraw_alloc.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 22, 2008
+ *
+ * LibRaw C++ interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __LIBRAW_ALLOC_H
+#define __LIBRAW_ALLOC_H
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+#define bzero(p,sz) memset(p,0,sz)
+#endif
+
+#ifdef __cplusplus
+
+#define MSIZE 32
+
+class libraw_memmgr
+{
+ public:
+ libraw_memmgr()
+ {
+ bzero(mems,sizeof(mems));
+ calloc_cnt=0;
+ }
+ void *malloc(size_t sz)
+ {
+ void *ptr = ::malloc(sz);
+ mem_ptr(ptr);
+ return ptr;
+ }
+ void *calloc(size_t n, size_t sz)
+ {
+ void *ptr = ::calloc(n,sz);
+ mem_ptr(ptr);
+ return ptr;
+ }
+ void free(void *ptr)
+ {
+ ::free(ptr);
+ forget_ptr(ptr);
+ }
+ void cleanup(void)
+ {
+ for(int i = 0; i< MSIZE; i++)
+ if(mems[i])
+ {
+// fprintf(stderr,"Found lost fragment at 0x%x\n",mems[i]);
+ free(mems[i]);
+ mems[i] = NULL;
+ }
+ }
+
+ private:
+ void *mems[MSIZE];
+ int calloc_cnt;
+ void mem_ptr(void *ptr)
+ {
+ if(ptr)
+ for(int i=0;i < MSIZE; i++)
+ if(!mems[i])
+ {
+ mems[i] = ptr;
+ break;
+ }
+ }
+ void forget_ptr(void *ptr)
+ {
+ if(ptr)
+ for(int i=0;i < MSIZE; i++)
+ if(mems[i] == ptr)
+ mems[i] = NULL;
+ }
+
+};
+
+#endif //C++
+
+#endif
diff --git a/libkdcraw/libraw/libraw/libraw_const.h b/libkdcraw/libraw/libraw/libraw_const.h
new file mode 100644
index 0000000..1c4b32c
--- /dev/null
+++ b/libkdcraw/libraw/libraw/libraw_const.h
@@ -0,0 +1,160 @@
+/* -*- C++ -*-
+ * File: libraw_const.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw error codes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIBRAW_ERRORS_H
+#define _LIBRAW_ERRORS_H
+
+enum LibRaw_constructor_flags
+{
+ LIBRAW_OPTIONS_NONE =0,
+ LIBRAW_OPIONS_NO_MEMERR_CALLBACK=1,
+ LIBRAW_OPIONS_NO_DATAERR_CALLBACK=1<<1
+};
+
+enum LibRaw_warnings
+{
+ LIBRAW_WARN_NONE =0,
+ LIBRAW_WARN_FOVEON_NOMATRIX =1,
+ LIBRAW_WARN_FOVEON_INVALIDWB =1<<1,
+ LIBRAW_WARN_BAD_CAMERA_WB =1<<2,
+ LIBRAW_WARN_NO_METADATA =1<<3,
+ LIBRAW_WARN_NO_JPEGLIB = 1<<4,
+ LIBRAW_WARN_NO_EMBEDDED_PROFILE = 1<<5,
+ LIBRAW_WARN_NO_INPUT_PROFILE = 1<<6,
+ LIBRAW_WARN_BAD_OUTPUT_PROFILE= 1<<7,
+ LIBRAW_WARN_NO_BADPIXELMAP=1<<8,
+ LIBRAW_WARN_BAD_DARKFRAME_FILE=1<<9,
+ LIBRAW_WARN_BAD_DARKFRAME_DIM=1<<10
+};
+
+enum LibRaw_exceptions
+{
+ LIBRAW_EXCEPTION_NONE =0,
+ LIBRAW_EXCEPTION_ALLOC =1,
+ LIBRAW_EXCEPTION_DECODE_RAW =2,
+ LIBRAW_EXCEPTION_DECODE_JPEG=3,
+ LIBRAW_EXCEPTION_IO_EOF =4,
+ LIBRAW_EXCEPTION_IO_CORRUPT =5,
+ LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK=6
+};
+
+
+enum LibRaw_colorstate
+{
+ LIBRAW_COLORSTATE_UNKNOWN =0,
+ LIBRAW_COLORSTATE_INIT =1,
+ LIBRAW_COLORSTATE_CONST =2,
+ LIBRAW_COLORSTATE_LOADED =3,
+ LIBRAW_COLORSTATE_CALCULATED=4,
+ LIBRAW_COLORSTATE_RESERVED1 =5,
+ LIBRAW_COLORSTATE_RESERVED2 =6,
+ LIBRAW_COLORSTATE_RESERVED3 =7
+};
+
+enum LibRaw_filtering
+{
+ LIBRAW_FILTERING_DEFAULT =0,
+ LIBRAW_FILTERING_NOZEROES =1, // no remove zeroes
+ LIBRAW_FILTERING_NOBLACKS =2, // no black subtraction
+ LIBRAW_FILTERING_NORAWCURVE =4, // no raw data postprocessing (e.g. PhaseOne corrections etc)
+ LIBRAW_FILTERING_NONE =7, // (_NOZEROES | _NOBLACKS | _NORAWCURVE)
+ LIBRAW_FILTERING_LIBRAWOWN =(8 | LIBRAW_FILTERING_NONE), // NONE + 8
+ LIBRAW_FILTERING_AUTOMATIC_BIT =16, // - restore automatic mode after processing
+ LIBRAW_FILTERING_AUTOMATIC = (LIBRAW_FILTERING_LIBRAWOWN | LIBRAW_FILTERING_AUTOMATIC_BIT)
+};
+
+
+enum LibRaw_progress
+{
+ LIBRAW_PROGRESS_START = 0,
+ LIBRAW_PROGRESS_OPEN = 1,
+ LIBRAW_PROGRESS_IDENTIFY = 1<<1,
+ LIBRAW_PROGRESS_SIZE_ADJUST = 1<<2,
+ LIBRAW_PROGRESS_LOAD_RAW = 1<<3,
+ LIBRAW_PROGRESS_REMOVE_ZEROES = 1<<4,
+ LIBRAW_PROGRESS_BAD_PIXELS = 1<<5,
+ LIBRAW_PROGRESS_DARK_FRAME = 1<<6,
+ LIBRAW_PROGRESS_FOVEON_INTERPOLATE = 1<<7,
+ LIBRAW_PROGRESS_SCALE_COLORS = 1<<8,
+ LIBRAW_PROGRESS_PRE_INTERPOLATE = 1<<9,
+ LIBRAW_PROGRESS_INTERPOLATE = 1<<10,
+ LIBRAW_PROGRESS_MIX_GREEN = 1<<11,
+ LIBRAW_PROGRESS_MEDIAN_FILTER = 1<<12,
+ LIBRAW_PROGRESS_HIGHLIGHTS = 1<<13,
+ LIBRAW_PROGRESS_FUJI_ROTATE = 1<<14,
+ LIBRAW_PROGRESS_FLIP = 1<<15,
+ LIBRAW_PROGRESS_APPLY_PROFILE = 1<<16,
+ LIBRAW_PROGRESS_CONVERT_RGB = 1<<17,
+ LIBRAW_PROGRESS_STRETCH = 1<<18,
+// reserved
+ LIBRAW_PROGRESS_STAGE19 = 1<<19,
+ LIBRAW_PROGRESS_STAGE20 = 1<<20,
+ LIBRAW_PROGRESS_STAGE21 = 1<<21,
+ LIBRAW_PROGRESS_STAGE22 = 1<<22,
+ LIBRAW_PROGRESS_STAGE23 = 1<<23,
+ LIBRAW_PROGRESS_STAGE24 = 1<<24,
+ LIBRAW_PROGRESS_STAGE25 = 1<<25,
+ LIBRAW_PROGRESS_STAGE26 = 1<<26,
+ LIBRAW_PROGRESS_STAGE27 = 1<<27,
+
+ LIBRAW_PROGRESS_THUMB_LOAD = 1<<28,
+ LIBRAW_PROGRESS_TRESERVED1 = 1<<29,
+ LIBRAW_PROGRESS_TRESERVED2 = 1<<30,
+ LIBRAW_PROGRESS_TRESERVED3 = 1<<31
+};
+#define LIBRAW_PROGRESS_THUMB_MASK 0x0fffffff
+
+enum LibRaw_errors
+{
+ LIBRAW_SUCCESS = 0,
+ LIBRAW_UNSPECIFIED_ERROR=-1,
+ LIBRAW_FILE_UNSUPPORTED = -2,
+ LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE=-3,
+ LIBRAW_OUT_OF_ORDER_CALL=-4,
+ LIBRAW_NO_THUMBNAIL=-5,
+ LIBRAW_UNSUPPORTED_THUMBNAIL=-6,
+ LIBRAW_CANNOT_ADDMASK=-7,
+ LIBRAW_UNSUFFICIENT_MEMORY=-100007,
+ LIBRAW_DATA_ERROR=-100008,
+ LIBRAW_IO_ERROR=-100009,
+ LIBRAW_CANCELLED_BY_CALLBACK=-100010
+};
+
+#define LIBRAW_FATAL_ERROR(ec) ((ec)<-100000)
+
+enum LibRaw_thumbnail_formats
+{
+ LIBRAW_THUMBNAIL_UNKNOWN=0,
+ LIBRAW_THUMBNAIL_JPEG=1,
+ LIBRAW_THUMBNAIL_BITMAP=2,
+ LIBRAW_THUMBNAIL_LAYER=4,
+ LIBRAW_THUMBNAIL_ROLLEI=5
+};
+
+enum LibRaw_image_formats
+{
+ LIBRAW_IMAGE_BITMAP=1,
+ LIBRAW_IMAGE_JPEG=2
+};
+
+#endif
diff --git a/libkdcraw/libraw/libraw/libraw_datastream.h b/libkdcraw/libraw/libraw/libraw_datastream.h
new file mode 100644
index 0000000..e8b2338
--- /dev/null
+++ b/libkdcraw/libraw/libraw/libraw_datastream.h
@@ -0,0 +1,303 @@
+/* -*- C -*-
+ * File: libraw_datastream.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sun Jan 18 13:07:35 2009
+ *
+ * LibRaw Data stream interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __LIBRAW_DATASTREAM_H
+#define __LIBRAW_DATASTREAM_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+
+#ifndef __cplusplus
+
+struct LibRaw_abstract_datastream;
+
+#else // __cplusplus
+
+#include "libraw_const.h"
+
+class LibRaw_buffer_datastream;
+
+class LibRaw_abstract_datastream
+{
+ public:
+ LibRaw_abstract_datastream(){substream=0;};
+ virtual ~LibRaw_abstract_datastream(void){if(substream) delete substream;}
+ virtual int valid(){return 0;}
+ // file input emulation
+ virtual int read(void *,size_t, size_t ){ return -1;}
+ virtual int seek(off_t o, int whence){return -1;}
+ virtual int tell(){return -1;}
+ virtual int get_char(){return -1;}
+ virtual char* gets(char *, int){ return NULL;}
+ virtual int scanf_one(const char *, void *){return -1;}
+ virtual int eof(){return -1;}
+
+ virtual const char* fname(){ return NULL;};
+ virtual int subfile_open(const char*){ return EINVAL;}
+ virtual void subfile_close(){}
+ virtual int tempbuffer_open(void*, size_t);
+ virtual void tempbuffer_close()
+ {
+ if(substream) delete substream;
+ substream = NULL;
+ }
+
+ protected:
+ LibRaw_abstract_datastream *substream;
+};
+
+
+class LibRaw_file_datastream : public LibRaw_abstract_datastream
+{
+ public:
+ LibRaw_file_datastream(const char *fname)
+ {
+ if(fname)
+ {filename = fname; f = fopen(fname,"rb");}
+ else
+ {filename=0;f=0;}
+ sav=0;
+ }
+
+ virtual ~LibRaw_file_datastream() {if(f)fclose(f); if(sav)fclose(sav);}
+
+ virtual int valid() { return f?1:0;}
+
+#define CHK() do {if(!f) throw LIBRAW_EXCEPTION_IO_EOF;}while(0)
+ virtual int read(void * ptr,size_t size, size_t nmemb)
+ {
+ CHK();
+ return substream?substream->read(ptr,size,nmemb):int(fread(ptr,size,nmemb,f));
+ }
+ virtual int eof()
+ {
+ CHK();
+ return substream?substream->eof():feof(f);
+ }
+ virtual int seek(off_t o, int whence)
+ {
+ CHK();
+ return substream?substream->seek(o,whence):fseek(f,o,whence);
+ }
+ virtual int tell()
+ {
+ CHK();
+ return substream?substream->tell():ftell(f);
+ }
+ virtual int get_char()
+ {
+ CHK();
+ return substream?substream->get_char():fgetc(f);
+ }
+ virtual char* gets(char *str, int sz)
+ {
+ CHK();
+ return substream?substream->gets(str,sz):fgets(str,sz,f);
+ }
+ virtual int scanf_one(const char *fmt, void*val)
+ {
+ CHK();
+ return substream?substream->scanf_one(fmt,val):fscanf(f,fmt,val);
+ }
+
+ virtual const char *fname() { return filename; }
+
+ // secondary
+ virtual int subfile_open(const char *fn)
+ {
+ if(sav) return EBUSY;
+ sav = f;
+ f = fopen(fn,"rb");
+ if(!f)
+ {
+ f = sav;
+ sav = NULL;
+ return ENOENT;
+ }
+ else
+ return 0;
+ }
+ virtual void subfile_close()
+ {
+ if(!sav) return;
+ fclose(f);
+ f = sav;
+ sav = 0;
+ }
+
+ private:
+ FILE *f,*sav;
+ const char *filename;
+};
+#undef CHK
+
+class LibRaw_buffer_datastream : public LibRaw_abstract_datastream
+{
+ public:
+ LibRaw_buffer_datastream(void *buffer, size_t bsize)
+ {
+ buf = (unsigned char*)buffer; streampos = 0; streamsize = bsize;
+ }
+ virtual ~LibRaw_buffer_datastream(){}
+ virtual int valid() { return buf?1:0;}
+ virtual int read(void * ptr,size_t sz, size_t nmemb)
+ {
+ if(substream) return substream->read(ptr,sz,nmemb);
+ size_t to_read = sz*nmemb;
+ if(to_read > streamsize - streampos)
+ to_read = streamsize-streampos;
+ if(to_read<1)
+ return 0;
+ memmove(ptr,buf+streampos,to_read);
+ streampos+=to_read;
+ return int((to_read+sz-1)/sz);
+ }
+
+ virtual int eof()
+ {
+ if(substream) return substream->eof();
+ return streampos >= streamsize;
+ }
+
+ virtual int seek(off_t o, int whence)
+ {
+ if(substream) return substream->seek(o,whence);
+ switch(whence)
+ {
+ case SEEK_SET:
+ if(o<0)
+ streampos = 0;
+ else if (size_t(o) > streamsize)
+ streampos = streamsize;
+ else
+ streampos = size_t(o);
+ return 0;
+ case SEEK_CUR:
+ if(o<0)
+ {
+ if(size_t(-o) >= streampos)
+ streampos = 0;
+ else
+ streampos += o;
+ }
+ else if (o>0)
+ {
+ if(o+streampos> streamsize)
+ streampos = streamsize;
+ else
+ streampos += o;
+ }
+ return 0;
+ case SEEK_END:
+ if(o>0)
+ streampos = streamsize;
+ else if ( size_t(-o) > streamsize)
+ streampos = 0;
+ else
+ streampos = streamsize+o;
+ return 0;
+ default:
+ return 0;
+ }
+ }
+
+ virtual int tell()
+ {
+ if(substream) return substream->tell();
+ return int(streampos);
+ }
+
+ virtual int get_char()
+ {
+ if(substream) return substream->get_char();
+ if(streampos>=streamsize)
+ return -1;
+ return buf[streampos++];
+ }
+ virtual char* gets(char *s, int sz)
+ {
+ if (substream) return substream->gets(s,sz);
+ unsigned char *psrc,*pdest,*str;
+ str = (unsigned char *)s;
+ psrc = buf+streampos;
+ pdest = str;
+ while ( (size_t(psrc - buf) < streamsize)
+ &&
+ ((pdest-str)<sz)
+ )
+ {
+ *pdest = *psrc;
+ if(*psrc == '\n')
+ break;
+ psrc++;
+ pdest++;
+ }
+ if(size_t(psrc-buf) < streamsize)
+ psrc++;
+ if((pdest-str)<sz)
+ *(++pdest)=0;
+ streampos = psrc - buf;
+ return s;
+ }
+ virtual int scanf_one(const char *fmt, void* val)
+ {
+ if(substream) return substream->scanf_one(fmt,val);
+ int scanf_res;
+ if(streampos>streamsize) return 0;
+ scanf_res = sscanf((char*)(buf+streampos),fmt,val);
+ if(scanf_res>0)
+ {
+ int xcnt=0;
+ while(streampos<streamsize)
+ {
+ streampos++;
+ xcnt++;
+ if(buf[streampos] == 0
+ || buf[streampos]==' '
+ || buf[streampos]=='\t'
+ || buf[streampos]=='\n'
+ || xcnt>24)
+ break;
+ }
+ }
+ return scanf_res;
+ }
+ private:
+ unsigned char *buf;
+ size_t streampos,streamsize;
+};
+
+inline int LibRaw_abstract_datastream::tempbuffer_open(void *buf, size_t size)
+{
+ if(substream) return EBUSY;
+ substream = new LibRaw_buffer_datastream(buf,size);
+ return substream?0:EINVAL;
+}
+
+
+#endif
+
+#endif
+
diff --git a/libkdcraw/libraw/libraw/libraw_internal.h b/libkdcraw/libraw/libraw/libraw_internal.h
new file mode 100644
index 0000000..109b3a8
--- /dev/null
+++ b/libkdcraw/libraw/libraw/libraw_internal.h
@@ -0,0 +1,241 @@
+/* -*- C++ -*-
+ * File: libraw_internal.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw internal data structures (not visible outside)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIBRAW_INTERNAL_TYPES_H
+#define _LIBRAW_INTERNAL_TYPES_H
+
+#include <stdio.h>
+#ifdef __cplusplus
+
+
+#ifndef CLASS
+#define CLASS LibRaw::
+#endif
+
+#else
+// C build
+#ifndef CLASS
+#define CLASS
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include "libraw_datastream.h"
+
+class LibRaw_TLS
+{
+public:
+ struct
+ {
+ unsigned bitbuf;
+ int vbits, reset;
+ }getbits;
+ struct
+ {
+ UINT64 bitbuf;
+ int vbits;
+
+ }ph1_bits;
+ int make_decoder_leaf;
+ struct
+ {
+ struct decode *dstart[18], *dindex;
+ const int *s;
+ }radc_token;
+ struct
+ {
+ unsigned pad[128], p;
+ }sony_decrypt;
+ unsigned foveon_decoder_huff[1024];
+ uchar jpeg_buffer[4096];
+ struct
+ {
+ uchar buf[0x4000];
+ int vbits, padding;
+ }pana_bits;
+
+ // init - should use in constructor/recycle
+ void init()
+ {
+ getbits.bitbuf = 0; getbits.vbits = getbits.reset = 0;
+ ph1_bits.bitbuf = 0; ph1_bits.vbits = 0;
+ pana_bits.vbits = 0;
+ }
+};
+
+
+class LibRaw_constants
+{
+ public:
+ static const float d65_white[3];
+ static const double xyz_rgb[3][3];
+};
+#endif // __cplusplus
+
+#ifdef WIN32
+typedef long off_t;
+#endif
+
+typedef struct
+{
+#ifndef __cplusplus
+ struct
+#endif
+ LibRaw_abstract_datastream *input;
+ int input_internal;
+// char *ifname;
+ char *meta_data;
+ off_t profile_offset;
+ off_t toffset;
+
+} internal_data_t;
+
+typedef struct
+{
+ unsigned mix_green;
+ unsigned raw_color;
+ unsigned use_gamma;
+ unsigned zero_is_bad;
+ ushort shrink;
+ ushort fuji_width;
+ ushort fwidth,fheight;
+} internal_output_params_t;
+
+#define LIBRAW_HISTOGRAM_SIZE 0x2000
+typedef struct
+{
+ int (*histogram)[LIBRAW_HISTOGRAM_SIZE];
+ unsigned *oprof;
+} output_data_t;
+
+typedef struct
+{
+ unsigned olympus_exif_cfa;
+ unsigned unique_id;
+ unsigned tiff_nifds;
+ int tiff_flip;
+}identify_data_t;
+
+typedef struct
+{
+ short order; // II* / MM* - file word byte order
+ ushort sraw_mul[4],cr2_slice[3];
+ unsigned kodak_cbpp;
+ off_t strip_offset, data_offset;
+ off_t meta_offset;
+ unsigned meta_length;
+ unsigned thumb_misc;
+ unsigned fuji_layout;
+ unsigned tiff_samples;
+ unsigned tiff_bps;
+ unsigned tiff_compress;
+ unsigned zero_after_ff;
+ unsigned tile_width, tile_length,load_flags;
+ unsigned data_error;
+}unpacker_data_t;
+
+
+
+typedef struct
+{
+ internal_data_t internal_data;
+ internal_output_params_t internal_output_params;
+ output_data_t output_data;
+ identify_data_t identify_data;
+ unpacker_data_t unpacker_data;
+// callbacks_t callbacks;
+} libraw_internal_data_t;
+
+
+struct decode
+{
+ struct decode *branch[2];
+ int leaf;
+};
+
+struct tiff_ifd_t
+{
+ int t_width, t_height, bps, comp, phint, offset, t_flip, samples, bytes;
+};
+
+
+struct jhead {
+ int bits, high, wide, clrs, sraw, psv, restart, vpred[6];
+ struct decode *huff[6];
+ ushort *row;
+};
+struct tiff_tag {
+ ushort tag, type;
+ int count;
+ union { char c[4]; short s[2]; int i; } val;
+};
+
+struct tiff_hdr {
+ ushort t_order, magic;
+ int ifd;
+ ushort pad, ntag;
+ struct tiff_tag tag[23];
+ int nextifd;
+ ushort pad2, nexif;
+ struct tiff_tag exif[4];
+ ushort pad3, ngps;
+ struct tiff_tag gpst[10];
+ short bps[4];
+ int rat[10];
+ unsigned gps[26];
+ char t_desc[512], t_make[64], t_model[64], soft[32], date[20], t_artist[64];
+};
+
+
+
+#ifdef DEBUG_STAGE_CHECKS
+#define CHECK_ORDER_HIGH(expected_stage) \
+ do { if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) >= expected_stage) {fprintf(stderr,"CHECK_HIGH: check %d >= %d\n",imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK,expected_stage);return LIBRAW_OUT_OF_ORDER_CALL;} } while(0)
+
+#define CHECK_ORDER_LOW(expected_stage) \
+ do { printf("Checking LOW %d/%d : %d\n",imgdata.progress_flags,expected_stage,imgdata.progress_flags<expected_stage); if( (imgdata.progress_flags&LIBRAW_PROGRESS_THUMB_MASK) < expected_stage ) { printf("failed!\n"); return LIBRAW_OUT_OF_ORDER_CALL;} } while(0)
+#define CHECK_ORDER_BIT(expected_stage) \
+ do { if(imgdata.progress_flags & expected_stage) return LIBRAW_OUT_OF_ORDER_CALL; } while(0)
+
+#define SET_PROC_FLAG(stage) do {imgdata.progress_flags |= stage; fprintf(stderr,"SET_FLAG: %d\n",stage); } while (0)
+
+#else
+
+#define CHECK_ORDER_HIGH(expected_stage) \
+ do { if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) >= expected_stage) \
+ {return LIBRAW_OUT_OF_ORDER_CALL;} } while(0)
+
+#define CHECK_ORDER_LOW(expected_stage) \
+ do { if((imgdata.progress_flags&LIBRAW_PROGRESS_THUMB_MASK) < expected_stage) \
+ return LIBRAW_OUT_OF_ORDER_CALL; } while(0)
+
+#define CHECK_ORDER_BIT(expected_stage) \
+ do { if(imgdata.progress_flags & expected_stage) return LIBRAW_OUT_OF_ORDER_CALL; } while(0)
+
+#define SET_PROC_FLAG(stage) do {imgdata.progress_flags |= stage;} while (0)
+
+#endif
+
+#endif
diff --git a/libkdcraw/libraw/libraw/libraw_types.h b/libkdcraw/libraw/libraw/libraw_types.h
new file mode 100644
index 0000000..c0c3e5e
--- /dev/null
+++ b/libkdcraw/libraw/libraw/libraw_types.h
@@ -0,0 +1,293 @@
+/* -*- C++ -*-
+ * File: libraw_types.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw C data structures
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIBRAW_TYPES_H
+#define _LIBRAW_TYPES_H
+
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+#include <stdio.h>
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef USE_LCMS
+#define NO_LCMS
+#endif
+
+#include "libraw_const.h"
+#include "libraw_version.h"
+
+typedef long long INT64;
+typedef unsigned long long UINT64;
+//#define ushort UshORt
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+
+#ifdef WIN32
+#ifdef LIBRAW_NODLL
+# define DllDef
+#else
+# ifdef LIBRAW_BUILDLIB
+# define DllDef __declspec( dllexport )
+# else
+# define DllDef __declspec( dllimport )
+# endif
+#endif
+// NO Win32
+#else
+# define DllDef
+#endif
+
+
+//class LibRaw;
+
+typedef void (* memory_callback)(void * data, const char *file, const char *where);
+
+DllDef void default_memory_callback(void *data,const char *file, const char *where);
+
+typedef void (*data_callback)(void *data,const char *file, const int offset);
+
+DllDef void default_data_callback(void *data,const char *file, const int offset);
+
+typedef int (* progress_callback) (void *data,enum LibRaw_progress stage, int iteration,int expected);
+
+typedef struct
+{
+ memory_callback mem_cb;
+ void* memcb_data;
+
+ data_callback data_cb;
+ void* datacb_data;
+
+ progress_callback progress_cb;
+ void *progresscb_data;
+} libraw_callbacks_t;
+
+// Output bitmap type
+
+typedef struct
+{
+ enum LibRaw_image_formats type;
+ ushort height,
+ width,
+ colors,
+ bits,
+ gamma_corrected;
+#ifdef _OPENMP
+#pragma omp firstprivate(colors,height,width)
+#endif
+ unsigned int data_size; // ðàçìåð ïîëÿ äàííûõ â áàéòàõ
+ unsigned char data[1]; // we'll allocate more!
+}libraw_processed_image_t;
+
+
+//Decoded from exif and used in calculations
+typedef struct
+{
+ char make[64];
+ char model[64];
+
+ unsigned raw_count;
+ unsigned dng_version;
+ unsigned is_foveon;
+ int colors;
+
+ unsigned filters; // camera CFA pattern mask
+ char cdesc[5];
+
+}libraw_iparams_t;
+
+typedef struct
+{
+ ushort raw_height,
+ raw_width,
+ height,
+ width,
+ top_margin,
+ left_margin;
+ ushort iheight,
+ iwidth;
+#ifdef _OPENMP
+#pragma omp firstprivate(iheight,iwidth)
+#endif
+ double pixel_aspect;
+ int flip;
+
+ // masked border sizes
+ ushort right_margin,bottom_margin; // right masked width and bottom height, inited after idendify()
+
+} libraw_image_sizes_t;
+
+//Phase One data
+struct ph1_t
+{
+ int format, key_off, t_black, black_off, split_col, tag_21a;
+ float tag_210;
+};
+
+
+typedef struct
+{
+ // 32 bits total
+ unsigned curve_state : 3;
+ unsigned rgb_cam_state : 3;
+ unsigned cmatrix_state : 3;
+ unsigned pre_mul_state : 3;
+ unsigned cam_mul_state : 3;
+ unsigned filler : 17;
+} color_data_state_t;
+
+typedef struct
+{
+ color_data_state_t color_flags;
+ ushort white[8][8]; // white block extracted from ciff/CRW
+ float cam_mul[4]; // camera white balance (from RAW)
+ float pre_mul[4]; // either set in identify() or calculated. Used on output
+ float cmatrix[3][4]; // camera color matrix
+ float rgb_cam[3][4]; // another way to set color matrix
+ float cam_xyz[4][3]; // Camera to XYZ matrix (DNG coeffs)
+ ushort curve[0x4001]; // camera tone curve/ljpeg curve
+ unsigned black;
+ unsigned maximum;
+ struct ph1_t phase_one_data;
+ float flash_used; // canon/CRW only
+ float canon_ev; // canon/CRW only
+ char model2[64];
+ // profile
+ void *profile;
+ unsigned profile_length;
+}libraw_colordata_t;
+
+typedef struct
+{
+ enum LibRaw_thumbnail_formats tformat;
+ ushort twidth,
+ theight;
+ unsigned tlength;
+ int tcolors;
+
+ // thumbnail buffer
+ char *thumb;
+}libraw_thumbnail_t;
+
+// Decoded from exif/raw, but not used in real calculations
+typedef struct
+{
+ float iso_speed;
+ float shutter;
+ float aperture;
+ float focal_len;
+ time_t timestamp;
+ unsigned shot_order;
+ unsigned gpsdata[32];
+ // string variables
+ char desc[512],
+ artist[64];
+} libraw_imgother_t;
+
+typedef struct
+{
+ unsigned greybox[4]; /* -A x1 y1 x2 y2 */
+ double aber[4]; /* -C */
+ double gamm[5]; /* -g */
+ float user_mul[4]; /* -r mul0 mul1 mul2 mul3 */
+ unsigned shot_select; /* -s */
+ float bright; /* -b */
+ float threshold; /* -n */
+#ifdef _OPENMP
+#pragma omp firstprivate(threshold)
+#endif
+ int half_size; /* -h */
+ int four_color_rgb; /* -f */
+ int document_mode; /* -d/-D */
+ int highlight; /* -H */
+// int verbose; /* -v */
+ int use_auto_wb; /* -a */
+ int use_camera_wb; /* -w */
+ int use_camera_matrix; /* +M/-M */
+ int output_color; /* -o */
+ char *output_profile; /* -o */
+ char *camera_profile; /* -p */
+ char *bad_pixels; /* -P */
+ char *dark_frame; /* -K */
+ int output_bps; /* -4 */
+ int gamma_16bit; /* -1 */
+ int output_tiff; /* -T */
+ int user_flip; /* -t */
+ int user_qual; /* -q */
+ int user_black; /* -k */
+ int user_sat; /* -S */
+
+ int med_passes; /* -m */
+ float auto_bright_thr;
+ int no_auto_bright; /* -W */
+ int use_fuji_rotate;/* -j */
+ enum LibRaw_filtering filtering_mode;
+}libraw_output_params_t;
+
+typedef struct
+{
+ ushort *buffer; // actual pixel buffer size=(raw_width*raw_height - width*height)
+ ushort *tl; // top left size=(top_margin*left_margin)
+ ushort *top; // top size=(top_margin*width)
+ ushort *tr; // top right size=((raw_width-width-left_margin)*top_margin)
+ ushort *left; // left size=(left_margin*height)
+ ushort *right; // right size=(raw_width-width-left_margin)*height;
+ ushort *bl; // bottom left size=(raw_height-height-top_margin)*left_margin
+ ushort *bottom; // bottom size=(raw_height-height-top_margin)*width
+ ushort *br; // bottom right size=(raw_height-height-top_margin)*
+ ushort (*ph1_black)[2]; // Phase One black
+}libraw_masked_t;
+
+typedef struct
+{
+ unsigned int progress_flags;
+ unsigned int process_warnings;
+ libraw_iparams_t idata;
+ libraw_image_sizes_t sizes;
+ libraw_colordata_t color;
+ libraw_imgother_t other;
+ libraw_thumbnail_t thumbnail;
+ libraw_masked_t masked_pixels;
+ ushort (*image)[4] ;
+#ifdef _OPENMP
+#pragma omp shared(image)
+#endif
+ libraw_output_params_t params;
+ // pointer to LibRaw class for use in C calls
+ void *parent_class;
+} libraw_data_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libkdcraw/libraw/libraw/libraw_version.h b/libkdcraw/libraw/libraw/libraw_version.h
new file mode 100644
index 0000000..4d5211f
--- /dev/null
+++ b/libkdcraw/libraw/libraw/libraw_version.h
@@ -0,0 +1,47 @@
+/* -*- C++ -*-
+ * File: libraw_version.h
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Mon Sept 8, 2008
+ *
+ * LibRaw C++ interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __VERSION_H
+#define __VERSION_H
+
+#define LIBRAW_MAJOR_VERSION 0
+#define LIBRAW_MINOR_VERSION 7
+#define LIBRAW_PATCH_VERSION 2
+#define LIBRAW_VERSION_TAIL Release
+
+#define _LIBRAW_VERSION_MAKE(a,b,c,d) #a"."#b"."#c"-"#d
+#define LIBRAW_VERSION_MAKE(a,b,c,d) _LIBRAW_VERSION_MAKE(a,b,c,d)
+
+#define LIBRAW_VERSION_STR LIBRAW_VERSION_MAKE(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,LIBRAW_PATCH_VERSION,LIBRAW_VERSION_TAIL)
+
+#define LIBRAW_MAKE_VERSION(major,minor,patch) \
+ (((major) << 16) | ((minor) << 8) | (patch))
+
+#define LIBRAW_VERSION \
+ LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,LIBRAW_PATCH_VERSION)
+
+#define LIBRAW_CHECK_VERSION(major,minor,patch) \
+ ( LibRaw::versionNumber() >= LIBRAW_MAKE_VERSION(major,minor,patch) )
+
+
+#endif
diff --git a/libkdcraw/libraw/samples/4channels.cpp b/libkdcraw/libraw/samples/4channels.cpp
new file mode 100644
index 0000000..d266c53
--- /dev/null
+++ b/libkdcraw/libraw/samples/4channels.cpp
@@ -0,0 +1,187 @@
+/* -*- C++ -*-
+ * File: 4channels.cpp
+ * Copyright 2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Mon Feb 09, 2009
+ *
+ * LibRaw sample
+ * Generates 4 TIFF file from RAW data, one file per channel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#ifndef WIN32
+#include <netinet/in.h>
+#else
+#include <winsock2.h>
+#endif
+
+#include "libraw/libraw.h"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+int main(int ac, char *av[])
+{
+ int i, ret;
+ int autoscale=0,filtering_mode=LIBRAW_FILTERING_DEFAULT,black_subtraction=1;
+ char outfn[1024],thumbfn[1024];
+
+ LibRaw RawProcessor;
+ if(ac<2)
+ {
+ usage:
+ printf(
+ "4channeld - LibRaw %s sample. %d cameras supported\n"
+ "Usage: %s [-s N] [-g] [-A] [-B] [-N] raw-files....\n"
+ "\t-s N - select Nth image in file (default=0)\n"
+ "\t-g - use gamma correction with gamma 2.2 (not precise,use for visual inspection only)\n"
+ "\t-A - autoscaling (by integer factor)\n"
+ "\t-B - no black subtraction\n"
+ "\t-N - no raw curve\n"
+ ,LibRaw::version(),
+ LibRaw::cameraCount(),
+ av[0]);
+ return 0;
+ }
+
+#define P1 RawProcessor.imgdata.idata
+#define S RawProcessor.imgdata.sizes
+#define C RawProcessor.imgdata.color
+#define T RawProcessor.imgdata.thumbnail
+#define P2 RawProcessor.imgdata.other
+#define OUT RawProcessor.imgdata.params
+
+ OUT.document_mode=2;
+ OUT.output_bps=16;
+ OUT.output_tiff=1;
+ OUT.user_flip=0;
+ OUT.no_auto_bright = 1;
+ OUT.half_size=1;
+ OUT.filtering_mode= LIBRAW_FILTERING_AUTOMATIC;
+
+ for (i=1;i<ac;i++)
+ {
+ if(av[i][0]=='-')
+ {
+ if(av[i][1]=='s' && av[i][2]==0)
+ {
+ i++;
+ OUT.shot_select=atoi(av[i]);
+ }
+ else if(av[i][1]=='g' && av[i][2]==0)
+ OUT.gamma_16bit=1;
+ else if(av[i][1]=='A' && av[i][2]==0)
+ autoscale=1;
+ else if(av[i][1]=='B' && av[i][2]==0)
+ {
+ filtering_mode |= (LIBRAW_FILTERING_NOZEROES | LIBRAW_FILTERING_NOBLACKS);
+ black_subtraction=0;
+ }
+ else if(av[i][1]=='N' && av[i][2]==0)
+ filtering_mode |= LIBRAW_FILTERING_NORAWCURVE;
+ else
+ goto usage;
+ continue;
+ }
+ if(filtering_mode)
+ OUT.filtering_mode = (LibRaw_filtering) filtering_mode;
+ int r,c;
+ printf("Processing file %s\n",av[i]);
+ if( (ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot open %s: %s\n",av[i],libraw_strerror(ret));
+ continue; // no recycle b/c open file will recycle itself
+ }
+ if(P1.is_foveon)
+ {
+ printf("Cannot process foveon image %s\n",av[i]);
+ continue ;
+ }
+ if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret));
+ continue;
+ }
+ if(black_subtraction && C.black>0)
+ {
+ for(int j=0; j<S.iheight*S.iwidth; j++)
+ for(int c = 0; c< 4; c++)
+ if(RawProcessor.imgdata.image[j][c]>C.black)
+ RawProcessor.imgdata.image[j][c]-=C.black;
+ else
+ RawProcessor.imgdata.image[j][c]=0;
+ }
+
+ if(autoscale)
+ {
+ unsigned max=0,scale;
+ for(int j=0; j<S.iheight*S.iwidth; j++)
+ for(int c = 0; c< 4; c++)
+ if(max < RawProcessor.imgdata.image[j][c])
+ max = RawProcessor.imgdata.image[j][c];
+ if (max >0 && max< 1<<15)
+ {
+ scale = (1<<16)/max;
+ printf("Scaling with multiplier=%d (max=%d)\n",scale,max);
+ for(int j=0; j<S.iheight*S.iwidth; j++)
+ for(c=0;c<4;c++)
+ RawProcessor.imgdata.image[j][c] *= scale;
+ }
+ printf("Black level (scaled)=%d\n",C.black*scale);
+ }
+ else
+ printf("Black level (unscaled)=%d\n",C.black);
+
+
+ // hack to make dcraw tiff writer happy
+ int isrgb=(P1.colors==4?0:1);
+ P1.colors = 1;
+ S.width = S.iwidth;
+ S.height = S.iheight;
+
+ for (int layer=0;layer<4;layer++)
+ {
+ if(layer>0)
+ {
+ for (int rc = 0; rc < S.iheight*S.iwidth; rc++)
+ RawProcessor.imgdata.image[rc][0] = RawProcessor.imgdata.image[rc][layer];
+ }
+ char lname[8];
+ if(isrgb)
+ {
+ snprintf(lname,7,"%c",(char*)("RGBG")[layer]);
+ if(layer==3)
+ strcat(lname,"2");
+ }
+ else
+ snprintf(lname,7,"%c",(char*)("GCMY")[layer]);
+
+ if(OUT.shot_select)
+ snprintf(outfn,sizeof(outfn),"%s-%d.%s.tiff",av[i],OUT.shot_select,lname);
+ else
+ snprintf(outfn,sizeof(outfn),"%s.%s.tiff",av[i],lname);
+
+ printf("Writing file %s\n",outfn);
+ if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn)))
+ fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret));
+ }
+
+ }
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/dcraw_emu.cpp b/libkdcraw/libraw/samples/dcraw_emu.cpp
new file mode 100644
index 0000000..704475a
--- /dev/null
+++ b/libkdcraw/libraw/samples/dcraw_emu.cpp
@@ -0,0 +1,281 @@
+/* -*- C++ -*-
+ * File: dcraw_emu.cpp
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sun Mar 23, 2008
+ *
+ * LibRaw simple C++ API (almost complete dcraw emulator)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#ifndef WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#endif
+
+#include "libraw/libraw.h"
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+
+void usage(const char *prog)
+{
+ printf("dcraw_emu: almost complete dcraw emulator\n");
+ printf("Usage: %s [OPTION]... [FILE]...\n", prog);
+ printf(
+"-v Verbose: print progress messages (repeated -v will add verbosity)\n"
+"-w Use camera white balance, if possible\n"
+"-a Average the whole image for white balance\n"
+"-A <x y w h> Average a grey box for white balance\n"
+"-r <r g b g> Set custom white balance\n"
+"+M/-M Use/don't use an embedded color matrix\n"
+"-C <r b> Correct chromatic aberration\n"
+"-P <file> Fix the dead pixels listed in this file\n"
+"-K <file> Subtract dark frame (16-bit raw PGM)\n"
+"-k <num> Set the darkness level\n"
+"-S <num> Set the saturation level\n"
+"-n <num> Set threshold for wavelet denoising\n"
+"-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)\n"
+"-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)\n"
+"-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)\n"
+#ifndef NO_LCMS
+"-o file Output ICC profile\n"
+"-p file Camera input profile (use \'embed\' for embedded profile)\n"
+#endif
+"-j Don't stretch or rotate raw pixels\n"
+"-W Don't automatically brighten the image\n"
+"-b <num> Adjust brightness (default = 1.0)\n"
+"-q [0-3] Set the interpolation quality\n"
+"-h Half-size color image (twice as fast as \"-q 0\")\n"
+"-f Interpolate RGGB as four colors\n"
+"-m <num> Apply a 3x3 median filter to R-G and B-G\n"
+"-s [0..N-1] Select one raw image from input file\n"
+"-4 Write 16-bit linear instead of 8-bit with gamma\n"
+"-g pow ts Set gamma curve to gamma pow and toe slope ts (default = 2.222 4.5)\n"
+"-T Write TIFF instead of PPM\n"
+#ifndef WIN32
+"-B Use mmap()-ed buffer instead of plain FILE I/O\n"
+#endif
+ );
+ exit(1);
+}
+
+static int verbosity=0;
+
+int cnt=0;
+int my_progress_callback(void *d,enum LibRaw_progress p,int iteration, int expected)
+{
+ char *passed = (char*)(d?d:"default string"); // data passed to callback at set_callback stage
+
+ if(verbosity>2) // verbosity set by repeat -v switches
+ {
+ printf("CB: %s pass %d of %d (data passed=%s)\n",libraw_strprogress(p),iteration,expected,passed);
+ }
+ else if (iteration == 0) // 1st iteration of each step
+ printf("Starting %s (expecting %d iterations)\n", libraw_strprogress(p),expected);
+ else if (iteration == expected-1)
+ printf("%s finished\n",libraw_strprogress(p));
+
+/// if(++cnt>10) return 1; // emulate user termination on 10-th callback call
+
+ return 0; // always return 0 to continue processing
+}
+
+
+int main(int argc, char *argv[])
+{
+ if(argc==1) usage(argv[0]);
+
+ LibRaw RawProcessor;
+ int i,arg,c,ret;
+ char opm,opt,*cp,*sp;
+ int use_mmap=0, msize;
+ void *iobuffer;
+
+#define OUT RawProcessor.imgdata.params
+
+ argv[argc] = "";
+ for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; )
+ {
+ opt = argv[arg++][1];
+ if ((cp = strchr (sp="nbrkStqmHACgU", opt)))
+ for (i=0; i < "11411111142"[cp-sp]-'0'; i++)
+ if (!isdigit(argv[arg+i][0]))
+ {
+ fprintf (stderr,"Non-numeric argument to \"-%c\"\n", opt);
+ return 1;
+ }
+ switch (opt)
+ {
+ case 'v': verbosity++; break;
+
+ case 'U': OUT.auto_bright_thr = atof(argv[arg++]); break;
+ case 'n': OUT.threshold = atof(argv[arg++]); break;
+ case 'b': OUT.bright = atof(argv[arg++]); break;
+ case 'P': OUT.bad_pixels = argv[arg++]; break;
+ case 'K': OUT.dark_frame = argv[arg++]; break;
+ case 'r':
+ for(c=0;c<4;c++)
+ OUT.user_mul[c] = atof(argv[arg++]);
+ break;
+ case 'C':
+ OUT.aber[0] = 1 / atof(argv[arg++]);
+ OUT.aber[2] = 1 / atof(argv[arg++]);
+ break;
+ case 'g':
+ OUT.gamm[0] = 1 / atof(argv[arg++]);
+ OUT.gamm[1] = atof(argv[arg++]);
+ break;
+ case 'k': OUT.user_black = atoi(argv[arg++]); break;
+ case 'S': OUT.user_sat = atoi(argv[arg++]); break;
+ case 't': OUT.user_flip = atoi(argv[arg++]); break;
+ case 'q': OUT.user_qual = atoi(argv[arg++]); break;
+ case 'm': OUT.med_passes = atoi(argv[arg++]); break;
+ case 'H': OUT.highlight = atoi(argv[arg++]); break;
+ case 's': OUT.shot_select = abs(atoi(argv[arg++])); break;
+ case 'o':
+ if(isdigit(argv[arg+1][0]) && !isdigit(argv[arg+1][1]))
+ OUT.output_color = atoi(argv[arg++]);
+#ifndef NO_LCMS
+ else
+ OUT.output_profile = argv[arg++];
+ break;
+ case 'p': OUT.camera_profile = argv[arg++];
+#endif
+ break;
+ case 'h': OUT.half_size = 1;
+ // no break: "-h" implies "-f"
+ case 'f':
+ OUT.four_color_rgb = 1;
+ break;
+ case 'A': for(c=0; c<4;c++) OUT.greybox[c] = atoi(argv[arg++]);
+ case 'a': OUT.use_auto_wb = 1; break;
+ case 'w': OUT.use_camera_wb = 1; break;
+ case 'M': OUT.use_camera_matrix = (opm == '+'); break;
+ case 'j': OUT.use_fuji_rotate = 0; break;
+ case 'W': OUT.no_auto_bright = 1; break;
+ case 'T': OUT.output_tiff = 1; break;
+ case '4': OUT.output_bps = 16; break;
+ case '1': OUT.gamma_16bit = 1; break;
+#ifndef WIN32
+ case 'B': use_mmap = 1; break;
+#endif
+ default:
+ fprintf (stderr,"Unknown option \"-%c\".\n", opt);
+ return 1;
+ }
+ }
+ putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field
+ OUT.filtering_mode = LIBRAW_FILTERING_AUTOMATIC;
+#define P1 RawProcessor.imgdata.idata
+#define S RawProcessor.imgdata.sizes
+#define C RawProcessor.imgdata.color
+#define T RawProcessor.imgdata.thumbnail
+#define P2 RawProcessor.imgdata.other
+
+ if(verbosity>1)
+ RawProcessor.set_progress_handler(my_progress_callback,(void*)"Sample data passed");
+#ifdef _OPENMP
+ if(verbosity)
+ printf ("Using %d threads\n", omp_get_max_threads());
+#endif
+
+ for ( ; arg < argc; arg++)
+ {
+ char outfn[1024];
+
+ if(verbosity) printf("Processing file %s\n",argv[arg]);
+#ifndef WIN32
+ if(use_mmap)
+ {
+ int file = open(argv[arg],O_RDONLY);
+ struct stat st;
+ if(file<0)
+ {
+ fprintf(stderr,"Cannot open %s: %s\n",argv[arg],strerror(errno));
+ continue;
+ }
+ if(fstat(file,&st))
+ {
+ fprintf(stderr,"Cannot stat %s: %s\n",argv[arg],strerror(errno));
+ close(file);
+ continue;
+ }
+ int pgsz = getpagesize();
+ msize = ((st.st_size+pgsz-1)/pgsz)*pgsz;
+ iobuffer = mmap(NULL,msize,PROT_READ,MAP_PRIVATE,file,0);
+ if(!iobuffer)
+ {
+ fprintf(stderr,"Cannot mmap %s: %s\n",argv[arg],strerror(errno));
+ close(file);
+ continue;
+ }
+ close(file);
+ if( (ret = RawProcessor.open_buffer(iobuffer,st.st_size) != LIBRAW_SUCCESS))
+ {
+ fprintf(stderr,"Cannot open_buffer %s: %s\n",argv[arg],libraw_strerror(ret));
+ continue; // no recycle b/c open file will recycle itself
+ }
+
+ }
+ else
+#endif
+ {
+ if( (ret = RawProcessor.open_file(argv[arg])) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot open %s: %s\n",argv[arg],libraw_strerror(ret));
+ continue; // no recycle b/c open_file will recycle itself
+ }
+ }
+ if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot unpack %s: %s\n",argv[arg],libraw_strerror(ret));
+ continue;
+ }
+ if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_process()))
+ {
+ fprintf(stderr,"Cannot do postpocessing on %s: %s\n",argv[arg],libraw_strerror(ret));
+ if(LIBRAW_FATAL_ERROR(ret))
+ continue;
+ }
+ snprintf(outfn,sizeof(outfn),
+ "%s.%s",
+ argv[arg], OUT.output_tiff ? "tiff" : (P1.colors>1?"ppm":"pgm"));
+
+ if(verbosity) printf("Writing file %s\n",outfn);
+
+ if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn)))
+ fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret));
+
+#ifndef WIN32
+ if(use_mmap && iobuffer)
+ {
+ munmap(iobuffer,msize);
+ iobuffer=0;
+ }
+#endif
+
+ RawProcessor.recycle(); // just for show this call
+ }
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/dcraw_half.c b/libkdcraw/libraw/samples/dcraw_half.c
new file mode 100644
index 0000000..814f697
--- /dev/null
+++ b/libkdcraw/libraw/samples/dcraw_half.c
@@ -0,0 +1,83 @@
+/* -*- C++ -*-
+ * File: dcraw_half.c
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw C API sample (emulates call to "dcraw -h")
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "libraw/libraw.h"
+
+
+#define HANDLE_FATAL_ERROR(ret)\
+ if(ret)\
+ {\
+ fprintf(stderr,"%s: libraw %s\n",av[i],libraw_strerror(ret));\
+ if(LIBRAW_FATAL_ERROR(ret))\
+ exit(1); \
+ }\
+
+#define HANDLE_ALL_ERRORS(ret)\
+ if(ret)\
+ {\
+ fprintf(stderr,"%s: libraw %s\n",av[i],libraw_strerror(ret));\
+ continue; \
+ }\
+
+
+int main(int ac, char *av[])
+{
+ int i;
+ libraw_data_t *iprc = libraw_init(0);
+
+ if(!iprc)
+ {
+ fprintf(stderr,"Cannot create libraw handle\n");
+ exit(1);
+ }
+
+ iprc->params.half_size = 1; /* dcraw -h */
+
+ for (i=1;i<ac;i++)
+ {
+ char outfn[1024];
+ int ret = libraw_open_file(iprc,av[i]);
+ HANDLE_ALL_ERRORS(ret);
+
+ printf("Processing %s (%s %s)\n",av[i],iprc->idata.make,iprc->idata.model);
+
+ ret = libraw_unpack(iprc);
+ HANDLE_ALL_ERRORS(ret);
+
+ ret = libraw_dcraw_process(iprc);
+ HANDLE_ALL_ERRORS(ret);
+
+ strcpy(outfn,av[i]);
+ strcat(outfn,".ppm");
+ printf("Writing to %s\n",outfn);
+
+ ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn);
+ HANDLE_FATAL_ERROR(ret);
+ }
+ libraw_close(iprc);
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/half_mt.c b/libkdcraw/libraw/samples/half_mt.c
new file mode 100644
index 0000000..7d5177c
--- /dev/null
+++ b/libkdcraw/libraw/samples/half_mt.c
@@ -0,0 +1,178 @@
+/* -*- C++ -*-
+ * File: halt_mt.c
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw C API mutithreaded sample (emulates call to "dcraw -h [-w] [-a] [-v]")
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <pthread.h>
+
+#include "libraw/libraw.h"
+
+#define HANDLE_ERRORS(ret) do { \
+ if(ret) \
+ { \
+ fprintf(stderr,"%s: %s\n",fn,libraw_strerror(ret)); \
+ if(LIBRAW_FATAL_ERROR(ret)) \
+ { \
+ libraw_close(iprc); \
+ return -1; \
+ } \
+ } \
+ }while(0)
+
+
+// global settings
+int verbose=0,use_camera_wb=0,use_auto_wb=0,tiff_mode=0;
+
+// global file queue
+pthread_mutex_t qm;
+char **queue=NULL;
+size_t qsize=0,qptr=0;
+
+char *get_next_file()
+{
+ char *ret;
+ if(!queue) return NULL;
+ if(qptr>=qsize) return NULL;
+ pthread_mutex_lock(&qm);
+ ret = queue[qptr++];
+ pthread_mutex_unlock(&qm);
+ return ret;
+}
+
+
+// thread routine
+int process_files(void *q)
+{
+ int ret;
+ int count=0;
+ char outfn[1024], *fn;
+ libraw_data_t *iprc = libraw_init(0);
+
+ if(!iprc)
+ {
+ fprintf(stderr,"Cannot create libraw handle\n");
+ return -1;
+ }
+
+ while((fn = get_next_file()))
+ {
+
+ iprc->params.half_size = 1; /* dcraw -h */
+ iprc->params.use_camera_wb = use_camera_wb;
+ iprc->params.use_auto_wb = use_auto_wb;
+ iprc->params.output_tiff = tiff_mode;
+
+ ret = libraw_open_file(iprc,fn);
+ if(verbose) fprintf(stderr,"%s: %s/%s\n",fn,iprc->idata.make,iprc->idata.model);
+ HANDLE_ERRORS(ret);
+
+ ret = libraw_unpack(iprc);
+ HANDLE_ERRORS(ret);
+
+ ret = libraw_dcraw_process(iprc);
+ HANDLE_ERRORS(ret);
+
+ snprintf(outfn,1023,"%s.ppm",fn);
+
+ if(verbose) fprintf(stderr,"Writing file %s\n",outfn);
+ ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn);
+ HANDLE_ERRORS(ret);
+ count++;
+ }
+ libraw_close(iprc);
+ return count;
+}
+
+void usage(const char*p)
+{
+ printf("%s: Multi-threaded LibRaw sample app. Emulates dcraw -h [-w] [-a]\n",p);
+ printf(
+ "Options:\n"
+ "-J n - set parrallel job coun (default 2)\n"
+ "-v - verbose\n"
+ "-w - use camera white balance\n"
+ "-a - average image for white balance\n");
+ exit(1);
+}
+
+int show_files(void *q)
+{
+ char *p;
+ int cnt = 0;
+ while(p = get_next_file())
+ {
+ printf("%s\n",p);
+ cnt++;
+ }
+ return cnt;
+
+}
+
+int main(int ac, char *av[])
+{
+ int i, thread_count,max_threads = 2;
+ pthread_t *threads;
+ if(ac<2)
+ usage(av[0]);
+
+ queue = calloc(ac-1,sizeof(queue[0]));
+
+ for (i=1;i<ac;i++)
+ {
+ if(av[i][0]=='-')
+ {
+ if(av[i][1]=='w') use_camera_wb = 1;
+ if(av[i][1]=='a') use_auto_wb = 1;
+ if(av[i][1]=='v') verbose = 1;
+ if(av[i][1]=='T') tiff_mode = 1;
+ if(av[i][1]=='J')
+ {
+ max_threads=atoi(av[++i]);
+ if(max_threads<1)
+ {
+ fprintf(stderr,"Job count should be at least 1\n");
+ exit(1);
+ }
+ }
+ }
+ else
+ queue[qsize++] = av[i];
+ }
+ pthread_mutex_init(&qm,NULL);
+ threads = calloc(max_threads,sizeof(threads[0]));
+ for(i=0;i<max_threads;i++)
+ pthread_create(&threads[i],NULL,process_files,NULL);
+ for(i=0;i<max_threads;i++)
+ {
+ int *iptr;
+ if(threads[i])
+ {
+ pthread_join(threads[i],&iptr);
+ if(iptr)
+ printf("Thread %d : %d files\n",i,(int)iptr);
+ }
+ }
+
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/half_mt_win32.c b/libkdcraw/libraw/samples/half_mt_win32.c
new file mode 100644
index 0000000..990a800
--- /dev/null
+++ b/libkdcraw/libraw/samples/half_mt_win32.c
@@ -0,0 +1,212 @@
+/* -*- C++ -*-
+ * File: halt_mt_win32.c
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw C API mutithreaded sample (emulates call to "dcraw -h [-w] [-a] [-v]")
+ * Win32 version
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <windows.h>
+#include "libraw/libraw.h"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+
+#define HANDLE_ERRORS(ret) do { \
+ if(ret) \
+ { \
+ fprintf(stderr,"%s: %s\n",fn,libraw_strerror(ret)); \
+ if(LIBRAW_FATAL_ERROR(ret)) \
+ { \
+ libraw_close(iprc); \
+ return -1; \
+ } \
+ } \
+ }while(0)
+
+
+// global settings
+int verbose=0,use_camera_wb=0,use_auto_wb=0,tiff_mode=0;
+
+// global file queue
+HANDLE qmutex;
+char **queue=NULL;
+size_t qsize=0,qptr=0;
+
+char *get_next_file()
+{
+ char *ret;
+ DWORD dwWaitResult;
+ if(!queue) return NULL;
+ if(qptr>=qsize) return NULL;
+
+ dwWaitResult = WaitForSingleObject(
+ qmutex, // handle to mutex
+ INFINITE); // no time-out interval
+ switch (dwWaitResult)
+ {
+ // The thread got ownership of the mutex
+ case WAIT_OBJECT_0:
+ ret = queue[qptr++];
+ ReleaseMutex(qmutex);
+ break;
+ case WAIT_ABANDONED:
+ return NULL; // cannot obtain the lock
+ };
+ return ret;
+}
+
+
+// thread routine
+int process_files(void *q)
+{
+ int ret;
+ int count=0;
+ char outfn[1024], *fn;
+ libraw_data_t *iprc = libraw_init(0);
+
+ if(!iprc)
+ {
+ fprintf(stderr,"Cannot create libraw handle\n");
+ return -1;
+ }
+
+ while((fn = get_next_file()))
+ {
+
+ iprc->params.half_size = 1; /* dcraw -h */
+ iprc->params.use_camera_wb = use_camera_wb;
+ iprc->params.use_auto_wb = use_auto_wb;
+ iprc->params.output_tiff = tiff_mode;
+
+ ret = libraw_open_file(iprc,fn);
+ if(verbose) fprintf(stderr,"%s: %s/%s\n",fn,iprc->idata.make,iprc->idata.model);
+ HANDLE_ERRORS(ret);
+
+ ret = libraw_unpack(iprc);
+ HANDLE_ERRORS(ret);
+
+ ret = libraw_dcraw_process(iprc);
+ HANDLE_ERRORS(ret);
+
+ snprintf(outfn,1023,"%s.%s",fn,tiff_mode?"tif":"ppm");
+
+ if(verbose) fprintf(stderr,"Writing file %s\n",outfn);
+ ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn);
+ HANDLE_ERRORS(ret);
+ count++;
+ }
+ libraw_close(iprc);
+ printf("Processed %d files\n",count);
+ return 0;
+}
+
+void usage(const char*p)
+{
+ printf(
+ "Options:\n"
+ "-J n - set parrallel job coun (default 2)\n"
+ "-v - verbose\n"
+ "-w - use camera white balance\n"
+ "-T - output TIFF instead of PPM\n"
+ "-a - average image for white balance\n");
+ exit(1);
+}
+
+int show_files(void *q)
+{
+ char *p;
+ int cnt = 0;
+ while(p = get_next_file())
+ {
+ printf("%s\n",p);
+ cnt++;
+ }
+ return cnt;
+
+}
+
+int main(int ac, char *av[])
+{
+ int i,max_threads = 2;
+ HANDLE *threads;
+ DWORD ThreadID;
+
+ if(ac<2)
+ usage(av[0]);
+
+ queue = calloc(ac-1,sizeof(queue[0]));
+
+ for (i=1;i<ac;i++)
+ {
+ if(av[i][0]=='-')
+ {
+ if(av[i][1]=='w') use_camera_wb = 1;
+ if(av[i][1]=='a') use_auto_wb = 1;
+ if(av[i][1]=='v') verbose = 1;
+ if(av[i][1]=='T') tiff_mode = 1;
+ if(av[i][1]=='J')
+ {
+ max_threads=atoi(av[++i]);
+ if(max_threads<1)
+ {
+ fprintf(stderr,"Job count should be at least 1\n");
+ exit(1);
+ }
+ }
+ }
+ else
+ queue[qsize++] = av[i];
+ }
+ qmutex = CreateMutex(NULL,FALSE,NULL);
+ threads = calloc(max_threads,sizeof(threads[0]));
+ for(i=0;i<max_threads;i++)
+ {
+
+ if (NULL == (threads[i] = CreateThread(
+ NULL, // default security attributes
+ 0, // default stack size
+ (LPTHREAD_START_ROUTINE) process_files,
+ NULL, // no thread function arguments
+ 0, // default creation flags
+ &ThreadID) // receive thread identifier
+ )
+ )
+ {
+ printf("CreateThread error: %d\n", GetLastError());
+ return 1;
+ }
+ }
+
+ WaitForMultipleObjects(max_threads, threads, TRUE, INFINITE);
+
+ // Close thread and mutex handles
+
+ for( i=0; i < max_threads; i++ )
+ CloseHandle(threads[i]);
+
+ CloseHandle(qmutex);
+
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/identify.cpp b/libkdcraw/libraw/samples/identify.cpp
new file mode 100644
index 0000000..a1e0f20
--- /dev/null
+++ b/libkdcraw/libraw/samples/identify.cpp
@@ -0,0 +1,147 @@
+/* -*- C++ -*-
+ * File: identify.cpp
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw C++ demo (emulates dcraw -i [-v])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include "libraw/libraw.h"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+
+int main(int ac, char *av[])
+{
+ int verbose = 0, ret,print_unpack=0,print_frame=0;
+ LibRaw MyCoolRawProcessor;
+
+ for (int i=1;i<ac;i++) {
+ if(av[i][0]=='-')
+ {
+ if(av[i][1]=='v' && av[i][2]==0) verbose++;
+ if(av[i][1]=='u' && av[i][2]==0) print_unpack++;
+ if(av[i][1]=='f' && av[i][2]==0) print_frame++;
+ continue;
+ }
+ if( (ret = MyCoolRawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
+ {
+ printf("Cannot decode %s: %s\n",av[i],libraw_strerror(ret));
+ continue; // no recycle, open_file will recycle
+ }
+ if(verbose) {
+
+#define P1 MyCoolRawProcessor.imgdata.idata
+#define P2 MyCoolRawProcessor.imgdata.other
+
+#define S MyCoolRawProcessor.imgdata.sizes
+#define O MyCoolRawProcessor.imgdata.params
+#define C MyCoolRawProcessor.imgdata.color
+#define T MyCoolRawProcessor.imgdata.thumbnail
+
+
+ if( (ret = MyCoolRawProcessor.adjust_sizes_info_only()))
+ {
+ printf("Cannot decode %s: %s\n",av[i],libraw_strerror(ret));
+ continue; // no recycle, open_file will recycle
+ }
+
+ printf ("\nFilename: %s\n", av[i]);
+ printf ("Timestamp: %s", ctime(&(P2.timestamp)));
+ printf ("Camera: %s %s\n", P1.make, P1.model);
+ if (P2.artist[0])
+ printf ("Owner: %s\n", P2.artist);
+ if (P1.dng_version) {
+ printf ("DNG Version: ");
+ for (int i=24; i >= 0; i -= 8)
+ printf ("%d%c", P1.dng_version >> i & 255, i ? '.':'\n');
+ }
+ printf ("ISO speed: %d\n", (int) P2.iso_speed);
+ printf ("Shutter: ");
+ if (P2.shutter > 0 && P2.shutter < 1)
+ P2.shutter = (printf ("1/"), 1 / P2.shutter);
+ printf ("%0.1f sec\n", P2.shutter);
+ printf ("Aperture: f/%0.1f\n", P2.aperture);
+ printf ("Focal length: %0.1f mm\n", P2.focal_len);
+ if(C.profile)
+ printf ("Embedded ICC profile: yes, %d bytes\n", C.profile_length);
+ else
+ printf ("Embedded ICC profile: no\n", C.profile_length);
+
+ printf ("Number of raw images: %d\n", P1.raw_count);
+ if (S.pixel_aspect != 1)
+ printf ("Pixel Aspect Ratio: %0.6f\n", S.pixel_aspect);
+ if (T.tlength)
+ printf ("Thumb size: %4d x %d\n", T.twidth, T.theight);
+ printf ("Full size: %4d x %d\n", S.raw_width, S.raw_height);
+
+ printf ("Image size: %4d x %d\n", S.width, S.height);
+ printf ("Output size: %4d x %d\n", S.iwidth, S.iheight);
+ printf ("Raw colors: %d", P1.colors);
+ if (P1.filters)
+ {
+ printf ("\nFilter pattern: ");
+ if (!P1.cdesc[3]) P1.cdesc[3] = 'G';
+ for (int i=0; i < 16; i++)
+ putchar (P1.cdesc[MyCoolRawProcessor.fc(i >> 1,i & 1)]);
+ }
+ printf ("\nDaylight multipliers:");
+ for(int c=0;c<P1.colors;c++) printf (" %f", C.pre_mul[c]);
+ if (C.cam_mul[0] > 0)
+ {
+ printf ("\nCamera multipliers:");
+ for(int c=0;c<4;c++) printf (" %f", C.cam_mul[c]);
+ }
+ char *csl[] = {"U","I","CO","L","CA"};
+ printf("\nColor sources /Legend: (U)nknown, (I)nit, (CO)nstant, (L)oaded, (CA)lculated/:\n");
+ printf("\tcurve=%s; rgb_cam=%s; cmatrix=%s, pre_mul=%s, cam_mul=%s",
+ csl[C.color_flags.curve_state],csl[C.color_flags.rgb_cam_state],
+ csl[C.color_flags.cmatrix_state],csl[C.color_flags.pre_mul_state],
+ csl[C.color_flags.cam_mul_state]);
+ putchar ('\n');
+ printf("Cam->XYZ matrix:\n");
+ for(int i=0; i< 4; i++)
+ printf("%6.4f\t%6.4f\t%6.4f\n",C.cam_xyz[i][0],C.cam_xyz[i][1],C.cam_xyz[i][2]);
+ }
+ else
+ {
+ if(print_unpack)
+ {
+ char frame[32]="";
+ if(print_frame)
+ snprintf(frame,32,"%dx%dx%dx%d",S.left_margin,S.top_margin,S.right_margin,S.bottom_margin);
+ printf ("%s\t%s\t%s\t%s/%s\n",
+ av[i],
+ MyCoolRawProcessor.unpack_function_name(),
+ frame,
+ P1.make, P1.model);
+ }
+ else
+ printf ("%s is a %s %s image.\n", av[i],P1.make, P1.model);
+ }
+ MyCoolRawProcessor.recycle();
+ }// endfor
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/mem_image.cpp b/libkdcraw/libraw/samples/mem_image.cpp
new file mode 100644
index 0000000..29fd7c4
--- /dev/null
+++ b/libkdcraw/libraw/samples/mem_image.cpp
@@ -0,0 +1,198 @@
+/* -*- C++ -*-
+ * File: mem_image.cpp
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw mem_image/mem_thumb API test. Resuls should be same (bitwise) as in dcraw [-4] [-e]
+ * Testing note: for ppm-thumbnails you should use dcraw -w -e for thumbnail extraction
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "libraw/libraw.h"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#include <winsock2.h>
+#pragma comment(lib, "ws2_32.lib")
+#else
+#include <netinet/in.h>
+#endif
+
+
+// no error reporting, only params check
+void write_ppm(libraw_processed_image_t *img, const char *basename)
+{
+ if(!img) return;
+ // type SHOULD be LIBRAW_IMAGE_BITMAP, but we'll check
+ if(img->type != LIBRAW_IMAGE_BITMAP) return;
+ // only 3-color images supported...
+ if(img->colors != 3) return;
+
+ char fn[1024];
+ snprintf(fn,1024,"%s.ppm",basename);
+ FILE *f = fopen(fn,"wb");
+ if(!f) return;
+ fprintf (f, "P6\n%d %d\n%d\n", img->width, img->height, (1 << img->bits)-1);
+/*
+ NOTE:
+ data in img->data is not converted to network byte order.
+ So, we should swap values on some architectures for dcraw compatibility
+ (unfortunately, xv cannot display 16-bit PPMs with network byte order data
+*/
+#define SWAP(a,b) { a ^= b; a ^= (b ^= a); }
+ if (img->bits == 16 && htons(0x55aa) != 0x55aa)
+ for(int i=0; i< img->data_size; i+=2)
+ SWAP(img->data[i],img->data[i+1]);
+#undef SWAP
+
+ fwrite(img->data,img->data_size,1,f);
+ fclose(f);
+}
+
+void write_thumb(libraw_processed_image_t *img, const char *basename)
+{
+ if(!img) return;
+
+ if(img->type == LIBRAW_IMAGE_BITMAP)
+ {
+ char fnt[1024];
+ snprintf(fnt,1024,"%s.thumb",basename);
+ write_ppm(img,fnt);
+ }
+ else if (img->type == LIBRAW_IMAGE_JPEG)
+ {
+ char fn[1024];
+ snprintf(fn,1024,"%s.thumb.jpg",basename);
+ FILE *f = fopen(fn,"wb");
+ if(!f) return;
+ fwrite(img->data,img->data_size,1,f);
+ fclose(f);
+ }
+}
+
+
+
+int main(int ac, char *av[])
+{
+ int i, ret, verbose=0, output_thumbs=0;
+
+ // don't use fixed size buffers in real apps!
+ char outfn[1024],thumbfn[1024];
+
+ LibRaw RawProcessor;
+
+ if(ac<2)
+ {
+ printf(
+ "mem_image - LibRaw sample, to illustrate work for memory buffers. Emulates dcraw [-4] [-1] [-e]\n"
+ "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n"
+ "\t-4 - output 16-bit PPM\n"
+ "\t-1 - gamma-correct 16-bit data\n"
+ "\t-e - extract thumbnails (same as dcraw -e in separate run)\n",
+ av[0]);
+ return 0;
+ }
+
+ putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field
+
+#define P1 RawProcessor.imgdata.idata
+#define S RawProcessor.imgdata.sizes
+#define C RawProcessor.imgdata.color
+#define T RawProcessor.imgdata.thumbnail
+#define P2 RawProcessor.imgdata.other
+#define OUT RawProcessor.imgdata.params
+
+
+ for (i=1;i<ac;i++)
+ {
+ if(av[i][0]=='-')
+ {
+ if(av[i][1]=='4' && av[i][2]==0)
+ OUT.output_bps = 16;
+ if(av[i][1]=='1' && av[i][2]==0)
+ OUT.gamma_16bit = 1;
+ if(av[i][1]=='e' && av[i][2]==0)
+ output_thumbs++;
+ continue;
+ }
+ printf("Processing %s\n",av[i]);
+ if( (ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot open %s: %s\n",av[i],libraw_strerror(ret));
+ continue; // no recycle b/c open file will recycle itself
+ }
+
+
+ if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret));
+ continue;
+ }
+
+ // we should call dcraw_process before thumbnail extraction because for
+ // some cameras (i.e. Kodak ones) white balance for thumbnal should be set
+ // from main image settings
+
+
+ ret = RawProcessor.dcraw_process();
+
+ if(LIBRAW_SUCCESS !=ret)
+ {
+ fprintf(stderr,"Cannot do postpocessing on %s: %s\n",
+ av[i],libraw_strerror(ret));
+ if(LIBRAW_FATAL_ERROR(ret))
+ continue;
+ }
+ libraw_processed_image_t *image = RawProcessor.dcraw_make_mem_image(&ret);
+ if(image)
+ {
+ write_ppm(image,av[i]);
+ free(image);
+ }
+ else
+ fprintf(stderr,"Cannot unpack %s to memory buffer: %s\n" , av[i],libraw_strerror(ret));
+
+ if(output_thumbs)
+ {
+
+ if( (ret = RawProcessor.unpack_thumb() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot unpack_thumb %s: %s\n",av[i],libraw_strerror(ret));
+ if(LIBRAW_FATAL_ERROR(ret))
+ continue; // skip to next file
+ }
+ else
+ {
+ libraw_processed_image_t *thumb = RawProcessor.dcraw_make_mem_thumb(&ret);
+ if(thumb)
+ {
+ write_thumb(thumb,av[i]);
+ free(thumb);
+ }
+ else
+ fprintf(stderr,"Cannot unpack thumbnail of %s to memory buffer: %s\n" , av[i],libraw_strerror(ret));
+ }
+
+ }
+
+ RawProcessor.recycle(); // just for show this call
+ }
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/simple_dcraw.cpp b/libkdcraw/libraw/samples/simple_dcraw.cpp
new file mode 100644
index 0000000..8c78c4d
--- /dev/null
+++ b/libkdcraw/libraw/samples/simple_dcraw.cpp
@@ -0,0 +1,213 @@
+/* -*- C++ -*-
+ * File: simple_dcraw.cpp
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw simple C++ API (emulates call to "dcraw [-D] [-T] [-v] [-e] [-4]")
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#endif
+
+#include "libraw/libraw.h"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+int my_progress_callback(void *unused_data,enum LibRaw_progress state,int iter, int expected)
+{
+ if(iter==0)
+ printf("CB: state=%x, expected %d iterations\n",state,expected);
+ return 0;
+}
+
+
+int main(int ac, char *av[])
+{
+ int i, ret, verbose=0, output_thumbs=0,use_mmap=0,msize;
+ void *file_buffer;
+
+ // don't use fixed size buffers in real apps!
+ char outfn[1024],thumbfn[1024];
+
+ LibRaw RawProcessor;
+ if(ac<2)
+ {
+ printf(
+ "simple_dcraw - LibRaw %s sample. Emulates dcraw [-D] [-T] [-v] [-e] [-B]\n"
+ " %d cameras supported\n"
+ "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n"
+ "\t-D - document mode emulation\n"
+ "\t-4 - 16-bit mode\n"
+ "\t-v - verbose output\n"
+ "\t-T - output TIFF files instead of .pgm/ppm\n"
+#ifndef WIN32
+ "\t-B - use mmap()-ed I/O (Unix only)\n"
+#endif
+ "\t-e - extract thumbnails (same as dcraw -e in separate run)\n",LibRaw::version(),
+ LibRaw::cameraCount(),
+ av[0]);
+ return 0;
+ }
+
+ putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field
+
+#define P1 RawProcessor.imgdata.idata
+#define S RawProcessor.imgdata.sizes
+#define C RawProcessor.imgdata.color
+#define T RawProcessor.imgdata.thumbnail
+#define P2 RawProcessor.imgdata.other
+#define OUT RawProcessor.imgdata.params
+
+
+ for (i=1;i<ac;i++)
+ {
+ if(av[i][0]=='-')
+ {
+ if(av[i][1]=='T' && av[i][2]==0)
+ OUT.output_tiff=1;
+ if(av[i][1]=='v' && av[i][2]==0)
+ verbose++;
+ if(av[i][1]=='e' && av[i][2]==0)
+ output_thumbs++;
+ if(av[i][1]=='D' && av[i][2]==0)
+ OUT.document_mode=2;
+ if(av[i][1]=='B' && av[i][2]==0)
+ use_mmap=1;
+ if(av[i][1]=='4' && av[i][2]==0)
+ OUT.output_bps=16;
+ if(av[i][1]=='C' && av[i][2]==0)
+ RawProcessor.set_progress_handler(my_progress_callback,NULL);
+ continue;
+ }
+
+ if(verbose) printf("Processing file %s\n",av[i]);
+
+#ifndef WIN32
+ if(use_mmap)
+ {
+ int file = open(av[i],O_RDONLY);
+ struct stat st;
+ if(file<0)
+ {
+ fprintf(stderr,"Cannot open %s: %s\n",av[i],strerror(errno));
+ continue;
+ }
+ if(fstat(file,&st))
+ {
+ fprintf(stderr,"Cannot stat %s: %s\n",av[i],strerror(errno));
+ close(file);
+ continue;
+ }
+ int pgsz = getpagesize();
+ msize = ((st.st_size+pgsz-1)/pgsz)*pgsz;
+ file_buffer = mmap(NULL,msize,PROT_READ,MAP_PRIVATE,file,0);
+ if(!file_buffer)
+ {
+ fprintf(stderr,"Cannot mmap %s: %s\n",av[i],strerror(errno));
+ close(file);
+ continue;
+ }
+ close(file);
+ if( (ret = RawProcessor.open_buffer(file_buffer,st.st_size) != LIBRAW_SUCCESS))
+ {
+ fprintf(stderr,"Cannot open_buffer %s: %s\n",av[i],libraw_strerror(ret));
+ continue; // no recycle b/c open file will recycle itself
+ }
+ }
+ else
+#endif
+ {
+ if( (ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot open_file %s: %s\n",av[i],libraw_strerror(ret));
+ continue; // no recycle b/c open file will recycle itself
+ }
+ }
+
+ if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret));
+ continue;
+ }
+
+ // thumbnail unpacking and output in the middle of main
+ // image processing - for test purposes!
+ if(output_thumbs)
+ {
+ if( (ret = RawProcessor.unpack_thumb() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot unpack_thumb %s: %s\n",av[i],libraw_strerror(ret));
+ if(LIBRAW_FATAL_ERROR(ret))
+ continue; // skip to next file
+ }
+ else
+ {
+ snprintf(thumbfn,sizeof(thumbfn),"%s.%s",
+ av[i],T.tformat == LIBRAW_THUMBNAIL_JPEG ? "thumb.jpg" : "thumb.ppm");
+
+ if(verbose) printf("Writing thumbnail file %s\n",thumbfn);
+ if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_thumb_writer(thumbfn)))
+ {
+ fprintf(stderr,"Cannot write %s: %s\n",thumbfn,libraw_strerror(ret));
+ if(LIBRAW_FATAL_ERROR(ret))
+ continue;
+ }
+ }
+ }
+
+ if(OUT.document_mode)
+ ret = RawProcessor.dcraw_document_mode_processing();
+ else
+ ret = RawProcessor.dcraw_process();
+
+ if(LIBRAW_SUCCESS !=ret)
+ {
+ fprintf(stderr,"Cannot do postpocessing on %s: %s\n",
+ av[i],libraw_strerror(ret));
+ if(LIBRAW_FATAL_ERROR(ret))
+ continue;
+ }
+ snprintf(outfn,sizeof(outfn),
+ "%s.%s",
+ av[i], OUT.output_tiff ? "tiff" : (P1.colors>1?"ppm":"pgm"));
+
+ if(verbose) printf("Writing file %s\n",outfn);
+
+ if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn)))
+ fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret));
+
+#ifndef WIN32
+ if(use_mmap && file_buffer)
+ {
+ munmap(file_buffer,msize);
+ file_buffer=0;
+ }
+#endif
+ RawProcessor.recycle(); // just for show this call
+ }
+ return 0;
+}
diff --git a/libkdcraw/libraw/samples/unprocessed_raw.cpp b/libkdcraw/libraw/samples/unprocessed_raw.cpp
new file mode 100644
index 0000000..15e9169
--- /dev/null
+++ b/libkdcraw/libraw/samples/unprocessed_raw.cpp
@@ -0,0 +1,156 @@
+/* -*- C++ -*-
+ * File: unprocessed_raw.cpp
+ * Copyright 2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Fri Jan 02, 2009
+ *
+ * LibRaw sample
+ * Generates unprocessed raw image: with masked pixels and without black subtraction
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#ifndef WIN32
+#include <netinet/in.h>
+#else
+#include <winsock2.h>
+#endif
+
+#include "libraw/libraw.h"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+int main(int ac, char *av[])
+{
+ int i, ret;
+ int verbose=1,autoscale=0;
+ char outfn[1024],thumbfn[1024];
+
+ LibRaw RawProcessor;
+ if(ac<2)
+ {
+ usage:
+ printf(
+ "unprocessed_raw - LibRaw %s sample. %d cameras supported\n"
+ "Usage: %s [-q] [-A] [-g] [-s N] [-N] raw-files....\n"
+ "\t-q - be quiet\n"
+ "\t-s N - select Nth image in file (default=0)\n"
+ "\t-g - use gamma correction with gamma 2.2 (not precise,use for visual inspection only)\n"
+ "\t-A - autoscaling (by integer factor)\n"
+ "\t-N - no raw curve\n"
+ ,LibRaw::version(),
+ LibRaw::cameraCount(),
+ av[0]);
+ return 0;
+ }
+
+#define P1 RawProcessor.imgdata.idata
+#define S RawProcessor.imgdata.sizes
+#define C RawProcessor.imgdata.color
+#define T RawProcessor.imgdata.thumbnail
+#define P2 RawProcessor.imgdata.other
+#define OUT RawProcessor.imgdata.params
+
+ OUT.document_mode=2;
+ OUT.output_bps=16;
+ OUT.output_tiff=1;
+ OUT.user_flip=0;
+ OUT.no_auto_bright = 1;
+ OUT.filtering_mode=(LibRaw_filtering)( LIBRAW_FILTERING_NOBLACKS|LIBRAW_FILTERING_NOZEROES);
+ for (i=1;i<ac;i++)
+ {
+ if(av[i][0]=='-')
+ {
+ if(av[i][1]=='q' && av[i][2]==0)
+ verbose=0;
+ else if(av[i][1]=='A' && av[i][2]==0)
+ autoscale=1;
+ else if(av[i][1]=='g' && av[i][2]==0)
+ OUT.gamma_16bit=1;
+ else if(av[i][1]=='N' && av[i][2]==0)
+ OUT.filtering_mode=LIBRAW_FILTERING_NONE;
+ else if(av[i][1]=='s' && av[i][2]==0)
+ {
+ i++;
+ OUT.shot_select=atoi(av[i]);
+ }
+ else
+ goto usage;
+ continue;
+ }
+ int r,c;
+ if(verbose) printf("Processing file %s\n",av[i]);
+ if( (ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot open %s: %s\n",av[i],libraw_strerror(ret));
+ continue; // no recycle b/c open file will recycle itself
+ }
+ if(verbose)
+ {
+ printf("Image size: %dx%d\nRaw size: %dx%d\n",S.width,S.height,S.raw_width,S.raw_height);
+ printf("Margins: top=%d, left=%d, right=%d, bottom=%d\n",
+ S.top_margin,S.left_margin,S.right_margin,S.bottom_margin);
+ }
+
+ if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret));
+ continue;
+ }
+ if(verbose)
+ printf("Unpacked....\n");
+
+ if( (ret = RawProcessor.add_masked_borders_to_bitmap() ) != LIBRAW_SUCCESS)
+ {
+ fprintf(stderr,"Cannot add mask data to bitmap %s\n",av[i]);
+ }
+ for(int r=0;r<S.iheight;r++)
+ for(c=0;c<S.iwidth;c++)
+ RawProcessor.imgdata.image[r*S.iwidth+c][0]
+ = RawProcessor.imgdata.image[r*S.iwidth+c][RawProcessor.FC(r,c)];
+
+ P1.colors=1;
+ if(autoscale)
+ {
+ unsigned max=0,scale;
+ for(int j=0; j<S.iheight*S.iwidth; j++)
+ if(max < RawProcessor.imgdata.image[j][0])
+ max = RawProcessor.imgdata.image[j][0];
+ if (max >0 && max< 1<<15)
+ {
+ scale = (1<<16)/max;
+ if(verbose)
+ printf("Scaling with multiplier=%d (max=%d)\n",scale,max);
+
+ for(int j=0; j<S.iheight*S.iwidth; j++)
+ RawProcessor.imgdata.image[j][0] *= scale;
+ }
+ }
+
+ if(OUT.shot_select)
+ snprintf(outfn,sizeof(outfn),"%s-%d.tiff",av[i],OUT.shot_select);
+ else
+ snprintf(outfn,sizeof(outfn),"%s.tiff",av[i]);
+
+ if(verbose) printf("Writing file %s\n",outfn);
+ if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn)))
+ fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret));
+ }
+ return 0;
+}
diff --git a/libkdcraw/libraw/src/libraw_c_api.cpp b/libkdcraw/libraw/src/libraw_c_api.cpp
new file mode 100644
index 0000000..8ce5736
--- /dev/null
+++ b/libkdcraw/libraw/src/libraw_c_api.cpp
@@ -0,0 +1,143 @@
+/* -*- C++ -*-
+ * File: libraw_c_api.cpp
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw C++ interface (implementation)
+ */
+#include <errno.h>
+#include "libraw/libraw.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ libraw_data_t *libraw_init(unsigned int flags)
+ {
+ LibRaw *ret = new LibRaw(flags);
+ return &(ret->imgdata);
+ }
+
+ const char* libraw_version() { return LibRaw::version();}
+ const char* libraw_strprogress(enum LibRaw_progress p) { return LibRaw::strprogress(p);}
+ int libraw_versionNumber() { return LibRaw::versionNumber();}
+ const char** libraw_cameraList() { return LibRaw::cameraList();}
+ int libraw_cameraCount() { return LibRaw::cameraCount(); }
+ const char* libraw_unpack_function_name(libraw_data_t* lr)
+ {
+ if(!lr) return "NULL parameter passed";
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->unpack_function_name();
+ }
+ int libraw_rotate_fuji_raw(libraw_data_t* lr)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->rotate_fuji_raw();
+ }
+
+ int libraw_add_masked_borders_to_bitmap(libraw_data_t* lr)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->add_masked_borders_to_bitmap();
+ }
+
+ int libraw_open_file(libraw_data_t* lr, const char *file)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->open_file(file);
+ }
+ int libraw_open_buffer(libraw_data_t* lr, void *buffer, size_t size)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->open_buffer(buffer,size);
+ }
+ int libraw_unpack(libraw_data_t* lr)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->unpack();
+ }
+ int libraw_unpack_thumb(libraw_data_t* lr)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->unpack_thumb();
+ }
+ void libraw_recycle(libraw_data_t* lr)
+ {
+ if(!lr) return;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ ip->recycle();
+ }
+ void libraw_close(libraw_data_t* lr)
+ {
+ if(!lr) return;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ delete ip;
+ }
+
+ void libraw_set_memerror_handler(libraw_data_t* lr, memory_callback cb,void *data)
+ {
+ if(!lr) return;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ ip->set_memerror_handler(cb,data);
+
+ }
+ void libraw_set_dataerror_handler(libraw_data_t* lr,data_callback func,void *data)
+ {
+ if(!lr) return;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ ip->set_dataerror_handler(func,data);
+
+ }
+ void libraw_set_progress_handler(libraw_data_t* lr, progress_callback cb,void *data)
+ {
+ if(!lr) return;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ ip->set_progress_handler(cb,data);
+
+ }
+
+ // DCRAW
+ int libraw_adjust_sizes_info_only(libraw_data_t* lr)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->adjust_sizes_info_only();
+ }
+
+ int libraw_dcraw_document_mode_processing(libraw_data_t* lr)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->dcraw_document_mode_processing();
+
+ }
+ int libraw_dcraw_ppm_tiff_writer(libraw_data_t* lr,const char *filename)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->dcraw_ppm_tiff_writer(filename);
+ }
+ int libraw_dcraw_thumb_writer(libraw_data_t* lr,const char *fname)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->dcraw_thumb_writer(fname);
+
+ }
+ int libraw_dcraw_process(libraw_data_t* lr)
+ {
+ if(!lr) return EINVAL;
+ LibRaw *ip = (LibRaw*) lr->parent_class;
+ return ip->dcraw_process();
+ }
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libkdcraw/libraw/src/libraw_cxx.cpp b/libkdcraw/libraw/src/libraw_cxx.cpp
new file mode 100644
index 0000000..be1ec0a
--- /dev/null
+++ b/libkdcraw/libraw/src/libraw_cxx.cpp
@@ -0,0 +1,1940 @@
+/* -*- C++ -*-
+ * File: libraw_cxx.cpp
+ * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru>
+ * Created: Sat Mar 8 , 2008
+ *
+ * LibRaw C++ interface (implementation)
+ */
+
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+#ifndef WIN32
+#include <netinet/in.h>
+#else
+#include <winsock2.h>
+#endif
+#define LIBRAW_LIBRARY_BUILD
+#include "libraw/libraw.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ void default_memory_callback(void *,const char *file,const char *where)
+ {
+ fprintf (stderr,"%s: Out of memory in %s\n", file?file:"unknown file", where);
+ }
+
+ void default_data_callback(void*,const char *file, const int offset)
+ {
+ if(offset < 0)
+ fprintf (stderr,"%s: Unexpected end of file\n", file?file:"unknown file");
+ else
+ fprintf (stderr,"%s: data corrupted at %d\n",file?file:"unknown file",offset);
+ }
+ const char *libraw_strerror(int e)
+ {
+ enum LibRaw_errors errorcode = (LibRaw_errors)e;
+ switch(errorcode)
+ {
+ case LIBRAW_SUCCESS:
+ return "No error";
+ case LIBRAW_UNSPECIFIED_ERROR:
+ return "Unspecified error";
+ case LIBRAW_FILE_UNSUPPORTED:
+ return "Unsupported file format or not RAW file";
+ case LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE:
+ return "Request for nonexisting image number";
+ case LIBRAW_OUT_OF_ORDER_CALL:
+ return "Out of order call of libraw function";
+ case LIBRAW_NO_THUMBNAIL:
+ return "No thumbnail in file";
+ case LIBRAW_UNSUPPORTED_THUMBNAIL:
+ return "Unsupported thumbnail format";
+ case LIBRAW_CANNOT_ADDMASK:
+ return "Cannot add masked pixels to resized image";
+ case LIBRAW_UNSUFFICIENT_MEMORY:
+ return "Unsufficient memory";
+ case LIBRAW_DATA_ERROR:
+ return "Corrupted data or unexpected EOF";
+ case LIBRAW_IO_ERROR:
+ return "Input/output error";
+ case LIBRAW_CANCELLED_BY_CALLBACK:
+ return "Cancelled by user callback";
+ default:
+ return "Unknown error code";
+ }
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+
+const double LibRaw_constants::xyz_rgb[3][3] =
+{
+ { 0.412453, 0.357580, 0.180423 },
+ { 0.212671, 0.715160, 0.072169 },
+ { 0.019334, 0.119193, 0.950227 }
+};
+
+const float LibRaw_constants::d65_white[3] = { 0.950456, 1, 1.088754 };
+
+#define P1 imgdata.idata
+#define S imgdata.sizes
+#define O imgdata.params
+#define C imgdata.color
+#define M imgdata.masked_pixels
+#define T imgdata.thumbnail
+#define IO libraw_internal_data.internal_output_params
+#define ID libraw_internal_data.internal_data
+
+#define EXCEPTION_HANDLER(e) do{ \
+ fprintf(stderr,"Exception %d caught\n",e); \
+ switch(e) \
+ { \
+ case LIBRAW_EXCEPTION_ALLOC: \
+ recycle(); \
+ return LIBRAW_UNSUFFICIENT_MEMORY; \
+ case LIBRAW_EXCEPTION_DECODE_RAW: \
+ case LIBRAW_EXCEPTION_DECODE_JPEG: \
+ recycle(); \
+ return LIBRAW_DATA_ERROR; \
+ case LIBRAW_EXCEPTION_IO_EOF: \
+ case LIBRAW_EXCEPTION_IO_CORRUPT: \
+ recycle(); \
+ return LIBRAW_IO_ERROR; \
+ case LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK:\
+ recycle(); \
+ return LIBRAW_CANCELLED_BY_CALLBACK; \
+ default: \
+ return LIBRAW_UNSPECIFIED_ERROR; \
+ } \
+ }while(0)
+
+void LibRaw::derror()
+{
+ if (!libraw_internal_data.unpacker_data.data_error && libraw_internal_data.internal_data.input)
+ {
+ if (libraw_internal_data.internal_data.input->eof())
+ {
+ if(callbacks.data_cb)(*callbacks.data_cb)(callbacks.datacb_data,
+ libraw_internal_data.internal_data.input->fname(),-1);
+ throw LIBRAW_EXCEPTION_IO_EOF;
+ }
+ else
+ {
+ if(callbacks.data_cb)(*callbacks.data_cb)(callbacks.datacb_data,
+ libraw_internal_data.internal_data.input->fname(),
+ libraw_internal_data.internal_data.input->tell());
+ throw LIBRAW_EXCEPTION_IO_CORRUPT;
+ }
+ }
+ libraw_internal_data.unpacker_data.data_error = 1;
+}
+LibRaw:: LibRaw(unsigned int flags)
+{
+ double aber[4] = {1,1,1,1};
+ double gamm[5] = { 0.45,4.5,0,0,0 };
+ unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
+#ifdef DCRAW_VERBOSE
+ verbose = 1;
+#else
+ verbose = 0;
+#endif
+ bzero(&imgdata,sizeof(imgdata));
+ bzero(&libraw_internal_data,sizeof(libraw_internal_data));
+ bzero(&callbacks,sizeof(callbacks));
+ callbacks.mem_cb = (flags & LIBRAW_OPIONS_NO_MEMERR_CALLBACK) ? NULL: &default_memory_callback;
+ callbacks.data_cb = (flags & LIBRAW_OPIONS_NO_DATAERR_CALLBACK)? NULL : &default_data_callback;
+ memmove(&imgdata.params.aber,&aber,sizeof(aber));
+ memmove(&imgdata.params.gamm,&gamm,sizeof(gamm));
+ memmove(&imgdata.params.greybox,&greybox,sizeof(greybox));
+
+ imgdata.params.bright=1;
+ imgdata.params.use_camera_matrix=-1;
+ imgdata.params.user_flip=-1;
+ imgdata.params.user_black=-1;
+ imgdata.params.user_sat=-1;
+ imgdata.params.user_qual=-1;
+ imgdata.params.output_color=1;
+ imgdata.params.output_bps=8;
+ imgdata.params.use_fuji_rotate=1;
+ imgdata.params.auto_bright_thr = 0.01;
+ imgdata.parent_class = this;
+ imgdata.progress_flags = 0;
+ tls = new LibRaw_TLS;
+ tls->init();
+}
+
+
+void* LibRaw:: malloc(size_t t)
+{
+ void *p = memmgr.malloc(t);
+ return p;
+}
+void* LibRaw:: calloc(size_t n,size_t t)
+{
+ void *p = memmgr.calloc(n,t);
+ return p;
+}
+void LibRaw:: free(void *p)
+{
+ memmgr.free(p);
+}
+
+
+int LibRaw:: 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 (imgdata.idata.filters != 1) return FC(row,col);
+ return filter[(row+imgdata.sizes.top_margin) & 15][(col+imgdata.sizes.left_margin) & 15];
+}
+
+void LibRaw:: recycle()
+{
+ if(libraw_internal_data.internal_data.input && libraw_internal_data.internal_data.input_internal)
+ {
+ delete libraw_internal_data.internal_data.input;
+ libraw_internal_data.internal_data.input = NULL;
+ }
+ libraw_internal_data.internal_data.input_internal = 0;
+#define FREE(a) do { if(a) { free(a); a = NULL;} }while(0)
+
+ FREE(imgdata.image);
+ FREE(imgdata.thumbnail.thumb);
+ FREE(libraw_internal_data.internal_data.meta_data);
+ FREE(libraw_internal_data.output_data.histogram);
+ FREE(libraw_internal_data.output_data.oprof);
+ FREE(imgdata.color.profile);
+ FREE(imgdata.masked_pixels.buffer);
+ FREE(imgdata.masked_pixels.ph1_black);
+#undef FREE
+#define ZERO(a) bzero(&a,sizeof(a))
+ ZERO(imgdata.masked_pixels);
+ ZERO(imgdata.sizes);
+ ZERO(libraw_internal_data.internal_output_params);
+#undef ZERO
+ memmgr.cleanup();
+ imgdata.thumbnail.tformat = LIBRAW_THUMBNAIL_UNKNOWN;
+ imgdata.progress_flags = 0;
+
+ tls->init();
+}
+
+const char * LibRaw::unpack_function_name()
+{
+ if(!load_raw) return "Function not set";
+
+ // sorted names order
+ if (load_raw == &LibRaw::adobe_dng_load_raw_lj) return "adobe_dng_load_raw_lj()";
+ if (load_raw == &LibRaw::adobe_dng_load_raw_nc) return "adobe_dng_load_raw_nc()";
+ if (load_raw == &LibRaw::canon_600_load_raw) return "canon_600_load_raw()";
+
+ if (load_raw == &LibRaw::canon_a5_load_raw) return "canon_a5_load_raw()";
+ if (load_raw == &LibRaw::canon_compressed_load_raw) return "canon_compressed_load_raw()";
+ if (load_raw == &LibRaw::canon_sraw_load_raw) return "canon_sraw_load_raw()";
+
+ if (load_raw == &LibRaw::casio_qv5700_load_raw ) return "casio_qv5700_load_raw()";
+ if (load_raw == &LibRaw::eight_bit_load_raw ) return "eight_bit_load_raw()";
+ if (load_raw == &LibRaw::foveon_load_raw ) return "foveon_load_raw()";
+ if (load_raw == &LibRaw::fuji_load_raw ) return "fuji_load_raw()";
+ // 10
+ if (load_raw == &LibRaw::hasselblad_load_raw ) return "hasselblad_load_raw()";
+ if (load_raw == &LibRaw::imacon_full_load_raw ) return "imacon_full_load_raw()";
+ if (load_raw == &LibRaw::kodak_262_load_raw ) return "kodak_262_load_raw()";
+
+ if (load_raw == &LibRaw::kodak_65000_load_raw ) return "kodak_65000_load_raw()";
+ if (load_raw == &LibRaw::kodak_dc120_load_raw ) return "kodak_dc120_load_raw()";
+ if (load_raw == &LibRaw::kodak_jpeg_load_raw ) return "kodak_jpeg_load_raw()";
+
+ if (load_raw == &LibRaw::kodak_radc_load_raw ) return "kodak_radc_load_raw()";
+ if (load_raw == &LibRaw::kodak_rgb_load_raw ) return "kodak_rgb_load_raw()";
+ if (load_raw == &LibRaw::kodak_yrgb_load_raw ) return "kodak_yrgb_load_raw()";
+ if (load_raw == &LibRaw::kodak_ycbcr_load_raw ) return "kodak_ycbcr_load_raw()";
+ // 20
+ if (load_raw == &LibRaw::leaf_hdr_load_raw ) return "leaf_hdr_load_raw()";
+ if (load_raw == &LibRaw::lossless_jpeg_load_raw) return "lossless_jpeg_load_raw()";
+ if (load_raw == &LibRaw::minolta_rd175_load_raw ) return "minolta_rd175_load_raw()";
+
+ if (load_raw == &LibRaw::nikon_compressed_load_raw) return "nikon_compressed_load_raw()";
+ if (load_raw == &LibRaw::nikon_e900_load_raw ) return "nikon_e900_load_raw()";
+ if (load_raw == &LibRaw::nokia_load_raw ) return "nokia_load_raw()";
+
+ if (load_raw == &LibRaw::olympus_e300_load_raw ) return "olympus_e300_load_raw()";
+ if (load_raw == &LibRaw::olympus_e410_load_raw ) return "olympus_e410_load_raw()";
+ if (load_raw == &LibRaw::packed_12_load_raw ) return "packed_12_load_raw()";
+ if (load_raw == &LibRaw::panasonic_load_raw ) return "panasonic_load_raw()";
+ // 30
+ if (load_raw == &LibRaw::pentax_k10_load_raw ) return "pentax_k10_load_raw()";
+ if (load_raw == &LibRaw::phase_one_load_raw ) return "phase_one_load_raw()";
+ if (load_raw == &LibRaw::phase_one_load_raw_c ) return "phase_one_load_raw_c()";
+
+ if (load_raw == &LibRaw::quicktake_100_load_raw ) return "quicktake_100_load_raw()";
+ if (load_raw == &LibRaw::rollei_load_raw ) return "rollei_load_raw()";
+ if (load_raw == &LibRaw::sinar_4shot_load_raw ) return "sinar_4shot_load_raw()";
+
+ if (load_raw == &LibRaw::smal_v6_load_raw ) return "smal_v6_load_raw()";
+ if (load_raw == &LibRaw::smal_v9_load_raw ) return "smal_v9_load_raw()";
+ if (load_raw == &LibRaw::sony_load_raw ) return "sony_load_raw()";
+ if (load_raw == &LibRaw::sony_arw_load_raw ) return "sony_arw_load_raw()";
+ // 40
+ if (load_raw == &LibRaw::sony_arw2_load_raw ) return "sony_arw2_load_raw()";
+ if (load_raw == &LibRaw::unpacked_load_raw ) return "unpacked_load_raw()";
+ // 42 total
+
+ return "Unknown unpack function";
+}
+
+
+void LibRaw:: merror (void *ptr, const char *where)
+{
+ if (ptr) return;
+ if(callbacks.mem_cb)(*callbacks.mem_cb)(callbacks.memcb_data,
+ libraw_internal_data.internal_data.input
+ ?libraw_internal_data.internal_data.input->fname()
+ :NULL,
+ where);
+ throw LIBRAW_EXCEPTION_ALLOC;
+}
+
+ushort * LibRaw::get_masked_pointer(int row, int col)
+{
+ if(row<0 || col < 0) return NULL;
+ if(!M.buffer) return NULL;
+ if(row < S.top_margin)
+ {
+ // top band
+ if(col < S.left_margin)
+ {
+ return &(M.tl[row*S.left_margin+col]);
+ }
+ else if (col < S.left_margin + S.width)
+ {
+ int icol = col - S.left_margin;
+ return &(M.top[row*S.width+icol]);
+ }
+ else if (col < S.raw_width)
+ {
+ int icol = col - S.left_margin - S.width;
+ return &(M.tr[row*S.right_margin+icol]);
+ }
+ else
+ return NULL; // out of bounds
+ }
+ else if (row < S.top_margin + S.height)
+ {
+ //normal image height
+ int irow = row - S.top_margin;
+ if(col < S.left_margin)
+ {
+ return &M.left[irow*S.left_margin + col];
+ }
+ else if (col < S.left_margin + S.width)
+ {
+ // central image
+ return NULL;
+ }
+ else if (col < S.raw_width)
+ {
+ int icol = col - S.left_margin - S.width;
+ return &M.right[irow*S.right_margin+icol];
+ }
+ else
+ return NULL; // out of bounds
+ }
+ else if (row < S.raw_height)
+ {
+ int irow = row - S.top_margin - S.height;
+ // bottom band
+ if(col < S.left_margin)
+ {
+ return &M.bl[irow*S.left_margin+col];
+ }
+ else if (col < S.left_margin + S.width)
+ {
+ int icol = col - S.left_margin;
+ return &M.bottom[irow*S.width + icol];
+ }
+ else if (col < S.raw_width)
+ {
+ int icol = col - S.left_margin - S.width;
+ return &M.br[irow*S.right_margin + icol];
+ }
+ else
+ return NULL; // out of bounds
+ }
+ else
+ {
+ // out of bounds
+ return NULL;
+ }
+ // fallback
+ return NULL;
+}
+
+void LibRaw:: init_masked_ptrs()
+{
+ if(!M.buffer) return;
+
+ // top band
+ M.tl = M.buffer;
+ M.top = M.tl +(S.top_margin*S.left_margin);
+ M.tr = M.top + (S.top_margin*S.width);
+
+ // left-right
+ M.left = M.tr + (S.top_margin * S.right_margin);
+ M.right = M.left + (S.left_margin * S.height);
+
+ // bottom band
+ M.bl = M.right + (S.right_margin * S.height);
+ M.bottom = M.bl + (S.left_margin * S.bottom_margin);
+ M.br = M.bottom + (S.width * S.bottom_margin);
+
+}
+
+int LibRaw::add_masked_borders_to_bitmap()
+{
+ CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE);
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
+
+ if(S.width != S.iwidth || S.height!=S.iheight)
+ return LIBRAW_CANNOT_ADDMASK;
+
+ if(P1.is_foveon || !P1.filters)
+ return LIBRAW_CANNOT_ADDMASK;
+
+ if(!imgdata.image)
+ return LIBRAW_OUT_OF_ORDER_CALL;
+
+ if(S.raw_width < S.width || S.raw_height < S.height)
+ return LIBRAW_SUCCESS; // nothing to do or already called
+
+ if(S.width == S.raw_width && S.height == S.raw_height)
+ return LIBRAW_SUCCESS; // nothing to do or already called
+
+ ushort (*newimage)[4];
+
+ newimage = (ushort (*)[4]) calloc (S.raw_height*S.raw_width, sizeof (*newimage));
+ merror (newimage, "add_masked_borders_to_bitmap()");
+
+ int r,c;
+ // top rows
+ for (r=0; r<S.top_margin;r++)
+ for(c=0;c<S.raw_width;c++)
+ {
+ ushort *p = get_masked_pointer(r,c);
+ if(p)
+ newimage[r*S.raw_width+c][FC(r,c)] = *p;
+ }
+ // middle rows
+ for (r=S.top_margin; r<S.top_margin+S.height;r++)
+ {
+ int row = r-S.top_margin;
+ for(c=0;c<S.left_margin;c++)
+ {
+ ushort *p = get_masked_pointer(r,c);
+ if(p)
+ newimage[r*S.raw_width+c][FC(r,c)] = *p;
+ }
+ for(c=S.left_margin; c<S.left_margin+S.iwidth;c++)
+ {
+ int col = c - S.left_margin;
+ newimage[r*S.raw_width+c][FC(r,c)] = imgdata.image[row*S.iwidth+col][FC(row,col)];
+ }
+ for(c=S.left_margin+S.iwidth;c<S.raw_width;c++)
+ {
+ ushort *p = get_masked_pointer(r,c);
+ if(p)
+ newimage[r*S.raw_width+c][FC(r,c)] = *p;
+ }
+ }
+ // bottom rows
+ for (r=S.top_margin+S.height; r<S.raw_height;r++)
+ for(c=0;c<S.raw_width;c++)
+ {
+ ushort *p = get_masked_pointer(r,c);
+ if(p)
+ newimage[r*S.raw_width+c][FC(r,c)] = *p;
+ }
+ free(imgdata.image);
+ imgdata.image=newimage;
+ S.iwidth = S.width = S.raw_width;
+ S.iheight = S.height = S.raw_height;
+ return LIBRAW_SUCCESS;
+}
+
+int LibRaw::open_file(const char *fname)
+{
+ // this stream will close on recycle()
+ LibRaw_file_datastream *stream = new LibRaw_file_datastream(fname);
+ if(!stream->valid())
+ {
+ delete stream;
+ return LIBRAW_IO_ERROR;
+ }
+ ID.input_internal = 0; // preserve from deletion on error
+ int ret = open_datastream(stream);
+ if (ret == LIBRAW_SUCCESS)
+ {
+ ID.input_internal =1 ; // flag to delete datastream on recycle
+ }
+ else
+ {
+ delete stream;
+ ID.input_internal = 0;
+ }
+ return ret;
+}
+
+int LibRaw::open_buffer(void *buffer, size_t size)
+{
+ // this stream will close on recycle()
+ if(!buffer || buffer==(void*)-1)
+ return LIBRAW_IO_ERROR;
+
+ LibRaw_buffer_datastream *stream = new LibRaw_buffer_datastream(buffer,size);
+ if(!stream->valid())
+ {
+ delete stream;
+ return LIBRAW_IO_ERROR;
+ }
+ ID.input_internal = 0; // preserve from deletion on error
+ int ret = open_datastream(stream);
+ if (ret == LIBRAW_SUCCESS)
+ {
+ ID.input_internal =1 ; // flag to delete datastream on recycle
+ }
+ else
+ {
+ delete stream;
+ ID.input_internal = 0;
+ }
+ return ret;
+}
+
+
+int LibRaw::open_datastream(LibRaw_abstract_datastream *stream)
+{
+
+ if(!stream)
+ return ENOENT;
+ if(!stream->valid())
+ return LIBRAW_IO_ERROR;
+ recycle();
+
+ try {
+ ID.input = stream;
+ SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN);
+
+ if (O.use_camera_matrix < 0)
+ O.use_camera_matrix = O.use_camera_wb;
+
+ identify();
+
+ if(IO.fuji_width)
+ {
+ IO.fwidth = S.width;
+ IO.fheight = S.height;
+ S.iwidth = S.width = IO.fuji_width << !libraw_internal_data.unpacker_data.fuji_layout;
+ S.iheight = S.height = S.raw_height;
+ S.raw_height += 2*S.top_margin;
+ }
+
+ int saved_raw_width = S.raw_width;
+ int saved_width = S.width;
+ // from packed_12_load_raw
+ if ((load_raw == &LibRaw:: packed_12_load_raw) && (S.raw_width * 2 >= S.width * 3))
+ {
+ // raw_width is in bytes!
+ S.raw_width = S.raw_width * 2 / 3;
+ }
+ else if (S.pixel_aspect < 0.95 || S.pixel_aspect > 1.05)
+ {
+ S.width*=S.pixel_aspect;
+ }
+
+ if(S.raw_width>S.width + S.left_margin)
+ S.right_margin = S.raw_width - S.width - S.left_margin;
+
+ if(S.raw_height > S.height + S.top_margin)
+ S.bottom_margin = S.raw_height - S.height - S.top_margin;
+
+ S.raw_width = saved_raw_width;
+ S.width = saved_width;
+
+ if(C.profile_length)
+ {
+ if(C.profile) free(C.profile);
+ C.profile = malloc(C.profile_length);
+ merror(C.profile,"LibRaw::open_file()");
+ ID.input->seek(ID.profile_offset,SEEK_SET);
+ ID.input->read(C.profile,C.profile_length,1);
+ }
+
+ SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY);
+ }
+ catch ( LibRaw_exceptions err) {
+ EXCEPTION_HANDLER(err);
+ }
+
+ if(P1.raw_count < 1)
+ return LIBRAW_FILE_UNSUPPORTED;
+
+ if (O.user_flip >= 0)
+ S.flip = O.user_flip;
+
+ switch ((S.flip+3600) % 360)
+ {
+ case 270: S.flip = 5; break;
+ case 180: S.flip = 3; break;
+ case 90: S.flip = 6; break;
+ }
+
+ write_fun = &LibRaw::write_ppm_tiff;
+
+ if (load_raw == &LibRaw::kodak_ycbcr_load_raw)
+ {
+ S.height += S.height & 1;
+ S.width += S.width & 1;
+ }
+
+ IO.shrink = P1.filters && (O.half_size || O.threshold || O.aber[0] != 1 || O.aber[2] != 1);
+ S.iheight = (S.height + IO.shrink) >> IO.shrink;
+ S.iwidth = (S.width + IO.shrink) >> IO.shrink;
+
+ SET_PROC_FLAG(LIBRAW_PROGRESS_SIZE_ADJUST);
+
+
+ return LIBRAW_SUCCESS;
+}
+
+int LibRaw::unpack(void)
+{
+ CHECK_ORDER_HIGH(LIBRAW_PROGRESS_LOAD_RAW);
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY);
+ try {
+
+ RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,0,2);
+ if (O.shot_select >= P1.raw_count)
+ return LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE;
+
+ if(!load_raw)
+ return LIBRAW_UNSPECIFIED_ERROR;
+
+ if (O.use_camera_matrix && C.cmatrix[0][0] > 0.25)
+ {
+ memcpy (C.rgb_cam, C.cmatrix, sizeof (C.cmatrix));
+ IO.raw_color = 0;
+ }
+ // already allocated ?
+ if(imgdata.image) free(imgdata.image);
+
+ imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image));
+ merror (imgdata.image, "unpack()");
+
+
+ if(S.top_margin || S.left_margin || S.right_margin || S.bottom_margin)
+ {
+ unsigned sz = S.raw_height*(S.left_margin+S.right_margin)
+ + S.width*(S.top_margin+S.bottom_margin);
+ imgdata.masked_pixels.buffer = (ushort*) calloc(sz, sizeof(ushort));
+ merror (imgdata.masked_pixels.buffer, "unpack()");
+ init_masked_ptrs();
+ }
+ if (libraw_internal_data.unpacker_data.meta_length)
+ {
+ libraw_internal_data.internal_data.meta_data =
+ (char *) malloc (libraw_internal_data.unpacker_data.meta_length);
+ merror (libraw_internal_data.internal_data.meta_data, "LibRaw::unpack()");
+ }
+ ID.input->seek(libraw_internal_data.unpacker_data.data_offset, SEEK_SET);
+ // foveon_load_raw produces different data for document_mode, we'll
+ // deal with it in dcraw_document_mode_processing
+ int save_document_mode = O.document_mode;
+ O.document_mode = 0;
+
+ if(!own_filtering_supported() && (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT))
+ O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC_BIT; // turn on black and zeroes filtering
+
+ (this->*load_raw)();
+
+ O.document_mode = save_document_mode;
+
+ if (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT)
+ O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; // restore automated mode
+
+ SET_PROC_FLAG(LIBRAW_PROGRESS_LOAD_RAW);
+ RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,1,2);
+
+ return 0;
+ }
+ catch ( LibRaw_exceptions err) {
+ EXCEPTION_HANDLER(err);
+ }
+}
+
+int LibRaw::dcraw_document_mode_processing(void)
+{
+ CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE);
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
+
+ try {
+
+ if(IO.fwidth)
+ rotate_fuji_raw();
+
+ if(!own_filtering_supported() && (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT))
+ O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC_BIT; // turn on black and zeroes filtering
+
+ O.document_mode = 2;
+ if(P1.is_foveon)
+ {
+ // filter image data for foveon document mode
+ short *iptr = (short *)imgdata.image;
+ for (int i=0; i < S.height*S.width*4; i++)
+ {
+ if ((short) iptr[i] < 0)
+ iptr[i] = 0;
+ }
+ SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE);
+ }
+
+ O.use_fuji_rotate = 0;
+ if (!(O.filtering_mode & LIBRAW_FILTERING_NOZEROES) && IO.zero_is_bad)
+ {
+ remove_zeroes();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES);
+ }
+ if(O.bad_pixels)
+ {
+ bad_pixels(O.bad_pixels);
+ SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS);
+ }
+ if (O.dark_frame)
+ {
+ subtract (O.dark_frame);
+ SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME);
+ }
+ if(O.filtering_mode & LIBRAW_FILTERING_NOBLACKS)
+ C.black=0;
+
+ if (O.user_black >= 0)
+ C.black = O.user_black;
+
+ if (O.user_sat > 0)
+ C.maximum = O.user_sat;
+
+ pre_interpolate();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE);
+
+ if (libraw_internal_data.internal_output_params.mix_green)
+ {
+ int i;
+ for (P1.colors=3, i=0; i < S.height*S.width; i++)
+ imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1;
+ }
+ SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN);
+
+ if (!P1.is_foveon && P1.colors == 3)
+ median_filter();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER);
+
+ if (!P1.is_foveon && O.highlight == 2)
+ blend_highlights();
+
+ if (!P1.is_foveon && O.highlight > 2)
+ recover_highlights();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);
+
+ if (O.use_fuji_rotate)
+ fuji_rotate();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE);
+#ifndef NO_LCMS
+ if(O.camera_profile)
+ {
+ apply_profile(O.camera_profile,O.output_profile);
+ SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE);
+ }
+#endif
+ if(!libraw_internal_data.output_data.histogram)
+ {
+ libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4);
+ merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_document_mode_processing()");
+ }
+ convert_to_rgb();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB);
+
+ if (O.use_fuji_rotate)
+ stretch();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH);
+
+ if (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT)
+ O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; // restore automated mode
+
+ return 0;
+ }
+ catch ( LibRaw_exceptions err) {
+ EXCEPTION_HANDLER(err);
+ }
+
+}
+
+#if 1
+#define FORC(cnt) for (c=0; c < cnt; c++)
+#define FORCC FORC(ret->colors)
+#define SWAP(a,b) { a ^= b; a ^= (b ^= a); }
+
+libraw_processed_image_t * LibRaw::dcraw_make_mem_thumb(int *errcode)
+{
+ if(!T.thumb)
+ {
+ if ( !ID.toffset)
+ {
+ if(errcode) *errcode= LIBRAW_NO_THUMBNAIL;
+ }
+ else
+ {
+ if(errcode) *errcode= LIBRAW_OUT_OF_ORDER_CALL;
+ }
+ return NULL;
+ }
+
+ if (T.tformat == LIBRAW_THUMBNAIL_BITMAP)
+ {
+ libraw_processed_image_t * ret =
+ (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t)+T.tlength);
+
+ if(!ret)
+ {
+ if(errcode) *errcode= ENOMEM;
+ return NULL;
+ }
+
+ bzero(ret,sizeof(libraw_processed_image_t));
+ ret->type = LIBRAW_IMAGE_BITMAP;
+ ret->height = T.theight;
+ ret->width = T.twidth;
+ ret->colors = 3;
+ ret->bits = 8;
+ ret->gamma_corrected = 1;
+ ret->data_size = T.tlength;
+ memmove(ret->data,T.thumb,T.tlength);
+ if(errcode) *errcode= 0;
+ return ret;
+ }
+ else if (T.tformat == LIBRAW_THUMBNAIL_JPEG)
+ {
+ ushort exif[5];
+ int mk_exif = 0;
+ if(strcmp(T.thumb+6,"Exif")) mk_exif = 1;
+
+ int dsize = T.tlength + mk_exif * (sizeof(exif)+sizeof(tiff_hdr));
+
+ libraw_processed_image_t * ret =
+ (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t)+dsize);
+
+ if(!ret)
+ {
+ if(errcode) *errcode= ENOMEM;
+ return NULL;
+ }
+
+ bzero(ret,sizeof(libraw_processed_image_t));
+
+ ret->type = LIBRAW_IMAGE_JPEG;
+ ret->data_size = dsize;
+
+ ret->data[0] = 0xff;
+ ret->data[1] = 0xd8;
+ if(mk_exif)
+ {
+ struct tiff_hdr th;
+ memcpy (exif, "\xff\xe1 Exif\0\0", 10);
+ exif[1] = htons (8 + sizeof th);
+ memmove(ret->data+2,exif,sizeof(exif));
+ tiff_head (&th, 0);
+ memmove(ret->data+(2+sizeof(exif)),&th,sizeof(th));
+ memmove(ret->data+(2+sizeof(exif)+sizeof(th)),T.thumb+2,T.tlength-2);
+ }
+ else
+ {
+ memmove(ret->data+2,T.thumb+2,T.tlength-2);
+ }
+ if(errcode) *errcode= 0;
+ return ret;
+
+ }
+ else
+ {
+ if(errcode) *errcode= LIBRAW_UNSUPPORTED_THUMBNAIL;
+ return NULL;
+
+ }
+}
+
+
+
+libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode)
+{
+ if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) < LIBRAW_PROGRESS_PRE_INTERPOLATE)
+ {
+ if(errcode) *errcode= LIBRAW_OUT_OF_ORDER_CALL;
+ return NULL;
+ }
+
+ if(!libraw_internal_data.output_data.histogram)
+ {
+ libraw_internal_data.output_data.histogram =
+ (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4);
+ merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_make_mem_image()");
+ }
+
+ unsigned ds = S.height * S.width * (O.output_bps/8) * P1.colors;
+ libraw_processed_image_t *ret = (libraw_processed_image_t*)::malloc(sizeof(libraw_processed_image_t)+ds);
+ if(!ret)
+ {
+ if(errcode) *errcode= ENOMEM;
+ return NULL;
+ }
+ bzero(ret,sizeof(libraw_processed_image_t));
+ // metadata init
+
+ int s_iheight = S.iheight;
+ int s_iwidth = S.iwidth;
+ int s_width = S.width;
+ int s_hwight = S.height;
+
+ S.iheight = S.height;
+ S.iwidth = S.width;
+
+
+ if (S.flip & 4) SWAP(S.height,S.width);
+
+
+ ret->type = LIBRAW_IMAGE_BITMAP;
+ ret->height = S.height;
+ ret->width = S.width;
+ ret->colors = P1.colors;
+ ret->bits = O.output_bps;
+ ret->gamma_corrected = (O.output_bps == 8)?1:O.gamma_16bit;
+
+ ret->data_size = ds;
+
+ // Cut'n'paste from write_tiff_ppm, should be generalized later
+ uchar *bufp = ret->data;
+ uchar *ppm;
+ ushort *ppm2,lut16[0x10000];
+ int c, row, col, soff, rstep, cstep;
+
+
+ if (ret->bits == 8 || ret->gamma_corrected ) gamma_lut (lut16);
+ soff = flip_index (0, 0);
+ cstep = flip_index (0, 1) - soff;
+ rstep = flip_index (1, 0) - flip_index (0, S.width);
+
+
+ for (row=0; row < ret->height; row++, soff += rstep)
+ {
+ ppm2 = (ushort*) (ppm = bufp);
+ for (col=0; col < ret->width; col++, soff += cstep)
+ if (ret->bits == 8)
+ FORCC ppm [col*ret->colors+c] = lut16[imgdata.image[soff][c]]/256;
+ else if(ret->gamma_corrected)
+ FORCC ppm2[col*ret->colors+c] = lut16[imgdata.image[soff][c]];
+ else
+ FORCC ppm2[col*ret->colors+c] = imgdata.image[soff][c];
+ bufp+=ret->colors*(ret->bits/8)*ret->width;
+ }
+ if(errcode) *errcode= 0;
+
+ S.iheight = s_iheight;
+ S.iwidth = s_iwidth;
+ S.width = s_width;
+ S.height = s_hwight;
+
+ return ret;
+}
+
+#undef FORC
+#undef FORCC
+#undef SWAP
+#endif
+
+
+int LibRaw::dcraw_ppm_tiff_writer(const char *filename)
+{
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
+
+ if(!imgdata.image)
+ return LIBRAW_OUT_OF_ORDER_CALL;
+
+ if(!filename)
+ return ENOENT;
+ FILE *f = fopen(filename,"wb");
+
+ if(!f)
+ return errno;
+
+ try {
+ if(!libraw_internal_data.output_data.histogram)
+ {
+ libraw_internal_data.output_data.histogram =
+ (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4);
+ merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_ppm_tiff_writer()");
+ }
+ write_ppm_tiff(f);
+ SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP);
+ fclose(f);
+ return 0;
+ }
+ catch ( LibRaw_exceptions err) {
+ fclose(f);
+ EXCEPTION_HANDLER(err);
+ }
+}
+
+void LibRaw::kodak_thumb_loader()
+{
+ // some kodak cameras
+ ushort s_height = S.height, s_width = S.width,s_iwidth = S.iwidth,s_iheight=S.iheight;
+ int s_colors = P1.colors;
+ unsigned s_filters = P1.filters;
+ ushort (*s_image)[4] = imgdata.image;
+
+
+ S.height = T.theight;
+ S.width = T.twidth;
+ P1.filters = 0;
+
+ if (thumb_load_raw == &CLASS kodak_ycbcr_load_raw)
+ {
+ S.height += S.height & 1;
+ S.width += S.width & 1;
+ }
+
+ imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image));
+ merror (imgdata.image, "LibRaw::kodak_thumb_loader()");
+
+ ID.input->seek(ID.toffset, SEEK_SET);
+ // read kodak thumbnail into T.image[]
+ (this->*thumb_load_raw)();
+
+ // copy-n-paste from image pipe
+#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 CLIP(x) LIM(x,0,65535)
+#define SWAP(a,b) { a ^= b; a ^= (b ^= a); }
+
+ // from scale_colors
+ {
+ double dmax;
+ float scale_mul[4];
+ int c,val;
+ for (dmax=DBL_MAX, c=0; c < 3; c++)
+ if (dmax > C.pre_mul[c])
+ dmax = C.pre_mul[c];
+
+ for( c=0; c< 3; c++)
+ scale_mul[c] = (C.pre_mul[c] / dmax) * 65535.0 / C.maximum;
+ scale_mul[3] = scale_mul[1];
+
+ size_t size = S.height * S.width;
+ for (int i=0; i < size*4 ; i++)
+ {
+ val = imgdata.image[0][i];
+ if(!val) continue;
+ val *= scale_mul[i & 3];
+ imgdata.image[0][i] = CLIP(val);
+ }
+ }
+
+ // from convert_to_rgb
+ ushort *img;
+ int row,col;
+
+ int (*t_hist)[LIBRAW_HISTOGRAM_SIZE] = (int (*)[LIBRAW_HISTOGRAM_SIZE]) calloc(sizeof(*t_hist),4);
+ merror (t_hist, "LibRaw::kodak_thumb_loader()");
+
+ float out[3],
+ out_cam[3][4] =
+ {
+ {2.81761312, -1.98369181, 0.166078627, 0},
+ {-0.111855984, 1.73688626, -0.625030339, 0},
+ {-0.0379119813, -0.891268849, 1.92918086, 0}
+ };
+
+ for (img=imgdata.image[0], row=0; row < S.height; row++)
+ for (col=0; col < S.width; col++, img+=4)
+ {
+ out[0] = out[1] = out[2] = 0;
+ for(int c=0;c<3;c++)
+ {
+ out[0] += out_cam[0][c] * img[c];
+ out[1] += out_cam[1][c] * img[c];
+ out[2] += out_cam[2][c] * img[c];
+ }
+ for(int c=0; c<3; c++)
+ img[c] = CLIP((int) out[c]);
+ for(int c=0; c<P1.colors;c++)
+ t_hist[c][img[c] >> 3]++;
+
+ }
+
+ // from gamma_lut
+ int (*save_hist)[LIBRAW_HISTOGRAM_SIZE] = libraw_internal_data.output_data.histogram;
+ libraw_internal_data.output_data.histogram = t_hist;
+
+ ushort *lut16 = (ushort*)calloc(0x10000,sizeof(ushort));
+ merror(lut16,"LibRaw::kodak_thumb_loader()");
+ gamma_lut(lut16);
+
+ libraw_internal_data.output_data.histogram = save_hist;
+
+ free(t_hist);
+
+ // from write_ppm_tiff - copy pixels into bitmap
+
+ S.iheight = S.height;
+ S.iwidth = S.width;
+ if (S.flip & 4) SWAP(S.height,S.width);
+
+ if(T.thumb) free(T.thumb);
+ T.thumb = (char*) calloc (S.width * S.height, P1.colors);
+ merror (T.thumb, "LibRaw::kodak_thumb_loader()");
+ T.tlength = S.width * S.height * P1.colors;
+
+ // from write_tiff_ppm
+ {
+ int soff = flip_index (0, 0);
+ int cstep = flip_index (0, 1) - soff;
+ int rstep = flip_index (1, 0) - flip_index (0, S.width);
+
+ for (int row=0; row < S.height; row++, soff += rstep)
+ {
+ char *ppm = T.thumb + row*S.width*P1.colors;
+ for (int col=0; col < S.width; col++, soff += cstep)
+ for(int c = 0; c < P1.colors; c++)
+ ppm [col*P1.colors+c] = lut16[imgdata.image[soff][c]]/256;
+ }
+ }
+ free(lut16);
+ // restore variables
+ free(imgdata.image);
+ imgdata.image = s_image;
+
+ T.twidth = S.width;
+ S.width = s_width;
+
+ S.iwidth = s_iwidth;
+ S.iheight = s_iheight;
+
+ T.theight = S.height;
+ S.height = s_height;
+
+ T.tcolors = P1.colors;
+ P1.colors = s_colors;
+
+ P1.filters = s_filters;
+}
+#undef MIN
+#undef MAX
+#undef LIM
+#undef CLIP
+#undef SWAP
+
+
+void LibRaw::foveon_thumb_loader (void)
+{
+ unsigned bwide, row, col, bitbuf=0, bit=1, c, i;
+ struct decode *dindex;
+ short pred[3];
+
+ if(T.thumb) free(T.thumb);
+ T.thumb = NULL;
+
+ bwide = get4();
+ if (bwide > 0)
+ {
+ if (bwide < T.twidth*3) return;
+ T.thumb = (char*)malloc(3*T.twidth * T.theight);
+ merror (T.thumb, "foveon_thumb()");
+ char *buf = (char*)malloc(bwide);
+ merror (buf, "foveon_thumb()");
+ for (row=0; row < T.theight; row++)
+ {
+ ID.input->read(buf, 1, bwide);
+ memmove(T.thumb+(row*T.twidth*3),buf,T.twidth*3);
+ }
+ free(buf);
+ T.tlength = 3*T.twidth * T.theight;
+ T.tformat = LIBRAW_THUMBNAIL_BITMAP;
+ return;
+ }
+ else
+ {
+ foveon_decoder (256, 0);
+ T.thumb = (char*)malloc(3*T.twidth * T.theight);
+ char *bufp = T.thumb;
+ merror (T.thumb, "foveon_thumb()");
+ for (row=0; row < T.theight; row++)
+ {
+ memset (pred, 0, sizeof pred);
+ if (!bit) get4();
+ for (bit=col=0; col < T.twidth; col++)
+ for(c=0;c<3;c++)
+ {
+ for (dindex=first_decode; dindex->branch[0]; )
+ {
+ if ((bit = (bit-1) & 31) == 31)
+ for (i=0; i < 4; i++)
+ bitbuf = (bitbuf << 8) + ID.input->get_char();
+ dindex = dindex->branch[bitbuf >> bit & 1];
+ }
+ pred[c] += dindex->leaf;
+ (*bufp++)=pred[c];
+ }
+ }
+ T.tformat = LIBRAW_THUMBNAIL_BITMAP;
+ T.tlength = 3*T.twidth * T.theight;
+ }
+ return;
+}
+
+
+// Äîñòàåò thumbnail èç ôàéëà, ñòàâèò thumb_format â ñîîòâåòñòâèè ñ ôîðìàòîì
+int LibRaw::unpack_thumb(void)
+{
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY);
+ CHECK_ORDER_BIT(LIBRAW_PROGRESS_THUMB_LOAD);
+
+ try {
+ if ( !ID.toffset)
+ {
+ return LIBRAW_NO_THUMBNAIL;
+ }
+ else if (thumb_load_raw)
+ {
+ kodak_thumb_loader();
+ T.tformat = LIBRAW_THUMBNAIL_BITMAP;
+ SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
+ return 0;
+ }
+ else
+ {
+ ID.input->seek(ID.toffset, SEEK_SET);
+ if ( write_thumb == &LibRaw::jpeg_thumb)
+ {
+ if(T.thumb) free(T.thumb);
+ T.thumb = (char *) malloc (T.tlength);
+ merror (T.thumb, "jpeg_thumb()");
+ ID.input->read (T.thumb, 1, T.tlength);
+ T.tcolors = 3;
+ T.tformat = LIBRAW_THUMBNAIL_JPEG;
+ SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
+ return 0;
+ }
+ else if (write_thumb == &LibRaw::ppm_thumb)
+ {
+ T.tlength = T.twidth * T.theight*3;
+ if(T.thumb) free(T.thumb);
+
+ T.thumb = (char *) malloc (T.tlength);
+ merror (T.thumb, "ppm_thumb()");
+
+ ID.input->read(T.thumb, 1, T.tlength);
+
+ T.tformat = LIBRAW_THUMBNAIL_BITMAP;
+ SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
+ return 0;
+
+ }
+ else if (write_thumb == &LibRaw::foveon_thumb)
+ {
+ foveon_thumb_loader();
+ // may return with error, so format is set in
+ // foveon thumb loader itself
+ SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD);
+ return 0;
+ }
+ // else if -- all other write_thumb cases!
+ else
+ {
+ return LIBRAW_UNSUPPORTED_THUMBNAIL;
+ }
+ }
+ // last resort
+ return LIBRAW_UNSUPPORTED_THUMBNAIL;
+ }
+ catch ( LibRaw_exceptions err) {
+ EXCEPTION_HANDLER(err);
+ }
+
+}
+
+int LibRaw::dcraw_thumb_writer(const char *fname)
+{
+// CHECK_ORDER_LOW(LIBRAW_PROGRESS_THUMB_LOAD);
+
+ if(!fname)
+ return ENOENT;
+
+ FILE *tfp = fopen(fname,"wb");
+
+ if(!tfp)
+ return errno;
+
+ if(!T.thumb)
+ {
+ fclose(tfp);
+ return LIBRAW_OUT_OF_ORDER_CALL;
+ }
+
+ try {
+ switch (T.tformat)
+ {
+ case LIBRAW_THUMBNAIL_JPEG:
+ jpeg_thumb_writer (tfp,T.thumb,T.tlength);
+ break;
+ case LIBRAW_THUMBNAIL_BITMAP:
+ fprintf (tfp, "P6\n%d %d\n255\n", T.twidth, T.theight);
+ fwrite (T.thumb, 1, T.tlength, tfp);
+ break;
+ default:
+ fclose(tfp);
+ return LIBRAW_UNSUPPORTED_THUMBNAIL;
+ }
+ fclose(tfp);
+ return 0;
+ }
+ catch ( LibRaw_exceptions err) {
+ fclose(tfp);
+ EXCEPTION_HANDLER(err);
+ }
+}
+
+int LibRaw::adjust_sizes_info_only(void)
+{
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY);
+ CHECK_ORDER_HIGH(LIBRAW_PROGRESS_FUJI_ROTATE);
+ if (O.use_fuji_rotate)
+ {
+ if (IO.fuji_width)
+ {
+ // restore saved values
+ if(IO.fheight)
+ {
+ S.height = IO.fheight;
+ S.width = IO.fwidth;
+ S.iheight = (S.height + IO.shrink) >> IO.shrink;
+ S.iwidth = (S.width + IO.shrink) >> IO.shrink;
+ S.raw_height -= 2*S.top_margin;
+ IO.fheight = IO.fwidth = 0; // prevent repeated calls
+ }
+ // dcraw code
+ IO.fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink;
+ S.iwidth = (ushort)(IO.fuji_width / sqrt(0.5));
+ S.iheight = (ushort)( (S.iheight - IO.fuji_width) / sqrt(0.5));
+ }
+ else
+ {
+ if (S.pixel_aspect < 1) S.iheight = (ushort)( S.iheight / S.pixel_aspect + 0.5);
+ if (S.pixel_aspect > 1) S.iwidth = (ushort) (S.iwidth * S.pixel_aspect + 0.5);
+ }
+ }
+ SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE);
+ if (S.flip & 4)
+ {
+ unsigned short t = S.iheight;
+ S.iheight=S.iwidth;
+ S.iwidth = t;
+ SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP);
+ }
+ return 0;
+}
+
+int LibRaw::rotate_fuji_raw(void)
+{
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
+ CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE);
+
+
+ if(!IO.fwidth) return LIBRAW_SUCCESS;
+ int row,col,r,c;
+ ushort (*newimage)[4];
+ ushort fiwidth,fiheight;
+
+ fiheight = (IO.fheight + IO.shrink) >> IO.shrink;
+ fiwidth = (IO.fwidth + IO.shrink) >> IO.shrink;
+
+ newimage = (ushort (*)[4]) calloc (fiheight*fiwidth, sizeof (*newimage));
+ merror(newimage,"rotate_fuji_raw()");
+ for(row=0;row<S.height;row++)
+ {
+ for(col=0;col<S.width;col++)
+ {
+
+ if (libraw_internal_data.unpacker_data.fuji_layout) {
+ r = IO.fuji_width - 1 - col + (row >> 1);
+ c = col + ((row+1) >> 1);
+ } else {
+ r = IO.fuji_width - 1 + row - (col >> 1);
+ c = row + ((col+1) >> 1);
+ }
+ newimage[((r) >> IO.shrink)*fiwidth + ((c) >> IO.shrink)][FC(r,c)] =
+ imgdata.image[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][FC(r,c)];
+ }
+ }
+ // restore fuji sizes!
+ S.height = IO.fheight;
+ S.width = IO.fwidth;
+ S.iheight = (S.height + IO.shrink) >> IO.shrink;
+ S.iwidth = (S.width + IO.shrink) >> IO.shrink;
+ S.raw_height -= 2*S.top_margin;
+ IO.fheight = IO.fwidth = 0; // prevent repeated calls
+
+ free(imgdata.image);
+ imgdata.image = newimage;
+ return LIBRAW_SUCCESS;
+
+}
+
+
+int LibRaw::dcraw_process(void)
+{
+ int quality,i;
+
+
+ CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
+ CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE);
+
+ try {
+
+ if(IO.fwidth)
+ rotate_fuji_raw();
+
+
+ if(!own_filtering_supported() && (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT))
+ O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC_BIT; // turn on black and zeroes filtering
+
+ if(O.half_size)
+ O.four_color_rgb = 1;
+
+ if (!(O.filtering_mode & LIBRAW_FILTERING_NOZEROES) && IO.zero_is_bad)
+ {
+ remove_zeroes();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES);
+ }
+ if(O.bad_pixels)
+ {
+ bad_pixels(O.bad_pixels);
+ SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS);
+ }
+ if (O.dark_frame)
+ {
+ subtract (O.dark_frame);
+ SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME);
+ }
+
+ quality = 2 + !IO.fuji_width;
+
+ if(O.filtering_mode & LIBRAW_FILTERING_NOBLACKS)
+ C.black=0;
+
+ if (O.user_qual >= 0) quality = O.user_qual;
+ if (O.user_black >= 0) C.black = O.user_black;
+ if (O.user_sat > 0) C.maximum = O.user_sat;
+
+ if (P1.is_foveon && !O.document_mode)
+ {
+ foveon_interpolate();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE);
+ }
+
+ if (!P1.is_foveon && O.document_mode < 2)
+ {
+ scale_colors();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_SCALE_COLORS);
+ }
+
+ pre_interpolate();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE);
+
+ if (P1.filters && !O.document_mode)
+ {
+ if (quality == 0)
+ lin_interpolate();
+ else if (quality == 1 || P1.colors > 3)
+ vng_interpolate();
+ else if (quality == 2)
+ ppg_interpolate();
+ else
+ ahd_interpolate();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_INTERPOLATE);
+ }
+ if (IO.mix_green)
+ {
+ for (P1.colors=3, i=0; i < S.height * S.width; i++)
+ imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1;
+ SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN);
+ }
+
+ if(!P1.is_foveon)
+ {
+ if (P1.colors == 3)
+ {
+ median_filter();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER);
+ }
+
+ if (O.highlight == 2)
+ {
+ blend_highlights();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);
+ }
+
+ if (O.highlight > 2)
+ {
+ recover_highlights();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);
+ }
+ }
+ if (O.use_fuji_rotate)
+ {
+ fuji_rotate();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE);
+ }
+
+ if(!libraw_internal_data.output_data.histogram)
+ {
+ libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4);
+ merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_process()");
+ }
+#ifndef NO_LCMS
+ if(O.camera_profile)
+ {
+ apply_profile(O.camera_profile,O.output_profile);
+ SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE);
+ }
+#endif
+
+ convert_to_rgb();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB);
+
+ if (O.use_fuji_rotate)
+ {
+ stretch();
+ SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH);
+ }
+ if (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT)
+ O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; // restore automated mode
+ return 0;
+ }
+ catch ( LibRaw_exceptions err) {
+ EXCEPTION_HANDLER(err);
+ }
+}
+
+// Supported cameras:
+static const char *static_camera_list[] =
+{
+"Adobe Digital Negative (DNG)",
+"Apple QuickTake 100",
+"Apple QuickTake 150",
+"Apple QuickTake 200",
+"AVT F-080C",
+"AVT F-145C",
+"AVT F-201C",
+"AVT F-510C",
+"AVT F-810C",
+"Canon PowerShot 600",
+"Canon PowerShot A5",
+"Canon PowerShot A5 Zoom",
+"Canon PowerShot A50",
+"Canon PowerShot A460 (CHDK hack)",
+"Canon PowerShot A530 (CHDK hack)",
+"Canon PowerShot A610 (CHDK hack)",
+"Canon PowerShot A620 (CHDK hack)",
+"Canon PowerShot A630 (CHDK hack)",
+"Canon PowerShot A640 (CHDK hack)",
+"Canon PowerShot A650 (CHDK hack)",
+"Canon PowerShot A710 IS (CHDK hack)",
+"Canon PowerShot A720 IS (CHDK hack)",
+"Canon PowerShot Pro70",
+"Canon PowerShot Pro90 IS",
+"Canon PowerShot G1",
+"Canon PowerShot G2",
+"Canon PowerShot G3",
+"Canon PowerShot G5",
+"Canon PowerShot G6",
+"Canon PowerShot G7 (CHDK hack)",
+"Canon PowerShot G9",
+"Canon PowerShot G10",
+"Canon PowerShot S2 IS (CHDK hack)",
+"Canon PowerShot S3 IS (CHDK hack)",
+"Canon PowerShot S5 IS (CHDK hack)",
+"Canon PowerShot SD300 (CHDK hack)",
+"Canon PowerShot S30",
+"Canon PowerShot S40",
+"Canon PowerShot S45",
+"Canon PowerShot S50",
+"Canon PowerShot S60",
+"Canon PowerShot S70",
+"Canon PowerShot Pro1",
+"Canon EOS D30",
+"Canon EOS D60",
+"Canon EOS 5D",
+"Canon EOS 5D Mark II",
+"Canon EOS 10D",
+"Canon EOS 20D",
+"Canon EOS 30D",
+"Canon EOS 40D",
+"Canon EOS 50D",
+"Canon EOS 300D / Digital Rebel / Kiss Digital",
+"Canon EOS 350D / Digital Rebel XT / Kiss Digital N",
+"Canon EOS 400D / Digital Rebel XTi / Kiss Digital X",
+"Canon EOS 450D / Digital Rebel XSi / Kiss Digital X2",
+"Canon EOS 1000D / Digital Rebel XS / Kiss Digital F",
+"Canon EOS D2000C",
+"Canon EOS-1D",
+"Canon EOS-1DS",
+"Canon EOS-1D Mark II",
+"Canon EOS-1D Mark III",
+"Canon EOS-1D Mark II N",
+"Canon EOS-1Ds Mark II",
+"Canon EOS-1Ds Mark III",
+"Casio QV-2000UX",
+"Casio QV-3000EX",
+"Casio QV-3500EX",
+"Casio QV-4000",
+"Casio QV-5700",
+"Casio QV-R41",
+"Casio QV-R51",
+"Casio QV-R61",
+"Casio EX-S100",
+"Casio EX-Z4",
+"Casio EX-Z50",
+"Casio EX-Z55",
+"Casio Exlim Pro 505",
+"Casio Exlim Pro 600",
+"Casio Exlim Pro 700",
+"Contax N Digital",
+"Creative PC-CAM 600",
+"Epson R-D1",
+"Foculus 531C",
+"Fuji FinePix E550",
+"Fuji FinePix E900",
+"Fuji FinePix F700",
+"Fuji FinePix F710",
+"Fuji FinePix F800",
+"Fuji FinePix F810",
+"Fuji FinePix S2Pro",
+"Fuji FinePix S3Pro",
+"Fuji FinePix S5Pro",
+"Fuji FinePix S20Pro",
+"Fuji FinePix S100FS",
+"Fuji FinePix S5000",
+"Fuji FinePix S5100/S5500",
+"Fuji FinePix S5200/S5600",
+"Fuji FinePix S6000fd",
+"Fuji FinePix S7000",
+"Fuji FinePix S9000/S9500",
+"Fuji FinePix S9100/S9600",
+"Fuji IS-1",
+"Hasselblad CFV",
+"Hasselblad H3D",
+"Hasselblad V96C",
+"Imacon Ixpress 16-megapixel",
+"Imacon Ixpress 22-megapixel",
+"Imacon Ixpress 39-megapixel",
+"ISG 2020x1520",
+"Kodak DC20 (see Oliver Hartman's page)",
+"Kodak DC25 (see Jun-ichiro Itoh's page)",
+"Kodak DC40",
+"Kodak DC50",
+"Kodak DC120 (also try kdc2tiff)",
+"Kodak DCS200",
+"Kodak DCS315C",
+"Kodak DCS330C",
+"Kodak DCS420",
+"Kodak DCS460",
+"Kodak DCS460A",
+"Kodak DCS520C",
+"Kodak DCS560C",
+"Kodak DCS620C",
+"Kodak DCS620X",
+"Kodak DCS660C",
+"Kodak DCS660M",
+"Kodak DCS720X",
+"Kodak DCS760C",
+"Kodak DCS760M",
+"Kodak EOSDCS1",
+"Kodak EOSDCS3B",
+"Kodak NC2000F",
+"Kodak ProBack",
+"Kodak PB645C",
+"Kodak PB645H",
+"Kodak PB645M",
+"Kodak DCS Pro 14n",
+"Kodak DCS Pro 14nx",
+"Kodak DCS Pro SLR/c",
+"Kodak DCS Pro SLR/n",
+"Kodak C330",
+"Kodak C603",
+"Kodak P850",
+"Kodak P880",
+"Kodak KAI-0340",
+"Konica KD-400Z",
+"Konica KD-510Z",
+"Leaf AFi 7",
+"Leaf Aptus 17",
+"Leaf Aptus 22",
+"Leaf Aptus 54S",
+"Leaf Aptus 65",
+"Leaf Aptus 75",
+"Leaf Aptus 75S",
+"Leaf Cantare",
+"Leaf CatchLight",
+"Leaf CMost",
+"Leaf DCB2",
+"Leaf Valeo 6",
+"Leaf Valeo 11",
+"Leaf Valeo 17",
+"Leaf Valeo 22",
+"Leaf Volare",
+"Leica Digilux 2",
+"Leica Digilux 3",
+"Leica D-LUX2",
+"Leica D-LUX3",
+"Leica D-LUX4",
+"Leica V-LUX1",
+"Logitech Fotoman Pixtura",
+"Mamiya ZD",
+"Micron 2010",
+"Minolta RD175",
+"Minolta DiMAGE 5",
+"Minolta DiMAGE 7",
+"Minolta DiMAGE 7i",
+"Minolta DiMAGE 7Hi",
+"Minolta DiMAGE A1",
+"Minolta DiMAGE A2",
+"Minolta DiMAGE A200",
+"Minolta DiMAGE G400",
+"Minolta DiMAGE G500",
+"Minolta DiMAGE G530",
+"Minolta DiMAGE G600",
+"Minolta DiMAGE Z2",
+"Minolta Alpha/Dynax/Maxxum 5D",
+"Minolta Alpha/Dynax/Maxxum 7D",
+"Nikon D1",
+"Nikon D1H",
+"Nikon D1X",
+"Nikon D2H",
+"Nikon D2Hs",
+"Nikon D2X",
+"Nikon D2Xs",
+"Nikon D3",
+"Nikon D3X",
+"Nikon D40",
+"Nikon D40X",
+"Nikon D50",
+"Nikon D60",
+"Nikon D70",
+"Nikon D70s",
+"Nikon D80",
+"Nikon D90",
+"Nikon D100",
+"Nikon D200",
+"Nikon D300",
+"Nikon D700",
+"Nikon E700 (\"DIAG RAW\" hack)",
+"Nikon E800 (\"DIAG RAW\" hack)",
+"Nikon E880 (\"DIAG RAW\" hack)",
+"Nikon E900 (\"DIAG RAW\" hack)",
+"Nikon E950 (\"DIAG RAW\" hack)",
+"Nikon E990 (\"DIAG RAW\" hack)",
+"Nikon E995 (\"DIAG RAW\" hack)",
+"Nikon E2100 (\"DIAG RAW\" hack)",
+"Nikon E2500 (\"DIAG RAW\" hack)",
+"Nikon E3200 (\"DIAG RAW\" hack)",
+"Nikon E3700 (\"DIAG RAW\" hack)",
+"Nikon E4300 (\"DIAG RAW\" hack)",
+"Nikon E4500 (\"DIAG RAW\" hack)",
+"Nikon E5000",
+"Nikon E5400",
+"Nikon E5700",
+"Nikon E8400",
+"Nikon E8700",
+"Nikon E8800",
+"Nikon Coolpix P6000",
+"Nikon Coolpix S6 (\"DIAG RAW\" hack)",
+"Nokia N95",
+"Olympus C3030Z",
+"Olympus C5050Z",
+"Olympus C5060WZ",
+"Olympus C7070WZ",
+"Olympus C70Z,C7000Z",
+"Olympus C740UZ",
+"Olympus C770UZ",
+"Olympus C8080WZ",
+"Olympus E-1",
+"Olympus E-3",
+"Olympus E-10",
+"Olympus E-20",
+"Olympus E-300",
+"Olympus E-330",
+"Olympus E-400",
+"Olympus E-410",
+"Olympus E-420",
+"Olympus E-500",
+"Olympus E-510",
+"Olympus E-520",
+"Olympus SP310",
+"Olympus SP320",
+"Olympus SP350",
+"Olympus SP500UZ",
+"Olympus SP510UZ",
+"Olympus SP550UZ",
+"Olympus SP560UZ",
+"Olympus SP570UZ",
+"Panasonic DMC-FZ8",
+"Panasonic DMC-FZ18",
+"Panasonic DMC-FZ28",
+"Panasonic DMC-FZ30",
+"Panasonic DMC-FZ50",
+"Panasonic DMC-FX150",
+"Panasonic DMC-G1",
+"Panasonic DMC-L1",
+"Panasonic DMC-L10",
+"Panasonic DMC-LC1",
+"Panasonic DMC-LX1",
+"Panasonic DMC-LX2",
+"Panasonic DMC-LX3",
+"Pentax *ist D",
+"Pentax *ist DL",
+"Pentax *ist DL2",
+"Pentax *ist DS",
+"Pentax *ist DS2",
+"Pentax K10D",
+"Pentax K20D",
+"Pentax K100D",
+"Pentax K100D Super",
+"Pentax K200D",
+"Pentax K2000/K-m",
+"Pentax Optio S",
+"Pentax Optio S4",
+"Pentax Optio 33WR",
+"Pentax Optio 750Z",
+"Phase One LightPhase",
+"Phase One H 10",
+"Phase One H 20",
+"Phase One H 25",
+"Phase One P 20",
+"Phase One P 25",
+"Phase One P 30",
+"Phase One P 45",
+"Pixelink A782",
+"Polaroid x530",
+"Rollei d530flex",
+"RoverShot 3320af",
+"Samsung GX-1S",
+"Samsung GX-10",
+"Samsung S85 (hacked)",
+"Sarnoff 4096x5440",
+"Sigma SD9",
+"Sigma SD10",
+"Sigma SD14",
+"Sinar 3072x2048",
+"Sinar 4080x4080",
+"Sinar 4080x5440",
+"Sinar STI format",
+"SMaL Ultra-Pocket 3",
+"SMaL Ultra-Pocket 4",
+"SMaL Ultra-Pocket 5",
+"Sony DSC-F828",
+"Sony DSC-R1",
+"Sony DSC-V3",
+"Sony DSLR-A100",
+"Sony DSLR-A200",
+"Sony DSLR-A300",
+"Sony DSLR-A350",
+"Sony DSLR-A700",
+"Sony DSLR-A900",
+"Sony XCD-SX910CR",
+"STV680 VGA",
+ NULL
+};
+
+const char** LibRaw::cameraList() { return static_camera_list;}
+int LibRaw::cameraCount() { return (sizeof(static_camera_list)/sizeof(static_camera_list[0]))-1; }
+
+
+const char * LibRaw::strprogress(enum LibRaw_progress p)
+{
+ switch(p)
+ {
+ case LIBRAW_PROGRESS_START:
+ return "Starting";
+ case LIBRAW_PROGRESS_OPEN :
+ return "Opening file";
+ case LIBRAW_PROGRESS_IDENTIFY :
+ return "Reading metadata";
+ case LIBRAW_PROGRESS_SIZE_ADJUST:
+ return "Adjusting size";
+ case LIBRAW_PROGRESS_LOAD_RAW:
+ return "Reading RAW data";
+ case LIBRAW_PROGRESS_REMOVE_ZEROES:
+ return "Clearing zero values";
+ case LIBRAW_PROGRESS_BAD_PIXELS :
+ return "Removing dead pixels";
+ case LIBRAW_PROGRESS_DARK_FRAME:
+ return "Subtracting dark frame data";
+ case LIBRAW_PROGRESS_FOVEON_INTERPOLATE:
+ return "Interpolating Foveon sensor data";
+ case LIBRAW_PROGRESS_SCALE_COLORS:
+ return "Scaling colors";
+ case LIBRAW_PROGRESS_PRE_INTERPOLATE:
+ return "Pre-interpolating";
+ case LIBRAW_PROGRESS_INTERPOLATE:
+ return "Interpolating";
+ case LIBRAW_PROGRESS_MIX_GREEN :
+ return "Mixing green channels";
+ case LIBRAW_PROGRESS_MEDIAN_FILTER :
+ return "Median filter";
+ case LIBRAW_PROGRESS_HIGHLIGHTS:
+ return "Highlight recovery";
+ case LIBRAW_PROGRESS_FUJI_ROTATE :
+ return "Rotating Fuji diagonal data";
+ case LIBRAW_PROGRESS_FLIP :
+ return "Flipping image";
+ case LIBRAW_PROGRESS_APPLY_PROFILE:
+ return "ICC conversion";
+ case LIBRAW_PROGRESS_CONVERT_RGB:
+ return "Converting to RGB";
+ case LIBRAW_PROGRESS_STRETCH:
+ return "Stretching image";
+ case LIBRAW_PROGRESS_THUMB_LOAD:
+ return "Loading thumbnail";
+ default:
+ return "Some strange things";
+ }
+}
diff --git a/libkdcraw/test/Makefile.am b/libkdcraw/test/Makefile.am
new file mode 100644
index 0000000..efb8c13
--- /dev/null
+++ b/libkdcraw/test/Makefile.am
@@ -0,0 +1,51 @@
+KDE_OPTIONS = nofinal
+METASOURCES = AUTO
+
+# LibRaw definitions
+KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DDCRAW_VERBOSE -DUSE_LCMS
+
+INCLUDES = -I../libraw -I../libkdcraw $(all_includes)
+
+check_PROGRAMS = raw2png identify simple_dcraw mem_image dcraw_emu 4channels unprocessed_raw
+
+# -------------------------------------------------------------
+
+raw2png_CFLAGS = $(all_includes)
+raw2png_SOURCES = raw2png.cpp
+raw2png_LDFLAGS = $(all_libraries) ../libkdcraw/libkdcraw.la
+
+# -------------------------------------------------------------
+
+identify_CFLAGS = $(all_includes)
+identify_SOURCES = ../libraw/samples/identify.cpp
+identify_LDFLAGS = $(all_libraries) ../libraw/libraw.la
+
+# -------------------------------------------------------------
+
+simple_dcraw_CFLAGS = $(all_includes)
+simple_dcraw_SOURCES = ../libraw/samples/simple_dcraw.cpp
+simple_dcraw_LDFLAGS = $(all_libraries) ../libraw/libraw.la
+
+# -------------------------------------------------------------
+
+mem_image_CFLAGS = $(all_includes)
+mem_image_SOURCES = ../libraw/samples/mem_image.cpp
+mem_image_LDFLAGS = $(all_libraries) ../libraw/libraw.la
+
+# -------------------------------------------------------------
+
+dcraw_emu_CFLAGS = $(all_includes)
+dcraw_emu_SOURCES = ../libraw/samples/dcraw_emu.cpp
+dcraw_emu_LDFLAGS = $(all_libraries) ../libraw/libraw.la
+
+# -------------------------------------------------------------
+
+4channels_CFLAGS = $(all_includes)
+4channels_SOURCES = ../libraw/samples/4channels.cpp
+4channels_LDFLAGS = $(all_libraries) ../libraw/libraw.la
+
+# -------------------------------------------------------------
+
+unprocessed_raw_CFLAGS = $(all_includes)
+unprocessed_raw_SOURCES = ../libraw/samples/unprocessed_raw.cpp
+unprocessed_raw_LDFLAGS = $(all_libraries) ../libraw/libraw.la
diff --git a/libkdcraw/test/raw2png.cpp b/libkdcraw/test/raw2png.cpp
new file mode 100644
index 0000000..114cdc5
--- /dev/null
+++ b/libkdcraw/test/raw2png.cpp
@@ -0,0 +1,123 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2008-15-09
+ * Description : a command line tool to convert RAW file to PNG
+ *
+ * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include "kdeversion.h"
+
+#if KDE_IS_VERSION(4,0,0)
+#include "qdebug.h"
+#define PRINT_DEBUG qDebug()
+#define ENDL
+#else
+#include "kdebug.h"
+#define PRINT_DEBUG kdDebug()
+#define ENDL << endl
+#endif
+
+// Local includes.
+
+#include "kdcraw.h"
+
+using namespace KDcrawIface;
+
+int main (int argc, char **argv)
+{
+ if(argc != 2)
+ {
+ PRINT_DEBUG << "raw2png - RAW Camera Image to PNG Converter" ENDL;
+ PRINT_DEBUG << "Usage: <rawfile>" ENDL;
+ return -1;
+ }
+
+ QString filePath(argv[1]);
+ QFileInfo input(filePath);
+ QString previewFilePath(input.baseName() + QString(".preview.png"));
+ QFileInfo previewOutput(previewFilePath);
+ QString halfFilePath(input.baseName() + QString(".half.png"));
+ QFileInfo halfOutput(halfFilePath);
+ QImage image;
+ DcrawInfoContainer identify;
+
+ // -----------------------------------------------------------
+
+ PRINT_DEBUG << "raw2png: Identify RAW image from " << input.fileName() ENDL;
+
+ KDcraw rawProcessor;
+ if (!rawProcessor.rawFileIdentify(identify, filePath))
+ {
+ PRINT_DEBUG << "raw2png: Idendify RAW image failed. Aborted..." ENDL;
+ return -1;
+ }
+
+ int width = identify.imageSize.width();
+ int height = identify.imageSize.height();
+
+ PRINT_DEBUG << "raw2png: Raw image info:" ENDL;
+ PRINT_DEBUG << "--- Date: " << identify.dateTime.toString(Qt::ISODate) ENDL;
+ PRINT_DEBUG << "--- Make: " << identify.make ENDL;
+ PRINT_DEBUG << "--- Model: " << identify.model ENDL;
+ PRINT_DEBUG << "--- Size: " << width << "x" << height ENDL;
+ PRINT_DEBUG << "--- Filter: " << identify.filterPattern ENDL;
+ PRINT_DEBUG << "--- Colors: " << identify.rawColors ENDL;
+
+ // -----------------------------------------------------------
+
+ PRINT_DEBUG << "raw2png: Loading RAW image preview" ENDL;
+
+ if (!rawProcessor.loadDcrawPreview(image, filePath))
+ {
+ PRINT_DEBUG << "raw2png: Loading RAW image preview failed. Aborted..." ENDL;
+ return -1;
+ }
+
+ PRINT_DEBUG << "raw2png: Saving preview image to "
+ << previewOutput.fileName() << " size ("
+ << image.width() << "x" << image.height()
+ << ")" ENDL;
+ image.save(previewFilePath, "PNG");
+
+ // -----------------------------------------------------------
+
+ PRINT_DEBUG << "raw2png: Loading half RAW image" ENDL;
+
+ image = QImage();
+ if (!rawProcessor.loadHalfPreview(image, filePath))
+ {
+ PRINT_DEBUG << "raw2png: Loading half RAW image failed. Aborted..." ENDL;
+ return -1;
+ }
+
+ PRINT_DEBUG << "raw2png: Saving half image to "
+ << halfOutput.fileName() << " size ("
+ << image.width() << "x" << image.height()
+ << ")" ENDL;
+ image.save(halfFilePath, "PNG");
+
+ return 0;
+}
diff --git a/po/pt_BR/Makefile.am b/po/pt_BR/Makefile.am
new file mode 100644
index 0000000..7337beb
--- /dev/null
+++ b/po/pt_BR/Makefile.am
@@ -0,0 +1,3 @@
+KDE_LANG = pt_BR
+SUBDIRS = $(AUTODIRS)
+POFILES = AUTO
diff --git a/po/pt_BR/libkdcraw.po b/po/pt_BR/libkdcraw.po
new file mode 100644
index 0000000..1b9e369
--- /dev/null
+++ b/po/pt_BR/libkdcraw.po
@@ -0,0 +1,413 @@
+# translation of libkdcraw.po to Brazilian Portuguese
+#
+# Luiz Fernando Ranghetti <elchevive@opensuse.org>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: libkdcraw\n"
+"POT-Creation-Date: 2008-09-15 08:37+0200\n"
+"PO-Revision-Date: 2008-11-27 21:15-0200\n"
+"Last-Translator: Luiz Fernando Ranghetti <elchevive@opensuse.org>\n"
+"Language-Team: Brazilian Portuguese <kde-i18n-pt_BR@mail.kde.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: libkdcraw/rcombobox.cpp:73 libkdcraw/rnuminput.cpp:74
+#: libkdcraw/rnuminput.cpp:172
+msgid "Reset to default value"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:183
+msgid "16 bits color depth"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:184
+msgid ""
+"<p>If enabled, all RAW files will be decoded in 16-bit color depth using a "
+"linear gamma curve. To prevent dark picture rendering in the editor, it is "
+"recommended to use Color Management in this mode."
+"<p>If disabled, all RAW files will be decoded in 8-bit color depth with a "
+"BT.709 gamma curve and a 99th-percentile white point. This mode is faster than "
+"16-bit decoding."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:203
+msgid "Interpolate RGB as four colors"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:204
+msgid ""
+"<p><b>Interpolate RGB as four colors</b>"
+"<p>The default is to assume that all green pixels are the same. If even-row "
+"green pixels are more sensitive to ultraviolet light than odd-row this "
+"difference causes a mesh pattern in the output; using this option solves this "
+"problem with minimal loss of detail."
+"<p>To resume, this option blurs the image a little, but it eliminates false 2x2 "
+"mesh patterns with VNG quality method or mazes with AHD quality method."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:217
+#, c-format
+msgid "libraw %1"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:220
+msgid "Visit dcraw project website"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:224
+msgid "Do not stretch or rotate pixels"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:225
+msgid ""
+"<p><b>Do not stretch or rotate pixels</b>"
+"<p>For Fuji Super CCD cameras, show the image tilted 45 degrees. For cameras "
+"with non-square pixels, do not stretch the image to its correct aspect ratio. "
+"In any case, this option guarantees that each output pixel corresponds to one "
+"RAW pixel."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:235
+msgid "Quality:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:237
+msgid "Bilinear"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:238
+msgid "VNG"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:239
+msgid "PPG"
+msgstr "PPG"
+
+#: libkdcraw/dcrawsettingswidget.cpp:240
+msgid "AHD"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:242
+msgid ""
+"<p><b>Quality (interpolation)</b>"
+"<p>Select here the demosaicing RAW images decoding interpolation method. A "
+"demosaicing algorithm is a digital image process used to interpolate a complete "
+"image from the partial raw data received from the color-filtered image sensor "
+"internal to many digital cameras in form of a matrix of colored pixels. Also "
+"known as CFA interpolation or color reconstruction, another common spelling is "
+"demosaicing. There are 4 methods to demosaicing RAW images:"
+"<p><b>Bilinear</b>: use high-speed but low-quality bilinear interpolation "
+"(default - for slow computer). In this method, the red value of a non-red pixel "
+"is computed as the average of the adjacent red pixels, and similar for blue and "
+"green."
+"<p><b>VNG</b>: use Variable Number of Gradients interpolation. This method "
+"computes gradients near the pixel of interest and uses the lower gradients "
+"(representing smoother and more similar parts of the image) to make an "
+"estimate."
+"<p><b>PPG</b>: use Patterned Pixel Grouping interpolation. Pixel Grouping uses "
+"assumptions about natural scenery in making estimates. It has fewer color "
+"artifacts on natural images than the Variable Number of Gradients method."
+"<p><b>AHD</b>: use Adaptive Homogeneity-Directed interpolation. This method "
+"selects the direction of interpolation so as to maximize a homogeneity metric, "
+"thus typically minimizing color artifacts."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:272
+msgid "Filter:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:273
+msgid ""
+"<p><b>Median Filter</b>"
+"<p>Set here the passes used by median filter applied after interpolation to "
+"Red-Green and Blue-Green channels."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:282
+msgid "Demosaicing"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:290
+msgid "Method:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:292
+msgid "Default D65"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:293
+msgid "Camera"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:294
+msgid "Automatic"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:295
+msgid "Manual"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:297
+msgid ""
+"<p><b>White Balance Method</b>"
+"<p>Configure the raw white balance :"
+"<p><b>Default D65</b>: Use a standard daylight D65 white balance (dcraw "
+"defaults)"
+"<p><b>Camera</b>: Use the white balance specified by the camera. If not "
+"available, reverts to default neutral white balance"
+"<p><b>Automatic</b>: Calculates an automatic white balance averaging the entire "
+"image"
+"<p><b>Manual</b>: Set a custom temperature and green level values"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:309
+msgid "T(K):"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:310
+msgid "<p><b>Temperature</b><p>Set here the color temperature in Kelvin."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:317
+msgid "Green:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:318
+msgid ""
+"<p>Set here the green component to set magenta color cast removal level."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:321
+msgid "Highlights:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:323
+msgid "Solid white"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:324
+msgid "Unclip"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:325
+msgid "Blend"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:326
+msgid "Rebuild"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:328
+msgid ""
+"<p><b>Highlights</b>"
+"<p>Select here the highlight clipping method:"
+"<p><b>Solid white</b>: clip all highlights to solid white"
+"<p><b>Unclip</b>: leave highlights unclipped in various shades of pink"
+"<p><b>Blend</b>:Blend clipped and unclipped values together for a gradual fade "
+"to white"
+"<p><b>Rebuild</b>: reconstruct highlights using a level value"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:337
+msgid "Level:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:341
+msgid ""
+"<p><b>Level</b>"
+"<p>Specify the reconstruct highlight level. Low values favor whites and high "
+"values favor colors."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:345
+msgid "Brightness:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:350
+msgid ""
+"<p><b>Brighness</b>"
+"<p>Specify the brightness level of output image.The default value is 1.0 (works "
+"in 8-bit mode only)."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:360
+msgid "Black:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:361
+msgid ""
+"<p><b>Black point</b>"
+"<p>Use a specific black point value to decode RAW pictures. If you set this "
+"option to off, the Black Point value will be automatically computed."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:368
+msgid ""
+"<p><b>Black point value</b>"
+"<p>Specify specific black point value of the output image."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:371
+msgid "White:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:372
+msgid ""
+"<p><b>White point</b>"
+"<p>Use a specific white point value to decode RAW pictures. If you set this "
+"option to off, the White Point value will be automatically computed."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:379
+msgid ""
+"<p><b>White point value</b>"
+"<p>Specify specific white point value of the output image."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:409
+msgid "White Balance"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:417
+msgid "Enable noise reduction"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:418
+msgid ""
+"<p><b>Enable Noise Reduction</b>"
+"<p>Use wavelets to erase noise while preserving real detail."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:424
+msgid "Threshold:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:425
+msgid ""
+"<p><b>Threshold</b>"
+"<p>Set here the noise reduction threshold value to use."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:428
+msgid "Enable Chromatic Aberration correction"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:429
+msgid ""
+"<p><b>Enable Chromatic Aberration correction</b>"
+"<p>Enlarge the raw red and blue layers by the given factors, typically 0.999 to "
+"1.001, to correct chromatic aberration."
+"<p>"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:433
+msgid "Red:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:438
+msgid ""
+"<p><b>Red multiplier</b>"
+"<p>Set here the magnification factor of the red layer"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:441
+msgid "Blue:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:446
+msgid ""
+"<p><b>Blue multiplier</b>"
+"<p>Set here the magnification factor of the blue layer"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:461
+msgid "Corrections"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:469
+msgid "Camera Profile:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:471
+msgid "None"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:472
+msgid "Embedded"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:473 libkdcraw/dcrawsettingswidget.cpp:492
+msgid "Custom"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:475
+msgid ""
+"<p><b>Camera Profile</b>"
+"<p>Select here the input color space used to decode RAW data."
+"<p><b>None</b>: no input color profile is used during RAW decoding."
+"<p><b>Embedded</b>: use embedded color profile from RAW file if exist."
+"<p><b>Custom</b>: use a custom input color space profile."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:483 libkdcraw/dcrawsettingswidget.cpp:513
+msgid "ICC Files (*.icc; *.icm)"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:485
+msgid "Workspace:"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:487
+msgid "Raw (linear)"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:488
+msgid "sRGB"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:489
+msgid "Adobe RGB"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:490
+msgid "Wide Gamut"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:491
+msgid "Pro-Photo"
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:494
+msgid ""
+"<p><b>Workspace</b>"
+"<p>Select here the output color space used to decode RAW data."
+"<p><b>Raw (linear)</b>: in this mode, no output color space is used during RAW "
+"decoding."
+"<p><b>sRGB</b>: this is a RGB color space, created cooperatively by "
+"Hewlett-Packard and Microsoft. It is the best choice for images destined for "
+"the Web and portrait photography."
+"<p><b>Adobe RGB</b>: this color space is an extended RGB color space, developed "
+"by Adobe. It is used for photography applications such as advertising and fine "
+"art."
+"<p><b>Wide Gamut</b>: this color space is an expanded version of the Adobe RGB "
+"color space."
+"<p><b>Pro-Photo</b>: this color space is an RGB color space, developed by "
+"Kodak, that offers an especially large gamut designed for use with photographic "
+"outputs in mind."
+"<p><b>Custom</b>: use a custom output color space profile."
+msgstr ""
+
+#: libkdcraw/dcrawsettingswidget.cpp:525
+msgid "Color Management"
+msgstr ""