From b649804cfddd20cf31630f99fe6af4c710085a27 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Tue, 16 Sep 2014 02:49:34 +0000 Subject: cleanup git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@2281 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- converter/other/cameratopam/camera.c | 241 ++--- converter/other/cameratopam/camera.h | 95 +- converter/other/cameratopam/cameratopam.c | 1166 ++++++++++++------------ converter/other/cameratopam/cameratopam.h | 6 + converter/other/cameratopam/canon.c | 6 +- converter/other/cameratopam/canon.h | 11 +- converter/other/cameratopam/foveon.c | 5 +- converter/other/cameratopam/foveon.h | 9 +- converter/other/cameratopam/global_variables.h | 1 - converter/other/cameratopam/identify.c | 11 +- converter/other/cameratopam/identify.h | 4 +- converter/other/cameratopam/ljpeg.c | 5 +- converter/other/cameratopam/ljpeg.h | 5 +- 13 files changed, 799 insertions(+), 766 deletions(-) create mode 100644 converter/other/cameratopam/cameratopam.h diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c index 4008dbb2..14d208e3 100644 --- a/converter/other/cameratopam/camera.c +++ b/converter/other/cameratopam/camera.c @@ -17,6 +17,7 @@ #include "mallocvar.h" #include "global_variables.h" +#include "cameratopam.h" #include "util.h" #include "decode.h" #include "bayer.h" @@ -55,67 +56,76 @@ merror (const void *ptr, const char *where) static void -adobe_copy_pixel (int row, int col, unsigned short **rp, bool use_secondary) -{ - unsigned r=row, c=col; - - if (fuji_secondary && use_secondary) (*rp)++; - if (filters) { - if (fuji_width) { - r = row + fuji_width - 1 - (col >> 1); - c = row + ((col+1) >> 1); - } - if (r < height && c < width) - BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; - *rp += 1 + fuji_secondary; - } else - for (c=0; c < tiff_samples; c++) { - image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp; - (*rp)++; +adobeCopyPixel(Image const image, + unsigned int const row, + unsigned int const col, + unsigned short ** const rp, + bool const useSecondary) { + + unsigned r=row, c=col; + + if (fuji_secondary && useSecondary) + ++(*rp); + if (filters) { + if (fuji_width) { + r = row + fuji_width - 1 - (col >> 1); + c = row + ((col+1) >> 1); + } + if (r < height && c < width) + BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; + *rp += 1 + fuji_secondary; + } else { + unsigned int c; + for (c = 0; c < tiff_samples; ++c) { + image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp; + ++(*rp); + } } - if (fuji_secondary && use_secondary) (*rp)--; + if (fuji_secondary && useSecondary) + --(*rp); } void -adobe_dng_load_raw_lj() -{ - int save, twide, trow=0, tcol=0, jrow, jcol; - struct jhead jh; - unsigned short *rp; +adobe_dng_load_raw_lj(Image const image) { - while (1) { - save = ftell(ifp); - fseek (ifp, get4(ifp), SEEK_SET); - if (!ljpeg_start (ifp, &jh)) break; - if (trow >= raw_height) break; - if (jh.high > raw_height-trow) - jh.high = raw_height-trow; - twide = jh.wide; - if (filters) twide *= jh.clrs; - else colors = jh.clrs; - if (fuji_secondary) twide /= 2; - if (twide > raw_width-tcol) - twide = raw_width-tcol; - - for (jrow=0; jrow < jh.high; jrow++) { - ljpeg_row (&jh); - for (rp=jh.row, jcol=0; jcol < twide; jcol++) - adobe_copy_pixel (trow+jrow, tcol+jcol, &rp, use_secondary); - } - fseek (ifp, save+4, SEEK_SET); - if ((tcol += twide) >= raw_width) { - tcol = 0; - trow += jh.high; + int save, twide, trow=0, tcol=0, jrow, jcol; + struct jhead jh; + unsigned short *rp; + + while (1) { + save = ftell(ifp); + fseek (ifp, get4(ifp), SEEK_SET); + if (!ljpeg_start (ifp, &jh)) break; + if (trow >= raw_height) break; + if (jh.high > raw_height-trow) + jh.high = raw_height-trow; + twide = jh.wide; + if (filters) twide *= jh.clrs; + else colors = jh.clrs; + if (fuji_secondary) twide /= 2; + if (twide > raw_width-tcol) + twide = raw_width-tcol; + + for (jrow=0; jrow < jh.high; jrow++) { + ljpeg_row (&jh); + for (rp=jh.row, jcol=0; jcol < twide; jcol++) + adobeCopyPixel(image, + trow+jrow, tcol+jcol, &rp, use_secondary); + } + fseek (ifp, save+4, SEEK_SET); + if ((tcol += twide) >= raw_width) { + tcol = 0; + trow += jh.high; + } + free (jh.row); } - free (jh.row); - } } void -adobe_dng_load_raw_nc() -{ +adobe_dng_load_raw_nc(Image const image) { + unsigned short *pixel, *rp; int row, col; @@ -124,7 +134,7 @@ adobe_dng_load_raw_nc() for (row=0; row < raw_height; row++) { read_shorts (ifp, pixel, raw_width * tiff_samples); for (rp=pixel, col=0; col < raw_width; col++) - adobe_copy_pixel (row, col, &rp, use_secondary); + adobeCopyPixel(image, row, col, &rp, use_secondary); } free (pixel); } @@ -134,8 +144,8 @@ adobe_dng_load_raw_nc() static int nikon_curve_offset; void -nikon_compressed_load_raw(void) -{ +nikon_compressed_load_raw(Image const image) { + static const unsigned char nikon_tree[] = { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, 5,4,3,6,2,7,1,0,8,9,11,10,12 @@ -176,8 +186,8 @@ nikon_compressed_load_raw(void) } void -nikon_load_raw() -{ +nikon_load_raw(Image const image) { + int irow, row, col, i; getbits(ifp, -1); @@ -294,8 +304,8 @@ minolta_z2() } void -nikon_e2100_load_raw() -{ +nikon_e2100_load_raw(Image const image) { + unsigned char data[3432], *dp; unsigned short pixel[2288], *pix; int row, col; @@ -322,8 +332,8 @@ nikon_e2100_load_raw() } void -nikon_e950_load_raw() -{ +nikon_e950_load_raw(Image const image) { + int irow, row, col; getbits(ifp, -1); @@ -341,8 +351,7 @@ nikon_e950_load_raw() The Fuji Super CCD is just a Bayer grid rotated 45 degrees. */ void -fuji_s2_load_raw() -{ +fuji_s2_load_raw(Image const image) { unsigned short pixel[2944]; int row, col, r, c; @@ -358,8 +367,7 @@ fuji_s2_load_raw() } void -fuji_s3_load_raw() -{ +fuji_s3_load_raw(Image const image) { unsigned short pixel[4352]; int row, col, r, c; @@ -374,42 +382,52 @@ fuji_s3_load_raw() } } -static void fuji_common_load_raw (int ncol, int icol, int nrow) -{ - unsigned short pixel[2048]; - int row, col, r, c; - - for (row=0; row < nrow; row++) { - read_shorts(ifp, pixel, ncol); - for (col=0; col <= icol; col++) { - r = icol - col + (row >> 1); - c = col + ((row+1) >> 1); - BAYER(r,c) = pixel[col]; +static void +fuji_common_load_raw(Image const image, + unsigned int const ncol, + unsigned int const icol, + unsigned int const nrow) { + + unsigned short pixel[2048]; + unsigned int row; + + for (row = 0; row < nrow; ++row) { + unsigned int col; + read_shorts(ifp, pixel, ncol); + for (col = 0; col <= icol; ++col) { + int const r = icol - col + (row >> 1); + int const c = col + ((row+1) >> 1); + BAYER(r,c) = pixel[col]; + } } - } } + + void -fuji_s5000_load_raw() -{ +fuji_s5000_load_raw(Image const image) { + fseek (ifp, (1472*4+24)*2, SEEK_CUR); - fuji_common_load_raw (1472, 1423, 2152); + fuji_common_load_raw(image, 1472, 1423, 2152); } + + void -fuji_s7000_load_raw() -{ - fuji_common_load_raw (2048, 2047, 3080); +fuji_s7000_load_raw(Image const image) { + + fuji_common_load_raw(image, 2048, 2047, 3080); } + + /* The Fuji Super CCD SR has two photodiodes for each pixel. The secondary has about 1/16 the sensitivity of the primary, but this ratio may vary. */ void -fuji_f700_load_raw() -{ +fuji_f700_load_raw(Image const image) { unsigned short pixel[2944]; int row, col, r, c, val; @@ -425,8 +443,7 @@ fuji_f700_load_raw() } void -rollei_load_raw() -{ +rollei_load_raw(Image const image) { unsigned char pixel[10]; unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; @@ -452,8 +469,7 @@ rollei_load_raw() } void -phase_one_load_raw() -{ +phase_one_load_raw(Image const image) { int row, col, a, b; unsigned short *pixel, akey, bkey; @@ -479,8 +495,7 @@ phase_one_load_raw() } void -ixpress_load_raw() -{ +ixpress_load_raw(Image const image) { unsigned short pixel[4090]; int row, col; @@ -494,8 +509,7 @@ ixpress_load_raw() } void -leaf_load_raw() -{ +leaf_load_raw(Image const image) { unsigned short *pixel; int r, c, row, col; @@ -514,8 +528,7 @@ leaf_load_raw() For this function only, raw_width is in bytes, not pixels! */ void -packed_12_load_raw() -{ +packed_12_load_raw(Image const image) { int row, col; getbits(ifp, -1); @@ -528,8 +541,7 @@ packed_12_load_raw() } void -unpacked_load_raw() -{ +unpacked_load_raw(Image const image) { unsigned short *pixel; int row, col; @@ -544,8 +556,7 @@ unpacked_load_raw() } void -olympus_e300_load_raw() -{ +olympus_e300_load_raw(Image const image) { unsigned char *data, *dp; unsigned short *pixel, *pix; int dwide, row, col; @@ -568,8 +579,7 @@ olympus_e300_load_raw() } void -olympus_cseries_load_raw() -{ +olympus_cseries_load_raw(Image const image) { int irow, row, col; for (irow=0; irow < height; irow++) { @@ -584,8 +594,7 @@ olympus_cseries_load_raw() } void -eight_bit_load_raw() -{ +eight_bit_load_raw(Image const image) { unsigned char *pixel; int row, col; @@ -601,8 +610,7 @@ eight_bit_load_raw() } void -casio_qv5700_load_raw() -{ +casio_qv5700_load_raw(Image const image) { unsigned char data[3232], *dp; unsigned short pixel[2576], *pix; int row, col; @@ -622,8 +630,7 @@ casio_qv5700_load_raw() } void -nucore_load_raw() -{ +nucore_load_raw(Image const image) { unsigned short *pixel; int irow, row, col; @@ -685,8 +692,7 @@ static int radc_token (int tree) : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) void -kodak_radc_load_raw() -{ +kodak_radc_load_raw(Image const image) { int row, col, tree, nreps, rep, step, c, s, r, x, y, val; unsigned int i; short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; @@ -765,7 +771,8 @@ kodak_radc_load_raw() #undef PREDICTOR #ifndef HAVE_JPEG -void kodak_jpeg_load_raw() {} +void +kodak_jpeg_load_raw(Image const Image) {} #else static bool @@ -782,7 +789,7 @@ fill_input_buffer (j_decompress_ptr cinfo) } void -kodak_jpeg_load_raw() +kodak_jpeg_load_raw(Image const image) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; @@ -823,7 +830,7 @@ kodak_jpeg_load_raw() #endif void -kodak_dc120_load_raw() +kodak_dc120_load_raw(Image const image) { static const int mul[4] = { 162, 192, 187, 92 }; static const int add[4] = { 0, 636, 424, 212 }; @@ -859,7 +866,7 @@ kodak_dc20_coeff (float const juice) } void -kodak_easy_load_raw() +kodak_easy_load_raw(Image const image) { unsigned char *pixel; unsigned row, col, icol; @@ -887,7 +894,7 @@ kodak_easy_load_raw() } void -kodak_compressed_load_raw() +kodak_compressed_load_raw(Image const image) { unsigned char c, blen[256]; unsigned short raw[6]; @@ -951,7 +958,7 @@ kodak_compressed_load_raw() } void -kodak_yuv_load_raw() +kodak_yuv_load_raw(Image const image) { unsigned char c, blen[384]; unsigned row, col, len, bits=0; @@ -1042,7 +1049,7 @@ static void sony_decrypt (unsigned *data, int len, int start, int key) } void -sony_load_raw() +sony_load_raw(Image const image) { unsigned char head[40]; struct pixel { @@ -1310,12 +1317,6 @@ parse_mos(FILE * const ifp, fread (data, 1, 40, ifp); skip = get4(ifp); from = ftell(ifp); -#ifdef USE_LCMS - if (!strcmp(data,"icc_camera_profile")) { - profile_length = skip; - profile_offset = from; - } -#endif if (!strcmp(data,"NeutObj_neutrals")) { for (i=0; i < 4; i++) fscanf (ifp, "%d", neut+i); diff --git a/converter/other/cameratopam/camera.h b/converter/other/cameratopam/camera.h index a1e884cf..02c3f2af 100644 --- a/converter/other/cameratopam/camera.h +++ b/converter/other/cameratopam/camera.h @@ -1,5 +1,10 @@ +#ifndef CAMERA_H_INCLUDED +#define CAMERA_H_INCLUDED + #include +#include "cameratopam.h" + void parse_ciff(FILE * const ifp, int const offset, @@ -21,20 +26,18 @@ void parse_mos(FILE * const ifp, int const offset); -void -adobe_dng_load_raw_lj(void); +typedef void LoadRawFn(Image const image); -void -adobe_dng_load_raw_nc(void); +LoadRawFn adobe_dng_load_raw_lj; + +LoadRawFn adobe_dng_load_raw_nc; int nikon_is_compressed(void); -void -nikon_compressed_load_raw(void); +LoadRawFn nikon_compressed_load_raw; -void -nikon_e950_load_raw(void); +LoadRawFn nikon_e950_load_raw; void nikon_e950_coeff(void); @@ -45,87 +48,63 @@ nikon_e990(void); int nikon_e2100(void); -void -nikon_e2100_load_raw(void); +LoadRawFn nikon_e2100_load_raw; int minolta_z2(void); -void -fuji_s2_load_raw(void); +LoadRawFn fuji_s2_load_raw; -void -fuji_s3_load_raw(void); +LoadRawFn fuji_s3_load_raw; -void -fuji_s5000_load_raw(void); +LoadRawFn fuji_s5000_load_raw; -void -unpacked_load_raw(void); +LoadRawFn unpacked_load_raw; -void -fuji_s7000_load_raw(void); +LoadRawFn fuji_s7000_load_raw; -void -fuji_f700_load_raw(void); +LoadRawFn fuji_f700_load_raw; -void -packed_12_load_raw(void); +LoadRawFn packed_12_load_raw; -void -eight_bit_load_raw(void); +LoadRawFn eight_bit_load_raw; -void -phase_one_load_raw(void); +LoadRawFn phase_one_load_raw; -void -ixpress_load_raw(void); +LoadRawFn ixpress_load_raw; -void -leaf_load_raw(void); +LoadRawFn leaf_load_raw; -void -olympus_e300_load_raw(void); +LoadRawFn olympus_e300_load_raw; -void -olympus_cseries_load_raw(void); +LoadRawFn olympus_cseries_load_raw; -void -sony_load_raw(void); +LoadRawFn sony_load_raw; -void -kodak_easy_load_raw(void); +LoadRawFn kodak_easy_load_raw; -void -kodak_compressed_load_raw(void); +LoadRawFn kodak_compressed_load_raw; -void -kodak_yuv_load_raw(void); +LoadRawFn kodak_yuv_load_raw; void kodak_dc20_coeff (float const juice); -void -kodak_radc_load_raw(void); +LoadRawFn kodak_radc_load_raw; -void -kodak_jpeg_load_raw(void); +LoadRawFn kodak_jpeg_load_raw; -void -kodak_dc120_load_raw(void); +LoadRawFn kodak_dc120_load_raw; -void -rollei_load_raw(void); +LoadRawFn rollei_load_raw; -void -casio_qv5700_load_raw(void); +LoadRawFn casio_qv5700_load_raw; -void -nucore_load_raw(void); +LoadRawFn nucore_load_raw; -void -nikon_load_raw(void); +LoadRawFn nikon_load_raw; int pentax_optio33(void); +#endif diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c index 0a25686a..cd8093ee 100644 --- a/converter/other/cameratopam/cameratopam.c +++ b/converter/other/cameratopam/cameratopam.c @@ -39,6 +39,7 @@ #include "pam.h" #include "global_variables.h" +#include "cameratopam.h" #include "util.h" #include "decode.h" #include "identify.h" @@ -65,7 +66,8 @@ int is_dng, is_canon, is_foveon, use_coeff, use_gamma; int trim, flip, xmag, ymag; int zero_after_ff; unsigned filters; -unsigned short (*image)[4], white[8][8], curve[0x1000]; +unsigned short white[8][8]; +unsigned short curve[0x1000]; int fuji_secondary; float cam_mul[4], pre_mul[4], coeff[3][4]; int histogram[3][0x2000]; @@ -73,11 +75,6 @@ jmp_buf failure; int use_secondary; bool verbose; -#ifdef USE_LCMS -#include -int profile_offset, profile_length; -#endif - #define CLASS #define FORC3 for (c=0; c < 3; c++) @@ -192,610 +189,660 @@ parseCommandLine(int argc, char ** argv, } -/* - Seach from the current directory up to the root looking for - a ".badpixels" file, and fix those pixels now. - */ -static void CLASS bad_pixels() -{ - FILE *fp=NULL; - char *fname, *cp, line[128]; - int len, time, row, col, r, c, rad, tot, n, fixed=0; - - if (!filters) return; - for (len=16 ; ; len *= 2) { - fname = malloc (len); - if (!fname) return; - if (getcwd (fname, len-12)) break; - free (fname); - if (errno != ERANGE) return; - } + +static void CLASS +fixBadPixels(Image const image) { +/*---------------------------------------------------------------------------- + Search from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. +-----------------------------------------------------------------------------*/ + FILE *fp=NULL; + char *fname, *cp, line[128]; + int len, time, row, col, r, c, rad, tot, n, fixed=0; + + if (!filters) return; + for (len=16 ; ; len *= 2) { + fname = malloc (len); + if (!fname) return; + if (getcwd (fname, len-12)) break; + free (fname); + if (errno != ERANGE) return; + } #if MSVCRT - if (fname[1] == ':') - memmove (fname, fname+2, len-2); - for (cp=fname; *cp; cp++) - if (*cp == '\\') *cp = '/'; + if (fname[1] == ':') + memmove (fname, fname+2, len-2); + for (cp=fname; *cp; cp++) + if (*cp == '\\') *cp = '/'; #endif - cp = fname + strlen(fname); - if (cp[-1] == '/') cp--; - while (*fname == '/') { - strcpy (cp, "/.badpixels"); - if ((fp = fopen (fname, "r"))) break; - if (cp == fname) break; - while (*--cp != '/'); - } - free (fname); - if (!fp) return; - while (fgets (line, 128, fp)) { - cp = strchr (line, '#'); - if (cp) *cp = 0; - if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; - if ((unsigned) col >= width || (unsigned) row >= height) continue; - if (time > timestamp) continue; - for (tot=n=0, rad=1; rad < 3 && n==0; rad++) - for (r = row-rad; r <= row+rad; r++) - for (c = col-rad; c <= col+rad; c++) - if ((unsigned) r < height && (unsigned) c < width && - (r != row || c != col) && FC(r,c) == FC(row,col)) { - tot += BAYER(r,c); - n++; - } - BAYER(row,col) = tot/n; - if (cmdline.verbose) { - if (!fixed++) - pm_message ("Fixed bad pixels at: %d,%d", col, row); + cp = fname + strlen(fname); + if (cp[-1] == '/') cp--; + while (*fname == '/') { + strcpy (cp, "/.badpixels"); + if ((fp = fopen (fname, "r"))) break; + if (cp == fname) break; + while (*--cp != '/'); } - } - fclose (fp); -} - -static void CLASS scale_colors() -{ - int row, col, c, val, shift=0; - int min[4], max[4], count[4]; - double sum[4], dmin; - - maximum -= black; - if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) { - FORC4 min[c] = INT_MAX; - FORC4 max[c] = count[c] = sum[c] = 0; - for (row=0; row < height; row++) - for (col=0; col < width; col++) - FORC4 { - val = image[row*width+col][c]; - if (!val) continue; - if (min[c] > val) min[c] = val; - if (max[c] < val) max[c] = val; - val -= black; - if (val > maximum-25) continue; - if (val < 0) val = 0; - sum[c] += val; - count[c]++; + free (fname); + if (!fp) return; + while (fgets (line, 128, fp)) { + cp = strchr (line, '#'); + if (cp) *cp = 0; + if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; + if ((unsigned) col >= width || (unsigned) row >= height) continue; + if (time > timestamp) continue; + for (tot=n=0, rad=1; rad < 3 && n==0; rad++) + for (r = row-rad; r <= row+rad; r++) + for (c = col-rad; c <= col+rad; c++) + if ((unsigned) r < height && (unsigned) c < width && + (r != row || c != col) && FC(r,c) == FC(row,col)) { + tot += BAYER(r,c); + n++; + } + BAYER(row,col) = tot/n; + if (cmdline.verbose) { + if (!fixed++) + pm_message ("Fixed bad pixels at: %d,%d", col, row); + } } - FORC4 pre_mul[c] = count[c] / sum[c]; - } - if (cmdline.use_camera_wb && camera_red != -1) { - FORC4 count[c] = sum[c] = 0; - for (row=0; row < 8; row++) - for (col=0; col < 8; col++) { - c = FC(row,col); - if ((val = white[row][col] - black) > 0) - sum[c] += val; - count[c]++; - } - val = 1; - FORC4 if (sum[c] == 0) val = 0; - if (val) - FORC4 pre_mul[c] = count[c] / sum[c]; - else if (camera_red && camera_blue) - memcpy (pre_mul, cam_mul, sizeof pre_mul); - else - pm_message ("Cannot use camera white balance."); - } - if (!use_coeff) { - pre_mul[0] *= cmdline.red_scale; - pre_mul[2] *= cmdline.blue_scale; - } - dmin = DBL_MAX; - FORC4 if (dmin > pre_mul[c]) - dmin = pre_mul[c]; - FORC4 pre_mul[c] /= dmin; - - while (maximum << shift < 0x8000) shift++; - FORC4 pre_mul[c] *= 1 << shift; - maximum <<= shift; - - if (cmdline.linear || cmdline.bright < 1) { - maximum *= cmdline.bright; - if (maximum > 0xffff) - maximum = 0xffff; - FORC4 pre_mul[c] *= cmdline.bright; - } - if (cmdline.verbose) { - fprintf (stderr, "Scaling with black=%d, pre_mul[] =", black); - FORC4 fprintf (stderr, " %f", pre_mul[c]); - fputc ('\n', stderr); - } - clip_max = cmdline.no_clip_color ? 0xffff : maximum; - for (row=0; row < height; row++) - for (col=0; col < width; col++) - FORC4 { - val = image[row*width+col][c]; - if (!val) continue; - val -= black; - val *= pre_mul[c]; - if (val < 0) val = 0; - if (val > clip_max) val = clip_max; - image[row*width+col][c] = val; - } + fclose (fp); } -/* - This algorithm is officially called: - - "Interpolation using a Threshold-based variable number of gradients" - described in http://www-ise.stanford.edu/~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. - */ -static void CLASS vng_interpolate() -{ - static const signed char *cp, terms[] = { - -2,-2,+0,-1,0,(char)0x01, -2,-2,+0,+0,1,(char)0x01, -2,-1,-1,+0,0,(char)0x01, - -2,-1,+0,-1,0,(char)0x02, -2,-1,+0,+0,0,(char)0x03, -2,-1,+0,+1,1,(char)0x01, - -2,+0,+0,-1,0,(char)0x06, -2,+0,+0,+0,1,(char)0x02, -2,+0,+0,+1,0,(char)0x03, - -2,+1,-1,+0,0,(char)0x04, -2,+1,+0,-1,1,(char)0x04, -2,+1,+0,+0,0,(char)0x06, - -2,+1,+0,+1,0,(char)0x02, -2,+2,+0,+0,1,(char)0x04, -2,+2,+0,+1,0,(char)0x04, - -1,-2,-1,+0,0,(char)0x80, -1,-2,+0,-1,0,(char)0x01, -1,-2,+1,-1,0,(char)0x01, - -1,-2,+1,+0,1,(char)0x01, -1,-1,-1,+1,0,(char)0x88, -1,-1,+1,-2,0,(char)0x40, - -1,-1,+1,-1,0,(char)0x22, -1,-1,+1,+0,0,(char)0x33, -1,-1,+1,+1,1,(char)0x11, - -1,+0,-1,+2,0,(char)0x08, -1,+0,+0,-1,0,(char)0x44, -1,+0,+0,+1,0,(char)0x11, - -1,+0,+1,-2,1,(char)0x40, -1,+0,+1,-1,0,(char)0x66, -1,+0,+1,+0,1,(char)0x22, - -1,+0,+1,+1,0,(char)0x33, -1,+0,+1,+2,1,(char)0x10, -1,+1,+1,-1,1,(char)0x44, - -1,+1,+1,+0,0,(char)0x66, -1,+1,+1,+1,0,(char)0x22, -1,+1,+1,+2,0,(char)0x10, - -1,+2,+0,+1,0,(char)0x04, -1,+2,+1,+0,1,(char)0x04, -1,+2,+1,+1,0,(char)0x04, - +0,-2,+0,+0,1,(char)0x80, +0,-1,+0,+1,1,(char)0x88, +0,-1,+1,-2,0,(char)0x40, - +0,-1,+1,+0,0,(char)0x11, +0,-1,+2,-2,0,(char)0x40, +0,-1,+2,-1,0,(char)0x20, - +0,-1,+2,+0,0,(char)0x30, +0,-1,+2,+1,1,(char)0x10, +0,+0,+0,+2,1,(char)0x08, - +0,+0,+2,-2,1,(char)0x40, +0,+0,+2,-1,0,(char)0x60, +0,+0,+2,+0,1,(char)0x20, - +0,+0,+2,+1,0,(char)0x30, +0,+0,+2,+2,1,(char)0x10, +0,+1,+1,+0,0,(char)0x44, - +0,+1,+1,+2,0,(char)0x10, +0,+1,+2,-1,1,(char)0x40, +0,+1,+2,+0,0,(char)0x60, - +0,+1,+2,+1,0,(char)0x20, +0,+1,+2,+2,0,(char)0x10, +1,-2,+1,+0,0,(char)0x80, - +1,-1,+1,+1,0,(char)0x88, +1,+0,+1,+2,0,(char)0x08, +1,+0,+2,-1,0,(char)0x40, - +1,+0,+2,+1,0,(char)0x10 - }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; - unsigned short (*brow[5])[4], *pix; - int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4]; - int row, col, shift, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; - int g, diff, thold, num, c; - - for (row=0; row < 8; row++) { /* Precalculate for bilinear */ - for (col=1; col < 3; col++) { - ip = code[row][col & 1]; - memset (sum, 0, sizeof sum); - for (y=-1; y <= 1; y++) - for (x=-1; x <= 1; x++) { - shift = (y==0) + (x==0); - if (shift == 2) continue; - color = FC(row+y,col+x); - *ip++ = (width*y + x)*4 + color; - *ip++ = shift; - *ip++ = color; - sum[color] += 1 << shift; +static void CLASS +scaleColors(Image const image) { + + int row; + int c; + int val; + int shift; + int min[4], max[4], count[4]; + double sum[4], dmin; + + shift = 0; /* initial value */ + + maximum -= black; + if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) { + unsigned int row; + FORC4 min[c] = INT_MAX; + FORC4 max[c] = count[c] = sum[c] = 0; + for (row = 0; row < height; ++row) { + unsigned int col; + for (col = 0; col < width; ++col) { + FORC4 { + int val; + val = image[row*width+col][c]; + if (!val) + continue; + if (min[c] > val) + min[c] = val; + if (max[c] < val) + max[c] = val; + val -= black; + if (val > maximum-25) + continue; + if (val < 0) + val = 0; + sum[c] += val; + ++count[c]; + } + } + } + FORC4 pre_mul[c] = count[c] / sum[c]; } - FORC4 - if (c != FC(row,col)) { - *ip++ = c; - *ip++ = sum[c]; + if (cmdline.use_camera_wb && camera_red != -1) { + unsigned int row; + FORC4 count[c] = sum[c] = 0; + for (row = 0; row < 8; ++row) { + unsigned int col; + for (col = 0; col < 8; ++col) { + c = FC(row,col); + if ((val = white[row][col] - black) > 0) + sum[c] += val; + ++count[c]; + } + } + val = 1; + FORC4 if (sum[c] == 0) val = 0; + if (val) + FORC4 pre_mul[c] = count[c] / sum[c]; + else if (camera_red && camera_blue) + memcpy(pre_mul, cam_mul, sizeof pre_mul); + else + pm_message ("Cannot use camera white balance."); } + if (!use_coeff) { + pre_mul[0] *= cmdline.red_scale; + pre_mul[2] *= cmdline.blue_scale; } - } - for (row=1; row < height-1; row++) { /* Do bilinear interpolation */ - for (col=1; col < width-1; col++) { - pix = image[row*width+col]; - ip = code[row & 7][col & 1]; - memset (sum, 0, sizeof sum); - for (g=8; g--; ) { - diff = pix[*ip++]; - diff <<= *ip++; - sum[*ip++] += diff; - } - for (g=colors; --g; ) { - c = *ip++; - pix[c] = sum[c] / *ip++; - } + dmin = DBL_MAX; + FORC4 if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + FORC4 pre_mul[c] /= dmin; + + while (maximum << shift < 0x8000) + ++shift; + FORC4 pre_mul[c] *= 1 << shift; + maximum <<= shift; + + if (cmdline.linear || cmdline.bright < 1) { + maximum *= cmdline.bright; + if (maximum > 0xffff) + maximum = 0xffff; + FORC4 pre_mul[c] *= cmdline.bright; } - } - if (cmdline.quick_interpolate) - return; - - for (row=0; row < 8; row++) { /* Precalculate for VNG */ - for (col=0; col < 2; col++) { - ip = code[row][col]; - for (cp=terms, t=0; t < 64; t++) { - y1 = *cp++; x1 = *cp++; - y2 = *cp++; x2 = *cp++; - weight = *cp++; - grads = *cp++; - color = FC(row+y1,col+x1); - if (FC(row+y2,col+x2) != color) continue; - diag = (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1; - if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; - *ip++ = (y1*width + x1)*4 + color; - *ip++ = (y2*width + x2)*4 + color; - *ip++ = weight; - for (g=0; g < 8; g++) - if (grads & 1<> 31; - gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]); - ip += 5; - if ((g = ip[-1]) == -1) continue; - gval[g] += diff; - while ((g = *ip++) != -1) - gval[g] += diff; - } - ip++; - gmin = gmax = gval[0]; /* Choose a threshold */ - for (g=1; g < 8; g++) { - if (gmin > gval[g]) gmin = gval[g]; - if (gmax < gval[g]) gmax = gval[g]; - } - if (gmax == 0) { - memcpy (brow[2][col], pix, sizeof *image); - continue; - } - thold = gmin + (gmax >> 1); - memset (sum, 0, sizeof sum); - color = FC(row,col); - for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ - if (gval[g] <= thold) { - FORC4 - if (c == color && ip[1]) - sum[c] += (pix[c] + pix[ip[1]]) >> 1; - else - sum[c] += pix[ip[0] + c]; - num++; + clip_max = cmdline.no_clip_color ? 0xffff : maximum; + for (row = 0; row < height; ++row) { + unsigned int col; + for (col = 0; col < width; ++col) { + FORC4 { + int val; + val = image[row*width+col][c]; + if (!val) + continue; + val -= black; + val *= pre_mul[c]; + if (val < 0) + val = 0; + if (val > clip_max) + val = clip_max; + image[row*width+col][c] = val; + } + } } - } - FORC4 { /* Save to buffer */ - t = pix[color]; - if (c != color) { - t += (sum[c] - sum[color])/num; - if (t < 0) t = 0; - if (t > clip_max) t = clip_max; +} + + + +static void CLASS +vngInterpolate(Image const image) { + + /* + This algorithm is officially called "Interpolation using a + Threshold-based variable number of gradients," described in + http://www-ise.stanford.edu/~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. + */ + + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,(char)0x01, -2,-2,+0,+0,1,(char)0x01, -2,-1,-1,+0,0,(char)0x01, + -2,-1,+0,-1,0,(char)0x02, -2,-1,+0,+0,0,(char)0x03, -2,-1,+0,+1,1,(char)0x01, + -2,+0,+0,-1,0,(char)0x06, -2,+0,+0,+0,1,(char)0x02, -2,+0,+0,+1,0,(char)0x03, + -2,+1,-1,+0,0,(char)0x04, -2,+1,+0,-1,1,(char)0x04, -2,+1,+0,+0,0,(char)0x06, + -2,+1,+0,+1,0,(char)0x02, -2,+2,+0,+0,1,(char)0x04, -2,+2,+0,+1,0,(char)0x04, + -1,-2,-1,+0,0,(char)0x80, -1,-2,+0,-1,0,(char)0x01, -1,-2,+1,-1,0,(char)0x01, + -1,-2,+1,+0,1,(char)0x01, -1,-1,-1,+1,0,(char)0x88, -1,-1,+1,-2,0,(char)0x40, + -1,-1,+1,-1,0,(char)0x22, -1,-1,+1,+0,0,(char)0x33, -1,-1,+1,+1,1,(char)0x11, + -1,+0,-1,+2,0,(char)0x08, -1,+0,+0,-1,0,(char)0x44, -1,+0,+0,+1,0,(char)0x11, + -1,+0,+1,-2,1,(char)0x40, -1,+0,+1,-1,0,(char)0x66, -1,+0,+1,+0,1,(char)0x22, + -1,+0,+1,+1,0,(char)0x33, -1,+0,+1,+2,1,(char)0x10, -1,+1,+1,-1,1,(char)0x44, + -1,+1,+1,+0,0,(char)0x66, -1,+1,+1,+1,0,(char)0x22, -1,+1,+1,+2,0,(char)0x10, + -1,+2,+0,+1,0,(char)0x04, -1,+2,+1,+0,1,(char)0x04, -1,+2,+1,+1,0,(char)0x04, + +0,-2,+0,+0,1,(char)0x80, +0,-1,+0,+1,1,(char)0x88, +0,-1,+1,-2,0,(char)0x40, + +0,-1,+1,+0,0,(char)0x11, +0,-1,+2,-2,0,(char)0x40, +0,-1,+2,-1,0,(char)0x20, + +0,-1,+2,+0,0,(char)0x30, +0,-1,+2,+1,1,(char)0x10, +0,+0,+0,+2,1,(char)0x08, + +0,+0,+2,-2,1,(char)0x40, +0,+0,+2,-1,0,(char)0x60, +0,+0,+2,+0,1,(char)0x20, + +0,+0,+2,+1,0,(char)0x30, +0,+0,+2,+2,1,(char)0x10, +0,+1,+1,+0,0,(char)0x44, + +0,+1,+1,+2,0,(char)0x10, +0,+1,+2,-1,1,(char)0x40, +0,+1,+2,+0,0,(char)0x60, + +0,+1,+2,+1,0,(char)0x20, +0,+1,+2,+2,0,(char)0x10, +1,-2,+1,+0,0,(char)0x80, + +1,-1,+1,+1,0,(char)0x88, +1,+0,+1,+2,0,(char)0x08, +1,+0,+2,-1,0,(char)0x40, + +1,+0,+2,+1,0,(char)0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + unsigned short (*brow[5])[4], *pix; + int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4]; + int row, col, shift, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num, c; + + for (row=0; row < 8; row++) { /* Precalculate for bilinear */ + for (col=1; col < 3; col++) { + ip = code[row][col & 1]; + memset (sum, 0, sizeof sum); + for (y=-1; y <= 1; y++) + for (x=-1; x <= 1; x++) { + shift = (y==0) + (x==0); + if (shift == 2) continue; + color = FC(row+y,col+x); + *ip++ = (width*y + x)*4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + FORC4 + if (c != FC(row,col)) { + *ip++ = c; + *ip++ = sum[c]; + } + } } - brow[2][col][c] = t; - } + for (row=1; row < height-1; row++) { /* Do bilinear interpolation */ + for (col=1; col < width-1; col++) { + pix = image[row*width+col]; + ip = code[row & 7][col & 1]; + memset (sum, 0, sizeof sum); + for (g=8; g--; ) { + diff = pix[*ip++]; + diff <<= *ip++; + sum[*ip++] += diff; + } + for (g=colors; --g; ) { + c = *ip++; + pix[c] = sum[c] / *ip++; + } + } + } + if (cmdline.quick_interpolate) + return; + + for (row=0; row < 8; row++) { /* Precalculate for VNG */ + for (col=0; col < 2; col++) { + ip = code[row][col]; + for (cp=terms, t=0; t < 64; t++) { + y1 = *cp++; x1 = *cp++; + y2 = *cp++; x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = FC(row+y1,col+x1); + if (FC(row+y2,col+x2) != color) continue; + diag = + (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1; + if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; + *ip++ = (y1*width + x1)*4 + color; + *ip++ = (y2*width + x2)*4 + color; + *ip++ = weight; + for (g=0; g < 8; g++) + if (grads & 1<> 31; + gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]); + ip += 5; + if ((g = ip[-1]) == -1) continue; + gval[g] += diff; + while ((g = *ip++) != -1) + gval[g] += diff; + } + ip++; + gmin = gmax = gval[0]; /* Choose a threshold */ + for (g=1; g < 8; g++) { + if (gmin > gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax >> 1); + memset (sum, 0, sizeof sum); + color = FC(row,col); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORC4 + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORC4 { /* Save to buffer */ + t = pix[color]; + if (c != color) { + t += (sum[c] - sum[color])/num; + if (t < 0) t = 0; + if (t > clip_max) t = clip_max; + } + brow[2][col][c] = 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]; } - 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]); + 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]); } -#ifdef USE_LCMS -static void -apply_profile(FILE * const ifP, - const char * const pfname) -{ - char *prof; - cmsHPROFILE hInProfile=NULL, hOutProfile; - cmsHTRANSFORM hTransform; - - if (pfname) - hInProfile = cmsOpenProfileFromFile (pfname, "r"); - else if (profile_length) { - prof = malloc (profile_length); - merror (prof, "apply_profile()"); - fseek (ifP, profile_offset, SEEK_SET); - fread (prof, 1, profile_length, ifP); - hInProfile = cmsOpenProfileFromMem (prof, profile_length); - free (prof); - } - if (!hInProfile) return; - if (cmdline.verbose) - pm_message( "Applying color profile..."); - maximum = 0xffff; - use_gamma = use_coeff = 0; - - hOutProfile = cmsCreate_sRGBProfile(); - hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, - hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); - cmsDoTransform (hTransform, image, image, width*height); - - cmsDeleteTransform (hTransform); - cmsCloseProfile (hInProfile); - cmsCloseProfile (hOutProfile); -} -#else -static void -apply_profile(FILE * const ifP, - const char * const pfname) -{ -} -#endif -/* + +static void CLASS +convertToRgb(Image const image) { +/*---------------------------------------------------------------------------- Convert the entire image to RGB colorspace and build a histogram. - */ -static void CLASS convert_to_rgb() -{ - int row, col, r, g, c=0; - unsigned short *img; - float rgb[3]; - - if (cmdline.document_mode) - colors = 1; - memset (histogram, 0, sizeof histogram); - for (row = trim; row < height-trim; row++) - for (col = trim; col < width-trim; col++) { - img = image[row*width+col]; - if (cmdline.document_mode) - c = FC(row,col); - if (colors == 4 && !use_coeff) /* Recombine the greens */ - img[1] = (img[1] + img[3]) >> 1; - if (colors == 1) /* RGB from grayscale */ - for (r=0; r < 3; r++) - rgb[r] = img[c]; - else if (use_coeff) { /* RGB via coeff[][] */ - for (r=0; r < 3; r++) - for (rgb[r]=g=0; g < colors; g++) - rgb[r] += img[g] * coeff[r][g]; - } else /* RGB from RGB (easy) */ - goto norgb; - for (r=0; r < 3; r++) { - if (rgb[r] < 0) rgb[r] = 0; - if (rgb[r] > clip_max) rgb[r] = clip_max; - img[r] = rgb[r]; - } -norgb: - for (r=0; r < 3; r++) - histogram[r][img[r] >> 3]++; +-----------------------------------------------------------------------------*/ + unsigned int row; + int r; + int g; + int c; + unsigned short *img; + float rgb[3]; + + c = 0; /* initial value */ + + if (cmdline.document_mode) + colors = 1; + + memset (histogram, 0, sizeof histogram); + + for (row = trim; row < height-trim; ++row) { + unsigned int col; + for (col = trim; col < width-trim; ++col) { + img = image[row*width+col]; + if (cmdline.document_mode) + c = FC(row,col); + if (colors == 4 && !use_coeff) /* Recombine the greens */ + img[1] = (img[1] + img[3]) >> 1; + if (colors == 1) { + /* RGB from grayscale */ + for (r = 0; r < 3; ++r) + rgb[r] = img[c]; + } else if (use_coeff) { /* RGB via coeff[][] */ + for (r = 0; r < 3; ++r) { + for (rgb[r]=g=0; g < colors; g++) + rgb[r] += img[g] * coeff[r][g]; + } + } else /* RGB from RGB (easy) */ + goto norgb; + for (r = 0; r < 3; ++r) { + if (rgb[r] < 0) rgb[r] = 0; + if (rgb[r] > clip_max) rgb[r] = clip_max; + img[r] = rgb[r]; + } + norgb: + for (r = 0; r < 3; ++r) + ++histogram[r][img[r] >> 3]; + } } } -static void CLASS fuji_rotate() -{ - int i, wide, high, row, col; - double step; - float r, c, fr, fc; - unsigned ur, uc; - unsigned short (*img)[4], (*pix)[4]; - - if (!fuji_width) return; - if (cmdline.verbose) - pm_message ("Rotating image 45 degrees..."); - fuji_width = (fuji_width + shrink) >> shrink; - step = sqrt(0.5); - wide = fuji_width / step; - high = (height - fuji_width) / step; - img = calloc (wide*high, 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; + + +static void CLASS +fujiRotate(Image * const imageP) { + + int wide; + int high; + unsigned int row; + double step; + float r, c, fr, fc; + unsigned short (*newImage)[4]; + unsigned short (*pix)[4]; + + if (fuji_width > 0) { + if (cmdline.verbose) + pm_message ("Rotating image 45 degrees..."); + + fuji_width = (fuji_width + shrink) >> shrink; + step = sqrt(0.5); + wide = fuji_width / step; + high = (height - fuji_width) / step; + newImage = calloc (wide*high, sizeof *newImage); + merror (newImage, "fujiRotate()"); + + for (row = 0; row < high; ++row) { + unsigned int col; + for (col = 0; col < wide; ++col) { + unsigned int ur = r = fuji_width + (row-col)*step; + unsigned int uc = c = (row+col)*step; + + unsigned int i; + + if (ur > height-2 || uc > width-2) + continue; + + fr = r - ur; + fc = c - uc; + pix = (*imageP) + ur * width + uc; + + for (i = 0; i < colors; ++i) { + newImage[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(*imageP); + width = wide; + height = high; + *imageP = newImage; + fuji_width = 0; } - free (image); - width = wide; - height = high; - image = img; - fuji_width = 0; } -static void CLASS flip_image() -{ + + +static void CLASS +flipImage(Image const image) { + unsigned *flag; - int size, base, dest, next, row, col, temp; + int size, base, dest; struct imageCell { unsigned char contents[8]; }; struct imageCell * img; - struct imageCell hold; switch ((flip+3600) % 360) { - case 270: flip = 5; break; - case 180: flip = 3; break; - case 90: flip = 6; + case 270: flip = 0x5; break; + case 180: flip = 0x3; break; + case 90: flip = 0x6; } img = (struct imageCell *) image; size = height * width; flag = calloc ((size+31) >> 5, sizeof *flag); - merror (flag, "flip_image()"); - for (base = 0; base < size; base++) { - if (flag[base >> 5] & (1 << (base & 31))) - continue; - dest = base; - hold = img[base]; - while (1) { - if (flip & 4) { - row = dest % height; - col = dest / height; - } else { - row = dest / width; - col = dest % width; + merror (flag, "flipImage()"); + for (base = 0; base < size; ++base) { + if (flag[base >> 5] & (1 << (base & 31))) { + /* nothing */ + } else { + struct imageCell const hold = img[base]; + dest = base; + while (true) { + unsigned int col; + unsigned int row; + int next; + if (flip & 0x4) { + row = dest % height; + col = dest / height; + } else { + row = dest / width; + col = dest % width; + } + if (flip & 0x2) + row = height - 1 - row; + if (flip & 1) + col = width - 1 - col; + next = row * width + col; + if (next == base) + break; + flag[next >> 5] |= 1 << (next & 31); + img[dest] = img[next]; + dest = next; } - if (flip & 2) - row = height - 1 - row; - if (flip & 1) - col = width - 1 - col; - next = row * width + col; - if (next == base) break; - flag[next >> 5] |= 1 << (next & 31); - img[dest] = img[next]; - dest = next; + img[dest] = hold; } - img[dest] = hold; } free (flag); - if (flip & 4) { - temp = height; + if (flip & 0x4) { + int const oldHeight = height; + int const oldYmag = ymag; + height = width; - width = temp; - temp = ymag; + width = oldHeight; ymag = xmag; - xmag = temp; + xmag = oldYmag; } } -/* - Write the image as an RGB PAM image - */ -static void CLASS write_pam_nonlinear (FILE *ofp) -{ - unsigned char lut[0x10000]; - int perc, c, val, total, i, row, col; - float white=0, r; - struct pam pam; - tuple * tuplerow; - - pam.size = sizeof(pam); - pam.len = PAM_STRUCT_SIZE(tuple_type); - pam.file = ofp; - pam.width = xmag*(width-trim*2); - pam.height = ymag*(height-trim*2); - pam.depth = 3; - pam.format = PAM_FORMAT; - pam.maxval = 255; - strcpy(pam.tuple_type, "RGB"); - - pnm_writepaminit(&pam); - - tuplerow = pnm_allocpamrow(&pam); - - perc = width * height * 0.01; /* 99th percentile white point */ - if (fuji_width) perc /= 2; - FORC3 { - for (val=0x2000, total=0; --val > 32; ) - if ((total += histogram[c][val]) > perc) break; - if (white < val) white = val; - } - white *= 8 / cmdline.bright; - for (i=0; i < 0x10000; i++) { - r = i / white; - val = 256 * ( !use_gamma ? r : - r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 ); - if (val > 255) val = 255; - lut[i] = val; - } - for (row=trim; row < height-trim; row++) { - for (col=trim; col < width-trim; col++) { - unsigned int plane; - for (plane=0; plane < pam.depth; ++plane) { - unsigned int copy; - for (copy=0; copy < xmag; ++copy) { - unsigned int const pamcol = xmag*(col-trim)+copy; - tuplerow[pamcol][plane] = lut[image[row*width+col][plane]]; - } - } - } - { - unsigned int copy; - for (copy=0; copy < ymag; ++copy) - pnm_writepamrow(&pam, tuplerow); - } - } - pnm_freepamrow(tuplerow); + + +static void CLASS +writePamLinear(FILE * const ofP, + Image const image) { +/*---------------------------------------------------------------------------- + Write the image 'image' to a 16-bit PAM file with linear color space +-----------------------------------------------------------------------------*/ + unsigned int row; + + struct pam pam; + tuple * tuplerow; + + if (maximum < 256) + maximum = 256; + + pam.size = sizeof(pam); + pam.len = PAM_STRUCT_SIZE(tuple_type); + pam.file = ofP; + pam.width = width-trim*2; + pam.height = height-trim*2; + pam.depth = 3; + pam.format = PAM_FORMAT; + pam.maxval = MAX(maximum, 256); + strcpy(pam.tuple_type, "RGB"); + + pnm_writepaminit(&pam); + + tuplerow = pnm_allocpamrow(&pam); + + for (row = trim; row < height-trim; row++) { + unsigned int col; + for (col = trim; col < width-trim; col++) { + unsigned int const pamCol = col - trim; + unsigned int plane; + for (plane = 0; plane < 3; ++plane) + tuplerow[pamCol][plane] = image[row*width+col][plane]; + } + pnm_writepamrow(&pam, tuplerow); + } + pnm_freepamrow(tuplerow); } -/* - Write the image to a 16-bit PAM file with linear color space - */ -static void CLASS write_pam_linear (FILE *ofp) -{ - int row; - - struct pam pam; - tuple * tuplerow; - - if (maximum < 256) maximum = 256; - - pam.size = sizeof(pam); - pam.len = PAM_STRUCT_SIZE(tuple_type); - pam.file = ofp; - pam.width = width-trim*2; - pam.height = height-trim*2; - pam.depth = 3; - pam.format = PAM_FORMAT; - pam.maxval = MAX(maximum, 256); - strcpy(pam.tuple_type, "RGB"); - - pnm_writepaminit(&pam); - - tuplerow = pnm_allocpamrow(&pam); - - for (row = trim; row < height-trim; row++) { - unsigned int col; - for (col = trim; col < width-trim; col++) { - unsigned int const pamCol = col - trim; - unsigned int plane; - for (plane = 0; plane < 3; ++plane) - tuplerow[pamCol][plane] = image[row*width+col][plane]; - } - pnm_writepamrow(&pam, tuplerow); - } - pnm_freepamrow(tuplerow); + + +static void CLASS +writePamNonlinear(FILE * const ofP, + Image const image) { +/*---------------------------------------------------------------------------- + Write the image 'image' as an RGB PAM image +-----------------------------------------------------------------------------*/ + unsigned char lut[0x10000]; + int perc; + int c; + int total; + int i; + unsigned int row; + float white; + float r; + struct pam pam; + tuple * tuplerow; + + white = 0; /* initial value */ + + pam.size = sizeof(pam); + pam.len = PAM_STRUCT_SIZE(tuple_type); + pam.file = ofP; + pam.width = xmag*(width-trim*2); + pam.height = ymag*(height-trim*2); + pam.depth = 3; + pam.format = PAM_FORMAT; + pam.maxval = 255; + strcpy(pam.tuple_type, "RGB"); + + pnm_writepaminit(&pam); + + tuplerow = pnm_allocpamrow(&pam); + + perc = width * height * 0.01; /* 99th percentile white point */ + if (fuji_width) perc /= 2; + FORC3 { + int val; + for (val=0x2000, total=0; --val > 32; ) + if ((total += histogram[c][val]) > perc) break; + if (white < val) + white = val; + } + white *= 8 / cmdline.bright; + for (i=0; i < 0x10000; ++i) { + int val; + r = i / white; + val = 256 * ( !use_gamma ? r : + r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 ); + if (val > 255) + val = 255; + lut[i] = val; + } + for (row = trim; row < height - trim; ++row) { + unsigned int col; + for (col = trim; col < width - trim; ++col) { + unsigned int plane; + for (plane=0; plane < pam.depth; ++plane) { + unsigned int copy; + for (copy=0; copy < xmag; ++copy) { + unsigned int const pamcol = xmag*(col-trim)+copy; + tuplerow[pamcol][plane] = lut[image[row*width+col][plane]]; + } + } + } + { + unsigned int copy; + for (copy = 0; copy < ymag; ++copy) + pnm_writepamrow(&pam, tuplerow); + } + } + pnm_freepamrow(tuplerow); } static void CLASS writePam(FILE * const ofP, + Image const image, bool const linear) { if (linear) - write_pam_linear(ofP); + writePamLinear(ofP, image); else - write_pam_nonlinear(ofP); + writePamNonlinear(ofP, image); } - static void CLASS -convertIt(FILE * const ifP, - FILE * const ofP, - loadRawFn const load_raw) { +convertIt(FILE * const ifP, + FILE * const ofP, + LoadRawFn * const load_raw) { + + Image image; shrink = cmdline.half_size && filters; iheight = (height + shrink) >> shrink; @@ -810,16 +857,16 @@ convertIt(FILE * const ifP, ifp = ifP; /* Set global variable for (*load_raw)() */ - load_raw(); - bad_pixels(); + load_raw(image); + fixBadPixels(image); height = iheight; width = iwidth; if (is_foveon) { if (cmdline.verbose) pm_message ("Foveon interpolation..."); - foveon_interpolate(coeff); + foveon_interpolate(image, coeff); } else { - scale_colors(); + scaleColors(image); } if (shrink) filters = 0; trim = 0; @@ -828,25 +875,27 @@ convertIt(FILE * const ifP, if (cmdline.verbose) pm_message ("%s interpolation...", cmdline.quick_interpolate ? "Bilinear":"VNG"); - vng_interpolate(); + vngInterpolate(image); } - fuji_rotate(); - apply_profile(ifP, cmdline.profile); + fujiRotate(&image); if (cmdline.verbose) pm_message ("Converting to RGB colorspace..."); - convert_to_rgb(); + convertToRgb(image); if (flip) { if (cmdline.verbose) pm_message ("Flipping image %c:%c:%c...", flip & 1 ? 'H':'0', flip & 2 ? 'V':'0', flip & 4 ? 'T':'0'); - flip_image(); + flipImage(image); } - writePam(ofP, cmdline.linear); + writePam(ofP, image, cmdline.linear); + + free(image); } + int main (int argc, char **argv) { @@ -854,7 +903,7 @@ main (int argc, char **argv) { FILE * ifP; int rc; - loadRawFn load_raw; + LoadRawFn * load_raw; pnm_init(&argc, argv); @@ -864,8 +913,6 @@ main (int argc, char **argv) { ifP = pm_openr(cmdline.inputFileName); - image = NULL; - rc = identify(ifP, cmdline.use_secondary, cmdline.use_camera_rgb, cmdline.red_scale, cmdline.blue_scale, @@ -884,7 +931,6 @@ main (int argc, char **argv) { } pm_close(ifP); pm_close(ofP); - free(image); return 0; } diff --git a/converter/other/cameratopam/cameratopam.h b/converter/other/cameratopam/cameratopam.h new file mode 100644 index 00000000..9ff33cb3 --- /dev/null +++ b/converter/other/cameratopam/cameratopam.h @@ -0,0 +1,6 @@ +#ifndef CAMERATOPAM_H_INCLUDED +#define CAMERATOPAM_H_INCLUDED + +typedef unsigned short (*Image)[4]; + +#endif diff --git a/converter/other/cameratopam/canon.c b/converter/other/cameratopam/canon.c index a34771d0..96a6210b 100644 --- a/converter/other/cameratopam/canon.c +++ b/converter/other/cameratopam/canon.c @@ -9,7 +9,7 @@ void -canon_600_load_raw(void) { +canon_600_load_raw(Image const image) { unsigned char data[1120], *dp; unsigned short pixel[896], *pix; int irow, orow, col; @@ -42,7 +42,7 @@ canon_600_load_raw(void) { void -canon_a5_load_raw(void) { +canon_a5_load_raw(Image const image) { unsigned char data[1940], *dp; unsigned short pixel[1552], *pix; int row, col; @@ -97,7 +97,7 @@ canon_has_lowbits() void -canon_compressed_load_raw(void) { +canon_compressed_load_raw(Image const image) { unsigned short *pixel, *prow; int lowbits, i, row, r, col, save, val; unsigned irow, icol; diff --git a/converter/other/cameratopam/canon.h b/converter/other/cameratopam/canon.h index 041cdc4d..fe6a5a08 100644 --- a/converter/other/cameratopam/canon.h +++ b/converter/other/cameratopam/canon.h @@ -1,13 +1,12 @@ #ifndef CANON_H_INCLUDED #define CANON_H_INCLUDED -void -canon_600_load_raw(void); +#include "camera.h" -void -canon_a5_load_raw(void); +LoadRawFn canon_600_load_raw; -void -canon_compressed_load_raw(void); +LoadRawFn canon_a5_load_raw; + +LoadRawFn canon_compressed_load_raw; #endif diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c index f439bd52..a3e5449a 100644 --- a/converter/other/cameratopam/foveon.c +++ b/converter/other/cameratopam/foveon.c @@ -211,7 +211,7 @@ foveon_load_camf() { void -foveon_load_raw() { +foveon_load_raw(Image const image) { struct decode *dindex; short diff[1024], pred[3]; @@ -391,7 +391,8 @@ static int foveon_apply_curve (short *curve, int i) } void -foveon_interpolate(float coeff[3][4]) { +foveon_interpolate(Image const image, + float coeff[3][4]) { static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h index f3177e50..c9bf48a8 100644 --- a/converter/other/cameratopam/foveon.h +++ b/converter/other/cameratopam/foveon.h @@ -1,13 +1,16 @@ #include "pm.h" +#include "cameratopam.h" +#include "camera.h" + void parse_foveon(FILE * const ifp); void -foveon_interpolate(float coeff[3][4]); +foveon_interpolate(Image const image, + float coeff[3][4]); -void -foveon_load_raw(void); +LoadRawFn foveon_load_raw; void foveon_coeff(int * const useCoeffP, diff --git a/converter/other/cameratopam/global_variables.h b/converter/other/cameratopam/global_variables.h index c8732d5a..2bfc08c9 100644 --- a/converter/other/cameratopam/global_variables.h +++ b/converter/other/cameratopam/global_variables.h @@ -23,7 +23,6 @@ extern time_t timestamp; extern int is_foveon; extern int is_dng; extern int is_canon; -extern unsigned short (*image)[4]; extern int maximum; extern int clip_max; extern short order; diff --git a/converter/other/cameratopam/identify.c b/converter/other/cameratopam/identify.c index b99496b7..cc6a2d8e 100644 --- a/converter/other/cameratopam/identify.c +++ b/converter/other/cameratopam/identify.c @@ -21,7 +21,6 @@ static bool const have64BitArithmetic = false; #endif -static loadRawFn load_raw; /* This does the same as the function of the same name in the GNU C library */ static const char *memmem_internal (const char *haystack, size_t haystacklen, @@ -264,7 +263,7 @@ identify(FILE * const ifp, float const blue_scale, unsigned int const four_color_rgb, const char * const inputFileName, - loadRawFn * const loadRawFnP) + LoadRawFn ** const loadRawFnP) { char head[32]; char * c; @@ -299,6 +298,7 @@ identify(FILE * const ifp, { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX", "MINOLTA", "Minolta", "Konica", "CASIO" }; float tmp; + LoadRawFn * load_raw; /* What format is this file? Set make[] if we recognize it. */ @@ -317,9 +317,6 @@ identify(FILE * const ifp, colors = 3; for (i=0; i < 0x1000; i++) curve[i] = i; maximum = 0xfff; -#ifdef USE_LCMS - profile_length = 0; -#endif order = get2(ifp); hlen = get4(ifp); @@ -449,7 +446,7 @@ identify(FILE * const ifp, goto dng_skip; } -/* We'll try to decode anything from Canon or Nikon. */ + /* We'll try to decode anything from Canon or Nikon. */ if (!filters) filters = 0x94949494; if ((is_canon = !strcmp(make,"Canon"))) @@ -459,7 +456,7 @@ identify(FILE * const ifp, load_raw = nikon_is_compressed() ? nikon_compressed_load_raw : nikon_load_raw; -/* Set parameters based on camera name (for non-DNG files). */ + /* Set parameters based on camera name (for non-DNG files). */ if (is_foveon) { if (!have64BitArithmetic) diff --git a/converter/other/cameratopam/identify.h b/converter/other/cameratopam/identify.h index 012b807c..62c9aae5 100644 --- a/converter/other/cameratopam/identify.h +++ b/converter/other/cameratopam/identify.h @@ -1,4 +1,4 @@ -typedef void (*loadRawFn)(); +#include "camera.h" int identify(FILE * const ifp, @@ -8,4 +8,4 @@ identify(FILE * const ifp, float const blue_scale, unsigned int const four_color_rgb, const char * const inputFileName, - loadRawFn * const loadRawFnP); + LoadRawFn ** const loadRawFnP); diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c index 18423f4f..29e4ff98 100644 --- a/converter/other/cameratopam/ljpeg.c +++ b/converter/other/cameratopam/ljpeg.c @@ -87,9 +87,10 @@ ljpeg_row (struct jhead *jh) } } + void -lossless_jpeg_load_raw(void) -{ +lossless_jpeg_load_raw(Image const image) { + int jwide, jrow, jcol, val, jidx, i, row, col; struct jhead jh; int min=INT_MAX; diff --git a/converter/other/cameratopam/ljpeg.h b/converter/other/cameratopam/ljpeg.h index 60832a3d..cfd68eb4 100644 --- a/converter/other/cameratopam/ljpeg.h +++ b/converter/other/cameratopam/ljpeg.h @@ -1,11 +1,12 @@ +#include "camera.h" + struct jhead { int bits, high, wide, clrs, vpred[4]; struct decode *huff[4]; unsigned short *row; }; -void -lossless_jpeg_load_raw(void); +LoadRawFn lossless_jpeg_load_raw; int ljpeg_start (FILE * ifp, struct jhead *jh); -- cgit 1.4.1