2058 lines
69 KiB
Diff
Executable File
2058 lines
69 KiB
Diff
Executable File
--- dcraw.c 2014-02-19 17:25:45.051457734 +0100
|
|
+++ dcraw.cc 2014-03-25 10:57:44.977344962 +0100
|
|
@@ -1,3 +1,15 @@
|
|
+/*RT*/#include <glib.h>
|
|
+/*RT*/#include <glib/gstdio.h>
|
|
+/*RT*/#undef MAX
|
|
+/*RT*/#undef MIN
|
|
+/*RT*/#undef ABS
|
|
+/*RT*/#include "rt_math.h"
|
|
+/*RT*/#define NO_LCMS
|
|
+/*RT*/#define NO_JPEG
|
|
+/*RT*/#define NO_JASPER
|
|
+/*RT*/#define LOCALTIME
|
|
+/*RT*/#define DJGPP
|
|
+
|
|
/*
|
|
dcraw.c -- Dave Coffin's raw photo decoder
|
|
Copyright 1997-2014 by Dave Coffin, dcoffin a cybercom o net
|
|
@@ -29,17 +41,17 @@
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
#define _USE_MATH_DEFINES
|
|
-#include <ctype.h>
|
|
-#include <errno.h>
|
|
+#include <cctype>
|
|
+#include <cerrno>
|
|
#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 <cfloat>
|
|
+#include <climits>
|
|
+#include <cmath>
|
|
+#include <csetjmp>
|
|
+#include <cstdio>
|
|
+#include <cstdlib>
|
|
+#include <cstring>
|
|
+#include <ctime>
|
|
#include <sys/types.h>
|
|
|
|
#if defined(DJGPP) || defined(__MINGW32__)
|
|
@@ -54,7 +66,6 @@
|
|
#ifdef WIN32
|
|
#include <sys/utime.h>
|
|
#include <winsock2.h>
|
|
-#pragma comment(lib, "ws2_32.lib")
|
|
#define snprintf _snprintf
|
|
#define strcasecmp stricmp
|
|
#define strncasecmp strnicmp
|
|
@@ -98,87 +109,38 @@
|
|
#define LONG_BIT (8 * sizeof (long))
|
|
#endif
|
|
|
|
-#if !defined(uchar)
|
|
-#define uchar unsigned char
|
|
-#endif
|
|
-#if !defined(ushort)
|
|
-#define ushort unsigned short
|
|
-#endif
|
|
-
|
|
+#define ushort UshORt
|
|
+typedef unsigned char uchar;
|
|
+typedef unsigned short ushort;
|
|
+
|
|
+#include "dcraw.h"
|
|
/*
|
|
- All global variables are defined here, and all functions that
|
|
+ RT All global variables are defined here, and all functions that
|
|
access them are prefixed with "CLASS". Note that a thread-safe
|
|
C++ class cannot have non-const static local variables.
|
|
*/
|
|
-FILE *ifp, *ofp;
|
|
-short order;
|
|
-const char *ifname;
|
|
-char *meta_data, xtrans[6][6];
|
|
-char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
|
|
-float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
|
|
-time_t timestamp;
|
|
-off_t strip_offset, data_offset;
|
|
-off_t thumb_offset, meta_offset, profile_offset;
|
|
-unsigned shot_order, kodak_cbpp, exif_cfa, unique_id;
|
|
-unsigned thumb_length, meta_length, profile_length;
|
|
-unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;
|
|
-unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
|
|
-unsigned black, maximum, mix_green, raw_color, zero_is_bad;
|
|
-unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
|
|
-unsigned tile_width, tile_length, gpsdata[32], load_flags;
|
|
-unsigned flip, tiff_flip, filters, colors;
|
|
-ushort raw_height, raw_width, height, width, top_margin, left_margin;
|
|
-ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
|
|
-ushort *raw_image, (*image)[4], cblack[4102];
|
|
-ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
|
|
-double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
|
|
-float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
|
|
-int mask[8][4];
|
|
-int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
|
|
-int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=1;
|
|
-int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
|
|
-int no_auto_bright=0;
|
|
-unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
|
|
-float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
|
|
-const double xyz_rgb[3][3] = { /* XYZ from RGB */
|
|
+
|
|
+const double xyz_rgb[3][3] = { // XYZ from RGB
|
|
{ 0.412453, 0.357580, 0.180423 },
|
|
{ 0.212671, 0.715160, 0.072169 },
|
|
{ 0.019334, 0.119193, 0.950227 } };
|
|
const float d65_white[3] = { 0.950456, 1, 1.088754 };
|
|
-int histogram[4][0x2000];
|
|
-void (*write_thumb)(), (*write_fun)();
|
|
-void (*load_raw)(), (*thumb_load_raw)();
|
|
-jmp_buf failure;
|
|
-
|
|
-struct decode {
|
|
- struct decode *branch[2];
|
|
- int leaf;
|
|
-} first_decode[2048], *second_decode, *free_decode;
|
|
-
|
|
-struct tiff_ifd {
|
|
- int width, height, bps, comp, phint, offset, flip, samples, bytes;
|
|
- int tile_width, tile_length;
|
|
-} tiff_ifd[10];
|
|
-
|
|
-struct ph1 {
|
|
- int format, key_off, black, black_off, split_col, tag_21a;
|
|
- float tag_210;
|
|
-} ph1;
|
|
|
|
-#define CLASS
|
|
+/* RT: Removed unused structs */
|
|
+#define CLASS DCraw::
|
|
|
|
#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 SQR(x) rtengine::SQR(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 MIN(a,b) rtengine::min(a,static_cast<typeof(a)>(b))
|
|
+#define MAX(a,b) rtengine::max(a,static_cast<typeof(a)>(b))
|
|
+#define LIM(x,min,max) rtengine::LIM(x,static_cast<typeof(x)>(min),static_cast<typeof(x)>(max))
|
|
+#define ULIM(x,y,z) rtengine::ULIM(x,static_cast<typeof(x)>(y),static_cast<typeof(x)>(z))
|
|
+#define CLIP(x) rtengine::CLIP(x)
|
|
#define SWAP(a,b) { a=a+b; b=a-b; a=a-b; }
|
|
|
|
/*
|
|
@@ -254,6 +216,7 @@
|
|
|
|
if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15];
|
|
if (filters == 9) return xtrans[(row+top_margin+6)%6][(col+left_margin+6)%6];
|
|
+
|
|
return FC(row,col);
|
|
}
|
|
|
|
@@ -296,6 +259,7 @@
|
|
fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp));
|
|
}
|
|
data_error++;
|
|
+/*RT*/ longjmp (failure, 1);
|
|
}
|
|
|
|
ushort CLASS sget2 (uchar *s)
|
|
@@ -369,7 +333,64 @@
|
|
{
|
|
if (fread (pixel, 2, count, ifp) < count) derror();
|
|
if ((order == 0x4949) == (ntohs(0x1234) == 0x1234))
|
|
- swab (pixel, pixel, count*2);
|
|
+ swab ((char*)pixel, (char*)pixel, count*2);
|
|
+}
|
|
+
|
|
+/* spline interpolation to 16 bit curve */
|
|
+void CLASS cubic_spline(const int *x_, const int *y_, const int len)
|
|
+{
|
|
+ float A[2*len][2*len], b[2*len], c[2*len], d[2*len];
|
|
+ float x[len], y[len];
|
|
+ int i, j;
|
|
+
|
|
+ memset(A, 0, sizeof(A));
|
|
+ memset(b, 0, sizeof(b));
|
|
+ memset(c, 0, sizeof(c));
|
|
+ memset(d, 0, sizeof(d));
|
|
+ for (i = 0; i < len; i++) {
|
|
+ x[i] = x_[i] / 65535.0;
|
|
+ y[i] = y_[i] / 65535.0;
|
|
+ }
|
|
+
|
|
+ for (i = len-1; i > 0; i--) {
|
|
+ b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]);
|
|
+ d[i-1] = x[i] - x[i-1];
|
|
+ }
|
|
+ for (i = 1; i < len-1; i++) {
|
|
+ A[i][i] = 2 * (d[i-1] + d[i]);
|
|
+ if (i > 1) {
|
|
+ A[i][i-1] = d[i-1];
|
|
+ A[i-1][i] = d[i-1];
|
|
+ }
|
|
+ A[i][len-1] = 6 * (b[i+1] - b[i]);
|
|
+ }
|
|
+ for(i = 1; i < len-2; i++) {
|
|
+ float v = A[i+1][i] / A[i][i];
|
|
+ for(j = 1; j <= len-1; j++) {
|
|
+ A[i+1][j] -= v * A[i][j];
|
|
+ }
|
|
+ }
|
|
+ for(i = len-2; i > 0; i--) {
|
|
+ float acc = 0;
|
|
+ for(j = i; j <= len-2; j++) {
|
|
+ acc += A[i][j]*c[j];
|
|
+ }
|
|
+ c[i] = (A[i][len-1] - acc) / A[i][i];
|
|
+ }
|
|
+ for (i = 0; i < 0x10000; i++) {
|
|
+ float x_out = (float)(i / 65535.0);
|
|
+ float y_out = 0;
|
|
+ for (j = 0; j < len-1; j++) {
|
|
+ if (x[j] <= x_out && x_out <= x[j+1]) {
|
|
+ float v = x_out - x[j];
|
|
+ y_out = y[j] +
|
|
+ ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j]) / 6) * v +
|
|
+ (c[j] * 0.5) * v*v +
|
|
+ ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v;
|
|
+ }
|
|
+ }
|
|
+ curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 : (ushort)nearbyintf(y_out * 65535.0));
|
|
+ }
|
|
}
|
|
|
|
void CLASS canon_600_fixed_wb (int temp)
|
|
@@ -541,10 +562,10 @@
|
|
return 0;
|
|
}
|
|
|
|
-unsigned CLASS getbithuff (int nbits, ushort *huff)
|
|
+unsigned CLASS getbithuff_t::operator() (int nbits, ushort *huff)
|
|
{
|
|
- static unsigned bitbuf=0;
|
|
- static int vbits=0, reset=0;
|
|
+/*RT static unsigned bitbuf=0; */
|
|
+/*RT static int vbits=0, reset=0; */
|
|
unsigned c;
|
|
|
|
if (nbits > 25) return 0;
|
|
@@ -1209,14 +1230,14 @@
|
|
int i, nz;
|
|
char tail[424];
|
|
|
|
- fseek (ifp, -sizeof tail, SEEK_END);
|
|
+ fseek (ifp, -(int)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;
|
|
}
|
|
|
|
-void CLASS jpeg_thumb();
|
|
+/*RT void CLASS jpeg_thumb(); */
|
|
|
|
void CLASS ppm_thumb()
|
|
{
|
|
@@ -1310,14 +1331,16 @@
|
|
void CLASS phase_one_flat_field (int is_float, int nc)
|
|
{
|
|
ushort head[8];
|
|
- unsigned wide, y, x, c, rend, cend, row, col;
|
|
+ unsigned wide, high, y, x, c, rend, cend, row, col;
|
|
float *mrow, num, mult[4];
|
|
|
|
read_shorts (head, 8);
|
|
- wide = head[2] / head[4];
|
|
+ if (head[2] == 0 || head[3] == 0 || head[4] == 0 || head[5] == 0) return; // RT: should not really happen, but when reverse-engineering IIQ files zero'd calibration data was used, so it's nice if not crashing.
|
|
+ wide = head[2] / head[4] + (head[2] % head[4] != 0);
|
|
+ high = head[3] / head[5] + (head[3] % head[5] != 0);
|
|
mrow = (float *) calloc (nc*wide, sizeof *mrow);
|
|
merror (mrow, "phase_one_flat_field()");
|
|
- for (y=0; y < head[3] / head[5]; y++) {
|
|
+ for (y=0; y < high; y++) {
|
|
for (x=0; x < wide; x++)
|
|
for (c=0; c < nc; c+=2) {
|
|
num = is_float ? getreal(11) : get2()/32768.0;
|
|
@@ -1326,14 +1349,14 @@
|
|
}
|
|
if (y==0) continue;
|
|
rend = head[1] + y*head[5];
|
|
- for (row = rend-head[5]; row < raw_height && row < rend; row++) {
|
|
+ for (row = rend-head[5]; row < raw_height && row < rend && row < head[1]+head[3]-head[5]; 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] + x*head[4];
|
|
- for (col = cend-head[4]; col < raw_width && col < cend; col++) {
|
|
+ for (col = cend-head[4]; col < raw_width && col < cend && col < head[0]+head[2]-head[4]; col++) {
|
|
c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0;
|
|
if (!(c & 1)) {
|
|
c = RAW(row,col) * mult[c];
|
|
@@ -1361,6 +1384,7 @@
|
|
{-2,-2}, {-2,2}, {2,-2}, {2,2} };
|
|
float poly[8], num, cfrac, frac, mult[2], *yval[2];
|
|
ushort *xval[2];
|
|
+ int qmult_applied = 0, qlin_applied = 0;
|
|
|
|
if (half_size || !meta_length) return;
|
|
if (verbose) fprintf (stderr,_("Phase One correction...\n"));
|
|
@@ -1437,6 +1461,154 @@
|
|
mindiff = diff;
|
|
off_412 = ftell(ifp) - 38;
|
|
}
|
|
+ } else if (tag == 0x41f && !qlin_applied) { /* Per quadrant linearization, P40+/P65+ */
|
|
+ ushort lc[2][2][16], ref[16];
|
|
+ int qr, qc;
|
|
+ /* Get curves for each quadrant (ordered top left, top right, bottom left, bottom right) */
|
|
+ for (qr = 0; qr < 2; qr++) {
|
|
+ for (qc = 0; qc < 2; qc++) {
|
|
+ for (i = 0; i < 16; i++) {
|
|
+ lc[qr][qc][i] = (ushort)get4();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /*
|
|
+ Each curve hold values along some exponential function, from ~20 to about ~50000, example:
|
|
+ 28 41 64 106 172 282 462 762 1240 2353 5111 10127 17867 27385 39122 58451
|
|
+ */
|
|
+
|
|
+ /* Derive a reference curve, by taking the average value in each column. Note: seems to work well,
|
|
+ but not 100% sure this is how the reference curve should be derived. */
|
|
+ for (i = 0; i < 16; i++) {
|
|
+ int v = 0;
|
|
+ for (qr = 0; qr < 2; qr++) {
|
|
+ for (qc = 0; qc < 2; qc++) {
|
|
+ v += lc[qr][qc][i];
|
|
+ }
|
|
+ }
|
|
+ ref[i] = (v + 2) >> 2;
|
|
+ }
|
|
+
|
|
+ /* Interpolate full calibration curves and apply. Spline interpolation used here,
|
|
+ as the curves are so coarsely specified and would get sharp corners if linearly
|
|
+ interpolated. */
|
|
+ for (qr = 0; qr < 2; qr++) {
|
|
+ for (qc = 0; qc < 2; qc++) {
|
|
+ int cx[18];
|
|
+ int cf[18];
|
|
+ for (i = 0; i < 16; i++) {
|
|
+ cx[1+i] = lc[qr][qc][i];
|
|
+ cf[1+i] = ref[i];
|
|
+ }
|
|
+ cx[0] = cf[0] = 0;
|
|
+ cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15];
|
|
+ cubic_spline(cx, cf, 18);
|
|
+ /* Apply curve in designated quadrant */
|
|
+ for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) {
|
|
+ for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) {
|
|
+ RAW(row,col) = curve[RAW(row,col)];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /* By some unknown reason some backs provide more than one copy of this tag, make sure
|
|
+ that we only apply this once. */
|
|
+ qlin_applied = 1;
|
|
+ } else if (tag == 0x41e && !qmult_applied) { /* Per quadrant multipliers P40+/P65+ */
|
|
+ float qmult[2][2] = { { 1, 1 }, { 1, 1 } };
|
|
+
|
|
+ /*
|
|
+ This tag has not been fully reverse-engineered, seems to be used only on P40+ and P65+ backs,
|
|
+ and will then have most values set to zero.
|
|
+
|
|
+ Layout:
|
|
+
|
|
+ - First 4 bytes contains 'II' (or 'MM' I guess if file is big endian, but don't think there are
|
|
+ any such backs produced) plus short integer 1
|
|
+ - The remaining 80 bytes seems to be 20 floats, most of them always zero. Example contents,
|
|
+ with map:
|
|
+
|
|
+ 0.000000, 0.000000, 0.080410, 0.078530,
|
|
+ 0.000000, 0.000000, 0.000000, 0.000000,
|
|
+ 0.104100, 0.103500, 0.000000, 0.000000,
|
|
+ 0.000000, 0.000000, 0.000000, 0.000000,
|
|
+ 0.089540, 0.092230, 0.000000, 0.000000
|
|
+
|
|
+ noeffect, noeffect, noeffect, topleft ,
|
|
+ noeffect, TL++ , global , noeffect,
|
|
+ noeffect, topright, , TR++ ,
|
|
+ , bottmlft, , BL++ ,
|
|
+ noeffect, bottmrgt, , BR++ ,
|
|
+
|
|
+ 'noeffect' tested with no effect, empty not tested, the ++ versions are stronger effect
|
|
+ multpliers that doesn't seem to be used, the global multiplier seems to unused as well.
|
|
+
|
|
+ It seems like one quadrant always is generally used as reference, (ie value 0 => multiplier 1.0),
|
|
+ but it's not always the same quadrant for different backs.
|
|
+
|
|
+ The 'noeffect' fields which actually have values are suspicious, maybe these multipliers are
|
|
+ used in Sensor+ or at some different ISO or something? They seem to be close to the ordinary
|
|
+ multipliers though so using the 'wrong' ones in some special case should yield quite good
|
|
+ result still.
|
|
+ */
|
|
+
|
|
+ /* We only read out the multipliers that are used and seem to have any effect and are used */
|
|
+ get4(); get4(); get4(); get4();
|
|
+ qmult[0][0] = 1.0 + getreal(11);
|
|
+ get4(); get4(); get4(); get4(); get4();
|
|
+ qmult[0][1] = 1.0 + getreal(11);
|
|
+ get4(); get4(); get4();
|
|
+ qmult[1][0] = 1.0 + getreal(11);
|
|
+ get4(); get4(); get4();
|
|
+ qmult[1][1] = 1.0 + getreal(11);
|
|
+ for (row=0; row < raw_height; row++) {
|
|
+ for (col=0; col < raw_width; col++) {
|
|
+ i = qmult[row >= ph1.split_row][col >= ph1.split_col] * RAW(row,col);
|
|
+ RAW(row,col) = LIM(i,0,65535);
|
|
+ }
|
|
+ }
|
|
+ /* By some unknown reason some backs provide more than one copy of this tag, make sure
|
|
+ that we only apply this once. */
|
|
+ qmult_applied = 1;
|
|
+ } else if (tag == 0x431 && !qmult_applied) { /* Per quadrant multiplication and linearization, IQ series backs */
|
|
+ ushort lc[2][2][7], ref[7];
|
|
+ int qr, qc;
|
|
+
|
|
+ /* Read reference curve */
|
|
+ for (i = 0; i < 7; i++) {
|
|
+ ref[i] = (ushort)get4();
|
|
+ }
|
|
+
|
|
+ /* Get multipliers for each quadrant */
|
|
+ for (qr = 0; qr < 2; qr++) {
|
|
+ for (qc = 0; qc < 2; qc++) {
|
|
+ for (i = 0; i < 7; i++) {
|
|
+ lc[qr][qc][i] = (ushort)get4();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /* Spline interpolation and apply in each quadrant */
|
|
+ for (qr = 0; qr < 2; qr++) {
|
|
+ for (qc = 0; qc < 2; qc++) {
|
|
+ int cx[9];
|
|
+ int cf[9];
|
|
+ for (i = 0; i < 7; i++) {
|
|
+ cx[1+i] = ref[i];
|
|
+ cf[1+i] = ((unsigned int)ref[i] * lc[qr][qc][i]) / 10000;
|
|
+ }
|
|
+ cx[0] = cf[0] = 0;
|
|
+ cx[8] = cf[8] = 65535;
|
|
+ cubic_spline(cx, cf, 9);
|
|
+ for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) {
|
|
+ for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) {
|
|
+ RAW(row,col) = curve[RAW(row,col)];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /* not seen any backs that have this tag multiplied, but just to make sure */
|
|
+ qmult_applied = 1;
|
|
+ qlin_applied = 1;
|
|
}
|
|
fseek (ifp, save, SEEK_SET);
|
|
}
|
|
@@ -1494,10 +1666,10 @@
|
|
}
|
|
}
|
|
|
|
-unsigned CLASS ph1_bithuff (int nbits, ushort *huff)
|
|
+unsigned CLASS ph1_bithuff_t::operator() (int nbits, ushort *huff)
|
|
{
|
|
- static UINT64 bitbuf=0;
|
|
- static int vbits=0;
|
|
+/*RT static UINT64 bitbuf=0; */
|
|
+/*RT static int vbits=0; */
|
|
unsigned c;
|
|
|
|
if (nbits == -1)
|
|
@@ -1523,8 +1695,10 @@
|
|
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 (*black)[2];
|
|
+ short (*black)[2], (*black2)[2];
|
|
|
|
+ black2 = (short (*)[2]) calloc (raw_width*2, 2);
|
|
+ merror (black2, "phase_one_load_raw_c()");
|
|
pixel = (ushort *) calloc (raw_width + raw_height*4, 2);
|
|
merror (pixel, "phase_one_load_raw_c()");
|
|
offset = (int *) (pixel + raw_width);
|
|
@@ -1535,6 +1709,9 @@
|
|
fseek (ifp, ph1.black_off, SEEK_SET);
|
|
if (ph1.black_off)
|
|
read_shorts ((ushort *) black[0], raw_height*2);
|
|
+ fseek (ifp, ph1.black_off2, SEEK_SET);
|
|
+ if (ph1.black_off2)
|
|
+ read_shorts ((ushort *) black2[0], raw_width*2);
|
|
for (i=0; i < 256; i++)
|
|
curve[i] = i*i / 3.969 + 0.5;
|
|
for (row=0; row < raw_height; row++) {
|
|
@@ -1558,11 +1735,12 @@
|
|
pixel[col] = curve[pixel[col]];
|
|
}
|
|
for (col=0; col < raw_width; col++) {
|
|
- i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col];
|
|
+ i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col] + black2[col][row >= ph1.split_row];
|
|
if (i > 0) RAW(row,col) = i;
|
|
}
|
|
}
|
|
free (pixel);
|
|
+ free (black2);
|
|
maximum = 0xfffc - ph1.black;
|
|
}
|
|
|
|
@@ -1757,10 +1935,10 @@
|
|
maximum = curve[0x3ff];
|
|
}
|
|
|
|
-unsigned CLASS pana_bits (int nbits)
|
|
+unsigned CLASS pana_bits_t::operator() (int nbits)
|
|
{
|
|
- static uchar buf[0x4000];
|
|
- static int vbits;
|
|
+/*RT static uchar buf[0x4000]; */
|
|
+/*RT static int vbits;*/
|
|
int byte;
|
|
|
|
if (!nbits) return vbits=0;
|
|
@@ -2049,11 +2227,11 @@
|
|
METHODDEF(boolean)
|
|
fill_input_buffer (j_decompress_ptr cinfo)
|
|
{
|
|
- static uchar jpeg_buffer[4096];
|
|
+/*RT static uchar jpeg_buffer[4096]; */
|
|
size_t nbytes;
|
|
|
|
nbytes = fread (jpeg_buffer, 1, 4096, ifp);
|
|
- swab (jpeg_buffer, jpeg_buffer, nbytes);
|
|
+ swab ((char*)jpeg_buffer, (char*)jpeg_buffer, nbytes);
|
|
cinfo->src->next_input_byte = jpeg_buffer;
|
|
cinfo->src->bytes_in_buffer = nbytes;
|
|
return TRUE;
|
|
@@ -2371,10 +2549,9 @@
|
|
maximum = (1 << (thumb_misc & 31)) - 1;
|
|
}
|
|
|
|
-void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
|
|
+void CLASS sony_decrypt_t::operator()(unsigned *data, int len, int start, int key)
|
|
{
|
|
- static unsigned pad[128], p;
|
|
-
|
|
+/*RT static unsigned pad[128], p;*/
|
|
if (start) {
|
|
for (p=0; p < 4; p++)
|
|
pad[p] = key = key * 48828125 + 1;
|
|
@@ -2462,11 +2639,13 @@
|
|
bit += 7;
|
|
}
|
|
for (i=0; i < 16; i++, col+=2)
|
|
- RAW(row,col) = curve[pix[i] << 1] >> 2;
|
|
+ RAW(row,col) = curve[pix[i] << 1]; // >> 2; RT: disabled shifting to avoid precision loss
|
|
col -= col & 1 ? 1:31;
|
|
}
|
|
}
|
|
free (data);
|
|
+ maximum = curve[0x7ff << 1]; // RT: fix maximum.
|
|
+ maximum = 16300; // RT: conservative white level tested on various ARW2 cameras. This constant was set in 2013-12-17, may need re-evaluation in the future.
|
|
}
|
|
|
|
void CLASS samsung_load_raw()
|
|
@@ -2691,7 +2870,7 @@
|
|
|
|
void CLASS foveon_decoder (unsigned size, unsigned code)
|
|
{
|
|
- static unsigned huff[1024];
|
|
+/*RT static unsigned huff[1024];*/
|
|
struct decode *cur;
|
|
int i, len;
|
|
|
|
@@ -3414,10 +3593,13 @@
|
|
}
|
|
}
|
|
} else {
|
|
- for (row=0; row < height; row++)
|
|
- for (col=0; col < width; col++)
|
|
+
|
|
+#pragma omp parallel for
|
|
+ for (int row=0; row < height; row++)
|
|
+ for (int col=0; col < width; col++)
|
|
BAYER2(row,col) = RAW(row+top_margin,col+left_margin);
|
|
}
|
|
+
|
|
if (mask[0][3] > 0) goto mask_set;
|
|
if (load_raw == &CLASS canon_load_raw ||
|
|
load_raw == &CLASS lossless_jpeg_load_raw) {
|
|
@@ -4011,239 +4193,8 @@
|
|
}
|
|
}
|
|
|
|
-void CLASS lin_interpolate()
|
|
-{
|
|
- int code[16][16][32], size=16, *ip, sum[4];
|
|
- int f, c, i, x, y, row, col, shift, color;
|
|
- ushort *pix;
|
|
-
|
|
- if (verbose) fprintf (stderr,_("Bilinear interpolation...\n"));
|
|
- if (filters == 9) size = 6;
|
|
- border_interpolate(1);
|
|
- for (row=0; row < size; row++)
|
|
- for (col=0; col < size; col++) {
|
|
- ip = code[row][col]+1;
|
|
- f = fcol(row,col);
|
|
- memset (sum, 0, sizeof sum);
|
|
- for (y=-1; y <= 1; y++)
|
|
- for (x=-1; x <= 1; x++) {
|
|
- shift = (y==0) + (x==0);
|
|
- color = fcol(row+y,col+x);
|
|
- if (color == f) continue;
|
|
- *ip++ = (width*y + x)*4 + color;
|
|
- *ip++ = shift;
|
|
- *ip++ = color;
|
|
- sum[color] += 1 << shift;
|
|
- }
|
|
- code[row][col][0] = (ip - code[row][col]) / 3;
|
|
- FORCC
|
|
- if (c != f) {
|
|
- *ip++ = c;
|
|
- *ip++ = 256 / sum[c];
|
|
- }
|
|
- }
|
|
- for (row=1; row < height-1; row++)
|
|
- for (col=1; col < width-1; col++) {
|
|
- pix = image[row*width+col];
|
|
- ip = code[row % size][col % size];
|
|
- memset (sum, 0, sizeof sum);
|
|
- for (i=*ip++; 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;
|
|
- }
|
|
-}
|
|
-
|
|
-/*
|
|
- This algorithm is officially called:
|
|
-
|
|
- "Interpolation using a Threshold-based variable number of gradients"
|
|
-
|
|
- described in http://scien.stanford.edu/pages/labsite/1999/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=8, pcol=2, *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();
|
|
- if (verbose) fprintf (stderr,_("VNG interpolation...\n"));
|
|
-
|
|
- if (filters == 1) prow = pcol = 16;
|
|
- if (filters == 9) prow = pcol = 6;
|
|
- ip = (int *) calloc (prow*pcol, 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 = fcol(row+y1,col+x1);
|
|
- if (fcol(row+y2,col+x2) != color) continue;
|
|
- diag = (fcol(row,col+1) == color && fcol(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 = fcol(row,col);
|
|
- if (fcol(row+y,col+x) != color && fcol(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 */
|
|
- 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 = fcol(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);
|
|
- if (verbose) fprintf (stderr,_("PPG interpolation...\n"));
|
|
+/* RT: delete interpolation functions */
|
|
|
|
-/* Fill in the green layer with gradients and pattern recognition: */
|
|
- 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: */
|
|
- 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: */
|
|
- 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);
|
|
- }
|
|
-}
|
|
|
|
void CLASS cielab (ushort rgb[3], short lab[3])
|
|
{
|
|
@@ -4504,112 +4455,7 @@
|
|
}
|
|
#undef fcol
|
|
|
|
-/*
|
|
- Adaptive Homogeneity-Directed interpolation is based on
|
|
- the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
|
|
- */
|
|
-void CLASS ahd_interpolate()
|
|
-{
|
|
- int i, j, top, left, row, col, tr, tc, c, d, val, hm[2];
|
|
- static const int dir[4] = { -1, 1, -TS, TS };
|
|
- unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
|
|
- ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4];
|
|
- short (*lab)[TS][TS][3], (*lix)[3];
|
|
- char (*homo)[TS][TS], *buffer;
|
|
-
|
|
- if (verbose) fprintf (stderr,_("AHD interpolation...\n"));
|
|
-
|
|
- cielab (0,0);
|
|
- border_interpolate(5);
|
|
- buffer = (char *) malloc (26*TS*TS);
|
|
- 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)
|
|
- 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];
|
|
- cielab (rix[0],lix[0]);
|
|
- }
|
|
-/* 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);
|
|
-}
|
|
#undef TS
|
|
|
|
void CLASS median_filter()
|
|
@@ -4779,7 +4625,7 @@
|
|
}
|
|
}
|
|
|
|
-int CLASS parse_tiff_ifd (int base);
|
|
+/*RT int CLASS parse_tiff_ifd (int base);*/
|
|
|
|
void CLASS parse_makernote (int base, int uptag)
|
|
{
|
|
@@ -4936,7 +4782,8 @@
|
|
cam_mul[2] = get4() << 2;
|
|
}
|
|
}
|
|
- if (tag == 0x15 && type == 2 && is_raw)
|
|
+ //if (tag == 0x15 && type == 2 && is_raw)
|
|
+ if (tag == 0x15 && type == 2 && is_raw && strstr(model, "Hasselblad ") != model) // RT: don't overwrite already parsed Hasselblad model
|
|
fread (model, 64, 1, ifp);
|
|
if (strstr(make,"PENTAX")) {
|
|
if (tag == 0x1b) tag = 0x1018;
|
|
@@ -5187,7 +5034,7 @@
|
|
{ "","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",
|
|
- "Aptus-II 7","","","Aptus-II 6","","","Aptus-II 10","Aptus-II 5",
|
|
+ "AFi-II 7","","","Aptus-II 6","","","Aptus-II 10","Aptus-II 5",
|
|
"","","","","Aptus-II 10R","Aptus-II 8","","Aptus-II 12","","AFi-II 12" };
|
|
float romm_cam[3][3];
|
|
|
|
@@ -5276,6 +5123,8 @@
|
|
wbi = -2;
|
|
}
|
|
if (tag == 2118) wbtemp = getint(type);
|
|
+ if (tag == 2120 + wbi) /* RT: wb tag for DCS760 */
|
|
+ FORC3 cam_mul[c] = 2048.0 / getreal(type); /* RT: wb tag for DCS760 */
|
|
if (tag == 2130 + wbi)
|
|
FORC3 mul[c] = getreal(type);
|
|
if (tag == 2140 + wbi && wbi >= 0)
|
|
@@ -5295,8 +5144,8 @@
|
|
}
|
|
}
|
|
|
|
-void CLASS parse_minolta (int base);
|
|
-int CLASS parse_tiff (int base);
|
|
+/*RT void CLASS parse_minolta (int base); */
|
|
+/*RT int CLASS parse_tiff (int base);*/
|
|
|
|
int CLASS parse_tiff_ifd (int base)
|
|
{
|
|
@@ -5309,7 +5158,7 @@
|
|
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;
|
|
+/*RT*/ IMFILE *sfp;
|
|
|
|
if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0])
|
|
return 1;
|
|
@@ -5660,10 +5509,21 @@
|
|
case 61450:
|
|
cblack[4] = cblack[5] = MIN(sqrt(len),64);
|
|
case 50714: /* BlackLevel */
|
|
- FORC (cblack[4] * cblack[5])
|
|
- cblack[6+c] = getreal(type);
|
|
- black = 0;
|
|
- break;
|
|
+ if(cblack[4] * cblack[5] == 0) {
|
|
+ int dblack[] = { 0,0,0,0 };
|
|
+ black = getreal(type);
|
|
+ if ((unsigned)(filters+1) < 1000) break;
|
|
+ dblack[0] = dblack[1] = dblack[2] = dblack[3] = black;
|
|
+ if (colors == 3)
|
|
+ filters |= ((filters >> 2 & 0x22222222) |
|
|
+ (filters << 2 & 0x88888888)) & filters << 1;
|
|
+ FORC4 cblack[filters >> (c << 1) & 3] = dblack[c];
|
|
+ } else {
|
|
+ FORC (cblack[4] * cblack[5])
|
|
+ cblack[6+c] = getreal(type);
|
|
+ }
|
|
+ black = 0;
|
|
+ break;
|
|
case 50715: /* BlackLevelDeltaH */
|
|
case 50716: /* BlackLevelDeltaV */
|
|
for (num=i=0; i < len; i++)
|
|
@@ -5741,12 +5601,15 @@
|
|
fread (buf, sony_length, 1, ifp);
|
|
sony_decrypt (buf, sony_length/4, 1, sony_key);
|
|
sfp = ifp;
|
|
- if ((ifp = tmpfile())) {
|
|
- fwrite (buf, sony_length, 1, ifp);
|
|
- fseek (ifp, 0, SEEK_SET);
|
|
- parse_tiff_ifd (-sony_offset);
|
|
- fclose (ifp);
|
|
- }
|
|
+/*RT*/ ifp = fopen (buf, sony_length);
|
|
+// if ((ifp = tmpfile())) {
|
|
+// fwrite (buf, sony_length, 1, ifp);
|
|
+// fseek (ifp, 0, SEEK_SET);
|
|
+ parse_tiff_ifd (-sony_offset);
|
|
+// fclose (ifp);
|
|
+// }
|
|
+ if(ifp)
|
|
+ fclose(ifp);
|
|
ifp = sfp;
|
|
free (buf);
|
|
}
|
|
@@ -5770,6 +5633,7 @@
|
|
int CLASS parse_tiff (int base)
|
|
{
|
|
int doff;
|
|
+ /*RT*/ if (exif_base == -1) exif_base = base;
|
|
|
|
fseek (ifp, base, SEEK_SET);
|
|
order = get2();
|
|
@@ -5847,7 +5711,7 @@
|
|
case 8: load_raw = &CLASS eight_bit_load_raw; break;
|
|
case 12: if (tiff_ifd[raw].phint == 2)
|
|
load_flags = 6;
|
|
- load_raw = &CLASS packed_load_raw; break;
|
|
+ load_raw = &CLASS packed_load_raw; break;
|
|
case 14: load_flags = 0;
|
|
case 16: load_raw = &CLASS unpacked_load_raw;
|
|
if (!strncmp(make,"OLYMPUS",7) &&
|
|
@@ -5963,7 +5827,7 @@
|
|
{
|
|
const char *file, *ext;
|
|
char *jname, *jfile, *jext;
|
|
- FILE *save=ifp;
|
|
+/*RT*/ IMFILE *save=ifp;
|
|
|
|
ext = strrchr (ifname, '.');
|
|
file = strrchr (ifname, '/');
|
|
@@ -5985,13 +5849,14 @@
|
|
} else
|
|
while (isdigit(*--jext)) {
|
|
if (*jext != '9') {
|
|
- (*jext)++;
|
|
+ (*jext)++;
|
|
break;
|
|
}
|
|
*jext = '0';
|
|
}
|
|
if (strcmp (jname, ifname)) {
|
|
- if ((ifp = fopen (jname, "rb"))) {
|
|
+/*RT*/ if ((ifp = fopen (jname))) {
|
|
+// if ((ifp = fopen (jname, "rb"))) {
|
|
if (verbose)
|
|
fprintf (stderr,_("Reading metadata from %s ...\n"), jname);
|
|
parse_tiff (12);
|
|
@@ -6256,6 +6121,8 @@
|
|
case 0x21d: ph1.black = data; break;
|
|
case 0x222: ph1.split_col = data; break;
|
|
case 0x223: ph1.black_off = data+base; break;
|
|
+ case 0x224: ph1.split_row = data; break;
|
|
+ case 0x225: ph1.black_off2= data+base; break;
|
|
case 0x301:
|
|
model[63] = 0;
|
|
fread (model, 1, 63, ifp);
|
|
@@ -6334,7 +6201,11 @@
|
|
order = get2();
|
|
hlen = get4();
|
|
if (get4() == 0x48454150) /* "HEAP" */
|
|
+/*RT*/ {
|
|
+/*RT*/ ciff_base = save+hlen;
|
|
+/*RT*/ ciff_len = len-hlen;
|
|
parse_ciff (save+hlen, len-hlen, 0);
|
|
+/*RT*/ }
|
|
if (parse_tiff (save+6)) apply_tiff();
|
|
fseek (ifp, save+len, SEEK_SET);
|
|
}
|
|
@@ -6586,7 +6457,8 @@
|
|
{
|
|
static const struct {
|
|
const char *prefix;
|
|
- short black, maximum, trans[12];
|
|
+ unsigned short black, maximum; // RT: Change to UShort
|
|
+ short trans[12];
|
|
} table[] = {
|
|
{ "AgfaPhoto DC-833m", 0, 0, /* DJC */
|
|
{ 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } },
|
|
@@ -7457,6 +7329,27 @@
|
|
}
|
|
break;
|
|
}
|
|
+ if (load_raw == &CLASS sony_arw2_load_raw) { // RT: arw2 scale fix
|
|
+ black <<= 2;
|
|
+ }
|
|
+ { /* Check for RawTherapee table overrides and extensions */
|
|
+ int black_level, white_level;
|
|
+ short trans[12];
|
|
+ if (dcraw_coeff_overrides(make, model, iso_speed, trans, &black_level, &white_level)) {
|
|
+ if (black_level > -1) {
|
|
+ black = (ushort)black_level;
|
|
+ }
|
|
+ if (white_level > -1) {
|
|
+ maximum = (ushort)white_level;
|
|
+ }
|
|
+ if (trans[0]) {
|
|
+ for (j=0; j < 12; j++) {
|
|
+ cam_xyz[0][j] = trans[j] / 10000.0;
|
|
+ }
|
|
+ cam_xyz_coeff (rgb_cam,cam_xyz);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
void CLASS simple_coeff (int index)
|
|
@@ -7764,13 +7657,20 @@
|
|
fread (head, 1, 32, ifp);
|
|
fseek (ifp, 0, SEEK_END);
|
|
flen = fsize = ftell(ifp);
|
|
- if ((cp = (char *) memmem (head, 32, "MMMM", 4)) ||
|
|
- (cp = (char *) memmem (head, 32, "IIII", 4))) {
|
|
+ /*RT*/ if (fsize<100000) {
|
|
+ is_raw = 0;
|
|
+ return;
|
|
+ }
|
|
+ /* RT: changed string constant */
|
|
+ if ((cp = (char *) memmem (head, 32, (char*)"MMMM", 4)) ||
|
|
+ (cp = (char *) memmem (head, 32, (char*)"IIII", 4))) {
|
|
parse_phase_one (cp-head);
|
|
if (cp-head && parse_tiff(0)) apply_tiff();
|
|
} else if (order == 0x4949 || order == 0x4d4d) {
|
|
if (!memcmp (head+6,"HEAPCCDR",8)) {
|
|
data_offset = hlen;
|
|
+/*RT*/ ciff_base = hlen;
|
|
+/*RT*/ ciff_len = fsize - hlen;
|
|
parse_ciff (hlen, flen-hlen, 0);
|
|
load_raw = &CLASS canon_load_raw;
|
|
} else if (parse_tiff(0)) apply_tiff();
|
|
@@ -7816,6 +7716,7 @@
|
|
fseek (ifp, 100+28*(shot_select > 0), SEEK_SET);
|
|
parse_tiff (data_offset = get4());
|
|
parse_tiff (thumb_offset+12);
|
|
+/*RT*/ exif_base = thumb_offset+12;
|
|
apply_tiff();
|
|
} else if (!memcmp (head,"RIFF",4)) {
|
|
fseek (ifp, 0, SEEK_SET);
|
|
@@ -7925,15 +7826,18 @@
|
|
if (make[0] == 0) parse_smal (0, flen);
|
|
if (make[0] == 0) {
|
|
parse_jpeg(0);
|
|
- if (!strncmp(model,"ov",2) && !fseek (ifp, -6404096, SEEK_END) &&
|
|
- fread (head, 1, 32, ifp) && !strcmp(head,"BRCMn")) {
|
|
- strcpy (make, "OmniVision");
|
|
- data_offset = ftell(ifp) + 0x8000-32;
|
|
- width = raw_width;
|
|
- raw_width = 2611;
|
|
- load_raw = &CLASS nokia_load_raw;
|
|
- filters = 0x16161616;
|
|
- } else is_raw = 0;
|
|
+ //RT fix for the use of fseek below
|
|
+ if (!strncmp(model,"ov",2)) {
|
|
+ fseek (ifp, -6404096, SEEK_END);
|
|
+ if (fread (head, 1, 32, ifp) && !strcmp(head,"BRCMn")) {
|
|
+ strcpy (make, "OmniVision");
|
|
+ data_offset = ftell(ifp) + 0x8000-32;
|
|
+ width = raw_width;
|
|
+ raw_width = 2611;
|
|
+ load_raw = &CLASS nokia_load_raw;
|
|
+ filters = 0x16161616;
|
|
+ } else is_raw = 0;
|
|
+ }
|
|
}
|
|
|
|
for (i=0; i < sizeof corp / sizeof *corp; i++)
|
|
@@ -7966,7 +7870,7 @@
|
|
if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */
|
|
{ height = 3124; width = 4688; filters = 0x16161616; }
|
|
if (width == 4352 && (!strcmp(model,"K-r") || !strcmp(model,"K-x")))
|
|
- { width = 4309; filters = 0x16161616; }
|
|
+/*RT*/ { width = 4308; filters = 0x16161616; }
|
|
if (width >= 4960 && !strncmp(model,"K-5",3))
|
|
{ left_margin = 10; width = 4950; filters = 0x16161616; }
|
|
if (width == 4736 && !strcmp(model,"K-7"))
|
|
@@ -8112,7 +8016,7 @@
|
|
width -= 44;
|
|
} else if (!strcmp(model,"D3200") ||
|
|
!strcmp(model,"D600") ||
|
|
- !strncmp(model,"D800",4)) {
|
|
+ !strcmp(model,"D800") || !strcmp(model,"D800E") ) {
|
|
width -= 46;
|
|
} else if (!strcmp(model,"D4") ||
|
|
!strcmp(model,"Df")) {
|
|
@@ -8394,6 +8298,7 @@
|
|
filters = 0x16161616;
|
|
}
|
|
} else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) {
|
|
+ if(raw_width > 0) { // avoid divide by zero
|
|
if ((flen - data_offset) / (raw_width*8/7) == raw_height)
|
|
load_raw = &CLASS panasonic_load_raw;
|
|
if (!load_raw) {
|
|
@@ -8411,6 +8316,7 @@
|
|
}
|
|
filters = 0x01010101 * (uchar) "\x94\x61\x49\x16"
|
|
[((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3];
|
|
+ }
|
|
} else if (!strcmp(model,"C770UZ")) {
|
|
height = 1718;
|
|
width = 2304;
|
|
@@ -8630,6 +8536,10 @@
|
|
memcpy (rgb_cam, cmatrix, sizeof cmatrix);
|
|
raw_color = 0;
|
|
}
|
|
+ if(!strncmp(make, "Samsung", 7) && !strncmp(model, "GX20",4))
|
|
+ adobe_coeff (make, model);
|
|
+ if(!strncmp(make, "Pentax", 6) && !strncmp(model, "K10D",4))
|
|
+ adobe_coeff (make, model);
|
|
if (raw_color) adobe_coeff (make, model);
|
|
if (load_raw == &CLASS kodak_radc_load_raw)
|
|
if (raw_color) adobe_coeff ("Apple","Quicktake");
|
|
@@ -8725,194 +8635,7 @@
|
|
}
|
|
#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];
|
|
- 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 };
|
|
-
|
|
- gamma_curve (gamm[0], gamm[1], 0, 0);
|
|
- 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);
|
|
- pcurve[3] = (short)(256/gamm[5]+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];
|
|
- }
|
|
- if (verbose)
|
|
- fprintf (stderr, raw_color ? _("Building histograms...\n") :
|
|
- _("Converting to %s colorspace...\n"), name[output_color-1]);
|
|
-
|
|
- memset (histogram, 0, sizeof histogram);
|
|
- 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[fcol(row,col)];
|
|
- FORCC histogram[c][img[c] >> 3]++;
|
|
- }
|
|
- if (colors == 4 && output_color) colors = 3;
|
|
- if (document_mode && filters) colors = 1;
|
|
-}
|
|
-
|
|
-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;
|
|
- if (verbose)
|
|
- fprintf (stderr,_("Rotating image 45 degrees...\n"));
|
|
- fuji_width = (fuji_width - 1 + shrink) >> shrink;
|
|
- step = sqrt(0.5);
|
|
- wide = fuji_width / step;
|
|
- high = (height - fuji_width) / step;
|
|
- img = (ushort (*)[4]) calloc (high, wide*sizeof *img);
|
|
- merror (img, "fuji_rotate()");
|
|
-
|
|
- 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;
|
|
-}
|
|
-
|
|
-void CLASS stretch()
|
|
-{
|
|
- ushort newdim, (*img)[4], *pix0, *pix1;
|
|
- int row, col, c;
|
|
- double rc, frac;
|
|
-
|
|
- if (pixel_aspect == 1) return;
|
|
- if (verbose) fprintf (stderr,_("Stretching the image...\n"));
|
|
- 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;
|
|
-}
|
|
-
|
|
-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;
|
|
-}
|
|
+/* RT: removed unused functions */
|
|
|
|
struct tiff_tag {
|
|
ushort tag, type;
|
|
@@ -8935,585 +8658,12 @@
|
|
unsigned gps[26];
|
|
char desc[512], make[64], model[64], soft[32], date[20], artist[64];
|
|
};
|
|
+/* RT: Delete from here */
|
|
+/*RT*/#undef SQR
|
|
+/*RT*/#undef MAX
|
|
+/*RT*/#undef MIN
|
|
+/*RT*/#undef ABS
|
|
+/*RT*/#undef LIM
|
|
+/*RT*/#undef ULIM
|
|
+/*RT*/#undef CLIP
|
|
|
|
-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->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->desc));
|
|
- tiff_set (&th->ntag, 271, 2, 64, TOFF(th->make));
|
|
- tiff_set (&th->ntag, 272, 2, 64, TOFF(th->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->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->desc, desc, 512);
|
|
- strncpy (th->make, make, 64);
|
|
- strncpy (th->model, model, 64);
|
|
- strcpy (th->soft, "dcraw v"DCRAW_VERSION);
|
|
- t = localtime (×tamp);
|
|
- 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->artist, artist, 64);
|
|
-}
|
|
-
|
|
-void CLASS jpeg_thumb()
|
|
-{
|
|
- char *thumb;
|
|
- ushort exif[5];
|
|
- struct tiff_hdr th;
|
|
-
|
|
- thumb = (char *) malloc (thumb_length);
|
|
- merror (thumb, "jpeg_thumb()");
|
|
- fread (thumb, 1, thumb_length, ifp);
|
|
- fputc (0xff, ofp);
|
|
- fputc (0xd8, ofp);
|
|
- if (strcmp (thumb+6, "Exif")) {
|
|
- memcpy (exif, "\xff\xe1 Exif\0\0", 10);
|
|
- exif[1] = htons (8 + sizeof th);
|
|
- fwrite (exif, 1, sizeof exif, ofp);
|
|
- tiff_head (&th, 0);
|
|
- fwrite (&th, 1, sizeof th, ofp);
|
|
- }
|
|
- fwrite (thumb+2, 1, thumb_length-2, ofp);
|
|
- free (thumb);
|
|
-}
|
|
-
|
|
-void CLASS write_ppm_tiff()
|
|
-{
|
|
- struct tiff_hdr th;
|
|
- uchar *ppm;
|
|
- ushort *ppm2;
|
|
- int c, row, col, soff, rstep, cstep;
|
|
- int perc, val, total, white=0x2000;
|
|
-
|
|
- perc = width * height * 0.01; /* 99th percentile white level */
|
|
- if (fuji_width) perc /= 2;
|
|
- if (!((highlight & ~2) || no_auto_bright))
|
|
- for (white=c=0; c < colors; c++) {
|
|
- for (val=0x2000, total=0; --val > 32; )
|
|
- if ((total += histogram[c][val]) > perc) break;
|
|
- if (white < val) white = val;
|
|
- }
|
|
- gamma_curve (gamm[0], gamm[1], 2, (white << 3)/bright);
|
|
- 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);
|
|
- 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] = curve[image[soff][c]] >> 8;
|
|
- else FORCC ppm2[col*colors+c] = curve[image[soff][c]];
|
|
- if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa)
|
|
- swab (ppm2, ppm2, width*colors*2);
|
|
- fwrite (ppm, colors*output_bps/8, width, ofp);
|
|
- }
|
|
- free (ppm);
|
|
-}
|
|
-
|
|
-int CLASS main (int argc, const char **argv)
|
|
-{
|
|
- int arg, status=0, quality, i, c;
|
|
- int timestamp_only=0, thumbnail_only=0, identify_only=0;
|
|
- int user_qual=-1, user_black=-1, user_sat=-1, user_flip=-1;
|
|
- int use_fuji_rotate=1, write_to_stdout=0, read_from_stdin=0;
|
|
- const char *sp, *bpfile=0, *dark_frame=0, *write_ext;
|
|
- char opm, opt, *ofname, *cp;
|
|
- struct utimbuf ut;
|
|
-#ifndef NO_LCMS
|
|
- const char *cam_profile=0, *out_profile=0;
|
|
-#endif
|
|
-
|
|
-#ifndef LOCALTIME
|
|
- putenv ((char *) "TZ=UTC");
|
|
-#endif
|
|
-#ifdef LOCALEDIR
|
|
- setlocale (LC_CTYPE, "");
|
|
- setlocale (LC_MESSAGES, "");
|
|
- bindtextdomain ("dcraw", LOCALEDIR);
|
|
- textdomain ("dcraw");
|
|
-#endif
|
|
-
|
|
- if (argc == 1) {
|
|
- printf(_("\nRaw photo decoder \"dcraw\" v%s"), DCRAW_VERSION);
|
|
- printf(_("\nby Dave Coffin, dcoffin a cybercom o net\n"));
|
|
- printf(_("\nUsage: %s [OPTION]... [FILE]...\n\n"), argv[0]);
|
|
- puts(_("-v Print verbose messages"));
|
|
- puts(_("-c Write image data to standard output"));
|
|
- puts(_("-e Extract embedded thumbnail image"));
|
|
- puts(_("-i Identify files without decoding them"));
|
|
- puts(_("-i -v Identify files and show metadata"));
|
|
- puts(_("-z Change file dates to camera timestamp"));
|
|
- puts(_("-w Use camera white balance, if possible"));
|
|
- puts(_("-a Average the whole image for white balance"));
|
|
- puts(_("-A <x y w h> Average a grey box for white balance"));
|
|
- puts(_("-r <r g b g> Set custom white balance"));
|
|
- puts(_("+M/-M Use/don't use an embedded color matrix"));
|
|
- puts(_("-C <r b> Correct chromatic aberration"));
|
|
- puts(_("-P <file> Fix the dead pixels listed in this file"));
|
|
- puts(_("-K <file> Subtract dark frame (16-bit raw PGM)"));
|
|
- puts(_("-k <num> Set the darkness level"));
|
|
- puts(_("-S <num> Set the saturation level"));
|
|
- puts(_("-n <num> Set threshold for wavelet denoising"));
|
|
- puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)"));
|
|
- puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)"));
|
|
- puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)"));
|
|
-#ifndef NO_LCMS
|
|
- puts(_("-o <file> Apply output ICC profile from file"));
|
|
- puts(_("-p <file> Apply camera ICC profile from file or \"embed\""));
|
|
-#endif
|
|
- puts(_("-d Document mode (no color, no interpolation)"));
|
|
- puts(_("-D Document mode without scaling (totally raw)"));
|
|
- puts(_("-j Don't stretch or rotate raw pixels"));
|
|
- puts(_("-W Don't automatically brighten the image"));
|
|
- puts(_("-b <num> Adjust brightness (default = 1.0)"));
|
|
- puts(_("-g <p ts> Set custom gamma curve (default = 2.222 4.5)"));
|
|
- puts(_("-q [0-3] Set the interpolation quality"));
|
|
- puts(_("-h Half-size color image (twice as fast as \"-q 0\")"));
|
|
- puts(_("-f Interpolate RGGB as four colors"));
|
|
- puts(_("-m <num> Apply a 3x3 median filter to R-G and B-G"));
|
|
- puts(_("-s [0..N-1] Select one raw image or \"all\" from each file"));
|
|
- puts(_("-6 Write 16-bit instead of 8-bit"));
|
|
- puts(_("-4 Linear 16-bit, same as \"-6 -W -g 1 1\""));
|
|
- puts(_("-T Write TIFF instead of PPM"));
|
|
- puts("");
|
|
- return 1;
|
|
- }
|
|
- argv[argc] = "";
|
|
- for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) {
|
|
- opt = argv[arg++][1];
|
|
- if ((cp = (char *) strchr (sp="nbrkStqmHACg", opt)))
|
|
- for (i=0; i < "114111111422"[cp-sp]-'0'; i++)
|
|
- if (!isdigit(argv[arg+i][0])) {
|
|
- fprintf (stderr,_("Non-numeric argument to \"-%c\"\n"), opt);
|
|
- return 1;
|
|
- }
|
|
- switch (opt) {
|
|
- case 'n': threshold = atof(argv[arg++]); break;
|
|
- case 'b': bright = atof(argv[arg++]); break;
|
|
- case 'r':
|
|
- FORC4 user_mul[c] = atof(argv[arg++]); break;
|
|
- case 'C': aber[0] = 1 / atof(argv[arg++]);
|
|
- aber[2] = 1 / atof(argv[arg++]); break;
|
|
- case 'g': gamm[0] = atof(argv[arg++]);
|
|
- gamm[1] = atof(argv[arg++]);
|
|
- if (gamm[0]) gamm[0] = 1/gamm[0]; break;
|
|
- case 'k': user_black = atoi(argv[arg++]); break;
|
|
- case 'S': user_sat = atoi(argv[arg++]); break;
|
|
- case 't': user_flip = atoi(argv[arg++]); break;
|
|
- case 'q': user_qual = atoi(argv[arg++]); break;
|
|
- case 'm': med_passes = atoi(argv[arg++]); break;
|
|
- case 'H': highlight = atoi(argv[arg++]); break;
|
|
- case 's':
|
|
- shot_select = abs(atoi(argv[arg]));
|
|
- multi_out = !strcmp(argv[arg++],"all");
|
|
- break;
|
|
- case 'o':
|
|
- if (isdigit(argv[arg][0]) && !argv[arg][1])
|
|
- output_color = atoi(argv[arg++]);
|
|
-#ifndef NO_LCMS
|
|
- else out_profile = argv[arg++];
|
|
- break;
|
|
- case 'p': cam_profile = argv[arg++];
|
|
-#endif
|
|
- break;
|
|
- case 'P': bpfile = argv[arg++]; break;
|
|
- case 'K': dark_frame = argv[arg++]; break;
|
|
- case 'z': timestamp_only = 1; break;
|
|
- case 'e': thumbnail_only = 1; break;
|
|
- case 'i': identify_only = 1; break;
|
|
- case 'c': write_to_stdout = 1; break;
|
|
- case 'v': verbose = 1; break;
|
|
- case 'h': half_size = 1; break;
|
|
- case 'f': four_color_rgb = 1; break;
|
|
- case 'A': FORC4 greybox[c] = atoi(argv[arg++]);
|
|
- case 'a': use_auto_wb = 1; break;
|
|
- case 'w': use_camera_wb = 1; break;
|
|
- case 'M': use_camera_matrix = 3 * (opm == '+'); break;
|
|
- case 'I': read_from_stdin = 1; break;
|
|
- case 'E': document_mode++;
|
|
- case 'D': document_mode++;
|
|
- case 'd': document_mode++;
|
|
- case 'j': use_fuji_rotate = 0; break;
|
|
- case 'W': no_auto_bright = 1; break;
|
|
- case 'T': output_tiff = 1; break;
|
|
- case '4': gamm[0] = gamm[1] =
|
|
- no_auto_bright = 1;
|
|
- case '6': output_bps = 16; break;
|
|
- default:
|
|
- fprintf (stderr,_("Unknown option \"-%c\".\n"), opt);
|
|
- return 1;
|
|
- }
|
|
- }
|
|
- if (arg == argc) {
|
|
- fprintf (stderr,_("No files to process.\n"));
|
|
- return 1;
|
|
- }
|
|
- if (write_to_stdout) {
|
|
- if (isatty(1)) {
|
|
- fprintf (stderr,_("Will not write an image to the terminal!\n"));
|
|
- return 1;
|
|
- }
|
|
-#if defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__)
|
|
- if (setmode(1,O_BINARY) < 0) {
|
|
- perror ("setmode()");
|
|
- return 1;
|
|
- }
|
|
-#endif
|
|
- }
|
|
- for ( ; arg < argc; arg++) {
|
|
- status = 1;
|
|
- raw_image = 0;
|
|
- image = 0;
|
|
- oprof = 0;
|
|
- meta_data = ofname = 0;
|
|
- ofp = stdout;
|
|
- if (setjmp (failure)) {
|
|
- if (fileno(ifp) > 2) fclose(ifp);
|
|
- if (fileno(ofp) > 2) fclose(ofp);
|
|
- status = 1;
|
|
- goto cleanup;
|
|
- }
|
|
- ifname = argv[arg];
|
|
- if (!(ifp = fopen (ifname, "rb"))) {
|
|
- perror (ifname);
|
|
- continue;
|
|
- }
|
|
- status = (identify(),!is_raw);
|
|
- if (user_flip >= 0)
|
|
- flip = user_flip;
|
|
- switch ((flip+3600) % 360) {
|
|
- case 270: flip = 5; break;
|
|
- case 180: flip = 3; break;
|
|
- case 90: flip = 6;
|
|
- }
|
|
- if (timestamp_only) {
|
|
- if ((status = !timestamp))
|
|
- fprintf (stderr,_("%s has no timestamp.\n"), ifname);
|
|
- else if (identify_only)
|
|
- printf ("%10ld%10d %s\n", (long) timestamp, shot_order, ifname);
|
|
- else {
|
|
- if (verbose)
|
|
- fprintf (stderr,_("%s time set to %d.\n"), ifname, (int) timestamp);
|
|
- ut.actime = ut.modtime = timestamp;
|
|
- utime (ifname, &ut);
|
|
- }
|
|
- goto next;
|
|
- }
|
|
- write_fun = &CLASS write_ppm_tiff;
|
|
- if (thumbnail_only) {
|
|
- if ((status = !thumb_offset)) {
|
|
- fprintf (stderr,_("%s has no thumbnail.\n"), ifname);
|
|
- goto next;
|
|
- } else if (thumb_load_raw) {
|
|
- load_raw = thumb_load_raw;
|
|
- data_offset = thumb_offset;
|
|
- height = thumb_height;
|
|
- width = thumb_width;
|
|
- filters = 0;
|
|
- colors = 3;
|
|
- } else {
|
|
- fseek (ifp, thumb_offset, SEEK_SET);
|
|
- write_fun = write_thumb;
|
|
- goto thumbnail;
|
|
- }
|
|
- }
|
|
- if (load_raw == &CLASS kodak_ycbcr_load_raw) {
|
|
- height += height & 1;
|
|
- width += width & 1;
|
|
- }
|
|
- if (identify_only && verbose && make[0]) {
|
|
- printf (_("\nFilename: %s\n"), ifname);
|
|
- printf (_("Timestamp: %s"), ctime(×tamp));
|
|
- printf (_("Camera: %s %s\n"), make, model);
|
|
- if (artist[0])
|
|
- printf (_("Owner: %s\n"), artist);
|
|
- if (dng_version) {
|
|
- printf (_("DNG Version: "));
|
|
- for (i=24; i >= 0; i -= 8)
|
|
- printf ("%d%c", dng_version >> i & 255, i ? '.':'\n');
|
|
- }
|
|
- printf (_("ISO speed: %d\n"), (int) iso_speed);
|
|
- printf (_("Shutter: "));
|
|
- if (shutter > 0 && shutter < 1)
|
|
- shutter = (printf ("1/"), 1 / shutter);
|
|
- printf (_("%0.1f sec\n"), shutter);
|
|
- printf (_("Aperture: f/%0.1f\n"), aperture);
|
|
- printf (_("Focal length: %0.1f mm\n"), focal_len);
|
|
- printf (_("Embedded ICC profile: %s\n"), profile_length ? _("yes"):_("no"));
|
|
- printf (_("Number of raw images: %d\n"), is_raw);
|
|
- if (pixel_aspect != 1)
|
|
- printf (_("Pixel Aspect Ratio: %0.6f\n"), pixel_aspect);
|
|
- if (thumb_offset)
|
|
- printf (_("Thumb size: %4d x %d\n"), thumb_width, thumb_height);
|
|
- printf (_("Full size: %4d x %d\n"), raw_width, raw_height);
|
|
- } else if (!is_raw)
|
|
- fprintf (stderr,_("Cannot decode file %s\n"), ifname);
|
|
- if (!is_raw) goto next;
|
|
- shrink = filters && (half_size || (!identify_only &&
|
|
- (threshold || aber[0] != 1 || aber[2] != 1)));
|
|
- iheight = (height + shrink) >> shrink;
|
|
- iwidth = (width + shrink) >> shrink;
|
|
- if (identify_only) {
|
|
- if (verbose) {
|
|
- if (document_mode == 3) {
|
|
- top_margin = left_margin = fuji_width = 0;
|
|
- height = raw_height;
|
|
- width = raw_width;
|
|
- }
|
|
- iheight = (height + shrink) >> shrink;
|
|
- iwidth = (width + shrink) >> shrink;
|
|
- if (use_fuji_rotate) {
|
|
- if (fuji_width) {
|
|
- fuji_width = (fuji_width - 1 + shrink) >> shrink;
|
|
- iwidth = fuji_width / sqrt(0.5);
|
|
- iheight = (iheight - fuji_width) / sqrt(0.5);
|
|
- } else {
|
|
- if (pixel_aspect < 1) iheight = iheight / pixel_aspect + 0.5;
|
|
- if (pixel_aspect > 1) iwidth = iwidth * pixel_aspect + 0.5;
|
|
- }
|
|
- }
|
|
- if (flip & 4)
|
|
- SWAP(iheight,iwidth);
|
|
- printf (_("Image size: %4d x %d\n"), width, height);
|
|
- printf (_("Output size: %4d x %d\n"), iwidth, iheight);
|
|
- printf (_("Raw colors: %d"), colors);
|
|
- if (filters) {
|
|
- printf (_("\nFilter pattern: "));
|
|
- for (i=0; i < 16; i++)
|
|
- putchar (cdesc[fcol(i >> 1,i & 1)]);
|
|
- }
|
|
- printf (_("\nDaylight multipliers:"));
|
|
- FORCC printf (" %f", pre_mul[c]);
|
|
- if (cam_mul[0] > 0) {
|
|
- printf (_("\nCamera multipliers:"));
|
|
- FORC4 printf (" %f", cam_mul[c]);
|
|
- }
|
|
- putchar ('\n');
|
|
- } else
|
|
- printf (_("%s is a %s %s image.\n"), ifname, make, model);
|
|
-next:
|
|
- fclose(ifp);
|
|
- continue;
|
|
- }
|
|
- if (meta_length) {
|
|
- meta_data = (char *) malloc (meta_length);
|
|
- merror (meta_data, "main()");
|
|
- }
|
|
- if (filters || colors == 1) {
|
|
- raw_image = (ushort *) calloc ((raw_height+7), raw_width*2);
|
|
- merror (raw_image, "main()");
|
|
- } else {
|
|
- image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image);
|
|
- merror (image, "main()");
|
|
- }
|
|
- if (verbose)
|
|
- fprintf (stderr,_("Loading %s %s image from %s ...\n"),
|
|
- make, model, ifname);
|
|
- if (shot_select >= is_raw)
|
|
- fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"),
|
|
- ifname, shot_select);
|
|
- fseeko (ifp, data_offset, SEEK_SET);
|
|
- if (raw_image && read_from_stdin)
|
|
- fread (raw_image, 2, raw_height*raw_width, stdin);
|
|
- else (*load_raw)();
|
|
- if (document_mode == 3) {
|
|
- top_margin = left_margin = fuji_width = 0;
|
|
- height = raw_height;
|
|
- width = raw_width;
|
|
- }
|
|
- iheight = (height + shrink) >> shrink;
|
|
- iwidth = (width + shrink) >> shrink;
|
|
- if (raw_image) {
|
|
- image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image);
|
|
- merror (image, "main()");
|
|
- crop_masked_pixels();
|
|
- free (raw_image);
|
|
- }
|
|
- if (zero_is_bad) remove_zeroes();
|
|
- bad_pixels (bpfile);
|
|
- if (dark_frame) subtract (dark_frame);
|
|
- quality = 2 + !fuji_width;
|
|
- if (user_qual >= 0) quality = user_qual;
|
|
- i = cblack[3];
|
|
- FORC3 if (i > cblack[c]) i = cblack[c];
|
|
- FORC4 cblack[c] -= i;
|
|
- black += i;
|
|
- i = cblack[6];
|
|
- FORC (cblack[4] * cblack[5])
|
|
- if (i > cblack[6+c]) i = cblack[6+c];
|
|
- FORC (cblack[4] * cblack[5])
|
|
- cblack[6+c] -= i;
|
|
- black += i;
|
|
- if (user_black >= 0) black = user_black;
|
|
- FORC4 cblack[c] += black;
|
|
- if (user_sat > 0) maximum = user_sat;
|
|
-#ifdef COLORCHECK
|
|
- colorcheck();
|
|
-#endif
|
|
- if (is_foveon) {
|
|
- if (document_mode || load_raw == &CLASS foveon_dp_load_raw) {
|
|
- for (i=0; i < height*width*4; i++)
|
|
- if ((short) image[0][i] < 0) image[0][i] = 0;
|
|
- } else foveon_interpolate();
|
|
- } else if (document_mode < 2)
|
|
- scale_colors();
|
|
- pre_interpolate();
|
|
- if (filters && !document_mode) {
|
|
- if (quality == 0)
|
|
- lin_interpolate();
|
|
- else if (quality == 1 || colors > 3)
|
|
- vng_interpolate();
|
|
- else if (quality == 2 && filters > 1000)
|
|
- ppg_interpolate();
|
|
- else if (filters == 9)
|
|
- xtrans_interpolate (quality*2-3);
|
|
- else
|
|
- ahd_interpolate();
|
|
- }
|
|
- if (mix_green)
|
|
- for (colors=3, i=0; i < height*width; i++)
|
|
- image[i][1] = (image[i][1] + image[i][3]) >> 1;
|
|
- if (!is_foveon && colors == 3) median_filter();
|
|
- if (!is_foveon && highlight == 2) blend_highlights();
|
|
- if (!is_foveon && highlight > 2) recover_highlights();
|
|
- if (use_fuji_rotate) fuji_rotate();
|
|
-#ifndef NO_LCMS
|
|
- if (cam_profile) apply_profile (cam_profile, out_profile);
|
|
-#endif
|
|
- convert_to_rgb();
|
|
- if (use_fuji_rotate) stretch();
|
|
-thumbnail:
|
|
- if (write_fun == &CLASS jpeg_thumb)
|
|
- write_ext = ".jpg";
|
|
- else if (output_tiff && write_fun == &CLASS write_ppm_tiff)
|
|
- write_ext = ".tiff";
|
|
- else
|
|
- write_ext = ".pgm\0.ppm\0.ppm\0.pam" + colors*5-5;
|
|
- ofname = (char *) malloc (strlen(ifname) + 64);
|
|
- merror (ofname, "main()");
|
|
- if (write_to_stdout)
|
|
- strcpy (ofname,_("standard output"));
|
|
- else {
|
|
- strcpy (ofname, ifname);
|
|
- if ((cp = strrchr (ofname, '.'))) *cp = 0;
|
|
- if (multi_out)
|
|
- sprintf (ofname+strlen(ofname), "_%0*d",
|
|
- snprintf(0,0,"%d",is_raw-1), shot_select);
|
|
- if (thumbnail_only)
|
|
- strcat (ofname, ".thumb");
|
|
- strcat (ofname, write_ext);
|
|
- ofp = fopen (ofname, "wb");
|
|
- if (!ofp) {
|
|
- status = 1;
|
|
- perror (ofname);
|
|
- goto cleanup;
|
|
- }
|
|
- }
|
|
- if (verbose)
|
|
- fprintf (stderr,_("Writing data to %s ...\n"), ofname);
|
|
- (*write_fun)();
|
|
- fclose(ifp);
|
|
- if (ofp != stdout) fclose(ofp);
|
|
-cleanup:
|
|
- if (meta_data) free (meta_data);
|
|
- if (ofname) free (ofname);
|
|
- if (oprof) free (oprof);
|
|
- if (image) free (image);
|
|
- if (multi_out) {
|
|
- if (++shot_select < is_raw) arg--;
|
|
- else shot_select = 0;
|
|
- }
|
|
- }
|
|
- return status;
|
|
-}
|