You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
813 lines
23 KiB
813 lines
23 KiB
/*
|
|
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 (×tamp));
|
|
#endif
|
|
}
|
|
fseek (ifp, save, SEEK_SET);
|
|
}
|
|
is_foveon = 1;
|
|
}
|