update against v14.0.x branch
---------- Forwarded message ---------
От: Андрей Рандрианасулу <randrik@xxxxxxx>
Date: пн, 7 нояб. 2022 г., 06:09
Subject: libraw update for libkdcraw from tde
To: randrianasulu <randrianasulu@xxxxxxxxx>
От: Андрей Рандрианасулу <randrik@xxxxxxx>
Date: пн, 7 нояб. 2022 г., 06:09
Subject: libraw update for libkdcraw from tde
To: randrianasulu <randrianasulu@xxxxxxxxx>
seems to work
Megapatch is for ray-V slackbuilds
--
Андрей Рандрианасулу
Андрей Рандрианасулу
Attachment:
libraw_update.png
Description: PNG image
diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/CMakeLists.txt libkdcraw/CMakeLists.txt --- libkdcraw-wrk/CMakeLists.txt 2022-11-07 08:15:53.602821808 +0300 +++ libkdcraw/CMakeLists.txt 2022-11-07 07:46:31.654795007 +0300 @@ -71,7 +71,7 @@ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TQT_CXX_FLAGS}" ) set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" ) set( CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined" ) - +set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -llcms -ljasper") ##### directories diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/dcraw/dcraw.c libkdcraw/libkdcraw/dcraw/dcraw.c --- libkdcraw-wrk/libkdcraw/dcraw/dcraw.c 2022-11-07 08:15:53.606821808 +0300 +++ libkdcraw/libkdcraw/dcraw/dcraw.c 2022-11-07 07:46:31.726795008 +0300 @@ -1,6 +1,6 @@ /* dcraw.c -- Dave Coffin's raw photo decoder - Copyright 1997-2008 by Dave Coffin, dcoffin a cybercom o net + Copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net This is a command-line ANSI C program to convert raw photos from any digital camera on any computer running any operating system. @@ -19,15 +19,15 @@ *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". - $Revision: 1.399 $ - $Date: 2008/03/05 01:29:34 $ + $Revision: 1.478 $ + $Date: 2018/06/01 20:36:25 $ */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#define DCRAW_VERSION "8.83" +#define DCRAW_VERSION "9.28" +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif #define _USE_MATH_DEFINES #include <ctype.h> #include <errno.h> @@ -41,26 +41,8 @@ #include <string.h> #include <time.h> #include <sys/types.h> -#include <locale.h> - -/* - NO_JPEG disables decoding of compressed Kodak DC120 files. - NO_LCMS disables the "-p" option. - */ -#ifdef HAVE_JPEG -#include <jpeglib.h> -#endif -#ifndef NO_LCMS -#include LCMS_HEADER -#endif -#ifdef LOCALEDIR -#include <libintl.h> -#define _(String) gettext(String) -#else -#define _(String) (String) -#endif -#ifdef DJGPP +#if defined(DJGPP) || defined(__MINGW32__) #define fseeko fseek #define ftello ftell #else @@ -86,51 +68,66 @@ typedef unsigned long long UINT64; #endif -#ifdef LJPEG_DECODE -#error Please compile dcraw.c by itself. -#error Do not link it with ljpeg_decode. +#ifdef NODEPS +#define NO_JASPER +#define NO_JPEG +#define NO_LCMS #endif - -#ifndef LONG_BIT -#define LONG_BIT (8 * sizeof (long)) +#ifndef NO_JASPER +#include <jasper/jasper.h> /* Decode Red camera movies */ +#endif +#ifndef NO_JPEG +#include <jpeglib.h> /* Decode compressed Kodak DC120 photos */ +#endif /* and Adobe Lossy DNGs */ +#ifndef NO_LCMS +#include <lcms2.h> /* Support color profiles */ +#endif +#ifdef LOCALEDIR +#include <libintl.h> +#define _(String) gettext(String) +#else +#define _(String) (String) #endif -#define ushort UshORt -typedef unsigned char uchar; -typedef unsigned short ushort; +#if !defined(uchar) +#define uchar unsigned char +#endif +#if !defined(ushort) +#define ushort unsigned short +#endif /* 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. + access them are prefixed with "CLASS". For thread-safety, all + non-const static local variables except cbrt[] must be declared + "thread_local". */ - -void swab(const void *restrict from, void *restrict to, ssize_t n); -void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); - -FILE *ifp; +FILE *ifp, *ofp; short order; -char *ifname, *meta_data; +const char *ifname; +char *meta_data, xtrans[6][6], xtrans_abs[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; -unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id; -off_t strip_offset, data_offset; -off_t thumb_offset, meta_offset, profile_offset; +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, use_gamma, zero_is_bad; +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]; +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; -int flip, tiff_flip, colors; -double pixel_aspect, aber[4]={1,1,1,1}; -ushort (*image)[4], white[8][8], curve[0x4001], cr2_slice[3], sraw_mul[4]; +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 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 }; @@ -141,7 +138,7 @@ { 0.019334, 0.119193, 0.950227 } }; const float d65_white[3] = { 0.950456, 1, 1.088754 }; int histogram[4][0x2000]; -void (*write_thumb)(FILE *), (*write_fun)(FILE *); +void (*write_thumb)(), (*write_fun)(); void (*load_raw)(), (*thumb_load_raw)(); jmp_buf failure; @@ -150,12 +147,15 @@ int leaf; } first_decode[2048], *second_decode, *free_decode; -struct { +struct tiff_ifd { int width, height, bps, comp, phint, offset, flip, samples, bytes; + int tile_width, tile_length; + float shutter; } tiff_ifd[10]; -struct { - int format, key_off, black, black_off, split_col, tag_21a; +struct ph1 { + int format, key_off, tag_21a; + int black, split_col, black_col, split_row, black_row; float tag_210; } ph1; @@ -172,8 +172,8 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) -#define CLIP(x) LIM(x,0,65535) -#define SWAP(a,b) { a ^= b; a ^= (b ^= a); } +#define CLIP(x) LIM((int)(x),0,65535) +#define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } /* In order to inline this calculation, I make the risky @@ -214,6 +214,9 @@ 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B */ +#define RAW(row,col) \ + raw_image[(row)*raw_width+(col)] + #define FC(row,col) \ (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) @@ -221,9 +224,9 @@ image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] #define BAYER2(row,col) \ - image[((row) >> shrink)*iwidth + ((col) >> shrink)][fc(row,col)] + image[((row) >> shrink)*iwidth + ((col) >> shrink)][fcol(row,col)] -int CLASS fc (int row, int col) +int CLASS fcol (int row, int col) { static const char filter[16][16] = { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, @@ -243,8 +246,9 @@ { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; - if (filters != 1) return FC(row,col); - return filter[(row+top_margin) & 15][(col+left_margin) & 15]; + if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15]; + if (filters == 9) return xtrans[(row+6) % 6][(col+6) % 6]; + return FC(row,col); } #ifndef __GLIBC__ @@ -258,9 +262,18 @@ return 0; } #define memmem my_memmem +char *my_strcasestr (char *haystack, const char *needle) +{ + char *c; + for (c = haystack; *c; c++) + if (!strncasecmp(c, needle, strlen(needle))) + return c; + return 0; +} +#define strcasestr my_strcasestr #endif -void CLASS merror (void *ptr, char *where) +void CLASS merror (void *ptr, const char *where) { if (ptr) return; fprintf (stderr,_("%s: Out of memory in %s\n"), ifname, where); @@ -276,7 +289,7 @@ else fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } - data_error = 1; + data_error++; } ushort CLASS sget2 (uchar *s) @@ -353,6 +366,61 @@ swab (pixel, pixel, count*2); } +void CLASS cubic_spline (const int *x_, const int *y_, const int len) +{ + float **A, *b, *c, *d, *x, *y; + int i, j; + + A = (float **) calloc (((2*len + 4)*sizeof **A + sizeof *A), 2*len); + if (!A) return; + A[0] = (float *) (A + 2*len); + for (i = 1; i < 2*len; i++) + A[i] = A[0] + 2*len*i; + y = len + (x = i + (d = i + (c = i + (b = A[0] + i*i)))); + 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)(y_out * 65535.0 + 0.5)); + } + free (A); +} + void CLASS canon_600_fixed_wb (int temp) { static const short mul[4][5] = { @@ -472,14 +540,13 @@ void CLASS canon_600_load_raw() { uchar data[1120], *dp; - ushort pixel[896], *pix; - int irow, row, col, val; - static const short mul[4][2] = - { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; + ushort *pix; + int irow, row; for (irow=row=0; irow < height; irow++) { - if (fread (data, 1, raw_width*5/4, ifp) < raw_width*5/4) derror(); - for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8) { + if (fread (data, 1, 1120, ifp) < 1120) derror(); + pix = raw_image + row*raw_width; + for (dp=data; dp < data+1120; dp+=10, pix+=8) { pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); @@ -489,14 +556,16 @@ pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); } - for (col=0; col < width; col++) - BAYER(row,col) = pixel[col]; - for (col=width; col < raw_width; col++) - black += pixel[col]; if ((row+=2) > height) row = 1; } - if (raw_width > width) - black = black / ((raw_width - width) * height) - 4; +} + +void CLASS canon_600_correct() +{ + int row, col, val; + static const short mul[4][2] = + { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; + for (row=0; row < height; row++) for (col=0; col < width; col++) { if ((val = BAYER(row,col) - black) < 0) val = 0; @@ -510,23 +579,6 @@ black = 0; } -void CLASS remove_zeroes() -{ - unsigned row, col, tot, n, r, c; - - for (row=0; row < height; row++) - for (col=0; col < width; col++) - if (BAYER(row,col) == 0) { - tot = n = 0; - for (r = row-2; r <= row+2; r++) - for (c = col-2; c <= col+2; c++) - if (r < height && c < width && - FC(r,c) == FC(row,col) && BAYER(r,c)) - tot += (n++,BAYER(r,c)); - if (n) BAYER(row,col) = tot/n; - } -} - int CLASS canon_s2is() { unsigned row; @@ -538,57 +590,33 @@ return 0; } -void CLASS canon_a5_load_raw() -{ - ushort data[2565], *dp, pixel; - int vbits=0, buf=0, row, col, bc=0; - - order = 0x4949; - for (row=-top_margin; row < raw_height-top_margin; row++) { - read_shorts (dp=data, raw_width * 10 / 16); - for (col=-left_margin; col < raw_width-left_margin; col++) { - if (vbits < 10) - buf = (vbits += 16, (buf << 16) + *dp++); - pixel = buf >> (vbits -= 10) & 0x3ff; - if ((unsigned) row < height && (unsigned) col < width) - BAYER(row,col) = pixel; - else if (col > 1-left_margin && col != width) - black += (bc++,pixel); - } - } - if (bc) black /= bc; - maximum = 0x3ff; - if (raw_width > 1600) remove_zeroes(); -} - -/* - getbits(-1) initializes the buffer - getbits(n) where 0 <= n <= 25 returns an n-bit integer - */ -unsigned CLASS getbits (int nbits) +unsigned CLASS getbithuff (int nbits, ushort *huff) { static unsigned bitbuf=0; static int vbits=0, reset=0; unsigned c; - if (nbits == -1) + if (nbits > 25) return 0; + if (nbits < 0) return bitbuf = vbits = reset = 0; - if (nbits == 0 || reset) return 0; - while (vbits < nbits) { - if ((c = fgetc(ifp)) == EOF) derror(); - if ((reset = zero_after_ff && c == 0xff && fgetc(ifp))) return 0; + if (nbits == 0 || vbits < 0) return 0; + while (!reset && vbits < nbits && (c = fgetc(ifp)) != EOF && + !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) { bitbuf = (bitbuf << 8) + (uchar) c; vbits += 8; } - vbits -= nbits; - return bitbuf << (32-nbits-vbits) >> (32-nbits); + c = bitbuf << (32-vbits) >> (32-nbits); + if (huff) { + vbits -= huff[c] >> 8; + c = (uchar) huff[c]; + } else + vbits -= nbits; + if (vbits < 0) derror(); + return c; } -void CLASS init_decoder() -{ - memset (first_decode, 0, sizeof first_decode); - free_decode = first_decode; -} +#define getbits(n) getbithuff(n,0) +#define gethuff(h) getbithuff(*h,h+1) /* Construct a decode tree according the specification in *source. @@ -616,33 +644,31 @@ 1111110 0x0b 1111111 0xff */ -uchar * CLASS make_decoder (const uchar *source, int level) +ushort * CLASS make_decoder_ref (const uchar **source) { - struct decode *cur; - static int leaf; - int i, next; + int max, len, h, i, j; + const uchar *count; + ushort *huff; - if (level==0) leaf=0; - cur = free_decode++; - if (free_decode > first_decode+2048) { - fprintf (stderr,_("%s: decoder table overflow\n"), ifname); - longjmp (failure, 2); - } - for (i=next=0; i <= leaf && next < 16; ) - i += source[next++]; - if (i > leaf) { - if (level < next) { - cur->branch[0] = free_decode; - make_decoder (source, level+1); - cur->branch[1] = free_decode; - make_decoder (source, level+1); - } else - cur->leaf = source[16 + leaf++]; - } - return (uchar *) source + 16 + leaf; + count = (*source += 16) - 17; + for (max=16; max && !count[max]; max--); + huff = (ushort *) calloc (1 + (1 << max), sizeof *huff); + merror (huff, "make_decoder()"); + huff[0] = max; + for (h=len=1; len <= max; len++) + for (i=0; i < count[len]; i++, ++*source) + for (j=0; j < 1 << (max-len); j++) + if (h <= 1 << max) + huff[h++] = len << 8 | **source; + return huff; +} + +ushort * CLASS make_decoder (const uchar *source) +{ + return make_decoder_ref (&source); } -void CLASS crw_init_tables (unsigned table) +void CLASS crw_init_tables (unsigned table, ushort *huff[2]) { static const uchar first_tree[3][29] = { { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, @@ -700,10 +726,8 @@ 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } }; if (table > 2) table = 2; - init_decoder(); - make_decoder ( first_tree[table], 0); - second_decode = free_decode; - make_decoder (second_tree[table], 0); + huff[0] = make_decoder ( first_tree[table]); + huff[1] = make_decoder (second_tree[table]); } /* @@ -727,33 +751,25 @@ return ret; } -void CLASS canon_compressed_load_raw() +void CLASS canon_load_raw() { - ushort *pixel, *prow; - int nblocks, lowbits, i, row, r, col, save, val; - unsigned irow, icol; - struct decode *decode, *dindex; + ushort *pixel, *prow, *huff[2]; + int nblocks, lowbits, i, c, row, r, save, val; int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; - uchar c; - crw_init_tables (tiff_compress); - pixel = (ushort *) calloc (raw_width*8, sizeof *pixel); - merror (pixel, "canon_compressed_load_raw()"); + crw_init_tables (tiff_compress, huff); lowbits = canon_has_lowbits(); if (!lowbits) maximum = 0x3ff; fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); zero_after_ff = 1; getbits(-1); for (row=0; row < raw_height; row+=8) { + pixel = raw_image + row*raw_width; nblocks = MIN (8, raw_height-row) * raw_width >> 6; for (block=0; block < nblocks; block++) { memset (diffbuf, 0, sizeof diffbuf); - decode = first_decode; for (i=0; i < 64; i++ ) { - for (dindex=decode; dindex->branch[0]; ) - dindex = dindex->branch[getbits(1)]; - leaf = dindex->leaf; - decode = second_decode; + leaf = gethuff(huff[i > 0]); if (leaf == 0 && i) break; if (leaf == 0xff) continue; i += leaf >> 4; @@ -786,91 +802,84 @@ } fseek (ifp, save, SEEK_SET); } - for (r=0; r < 8; r++) { - irow = row - top_margin + r; - if (irow >= height) continue; - for (col=0; col < raw_width; col++) { - icol = col - left_margin; - if (icol < width) - BAYER(irow,icol) = pixel[r*raw_width+col]; - else - black += pixel[r*raw_width+col]; - } - } } - free (pixel); - if (raw_width > width) - black /= (raw_width - width) * height; + FORC(2) free (huff[c]); } -/* - Not a full implementation of Lossless JPEG, just - enough to decode Canon, Kodak and Adobe DNG images. - */ struct jhead { - int bits, high, wide, clrs, psv, restart, vpred[4]; - struct CLASS decode *huff[4]; - ushort *row; + int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort quant[64], idct[64], *huff[20], *free[20], *row; }; int CLASS ljpeg_start (struct jhead *jh, int info_only) { - int i, tag, len; - uchar data[0x10000], *dp; + ushort c, tag, len; + uchar data[0x10000]; + const uchar *dp; - init_decoder(); memset (jh, 0, sizeof *jh); - for (i=0; i < 4; i++) - jh->huff[i] = free_decode; jh->restart = INT_MAX; - fread (data, 2, 1, ifp); - if (data[1] != 0xd8) return 0; + if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; do { - fread (data, 2, 2, ifp); + if (!fread (data, 2, 2, ifp)) return 0; tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; fread (data, 1, len, ifp); switch (tag) { - case 0xffc0: data[7] = 0; case 0xffc3: + jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; + case 0xffc1: + case 0xffc0: + jh->algo = tag & 0xff; jh->bits = data[0]; jh->high = data[1] << 8 | data[2]; jh->wide = data[3] << 8 | data[4]; - jh->clrs = data[5] + (data[7] == 0x21); + jh->clrs = data[5] + jh->sraw; if (len == 9 && !dng_version) getc(ifp); break; case 0xffc4: if (info_only) break; - for (dp = data; dp < data+len && *dp < 4; ) { - jh->huff[*dp] = free_decode; - dp = make_decoder (++dp, 0); - } + for (dp = data; dp < data+len && !((c = *dp++) & -20); ) + jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); break; case 0xffda: jh->psv = data[1+data[0]*2]; + jh->bits -= data[3+data[0]*2] & 15; + break; + case 0xffdb: + FORC(64) jh->quant[c] = data[c*2+1] << 8 | data[c*2+2]; break; case 0xffdd: jh->restart = data[0] << 8 | data[1]; } } while (tag != 0xffda); + if (jh->bits > 16 || jh->clrs > 6 || + !jh->bits || !jh->high || !jh->wide || !jh->clrs) return 0; if (info_only) return 1; - if (jh->clrs == 4) { - jh->huff[3] = jh->huff[2] = jh->huff[1]; - jh->huff[1] = jh->huff[0]; + if (!jh->huff[0]) return 0; + FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + if (jh->sraw) { + FORC(4) jh->huff[2+c] = jh->huff[1]; + FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; } jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); merror (jh->row, "ljpeg_start()"); return zero_after_ff = 1; } -int CLASS ljpeg_diff (struct decode *dindex) +void CLASS ljpeg_end (struct jhead *jh) +{ + int c; + FORC4 if (jh->free[c]) free (jh->free[c]); + free (jh->row); +} + +int CLASS ljpeg_diff (ushort *huff) { int len, diff; - while (dindex->branch[0]) - dindex = dindex->branch[getbits(1)]; - len = dindex->leaf; + len = gethuff(huff); if (len == 16 && (!dng_version || dng_version >= 0x1010000)) return -32768; diff = getbits(len); @@ -881,22 +890,24 @@ ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) { - int col, c, diff, pred; + int col, c, diff, pred, spred=0; ushort mark=0, *row[3]; if (jrow * jh->wide % jh->restart == 0) { - FORC4 jh->vpred[c] = 1 << (jh->bits-1); - if (jrow) + FORC(6) jh->vpred[c] = 1 << (jh->bits-1); + if (jrow) { + fseek (ifp, -2, SEEK_CUR); do mark = (mark << 8) + (c = fgetc(ifp)); while (c != EOF && mark >> 4 != 0xffd); + } getbits(-1); } FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); for (col=0; col < jh->wide; col++) FORC(jh->clrs) { diff = ljpeg_diff (jh->huff[c]); - if (jh->clrs == 4 && c < 2 && (col | c)) - pred = row[0][(c << 1)-3]; + if (jh->sraw && c <= jh->sraw && (col | c)) + pred = spred; else if (col) pred = row[0][-jh->clrs]; else pred = (jh->vpred[c] += diff) - diff; if (jrow && col) switch (jh->psv) { @@ -910,6 +921,7 @@ default: pred = 0; } if ((**row = pred + diff) >> jh->bits) derror(); + if (c <= jh->sraw) spred = **row; row[0]++; row[1]++; } return row[2]; @@ -919,7 +931,6 @@ { int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0; struct jhead jh; - int min=INT_MAX; ushort *rp; if (!ljpeg_start (&jh, 0)) return; @@ -927,109 +938,158 @@ for (jrow=0; jrow < jh.high; jrow++) { rp = ljpeg_row (jrow, &jh); + if (load_flags & 1) + row = jrow & 1 ? height-1-jrow/2 : jrow/2; for (jcol=0; jcol < jwide; jcol++) { - val = *rp++; - if (jh.bits <= 12) - val = curve[val]; + val = curve[*rp++]; if (cr2_slice[0]) { jidx = jrow*jwide + jcol; - i = jidx / (cr2_slice[1]*jh.high); + i = jidx / (cr2_slice[1]*raw_height); if ((j = i >= cr2_slice[0])) i = cr2_slice[0]; - jidx -= i * (cr2_slice[1]*jh.high); + jidx -= i * (cr2_slice[1]*raw_height); row = jidx / cr2_slice[1+j]; col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; } if (raw_width == 3984 && (col -= 2) < 0) col += (row--,raw_width); - if ((unsigned) (row-top_margin) < height) { - if ((unsigned) (col-left_margin) < width) { - BAYER(row-top_margin,col-left_margin) = val; - if (min > val) min = val; - } else black += val; - } + if ((unsigned) row < raw_height) RAW(row,col) = val; if (++col >= raw_width) col = (row++,0); } } - free (jh.row); - if (raw_width > width) - black /= (raw_width - width) * height; - if (!strcasecmp(make,"KODAK")) - black = min; + ljpeg_end (&jh); } void CLASS canon_sraw_load_raw() { struct jhead jh; - short *rp=0, *ip; + short *rp=0, (*ip)[4]; int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; + int v[3]={0,0,0}, ver, hue; + char *cp; - if (!ljpeg_start (&jh, 0)) return; - jwide = (jh.wide >>= 1) * 4; + if (!ljpeg_start (&jh, 0) || jh.clrs < 4) return; + jwide = (jh.wide >>= 1) * jh.clrs; for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { scol = ecol; - ecol += cr2_slice[1] >> 1; - if (!cr2_slice[0] || ecol > width-1) ecol = width & -2; - for (row=0; row < height; row++) { - ip = (short *) image[row*width+scol]; - for (col=scol; col < ecol; col+=2, jcol+=4, ip+=8) { + ecol += cr2_slice[1] * 2 / jh.clrs; + if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; + for (row=0; row < height; row += (jh.clrs >> 1) - 1) { + ip = (short (*)[4]) image + row*width; + for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { if ((jcol %= jwide) == 0) rp = (short *) ljpeg_row (jrow++, &jh); - ip[0] = rp[jcol]; - ip[4] = rp[jcol+1]; - ip[1] = (short) (rp[jcol+2] << 2) >> 2; - ip[2] = (short) (rp[jcol+3] << 2) >> 2; + if (col >= width) continue; + FORC (jh.clrs-2) + ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; + ip[col][1] = rp[jcol+jh.clrs-2] - 16384; + ip[col][2] = rp[jcol+jh.clrs-1] - 16384; } } } - for (row=0; row < height; row++) { - ip = (short *) image[row*width+1]; - for (col=1; col < width-1; col+=2, ip+=8) { - ip[1] = (ip[-3] + ip[5] + 1) >> 1; - ip[2] = (ip[-2] + ip[6] + 1) >> 1; - } - if (col < width) { ip[1] = ip[-3]; ip[2] = ip[-2]; } - ip = (short *) image[row*width]; - for (col=0; col < width; col++, ip+=4) { - pix[0] = ip[2] + ip[0]; - pix[2] = ip[1] + ip[0]; - pix[1] = ((ip[0] << 12) - ip[1]*778 - (ip[2] << 11)) >> 12; - FORC3 ip[c] = CLIP((pix[c] - 512) * sraw_mul[c] >> 10); + for (cp=model2; *cp && !isdigit(*cp); cp++); + sscanf (cp, "%d.%d.%d", v, v+1, v+2); + ver = (v[0]*1000 + v[1])*1000 + v[2]; + hue = (jh.sraw+1) << 2; + if (unique_id >= 0x80000281 || (unique_id == 0x80000218 && ver > 1000006)) + hue = jh.sraw << 1; + ip = (short (*)[4]) image; + rp = ip[0]; + for (row=0; row < height; row++, ip+=width) { + if (row & (jh.sraw >> 1)) + for (col=0; col < width; col+=2) + for (c=1; c < 3; c++) + if (row == height-1) + ip[col][c] = ip[col-width][c]; + else ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; + for (col=1; col < width; col+=2) + for (c=1; c < 3; c++) + if (col == width-1) + ip[col][c] = ip[col-1][c]; + else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; + } + for ( ; rp < ip[0]; rp+=4) { + if (unique_id == 0x80000218 || + unique_id == 0x80000250 || + unique_id == 0x80000261 || + unique_id == 0x80000281 || + unique_id == 0x80000287) { + rp[1] = (rp[1] << 2) + hue; + rp[2] = (rp[2] << 2) + hue; + pix[0] = rp[0] + (( 50*rp[1] + 22929*rp[2]) >> 14); + pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); + pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); + } else { + if (unique_id < 0x80000218) rp[0] -= 512; + pix[0] = rp[0] + rp[2]; + pix[2] = rp[0] + rp[1]; + pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12); } + FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); } - free (jh.row); + ljpeg_end (&jh); maximum = 0x3fff; } -void CLASS adobe_copy_pixel (int row, int col, ushort **rp) +void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { - unsigned r, c; + int c; - r = row -= top_margin; - c = col -= left_margin; - if (is_raw == 2 && shot_select) (*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 += is_raw; + if (tiff_samples == 2 && shot_select) (*rp)++; + if (raw_image) { + if (row < raw_height && col < raw_width) + RAW(row,col) = curve[**rp]; + *rp += tiff_samples; } else { - if (r < height && c < width) + if (row < height && col < width) FORC(tiff_samples) - image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c]; + image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } - if (is_raw == 2 && shot_select) (*rp)--; + if (tiff_samples == 2 && shot_select) (*rp)--; +} + +void CLASS ljpeg_idct (struct jhead *jh) +{ + int c, i, j, len, skip, coef; + float work[3][8][8]; + static float cs[106] = { 0 }; + static const uchar zigzag[80] = + { 0, 1, 8,16, 9, 2, 3,10,17,24,32,25,18,11, 4, 5,12,19,26,33, + 40,48,41,34,27,20,13, 6, 7,14,21,28,35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54, + 47,55,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 }; + + if (!cs[0]) + FORC(106) cs[c] = cos((c & 31)*M_PI/16)/2; + memset (work, 0, sizeof work); + work[0][0][0] = jh->vpred[0] += ljpeg_diff (jh->huff[0]) * jh->quant[0]; + for (i=1; i < 64; i++ ) { + len = gethuff (jh->huff[16]); + i += skip = len >> 4; + if (!(len &= 15) && skip < 15) break; + coef = getbits(len); + if ((coef & (1 << (len-1))) == 0) + coef -= (1 << len) - 1; + ((float *)work)[zigzag[i]] = coef * jh->quant[i]; + } + FORC(8) work[0][0][c] *= M_SQRT1_2; + FORC(8) work[0][c][0] *= M_SQRT1_2; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[1][i][j] += work[0][i][c] * cs[(j*2+1)*c]; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[2][i][j] += work[1][c][j] * cs[(i*2+1)*c]; + + FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5); } -void CLASS adobe_dng_load_raw_lj() +void CLASS lossless_dng_load_raw() { - unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; struct jhead jh; ushort *rp; @@ -1040,29 +1100,47 @@ if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; - jwide /= is_raw; - for (row=col=jrow=0; jrow < jh.high; jrow++) { - rp = ljpeg_row (jrow, &jh); - for (jcol=0; jcol < jwide; jcol++) { - adobe_copy_pixel (trow+row, tcol+col, &rp); - if (++col >= tile_width || col >= raw_width) - row += 1 + (col = 0); - } + jwide /= MIN (is_raw, tiff_samples); + switch (jh.algo) { + case 0xc1: + jh.vpred[0] = 16384; + getbits(-1); + for (jrow=0; jrow+7 < jh.high; jrow += 8) { + for (jcol=0; jcol+7 < jh.wide; jcol += 8) { + ljpeg_idct (&jh); + rp = jh.idct; + row = trow + jcol/tile_width + jrow*2; + col = tcol + jcol%tile_width; + for (i=0; i < 16; i+=2) + for (j=0; j < 8; j++) + adobe_copy_pixel (row+i, col+j, &rp); + } + } + break; + case 0xc3: + for (row=col=jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + adobe_copy_pixel (trow+row, tcol+col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + } } fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); - free (jh.row); + ljpeg_end (&jh); } } -void CLASS adobe_dng_load_raw_nc() +void CLASS packed_dng_load_raw() { ushort *pixel, *rp; int row, col; - pixel = (ushort *) calloc (raw_width * tiff_samples, sizeof *pixel); - merror (pixel, "adobe_dng_load_raw_nc()"); + pixel = (ushort *) calloc (raw_width, tiff_samples*sizeof *pixel); + merror (pixel, "packed_dng_load_raw()"); for (row=0; row < raw_height; row++) { if (tiff_bps == 16) read_shorts (pixel, raw_width * tiff_samples); @@ -1077,29 +1155,34 @@ free (pixel); } -void CLASS pentax_k10_load_raw() +void CLASS pentax_load_raw() { - static const uchar pentax_tree[] = - { 0,2,3,1,1,1,1,1,1,2,0,0,0,0,0,0, - 3,4,2,5,1,6,0,7,8,9,10,11,12 }; - int row, col, diff; + ushort bit[2][15], huff[4097]; + int dep, row, col, diff, c, i; ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; - init_decoder(); - make_decoder (pentax_tree, 0); + fseek (ifp, meta_offset, SEEK_SET); + dep = (get2() + 12) & 15; + fseek (ifp, 12, SEEK_CUR); + FORC(dep) bit[0][c] = get2(); + FORC(dep) bit[1][c] = fgetc(ifp); + FORC(dep) + for (i=bit[0][c]; i <= ((bit[0][c]+(4096 >> bit[1][c])-1) & 4095); ) + huff[++i] = bit[1][c] << 8 | c; + huff[0] = 12; + fseek (ifp, data_offset, SEEK_SET); getbits(-1); - for (row=0; row < height; row++) + for (row=0; row < raw_height; row++) for (col=0; col < raw_width; col++) { - diff = ljpeg_diff (first_decode); + diff = ljpeg_diff (huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; - if (col < width) - BAYER(row,col) = hpred[col & 1]; - if (hpred[col & 1] >> 12) derror(); + RAW(row,col) = hpred[col & 1]; + if (hpred[col & 1] >> tiff_bps) derror(); } } -void CLASS nikon_compressed_load_raw() +void CLASS nikon_load_raw() { static const uchar nikon_tree[][32] = { { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ @@ -1114,17 +1197,16 @@ 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 }, { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } }; - struct decode *dindex; - ushort ver0, ver1, vpred[2][2], hpred[2], csize; - int i, max, step=0, huff=0, split=0, row, col, len, shl, diff; + ushort *huff, ver0, ver1, vpred[2][2], hpred[2], csize; + int i, min, max, step=0, tree=0, split=0, row, col, len, shl, diff; fseek (ifp, meta_offset, SEEK_SET); ver0 = fgetc(ifp); ver1 = fgetc(ifp); if (ver0 == 0x49 || ver1 == 0x58) fseek (ifp, 2110, SEEK_CUR); - if (ver0 == 0x46) huff = 2; - if (tiff_bps == 14) huff += 3; + if (ver0 == 0x46) tree = 2; + if (tiff_bps == 14) tree += 3; read_shorts (vpred[0], 4); max = 1 << tiff_bps & 0x7fff; if ((csize = get2()) > 1) @@ -1139,72 +1221,49 @@ split = get2(); } else if (ver0 != 0x46 && csize <= 0x4001) read_shorts (curve, max=csize); - init_decoder(); - make_decoder (nikon_tree[huff], 0); + while (curve[max-2] == curve[max-1]) max--; + huff = make_decoder (nikon_tree[tree]); fseek (ifp, data_offset, SEEK_SET); getbits(-1); - for (row=0; row < height; row++) { + for (min=row=0; row < height; row++) { if (split && row == split) { - init_decoder(); - make_decoder (nikon_tree[huff+1], 0); + free (huff); + huff = make_decoder (nikon_tree[tree+1]); + max += (min = 16) << 1; } for (col=0; col < raw_width; col++) { - for (dindex=first_decode; dindex->branch[0]; ) - dindex = dindex->branch[getbits(1)]; - len = dindex->leaf & 15; - shl = dindex->leaf >> 4; + i = gethuff(huff); + len = i & 15; + shl = i >> 4; diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - !shl; if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; - if (hpred[col & 1] >= max) derror(); - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = curve[hpred[col & 1] & 0x3fff]; + if ((ushort)(hpred[col & 1] + min) >= max) derror(); + RAW(row,col) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; } } + free (huff); } -void CLASS nikon_load_raw() +void CLASS nikon_yuv_load_raw() { - int irow, row, col, i; + int row, col, yuv[4], rgb[3], b, c; + UINT64 bitbuf=0; - getbits(-1); - for (irow=0; irow < height; irow++) { - row = irow; - if (make[0] == 'O' || model[0] == 'E') { - row = irow * 2 % height + irow / (height/2); - if (row == 1 && data_offset == 0) { - fseek (ifp, 0, SEEK_END); - fseek (ifp, ftell(ifp)/2, SEEK_SET); - getbits(-1); - } - } + for (row=0; row < raw_height; row++) for (col=0; col < raw_width; col++) { - i = getbits(12); - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = i; - if (tiff_compress > 32768 && (col % 10) == 9) - if (getbits(8)) derror(); + if (!(b = col & 1)) { + bitbuf = 0; + FORC(6) bitbuf |= (UINT64) fgetc(ifp) << c*8; + FORC(4) yuv[c] = (bitbuf >> c*12 & 0xfff) - (c >> 1 << 11); + } + rgb[0] = yuv[b] + 1.370705*yuv[3]; + rgb[1] = yuv[b] - 0.337633*yuv[2] - 0.698001*yuv[3]; + rgb[2] = yuv[b] + 1.732446*yuv[2]; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,0xfff)] / cam_mul[c]; } - } -} - -/* - Figure out if a NEF file is compressed. These fancy heuristics - are only needed for the D100, thanks to a bug in some cameras - that tags all images as "compressed". - */ -int CLASS nikon_is_compressed() -{ - uchar test[256]; - int i; - - fseek (ifp, data_offset, SEEK_SET); - fread (test, 1, 256, ifp); - for (i=15; i < 256; i+=16) - if (test[i]) return 1; - return 0; } /* @@ -1251,10 +1310,10 @@ int bits; char make[12], model[15]; } table[] = { - { 0x00, "PENTAX", "Optio 33WR" }, - { 0x03, "NIKON", "E3200" }, - { 0x32, "NIKON", "E3700" }, - { 0x33, "OLYMPUS", "C740UZ" } }; + { 0x00, "Pentax", "Optio 33WR" }, + { 0x03, "Nikon", "E3200" }, + { 0x32, "Nikon", "E3700" }, + { 0x33, "Olympus", "C740UZ" } }; fseek (ifp, 3072, SEEK_SET); fread (dp, 1, 24, ifp); @@ -1271,105 +1330,46 @@ */ int CLASS minolta_z2() { - int i; + int i, nz; char tail[424]; fseek (ifp, -sizeof tail, SEEK_END); fread (tail, 1, sizeof tail, ifp); - for (i=0; i < sizeof tail; i++) - if (tail[i]) return 1; - return 0; -} - -/* Here raw_width is in bytes, not pixels. */ -void CLASS nikon_e900_load_raw() -{ - int offset=0, irow, row, col; - - for (irow=0; irow < height; irow++) { - row = irow * 2 % height; - if (row == 1) - offset = - (-offset & -4096); - fseek (ifp, offset, SEEK_SET); - offset += raw_width; - getbits(-1); - for (col=0; col < width; col++) - BAYER(row,col) = getbits(10); - } -} - -void CLASS nikon_e2100_load_raw() -{ - uchar data[4608], *dp; - ushort pixel[3072], *pix; - int row, col; - - for (row=0; row <= height; row+=2) { - if (row == height) { - fseek (ifp, 0, SEEK_END); - fseek (ifp, ftell(ifp)/2, SEEK_SET); - row = 1; - } - fread (data, 1, width*3/2, ifp); - for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) { - pix[0] = (dp[2] >> 4) + (dp[ 3] << 4); - pix[1] = (dp[2] << 8) + dp[ 1]; - pix[2] = (dp[7] >> 4) + (dp[ 0] << 4); - pix[3] = (dp[7] << 8) + dp[ 6]; - pix[4] = (dp[4] >> 4) + (dp[ 5] << 4); - pix[5] = (dp[4] << 8) + dp[11]; - pix[6] = (dp[9] >> 4) + (dp[10] << 4); - pix[7] = (dp[9] << 8) + dp[ 8]; - } - for (col=0; col < width; col++) - BAYER(row,col) = (pixel[col] & 0xfff); - } + for (nz=i=0; i < sizeof tail; i++) + if (tail[i]) nz++; + return nz > 20; } -/* - The Fuji Super CCD is just a Bayer grid rotated 45 degrees. - */ -void CLASS fuji_load_raw() -{ - ushort *pixel; - int wide, row, col, r, c; - - fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); - wide = fuji_width << !fuji_layout; - pixel = (ushort *) calloc (wide, sizeof *pixel); - merror (pixel, "fuji_load_raw()"); - for (row=0; row < raw_height; row++) { - read_shorts (pixel, wide); - fseek (ifp, 2*(raw_width - wide), SEEK_CUR); - for (col=0; col < wide; col++) { - if (fuji_layout) { - r = fuji_width - 1 - col + (row >> 1); - c = col + ((row+1) >> 1); - } else { - r = fuji_width - 1 + row - (col >> 1); - c = row + ((col+1) >> 1); - } - BAYER(r,c) = pixel[col]; - } - } - free (pixel); -} - -void CLASS jpeg_thumb (FILE *tfp); +void CLASS jpeg_thumb(); -void CLASS ppm_thumb (FILE *tfp) +void CLASS ppm_thumb() { char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) malloc (thumb_length); merror (thumb, "ppm_thumb()"); - fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fread (thumb, 1, thumb_length, ifp); - fwrite (thumb, 1, thumb_length, tfp); + fwrite (thumb, 1, thumb_length, ofp); + free (thumb); +} + +void CLASS ppm16_thumb() +{ + int i; + char *thumb; + thumb_length = thumb_width*thumb_height*3; + thumb = (char *) calloc (thumb_length, 2); + merror (thumb, "ppm16_thumb()"); + read_shorts ((ushort *) thumb, thumb_length); + for (i=0; i < thumb_length; i++) + thumb[i] = ((ushort *) thumb)[i] >> 8; + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fwrite (thumb, 1, thumb_length, ofp); free (thumb); } -void CLASS layer_thumb (FILE *tfp) +void CLASS layer_thumb() { int i, c; char *thumb, map[][4] = { "012","102" }; @@ -1378,15 +1378,15 @@ thumb_length = thumb_width*thumb_height; thumb = (char *) calloc (colors, thumb_length); merror (thumb, "layer_thumb()"); - fprintf (tfp, "P%d\n%d %d\n255\n", + fprintf (ofp, "P%d\n%d %d\n255\n", 5 + (colors >> 1), thumb_width, thumb_height); fread (thumb, thumb_length, colors, ifp); for (i=0; i < thumb_length; i++) - FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], tfp); + FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], ofp); free (thumb); } -void CLASS rollei_thumb (FILE *tfp) +void CLASS rollei_thumb() { unsigned i; ushort *thumb; @@ -1394,12 +1394,12 @@ thumb_length = thumb_width * thumb_height; thumb = (ushort *) calloc (thumb_length, 2); merror (thumb, "rollei_thumb()"); - fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); read_shorts (thumb, thumb_length); for (i=0; i < thumb_length; i++) { - putc (thumb[i] << 3, tfp); - putc (thumb[i] >> 5 << 2, tfp); - putc (thumb[i] >> 11 << 3, tfp); + putc (thumb[i] << 3, ofp); + putc (thumb[i] >> 5 << 2, ofp); + putc (thumb[i] >> 11 << 3, ofp); } free (thumb); } @@ -1407,7 +1407,7 @@ void CLASS rollei_load_raw() { uchar pixel[10]; - unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; + unsigned iten=0, isix, i, buffer=0, todo[16]; isix = raw_width * raw_height * 5 / 8; while (fread (pixel, 1, 10, ifp) == 10) { @@ -1420,32 +1420,30 @@ todo[i] = isix++; todo[i+1] = buffer >> (14-i)*5; } - for (i=0; i < 16; i+=2) { - row = todo[i] / raw_width - top_margin; - col = todo[i] % raw_width - left_margin; - if (row < height && col < width) - BAYER(row,col) = (todo[i+1] & 0x3ff); - } + for (i=0; i < 16; i+=2) + raw_image[todo[i]] = (todo[i+1] & 0x3ff); } maximum = 0x3ff; } -int CLASS bayer (unsigned row, unsigned col) +int CLASS raw (unsigned row, unsigned col) { - return (row < height && col < width) ? BAYER(row,col) : 0; + return (row < raw_height && col < raw_width) ? RAW(row,col) : 0; } void CLASS phase_one_flat_field (int is_float, int nc) { ushort head[8]; - unsigned wide, y, x, c, rend, cend, row, col; + 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] * head[3] * head[4] * head[5] == 0) return; + 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; @@ -1453,19 +1451,23 @@ else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; } if (y==0) continue; - rend = head[1]-top_margin + y*head[5]; - for (row = rend-head[5]; row < height && row < rend; row++) { + rend = head[1] + y*head[5]; + 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]-left_margin + x*head[4]; - for (col = cend-head[4]; col < width && col < cend; col++) { - c = nc > 2 ? FC(row,col) : 0; + cend = head[0] + x*head[4]; + 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 = BAYER(row,col) * mult[c]; - BAYER(row,col) = LIM(c,0,65535); + c = RAW(row,col) * mult[c]; + RAW(row,col) = LIM(c,0,65535); } for (c=0; c < nc; c+=2) mult[c] += mult[c+1]; @@ -1488,7 +1490,8 @@ { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, {-2,-2}, {-2,2}, {2,-2}, {2,2} }; float poly[8], num, cfrac, frac, mult[2], *yval[2]; - ushort curve[0x10000], *xval[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")); @@ -1519,37 +1522,37 @@ num = num * i + poly[j]; curve[i] = LIM(num+i,0,65535); } apply: /* apply to whole image */ - for (row=0; row < height; row++) - for (col = (tag & 1)*ph1.split_col; col < width; col++) - BAYER(row,col) = curve[BAYER(row,col)]; + for (row=0; row < raw_height; row++) + for (col = (tag & 1)*ph1.split_col; col < raw_width; col++) + RAW(row,col) = curve[RAW(row,col)]; } else if (tag == 0x400) { /* Sensor defects */ while ((len -= 8) >= 0) { - col = get2() - left_margin; - row = get2() - top_margin; + col = get2(); + row = get2(); type = get2(); get2(); - if (col >= width) continue; - if (type == 131) /* Bad column */ - for (row=0; row < height; row++) - if (FC(row,col) == 1) { + if (col >= raw_width) continue; + if (type == 131 || type == 137) /* Bad column */ + for (row=0; row < raw_height; row++) + if (FC(row-top_margin,col-left_margin) == 1) { for (sum=i=0; i < 4; i++) - sum += val[i] = bayer (row+dir[i][0], col+dir[i][1]); + sum += val[i] = raw (row+dir[i][0], col+dir[i][1]); for (max=i=0; i < 4; i++) { dev[i] = abs((val[i] << 2) - sum); if (dev[max] < dev[i]) max = i; } - BAYER(row,col) = (sum - val[max])/3.0 + 0.5; + RAW(row,col) = (sum - val[max])/3.0 + 0.5; } else { for (sum=0, i=8; i < 12; i++) - sum += bayer (row+dir[i][0], col+dir[i][1]); - BAYER(row,col) = 0.5 + sum * 0.0732233 + - (bayer(row,col-2) + bayer(row,col+2)) * 0.3535534; + sum += raw (row+dir[i][0], col+dir[i][1]); + RAW(row,col) = 0.5 + sum * 0.0732233 + + (raw(row,col-2) + raw(row,col+2)) * 0.3535534; } else if (type == 129) { /* Bad pixel */ - if (row >= height) continue; - j = (FC(row,col) != 1) * 4; + if (row >= raw_height) continue; + j = (FC(row-top_margin,col-left_margin) != 1) * 4; for (sum=0, i=j; i < j+8; i++) - sum += bayer (row+dir[i][0], col+dir[i][1]); - BAYER(row,col) = (sum + 4) >> 3; + sum += raw (row+dir[i][0], col+dir[i][1]); + RAW(row,col) = (sum + 4) >> 3; } } } else if (tag == 0x401) { /* All-color flat fields */ @@ -1565,6 +1568,83 @@ mindiff = diff; off_412 = ftell(ifp) - 38; } + } else if (tag == 0x41f && !qlin_applied) { /* Quadrant linearization */ + ushort lc[2][2][16], ref[16]; + int qr, qc; + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 16; i++) + lc[qr][qc][i] = get4(); + 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; + } + for (qr = 0; qr < 2; qr++) { + for (qc = 0; qc < 2; qc++) { + int cx[19], cf[19]; + 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) ref[15] * 65535) / lc[qr][qc][15]; + cx[18] = cf[18] = 65535; + cubic_spline(cx, cf, 19); + 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)]; + } + } + qlin_applied = 1; + } else if (tag == 0x41e && !qmult_applied) { /* Quadrant multipliers */ + float qmult[2][2] = { { 1, 1 }, { 1, 1 } }; + 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); + } + qmult_applied = 1; + } else if (tag == 0x431 && !qmult_applied) { /* Quadrant combined */ + ushort lc[2][2][7], ref[7]; + int qr, qc; + for (i = 0; i < 7; i++) + ref[i] = get4(); + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 7; i++) + lc[qr][qc][i] = get4(); + for (qr = 0; qr < 2; qr++) { + for (qc = 0; qc < 2; qc++) { + int cx[9], cf[9]; + for (i = 0; i < 7; i++) { + cx[1+i] = ref[i]; + cf[1+i] = ((unsigned) 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)]; + } + } + qmult_applied = 1; + qlin_applied = 1; } fseek (ifp, save, SEEK_SET); } @@ -1583,11 +1663,11 @@ for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) xval[i][j] = get2(); - for (row=0; row < height; row++) - for (col=0; col < width; col++) { + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { cfrac = (float) col * head[3] / raw_width; cfrac -= cip = cfrac; - num = BAYER(row,col) * 0.5; + num = RAW(row,col) * 0.5; for (i=cip; i < cip+2; i++) { for (k=j=0; j < head[1]; j++) if (num < xval[0][k = head[1]*i+j]) break; @@ -1595,9 +1675,8 @@ (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); } - i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) - * (row + top_margin) + num) * 2; - BAYER(row,col) = LIM(i,0,65535); + i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) * row + num) * 2; + RAW(row,col) = LIM(i,0,65535); } free (yval[0]); } @@ -1605,35 +1684,29 @@ void CLASS phase_one_load_raw() { - int row, col, a, b; - ushort *pixel, akey, bkey, mask; + int a, b, i; + ushort akey, bkey, mask; fseek (ifp, ph1.key_off, SEEK_SET); akey = get2(); bkey = get2(); mask = ph1.format == 1 ? 0x5555:0x1354; - fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET); - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "phase_one_load_raw()"); - for (row=0; row < height; row++) { - read_shorts (pixel, raw_width); - for (col=0; col < raw_width; col+=2) { - a = pixel[col+0] ^ akey; - b = pixel[col+1] ^ bkey; - pixel[col+0] = (a & mask) | (b & ~mask); - pixel[col+1] = (b & mask) | (a & ~mask); + fseek (ifp, data_offset, SEEK_SET); + read_shorts (raw_image, raw_width*raw_height); + if (ph1.format) + for (i=0; i < raw_width*raw_height; i+=2) { + a = raw_image[i+0] ^ akey; + b = raw_image[i+1] ^ bkey; + raw_image[i+0] = (a & mask) | (b & ~mask); + raw_image[i+1] = (b & mask) | (a & ~mask); } - for (col=0; col < width; col++) - BAYER(row,col) = pixel[col+left_margin]; - } - free (pixel); - phase_one_correct(); } -unsigned CLASS ph1_bits (int nbits) +unsigned CLASS ph1_bithuff (int nbits, ushort *huff) { static UINT64 bitbuf=0; static int vbits=0; + unsigned c; if (nbits == -1) return bitbuf = vbits = 0; @@ -1642,27 +1715,38 @@ bitbuf = bitbuf << 32 | get4(); vbits += 32; } + c = bitbuf << (64-vbits) >> (64-nbits); + if (huff) { + vbits -= huff[c] >> 8; + return (uchar) huff[c]; + } vbits -= nbits; - return bitbuf << (64-nbits-vbits) >> (64-nbits); + return c; } +#define ph1_bits(n) ph1_bithuff(n,0) +#define ph1_huff(h) ph1_bithuff(*h,h+1) void CLASS phase_one_load_raw_c() { static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; int *offset, len[2], pred[2], row, col, i, j; ushort *pixel; - short (*black)[2]; + short (*cblack)[2], (*rblack)[2]; - pixel = (ushort *) calloc (raw_width + raw_height*4, 2); + pixel = (ushort *) calloc (raw_width*3 + raw_height*4, 2); merror (pixel, "phase_one_load_raw_c()"); offset = (int *) (pixel + raw_width); fseek (ifp, strip_offset, SEEK_SET); for (row=0; row < raw_height; row++) offset[row] = get4(); - black = (short (*)[2]) offset + raw_height; - fseek (ifp, ph1.black_off, SEEK_SET); - if (ph1.black_off) - read_shorts ((ushort *) black[0], raw_height*2); + cblack = (short (*)[2]) (offset + raw_height); + fseek (ifp, ph1.black_col, SEEK_SET); + if (ph1.black_col) + read_shorts ((ushort *) cblack[0], raw_height*2); + rblack = cblack + raw_height; + fseek (ifp, ph1.black_row, SEEK_SET); + if (ph1.black_row) + read_shorts ((ushort *) rblack[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++) { @@ -1685,94 +1769,127 @@ if (ph1.format == 5 && pixel[col] < 256) pixel[col] = curve[pixel[col]]; } - if ((unsigned) (row-top_margin) < height) - for (col=0; col < width; col++) { - i = (pixel[col+left_margin] << 2) - - ph1.black + black[row][col >= ph1.split_col]; - if (i > 0) BAYER(row-top_margin,col) = i; - } + for (col=0; col < raw_width; col++) { + i = (pixel[col] << 2*(ph1.format != 8)) - ph1.black + + cblack[row][col >= ph1.split_col] + + rblack[col][row >= ph1.split_row]; + if (i > 0) RAW(row,col) = i; + } } free (pixel); - phase_one_correct(); maximum = 0xfffc - ph1.black; } void CLASS hasselblad_load_raw() { struct jhead jh; - struct decode *dindex; - int row, col, pred[2], len[2], diff, i; + int shot, row, col, *back[5], len[2], diff[12], pred, sh, f, s, c; + unsigned upix, urow, ucol; + ushort *ip; if (!ljpeg_start (&jh, 0)) return; - free (jh.row); + order = 0x4949; ph1_bits(-1); - for (row=-top_margin; row < height; row++) { - pred[0] = pred[1] = 0x8000; - for (col=-left_margin; col < raw_width-left_margin; col+=2) { - for (i=0; i < 2; i++) { - for (dindex=jh.huff[0]; dindex->branch[0]; ) - dindex = dindex->branch[ph1_bits(1)]; - len[i] = dindex->leaf; - } - for (i=0; i < 2; i++) { - diff = ph1_bits(len[i]); - if ((diff & (1 << (len[i]-1))) == 0) - diff -= (1 << len[i]) - 1; - pred[i] += diff; - if (row >= 0 && (unsigned)(col+i) < width) - BAYER(row,col+i) = pred[i]; + back[4] = (int *) calloc (raw_width, 3*sizeof **back); + merror (back[4], "hasselblad_load_raw()"); + FORC3 back[c] = back[4] + c*raw_width; + cblack[6] >>= sh = tiff_samples > 1; + shot = LIM(shot_select, 1, tiff_samples) - 1; + for (row=0; row < raw_height; row++) { + FORC4 back[(c+3) & 3] = back[c]; + for (col=0; col < raw_width; col+=2) { + for (s=0; s < tiff_samples*2; s+=2) { + FORC(2) len[c] = ph1_huff(jh.huff[0]); + FORC(2) { + diff[s+c] = ph1_bits(len[c]); + if ((diff[s+c] & (1 << (len[c]-1))) == 0) + diff[s+c] -= (1 << len[c]) - 1; + if (diff[s+c] == 65535) diff[s+c] = -32768; + } + } + for (s=col; s < col+2; s++) { + pred = 0x8000 + load_flags; + if (col) pred = back[2][s-2]; + if (col && row > 1) switch (jh.psv) { + case 11: pred += back[0][s]/2 - back[0][s-2]/2; break; + } + f = (row & 1)*3 ^ ((col+s) & 1); + FORC (tiff_samples) { + pred += diff[(s & 1)*tiff_samples+c]; + upix = pred >> sh & 0xffff; + if (raw_image && c == shot) + RAW(row,s) = upix; + if (image) { + urow = row-top_margin + (c & 1); + ucol = col-left_margin - ((c >> 1) & 1); + ip = &image[urow*width+ucol][f]; + if (urow < height && ucol < width) + *ip = c < 4 ? upix : (*ip + upix) >> 1; + } + } + back[2][s] = pred; } } } - maximum = 0xffff; + free (back[4]); + ljpeg_end (&jh); + if (image) mix_green = 1; } void CLASS leaf_hdr_load_raw() { - ushort *pixel; + ushort *pixel=0; unsigned tile=0, r, c, row, col; - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "leaf_hdr_load_raw()"); + if (!filters) { + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "leaf_hdr_load_raw()"); + } FORC(tiff_samples) for (r=0; r < raw_height; r++) { if (r % tile_length == 0) { fseek (ifp, data_offset + 4*tile++, SEEK_SET); - fseek (ifp, get4() + 2*left_margin, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); } if (filters && c != shot_select) continue; + if (filters) pixel = raw_image + r*raw_width; read_shorts (pixel, raw_width); - if ((row = r - top_margin) >= height) continue; - for (col=0; col < width; col++) - if (filters) BAYER(row,col) = pixel[col]; - else image[row*width+col][c] = pixel[col]; + if (!filters && (row = r - top_margin) < height) + for (col=0; col < width; col++) + image[row*width+col][c] = pixel[col+left_margin]; } - free (pixel); if (!filters) { maximum = 0xffff; raw_color = 1; + free (pixel); } } -void CLASS unpacked_load_raw(); +void CLASS unpacked_load_raw() +{ + int row, col, bits=0; + + while (1 << ++bits < maximum); + read_shorts (raw_image, raw_width*raw_height); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) + if ((RAW(row,col) >>= load_flags) >> bits + && (unsigned) (row-top_margin) < height + && (unsigned) (col-left_margin) < width) derror(); +} void CLASS sinar_4shot_load_raw() { ushort *pixel; unsigned shot, row, col, r, c; - if ((shot = shot_select) || half_size) { - if (shot) shot--; - if (shot > 3) shot = 3; + if (raw_image) { + shot = LIM (shot_select, 1, 4) - 1; fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); unpacked_load_raw(); return; } - free (image); - image = (ushort (*)[4]) - calloc ((iheight=height)*(iwidth=width), sizeof *image); - merror (image, "sinar_4shot_load_raw()"); pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "sinar_4shot_load_raw()"); for (shot=0; shot < 4; shot++) { @@ -1783,199 +1900,197 @@ if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; for (col=0; col < raw_width; col++) { if ((c = col-left_margin - (shot & 1)) >= width) continue; - image[r*width+c][FC(row,col)] = pixel[col]; + image[r*width+c][(row & 1)*3 ^ (~col & 1)] = pixel[col]; } } } free (pixel); - shrink = filters = 0; + mix_green = 1; } void CLASS imacon_full_load_raw() { int row, col; + if (!image) return; for (row=0; row < height; row++) for (col=0; col < width; col++) read_shorts (image[row*width+col], 3); } -void CLASS packed_12_load_raw() +void CLASS packed_load_raw() { - int row, col; - - if (raw_width * 2 < width * 3) - raw_width = raw_width * 3 / 2; /* Convert raw_width to bytes */ - getbits(-1); - for (row=0; row < height; row++) { - for (col=0; col < left_margin; col++) - getbits(12); - for (col=0; col < width; col++) - BAYER(row,col) = getbits(12); - for (col = (width+left_margin)*3/2; col < raw_width; col++) - if (getbits(8) && raw_width-col < 35 && width != 3896) derror(); - } -} + int vbits=0, bwide, rbits, bite, half, irow, row, col, val, i; + UINT64 bitbuf=0; -void CLASS unpacked_load_raw() -{ - ushort *pixel; - int row, col, bits=0; - - while (1 << ++bits < maximum); - fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); - pixel = (ushort *) calloc (width, sizeof *pixel); - merror (pixel, "unpacked_load_raw()"); - for (row=0; row < height; row++) { - read_shorts (pixel, width); - fseek (ifp, 2*(raw_width - width), SEEK_CUR); - for (col=0; col < width; col++) - if ((BAYER2(row,col) = pixel[col]) >> bits) derror(); + bwide = raw_width * tiff_bps / 8; + bwide += bwide & load_flags >> 9; + rbits = bwide * 8 - raw_width * tiff_bps; + if (load_flags & 1) bwide = bwide * 16 / 15; + bite = 8 + (load_flags & 56); + half = (raw_height+1) >> 1; + for (irow=0; irow < raw_height; irow++) { + row = irow; + if (load_flags & 2 && + (row = irow % half * 2 + irow / half) == 1 && + load_flags & 4) { + if (vbits=0, tiff_compress) + fseek (ifp, data_offset - (-half*bwide & -2048), SEEK_SET); + else { + fseek (ifp, 0, SEEK_END); + fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET); + } + } + for (col=0; col < raw_width; col++) { + for (vbits -= tiff_bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= ((UINT64) fgetc(ifp) << i); + } + val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); + RAW(row,col ^ (load_flags >> 6 & 3)) = val; + if (load_flags & 1 && (col % 10) == 9 && fgetc(ifp) && + row < height+top_margin && col < width+left_margin) derror(); + } + vbits -= rbits; } - free (pixel); } void CLASS nokia_load_raw() { uchar *data, *dp; - ushort *pixel, *pix; - int dwide, row, c; + int rev, dwide, row, col, c; + double sum[]={0,0}; - dwide = raw_width * 5 / 4; - data = (uchar *) malloc (dwide + raw_width*2); + rev = 3 * (order == 0x4949); + dwide = (raw_width * 5 + 1) / 4; + data = (uchar *) malloc (dwide*2); merror (data, "nokia_load_raw()"); - pixel = (ushort *) (data + dwide); for (row=0; row < raw_height; row++) { - if (fread (data, 1, dwide, ifp) < dwide) derror(); - for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=5, pix+=4) - FORC4 pix[c] = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); - if (row < top_margin) - FORC(width) black += pixel[c]; - else - FORC(width) BAYER(row-top_margin,c) = pixel[c]; + if (fread (data+dwide, 1, dwide, ifp) < dwide) derror(); + FORC(dwide) data[c] = data[dwide+(c ^ rev)]; + for (dp=data, col=0; col < raw_width; dp+=5, col+=4) + FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } free (data); - if (top_margin) black /= top_margin * width; maximum = 0x3ff; + if (strcmp(make,"OmniVision")) return; + row = raw_height/2; + FORC(width-1) { + sum[ c & 1] += SQR(RAW(row,c)-RAW(row+1,c+1)); + sum[~c & 1] += SQR(RAW(row+1,c)-RAW(row,c+1)); + } + if (sum[1] > sum[0]) filters = 0x4b4b4b4b; } -unsigned CLASS pana_bits (int nbits) +void CLASS canon_rmf_load_raw() { - static uchar buf[16], vbits=0; + int row, col, bits, orow, ocol, c; + + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width-2; col+=3) { + bits = get4(); + FORC3 { + orow = row; + if ((ocol = col+c-4) < 0) { + ocol += raw_width; + if ((orow -= 2) < 0) + orow += raw_height; + } + RAW(orow,ocol) = curve[bits >> (10*c+2) & 0x3ff]; + } + } + maximum = curve[0x3ff]; +} - if (!vbits && fread (buf, 1, 16, ifp) < 16) derror(); - vbits = (vbits - nbits) & 127; - return (buf[(vbits >> 3)+1] << 8 | buf[vbits >> 3]) - >> (vbits & 7) & ~(-1 << nbits); +unsigned CLASS pana_bits (int nbits) +{ + static uchar buf[0x4000]; + static int vbits; + int byte; + + if (!nbits) return vbits=0; + if (!vbits) { + fread (buf+load_flags, 1, 0x4000-load_flags, ifp); + fread (buf, 1, load_flags, ifp); + } + vbits = (vbits - nbits) & 0x1ffff; + byte = vbits >> 3 ^ 0x3ff0; + return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits); } void CLASS panasonic_load_raw() { int row, col, i, j, sh=0, pred[2], nonz[2]; - raw_width = (raw_width+13)/14*14; + pana_bits(0); for (row=0; row < height; row++) for (col=0; col < raw_width; col++) { - if ((i = col % 14) < 2) - nonz[i] = pred[i] = pana_bits(12); - else { - if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); + if ((i = col % 14) == 0) + pred[0] = pred[1] = nonz[0] = nonz[1] = 0; + if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); + if (nonz[i & 1]) { if ((j = pana_bits(8))) { if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) pred[i & 1] &= ~(-1 << sh); - pred[i & 1] += nonz[i & 1] ? j << sh : j; - nonz[i & 1] = 1; + pred[i & 1] += j << sh; } - } - if (col < width) - if ((BAYER(row,col) = pred[col & 1]) >> 12) derror(); - } - maximum = 0xf96; - black = 15; -} - -void CLASS olympus_e300_load_raw() -{ - uchar *data, *dp; - ushort *pixel, *pix; - int dwide, row, col; - - dwide = raw_width * 16 / 10; - fseek (ifp, dwide*top_margin, SEEK_CUR); - data = (uchar *) malloc (dwide + raw_width*2); - merror (data, "olympus_e300_load_raw()"); - pixel = (ushort *) (data + dwide); - for (row=0; row < height; row++) { - if (fread (data, 1, dwide, ifp) < dwide) derror(); - for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) { - if (((dp-data) & 15) == 15) - if (*dp++ && pix < pixel+width+left_margin) derror(); - pix[0] = dp[1] << 8 | dp[0]; - pix[1] = dp[2] << 4 | dp[1] >> 4; + } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) + pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); + if ((RAW(row,col) = pred[col & 1]) > 4098 && col < width) derror(); } - for (col=0; col < width; col++) - BAYER(row,col) = (pixel[col+left_margin] & 0xfff); - } - free (data); - maximum >>= 4; - black >>= 4; } -void CLASS olympus_e410_load_raw() +void CLASS olympus_load_raw() { - int row, col, nbits, sign, low, high, i, w, n, nw; + ushort huff[4096]; + int row, col, nbits, sign, low, high, i, c, w, n, nw; int acarry[2][3], *carry, pred, diff; + huff[n=0] = 0xc0c; + for (i=12; i--; ) + FORC(2048 >> i) huff[++n] = (i+1) << 8 | i; fseek (ifp, 7, SEEK_CUR); getbits(-1); for (row=0; row < height; row++) { memset (acarry, 0, sizeof acarry); - for (col=0; col < width; col++) { + for (col=0; col < raw_width; col++) { carry = acarry[col & 1]; i = 2 * (carry[2] < 3); for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); - sign = getbits(1) * -1; - low = getbits(2); - for (high=0; high < 12; high++) - if (getbits(1)) break; - if (high == 12) + low = (sign = getbits(3)) & 3; + sign = sign << 29 >> 31; + if ((high = getbithuff(12,huff)) == 12) high = getbits(16-nbits) >> 1; carry[0] = (high << nbits) | getbits(nbits); diff = (carry[0] ^ sign) + carry[1]; carry[1] = (diff*3 + carry[1]) >> 5; carry[2] = carry[0] > 16 ? 0 : carry[2]+1; + if (col >= width) continue; if (row < 2 && col < 2) pred = 0; - else if (row < 2) pred = BAYER(row,col-2); - else if (col < 2) pred = BAYER(row-2,col); + else if (row < 2) pred = RAW(row,col-2); + else if (col < 2) pred = RAW(row-2,col); else { - w = BAYER(row,col-2); - n = BAYER(row-2,col); - nw = BAYER(row-2,col-2); + w = RAW(row,col-2); + n = RAW(row-2,col); + nw = RAW(row-2,col-2); if ((w < nw && nw < n) || (n < nw && nw < w)) { if (ABS(w-nw) > 32 || ABS(n-nw) > 32) pred = w + n - nw; else pred = (w + n) >> 1; } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; } - if ((BAYER(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); + if ((RAW(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); } } } -void CLASS olympus_cseries_load_raw() +void CLASS canon_crx_load_raw() { - int irow, row, col; +} - for (irow=0; irow < height; irow++) { - row = irow * 2 % height + irow / (height/2); - if (row < 2) { - fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET); - getbits(-1); - } - for (col=0; col < width; col++) - BAYER(row,col) = getbits(12); - } - black >>= 4; +void CLASS fuji_xtrans_load_raw() +{ } void CLASS minolta_rd175_load_raw() @@ -1995,37 +2110,17 @@ } if ((box < 12) && (box & 1)) { for (col=0; col < 1533; col++, row ^= 1) - if (col != 1) BAYER(row,col) = (col+1) & 2 ? + if (col != 1) RAW(row,col) = (col+1) & 2 ? pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; - BAYER(row,1) = pixel[1] << 1; - BAYER(row,1533) = pixel[765] << 1; + RAW(row,1) = pixel[1] << 1; + RAW(row,1533) = pixel[765] << 1; } else for (col=row & 1; col < 1534; col+=2) - BAYER(row,col) = pixel[col/2] << 1; + RAW(row,col) = pixel[col/2] << 1; } maximum = 0xff << 1; } -void CLASS casio_qv5700_load_raw() -{ - uchar data[3232], *dp; - ushort pixel[2576], *pix; - int row, col; - - for (row=0; row < height; row++) { - fread (data, 1, 3232, ifp); - for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) { - pix[0] = (dp[0] << 2) + (dp[1] >> 6); - pix[1] = (dp[1] << 4) + (dp[2] >> 4); - pix[2] = (dp[2] << 6) + (dp[3] >> 2); - pix[3] = (dp[3] << 8) + (dp[4] ); - } - for (col=0; col < width; col++) - BAYER(row,col) = (pixel[col] & 0x3ff); - } - maximum = 0x3fc; -} - void CLASS quicktake_100_load_raw() { uchar pixel[484][644]; @@ -2089,32 +2184,20 @@ } for (row=0; row < height; row++) for (col=0; col < width; col++) - BAYER(row,col) = curve[pixel[row+2][col+2]]; + RAW(row,col) = curve[pixel[row+2][col+2]]; maximum = 0x3ff; } -const int * CLASS make_decoder_int (const int *source, int level) -{ - struct decode *cur; +#define radc_token(tree) ((signed char) getbithuff(8,huff[tree])) - cur = free_decode++; - if (level < source[0]) { - cur->branch[0] = free_decode; - source = make_decoder_int (source, level+1); - cur->branch[1] = free_decode; - source = make_decoder_int (source, level+1); - } else { - cur->leaf = source[1]; - source += 2; - } - return source; -} +#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) + +#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ +: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) -int CLASS radc_token (int tree) +void CLASS kodak_radc_load_raw() { - int t; - static struct decode *dstart[18], *dindex; - static const int *s, source[] = { + static const char src[] = { 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, @@ -2134,37 +2217,24 @@ 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 }; - - if (free_decode == first_decode) - for (s=source, t=0; t < 18; t++) { - dstart[t] = free_decode; - s = make_decoder_int (s, 0); - } - if (tree == 18) { - if (kodak_cbpp == 243) - return (getbits(6) << 2) + 2; /* most DC50 photos */ - else - return (getbits(5) << 3) + 4; /* DC40, Fotoman Pixtura */ - } - for (dindex = dstart[tree]; dindex->branch[0]; ) - dindex = dindex->branch[getbits(1)]; - return dindex->leaf; -} - -#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) - -#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ -: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) - -void CLASS kodak_radc_load_raw() -{ + ushort huff[19][256]; int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; + static const ushort pt[] = + { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 }; - init_decoder(); + for (i=2; i < 12; i+=2) + for (c=pt[i-2]; c <= pt[i]; c++) + curve[c] = (float) + (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5; + for (s=i=0; i < sizeof src; i+=2) + FORC(256 >> src[i]) + ((ushort *)huff)[s++] = src[i] << 8 | (uchar) src[i+1]; + s = kodak_cbpp == 243 ? 2 : 3; + FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1); getbits(-1); for (i=0; i < sizeof(buf)/sizeof(short); i++) - buf[0][0][i] = 2048; + ((short *)buf)[i] = 2048; for (row=0; row < height; row+=4) { FORC3 mul[c] = getbits(6); FORC3 { @@ -2173,7 +2243,7 @@ x = ~(-1 << (s-1)); val <<= 12-s; for (i=0; i < sizeof(buf[0])/sizeof(short); i++) - buf[c][0][i] = (buf[c][0][i] * val + x) >> s; + ((short *)buf[c])[i] = (((short *)buf[c])[i] * val + x) >> s; last[c] = mul[c]; for (r=0; r <= !c; r++) { buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; @@ -2181,7 +2251,7 @@ if ((tree = radc_token(tree))) { col -= 2; if (tree == 8) - FORYX buf[c][y][x] = radc_token(tree+10) * mul[c]; + FORYX buf[c][y][x] = (uchar) radc_token(18) * mul[c]; else FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; } else @@ -2201,8 +2271,8 @@ for (x=0; x < width/2; x++) { val = (buf[c][y+1][x] << 4) / mul[c]; if (val < 0) val = 0; - if (c) BAYER(row+y*2+c-1,x*2+2-c) = val; - else BAYER(row+r*2+y,x*2+y) = val; + if (c) RAW(row+y*2+c-1,x*2+2-c) = val; + else RAW(row+r*2+y,x*2+y) = val; } memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); } @@ -2212,20 +2282,22 @@ if ((x+y) & 1) { r = x ? x-1 : x+1; s = x+1 < width ? x+1 : x-1; - val = (BAYER(y,x)-2048)*2 + (BAYER(y,r)+BAYER(y,s))/2; + val = (RAW(y,x)-2048)*2 + (RAW(y,r)+RAW(y,s))/2; if (val < 0) val = 0; - BAYER(y,x) = val; + RAW(y,x) = val; } } - maximum = 0xfff; - use_gamma = 0; + for (i=0; i < height*width; i++) + raw_image[i] = curve[raw_image[i]]; + maximum = 0x3fff; } #undef FORYX #undef PREDICTOR -#ifdef HAVE_JPEG +#ifdef NO_JPEG void CLASS kodak_jpeg_load_raw() {} +void CLASS lossy_dng_load_raw() {} #else METHODDEF(boolean) @@ -2270,16 +2342,81 @@ jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < width; col+=2) { - BAYER(row+0,col+0) = pixel[col+0][1] << 1; - BAYER(row+1,col+1) = pixel[col+1][1] << 1; - BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; - BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; + RAW(row+0,col+0) = pixel[col+0][1] << 1; + RAW(row+1,col+1) = pixel[col+1][1] << 1; + RAW(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; + RAW(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; } } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); maximum = 0xff << 1; } + +void CLASS gamma_curve (double pwr, double ts, int mode, int imax); + +void CLASS lossy_dng_load_raw() +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPARRAY buf; + JSAMPLE (*pixel)[3]; + unsigned sorder=order, ntags, opcode, deg, i, j, c; + unsigned save=data_offset-4, trow=0, tcol=0, row, col; + ushort cur[3][256]; + double coeff[9], tot; + + if (meta_offset) { + fseek (ifp, meta_offset, SEEK_SET); + order = 0x4d4d; + ntags = get4(); + while (ntags--) { + opcode = get4(); get4(); get4(); + if (opcode != 8) + { fseek (ifp, get4(), SEEK_CUR); continue; } + fseek (ifp, 20, SEEK_CUR); + if ((c = get4()) > 2) break; + fseek (ifp, 12, SEEK_CUR); + if ((deg = get4()) > 8) break; + for (i=0; i <= deg && i < 9; i++) + coeff[i] = getreal(12); + for (i=0; i < 256; i++) { + for (tot=j=0; j <= deg; j++) + tot += coeff[j] * pow(i/255.0, j); + cur[c][i] = tot*0xffff; + } + } + order = sorder; + } else { + gamma_curve (1/2.4, 12.92, 1, 255); + FORC3 memcpy (cur[c], curve, sizeof cur[0]); + } + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + while (trow < raw_height) { + fseek (ifp, save+=4, SEEK_SET); + if (tile_length < INT_MAX) + fseek (ifp, get4(), SEEK_SET); + jpeg_stdio_src (&cinfo, ifp); + jpeg_read_header (&cinfo, TRUE); + jpeg_start_decompress (&cinfo); + buf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width*3, 1); + while (cinfo.output_scanline < cinfo.output_height && + (row = trow + cinfo.output_scanline) < height) { + jpeg_read_scanlines (&cinfo, buf, 1); + pixel = (JSAMPLE (*)[3]) buf[0]; + for (col=0; col < cinfo.output_width && tcol+col < width; col++) { + FORC3 image[row*width+tcol+col][c] = cur[c][pixel[col][c]]; + } + } + jpeg_abort_decompress (&cinfo); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); + } + jpeg_destroy_decompress (&cinfo); + maximum = 0xffff; +} #endif void CLASS kodak_dc120_load_raw() @@ -2293,7 +2430,7 @@ if (fread (pixel, 1, 848, ifp) < 848) derror(); shift = row * mul[row & 3] + add[row & 3]; for (col=0; col < width; col++) - BAYER(row,col) = (ushort) pixel[(col + shift) % 848]; + RAW(row,col) = (ushort) pixel[(col + shift) % 848]; } maximum = 0xff; } @@ -2301,25 +2438,65 @@ void CLASS eight_bit_load_raw() { uchar *pixel; - unsigned row, col, val, lblack=0; + unsigned row, col; pixel = (uchar *) calloc (raw_width, sizeof *pixel); merror (pixel, "eight_bit_load_raw()"); - fseek (ifp, top_margin*raw_width, SEEK_CUR); - for (row=0; row < height; row++) { + for (row=0; row < raw_height; row++) { if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); - for (col=0; col < raw_width; col++) { - val = curve[pixel[col]]; - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = val; - else lblack += val; + for (col=0; col < raw_width; col++) + RAW(row,col) = curve[pixel[col]]; + } + free (pixel); + maximum = curve[0xff]; +} + +void CLASS kodak_c330_load_raw() +{ + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *) calloc (raw_width, 2*sizeof *pixel); + merror (pixel, "kodak_c330_load_raw()"); + for (row=0; row < height; row++) { + if (fread (pixel, raw_width, 2, ifp) < 2) derror(); + if (load_flags && (row & 31) == 31) + fseek (ifp, raw_width*32, SEEK_CUR); + for (col=0; col < width; col++) { + y = pixel[col*2]; + cb = pixel[(col*2 & -4) | 1] - 128; + cr = pixel[(col*2 & -4) | 3] - 128; + rgb[1] = y - ((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; + } + } + free (pixel); + maximum = curve[0xff]; +} + +void CLASS kodak_c603_load_raw() +{ + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); + merror (pixel, "kodak_c603_load_raw()"); + for (row=0; row < height; row++) { + if (~row & 1) + if (fread (pixel, raw_width, 3, ifp) < 3) derror(); + for (col=0; col < width; col++) { + y = pixel[width*2*(row & 1) + col]; + cb = pixel[width + (col & -2)] - 128; + cr = pixel[width + (col & -2)+1] - 128; + rgb[1] = y - ((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; } } free (pixel); - if (raw_width > width+1) - black = lblack / ((raw_width - width) * height); - if (!strncmp(model,"DC2",3)) - black = 0; maximum = curve[0xff]; } @@ -2328,22 +2505,17 @@ static const uchar kodak_tree[2][26] = { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; - struct decode *decode[2]; + ushort *huff[2]; uchar *pixel; - int *strip, ns, i, row, col, chess, pi=0, pi1, pi2, pred, val; + int *strip, ns, c, row, col, chess, pi=0, pi1, pi2, pred, val; - init_decoder(); - for (i=0; i < 2; i++) { - decode[i] = free_decode; - make_decoder (kodak_tree[i], 0); - } + FORC(2) huff[c] = make_decoder (kodak_tree[c]); ns = (raw_height+63) >> 5; pixel = (uchar *) malloc (raw_width*32 + ns*4); merror (pixel, "kodak_262_load_raw()"); strip = (int *) (pixel + raw_width*32); order = 0x4d4d; - for (i=0; i < ns; i++) - strip[i] = get4(); + FORC(ns) strip[c] = get4(); for (row=0; row < raw_height; row++) { if ((row & 31) == 0) { fseek (ifp, strip[row >> 5], SEEK_SET); @@ -2359,17 +2531,14 @@ if (pi2 < 0) pi2 = pi1; if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; - pixel[pi] = val = pred + ljpeg_diff (decode[chess]); + pixel[pi] = val = pred + ljpeg_diff (huff[chess]); if (val >> 8) derror(); val = curve[pixel[pi++]]; - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = val; - else black += val; + RAW(row,col) = val; } } free (pixel); - if (raw_width > width) - black /= (raw_width - width) * height; + FORC(2) free (huff[c]); } int CLASS kodak_65000_decode (short *out, int bsize) @@ -2429,7 +2598,7 @@ len = MIN (256, width-col); ret = kodak_65000_decode (buf, len); for (i=0; i < len; i++) - if ((BAYER(row,col+i) = curve[ret ? buf[i] : + if ((RAW(row,col+i) = curve[ret ? buf[i] : (pred[i & 1] += buf[i])]) >> 12) derror(); } } @@ -2440,6 +2609,7 @@ int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; ushort *ip; + if (!image) return; for (row=0; row < height; row+=2) for (col=0; col < width; col+=128) { len = MIN (128, width-col); @@ -2500,8 +2670,8 @@ for (p=0; p < 127; p++) pad[p] = htonl(pad[p]); } - while (len--) - *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; + while (len-- && p++) + *data++ ^= pad[(p-1) & 127] = pad[p & 127] ^ pad[(p+64) & 127]; } void CLASS sony_load_raw() @@ -2516,44 +2686,37 @@ key = get4(); fseek (ifp, 164600, SEEK_SET); fread (head, 1, 40, ifp); - sony_decrypt ((unsigned int *) head, 10, 1, key); + sony_decrypt ((unsigned *) head, 10, 1, key); for (i=26; i-- > 22; ) key = key << 8 | head[i]; fseek (ifp, data_offset, SEEK_SET); - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "sony_load_raw()"); - for (row=0; row < height; row++) { + for (row=0; row < raw_height; row++) { + pixel = raw_image + row*raw_width; if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); - sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key); - for (col=9; col < left_margin; col++) - black += ntohs(pixel[col]); - for (col=0; col < width; col++) - if ((BAYER(row,col) = ntohs(pixel[col+left_margin])) >> 14) - derror(); + sony_decrypt ((unsigned *) pixel, raw_width/2, !row, key); + for (col=0; col < raw_width; col++) + if ((pixel[col] = ntohs(pixel[col])) >> 14) derror(); } - free (pixel); - if (left_margin > 9) - black /= (left_margin-9) * height; maximum = 0x3ff0; } void CLASS sony_arw_load_raw() { - int col, row, len, diff, sum=0; - + ushort huff[32770]; + static const ushort tab[18] = + { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, + 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 }; + int i, c, n, col, row, sum=0; + + huff[0] = 15; + for (n=i=0; i < 18; i++) + FORC(32768 >> (tab[i] >> 8)) huff[++n] = tab[i]; getbits(-1); for (col = raw_width; col--; ) for (row=0; row < raw_height+1; row+=2) { if (row == raw_height) row = 1; - len = 4 - getbits(2); - if (len == 3 && getbits(1)) len = 0; - if (len == 4) - while (len < 17 && !getbits(1)) len++; - diff = getbits(len); - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - if ((sum += diff) >> 12) derror(); - if (row < height) BAYER(row,col) = sum; + if ((sum += ljpeg_diff(huff)) >> 12) derror(); + if (row < height) RAW(row,col) = sum; } } @@ -2563,37 +2726,132 @@ ushort pix[16]; int row, col, val, max, min, imax, imin, sh, bit, i; - data = (uchar *) malloc (raw_width*tiff_bps >> 3); + data = (uchar *) malloc (raw_width+1); merror (data, "sony_arw2_load_raw()"); for (row=0; row < height; row++) { - fread (data, 1, raw_width*tiff_bps >> 3, ifp); - if (tiff_bps == 8) { - for (dp=data, col=0; col < width-30; dp+=16) { - max = 0x7ff & (val = sget4(dp)); - min = 0x7ff & val >> 11; - imax = 0x0f & val >> 22; - imin = 0x0f & val >> 26; - for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); - for (bit=30, i=0; i < 16; i++) - if (i == imax) pix[i] = max; - else if (i == imin) pix[i] = min; - else { - pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; - if (pix[i] > 0x7ff) pix[i] = 0x7ff; - bit += 7; - } - for (i=0; i < 16; i++, col+=2) - BAYER(row,col) = curve[pix[i] << 1] >> 1; - col -= col & 1 ? 1:31; - } - } else if (tiff_bps == 12) - for (dp=data, col=0; col < width; dp+=3, col+=2) { - BAYER(row,col) = ((dp[1] << 8 | dp[0]) & 0xfff) << 1; - BAYER(row,col+1) = (dp[2] << 4 | dp[1] >> 4) << 1; - } + fread (data, 1, raw_width, ifp); + for (dp=data, col=0; col < raw_width-30; dp+=16) { + max = 0x7ff & (val = sget4(dp)); + min = 0x7ff & val >> 11; + imax = 0x0f & val >> 22; + imin = 0x0f & val >> 26; + for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); + for (bit=30, i=0; i < 16; i++) + if (i == imax) pix[i] = max; + else if (i == imin) pix[i] = min; + else { + pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; + if (pix[i] > 0x7ff) pix[i] = 0x7ff; + bit += 7; + } + for (i=0; i < 16; i++, col+=2) + RAW(row,col) = curve[pix[i] << 1] >> 2; + col -= col & 1 ? 1:31; + } } free (data); - maximum = 0x1fff; +} + +void CLASS samsung_load_raw() +{ + int row, col, c, i, dir, op[4], len[4]; + + order = 0x4949; + for (row=0; row < raw_height; row++) { + fseek (ifp, strip_offset+row*4, SEEK_SET); + fseek (ifp, data_offset+get4(), SEEK_SET); + ph1_bits(-1); + FORC4 len[c] = row < 2 ? 7:4; + for (col=0; col < raw_width; col+=16) { + dir = ph1_bits(1); + FORC4 op[c] = ph1_bits(2); + FORC4 switch (op[c]) { + case 3: len[c] = ph1_bits(4); break; + case 2: len[c]--; break; + case 1: len[c]++; + } + for (c=0; c < 16; c+=2) { + i = len[((c & 1) << 1) | (c >> 3)]; + RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) + + (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128); + if (c == 14) c = -1; + } + } + } + for (row=0; row < raw_height-1; row+=2) + for (col=0; col < raw_width-1; col+=2) + SWAP (RAW(row,col+1), RAW(row+1,col)); +} + +void CLASS samsung2_load_raw() +{ + static const ushort tab[14] = + { 0x304,0x307,0x206,0x205,0x403,0x600,0x709, + 0x80a,0x90b,0xa0c,0xa0d,0x501,0x408,0x402 }; + ushort huff[1026], vpred[2][2] = {{0,0},{0,0}}, hpred[2]; + int i, c, n, row, col, diff; + + huff[0] = 10; + for (n=i=0; i < 14; i++) + FORC(1024 >> (tab[i] >> 8)) huff[++n] = tab[i]; + getbits(-1); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + diff = ljpeg_diff (huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + RAW(row,col) = hpred[col & 1]; + if (hpred[col & 1] >> tiff_bps) derror(); + } +} + +void CLASS samsung3_load_raw() +{ + int opt, init, mag, pmode, row, tab, col, pred, diff, i, c; + ushort lent[3][2], len[4], *prow[2]; + + order = 0x4949; + fseek (ifp, 9, SEEK_CUR); + opt = fgetc(ifp); + init = (get2(),get2()); + for (row=0; row < raw_height; row++) { + fseek (ifp, (data_offset-ftell(ifp)) & 15, SEEK_CUR); + ph1_bits(-1); + mag = 0; pmode = 7; + FORC(6) ((ushort *)lent)[c] = row < 2 ? 7:4; + prow[ row & 1] = &RAW(row-1,1-((row & 1) << 1)); // green + prow[~row & 1] = &RAW(row-2,0); // red and blue + for (tab=0; tab+15 < raw_width; tab+=16) { + if (~opt & 4 && !(tab & 63)) { + i = ph1_bits(2); + mag = i < 3 ? mag-'2'+"204"[i] : ph1_bits(12); + } + if (opt & 2) + pmode = 7 - 4*ph1_bits(1); + else if (!ph1_bits(1)) + pmode = ph1_bits(3); + if (opt & 1 || !ph1_bits(1)) { + FORC4 len[c] = ph1_bits(2); + FORC4 { + i = ((row & 1) << 1 | (c & 1)) % 3; + len[c] = len[c] < 3 ? lent[i][0]-'1'+"120"[len[c]] : ph1_bits(4); + lent[i][0] = lent[i][1]; + lent[i][1] = len[c]; + } + } + FORC(16) { + col = tab + (((c & 7) << 1)^(c >> 3)^(row & 1)); + pred = (pmode == 7 || row < 2) + ? (tab ? RAW(row,tab-2+(col & 1)) : init) + : (prow[col & 1][col-'4'+"0224468"[pmode]] + + prow[col & 1][col-'4'+"0244668"[pmode]] + 1) >> 1; + diff = ph1_bits (i = len[c >> 2]); + if (diff >> (i-1)) diff -= 1 << i; + diff = diff * (mag*2+1) + mag; + RAW(row,col) = pred + diff; + } + } + } } #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) @@ -2606,13 +2864,14 @@ { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; int low, high=0xff, carry=0, nbits=8; - int s, count, bin, next, i, sym[3]; + int pix, s, count, bin, next, i, sym[3]; uchar diff, pred[]={0,0}; ushort data=0, range=0; - unsigned pix, row, col; fseek (ifp, seg[0][1]+1, SEEK_SET); getbits(-1); + if (seg[1][0] > raw_width*raw_height) + seg[1][0] = raw_width*raw_height; for (pix=seg[0][0]; pix < seg[1][0]; pix++) { for (s=0; s < 3; s++) { data = data << nbits | getbits(nbits); @@ -2655,12 +2914,8 @@ diff = diff ? -diff : 0x80; if (ftell(ifp) + 12 >= seg[1][1]) diff = 0; - pred[pix & 1] += diff; - row = pix / raw_width - top_margin; - col = pix % raw_width - left_margin; - if (row < height && col < width) - BAYER(row,col) = pred[pix & 1]; - if (!(pix & 1) && HOLE(row)) pix += 2; + raw_image[pix] = pred[pix & 1] += diff; + if (!(pix & 1) && HOLE(pix / raw_width)) pix += 2; } maximum = 0xff; } @@ -2675,7 +2930,6 @@ seg[1][0] = raw_width * raw_height; seg[1][1] = INT_MAX; smal_decode_segment (seg, 0); - use_gamma = 0; } int CLASS median4 (int *p) @@ -2698,21 +2952,21 @@ for (row=2; row < height-2; row++) { if (!HOLE(row)) continue; for (col=1; col < width-1; col+=4) { - val[0] = BAYER(row-1,col-1); - val[1] = BAYER(row-1,col+1); - val[2] = BAYER(row+1,col-1); - val[3] = BAYER(row+1,col+1); - BAYER(row,col) = median4(val); + val[0] = RAW(row-1,col-1); + val[1] = RAW(row-1,col+1); + val[2] = RAW(row+1,col-1); + val[3] = RAW(row+1,col+1); + RAW(row,col) = median4(val); } for (col=2; col < width-2; col+=4) if (HOLE(row-2) || HOLE(row+2)) - BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1; + RAW(row,col) = (RAW(row,col-2) + RAW(row,col+2)) >> 1; else { - val[0] = BAYER(row,col-2); - val[1] = BAYER(row,col+2); - val[2] = BAYER(row-2,col); - val[3] = BAYER(row+2,col); - BAYER(row,col) = median4(val); + val[0] = RAW(row,col-2); + val[1] = RAW(row,col+2); + val[2] = RAW(row-2,col); + val[3] = RAW(row+2,col); + RAW(row,col) = median4(val); } } } @@ -2723,10 +2977,10 @@ fseek (ifp, 67, SEEK_SET); offset = get4(); - nseg = fgetc(ifp); + nseg = (uchar) fgetc(ifp); fseek (ifp, offset, SEEK_SET); for (i=0; i < nseg*2; i++) - seg[0][i] = get4() + data_offset*(i & 1); + ((unsigned *)seg)[i] = get4() + data_offset*(i & 1); fseek (ifp, 78, SEEK_SET); holes = fgetc(ifp); fseek (ifp, 88, SEEK_SET); @@ -2737,6 +2991,58 @@ if (holes) fill_holes (holes); } +void CLASS redcine_load_raw() +{ +#ifndef NO_JASPER + int c, row, col; + jas_stream_t *in; + jas_image_t *jimg; + jas_matrix_t *jmat; + jas_seqent_t *data; + ushort *img, *pix; + + jas_init(); + in = jas_stream_fopen (ifname, "rb"); + jas_stream_seek (in, data_offset+20, SEEK_SET); + jimg = jas_image_decode (in, -1, 0); + if (!jimg) longjmp (failure, 3); + jmat = jas_matrix_create (height/2, width/2); + merror (jmat, "redcine_load_raw()"); + img = (ushort *) calloc ((height+2), (width+2)*2); + merror (img, "redcine_load_raw()"); + FORC4 { + jas_image_readcmpt (jimg, c, 0, 0, width/2, height/2, jmat); + data = jas_matrix_getref (jmat, 0, 0); + for (row = c >> 1; row < height; row+=2) + for (col = c & 1; col < width; col+=2) + img[(row+1)*(width+2)+col+1] = data[(row/2)*(width/2)+col/2]; + } + for (col=1; col <= width; col++) { + img[col] = img[2*(width+2)+col]; + img[(height+1)*(width+2)+col] = img[(height-1)*(width+2)+col]; + } + for (row=0; row < height+2; row++) { + img[row*(width+2)] = img[row*(width+2)+2]; + img[(row+1)*(width+2)-1] = img[(row+1)*(width+2)-3]; + } + for (row=1; row <= height; row++) { + pix = img + row*(width+2) + (col = 1 + (FC(row,1) & 1)); + for ( ; col <= width; col+=2, pix+=2) { + c = (((pix[0] - 0x800) << 3) + + pix[-(width+2)] + pix[width+2] + pix[-1] + pix[1]) >> 2; + pix[0] = LIM(c,0,4095); + } + } + for (row=0; row < height; row++) + for (col=0; col < width; col++) + RAW(row,col) = curve[img[(row+1)*(width+2)+col+1]]; + free (img); + jas_matrix_destroy (jmat); + jas_image_destroy (jimg); + jas_stream_close (in); +#endif +} + /* RESTRICTED code starts here */ void CLASS foveon_decoder (unsigned size, unsigned code) @@ -2748,7 +3054,8 @@ if (!code) { for (i=0; i < size; i++) huff[i] = get4(); - init_decoder(); + memset (first_decode, 0, sizeof first_decode); + free_decode = first_decode; } cur = free_decode++; if (free_decode > first_decode+2048) { @@ -2770,7 +3077,7 @@ foveon_decoder (size, code+1); } -void CLASS foveon_thumb (FILE *tfp) +void CLASS foveon_thumb() { unsigned bwide, row, col, bitbuf=0, bit=1, c, i; char *buf; @@ -2778,14 +3085,14 @@ short pred[3]; bwide = get4(); - fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fprintf (ofp, "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); + fwrite (buf, 3, thumb_width, ofp); } free (buf); return; @@ -2804,41 +3111,26 @@ dindex = dindex->branch[bitbuf >> bit & 1]; } pred[c] += dindex->leaf; - fputc (pred[c], tfp); + fputc (pred[c], ofp); } } } -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() +void CLASS foveon_sd_load_raw() { struct decode *dindex; short diff[1024]; unsigned bitbuf=0; - int pred[3], fixed, row, col, bit=-1, c, i; + int pred[3], row, col, bit=-1, c, i; - fixed = get4(); read_shorts ((ushort *) diff, 1024); - if (!fixed) foveon_decoder (1024, 0); + if (!load_flags) foveon_decoder (1024, 0); for (row=0; row < height; row++) { memset (pred, 0, sizeof pred); - if (!bit && !fixed && atoi(model+2) < 14) get4(); + if (!bit && !load_flags && atoi(model+2) < 14) get4(); for (col=bit=0; col < width; col++) { - if (fixed) { + if (load_flags) { bitbuf = get4(); FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; } @@ -2855,10 +3147,83 @@ 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(); +} + +void CLASS foveon_huff (ushort *huff) +{ + int i, j, clen, code; + + huff[0] = 8; + for (i=0; i < 13; i++) { + clen = getc(ifp); + code = getc(ifp); + for (j=0; j < 256 >> clen; ) + huff[code+ ++j] = clen << 8 | i; + } + get2(); +} + +void CLASS foveon_dp_load_raw() +{ + unsigned c, roff[4], row, col, diff; + ushort huff[512], vpred[2][2], hpred[2]; + + fseek (ifp, 8, SEEK_CUR); + foveon_huff (huff); + roff[0] = 48; + FORC3 roff[c+1] = -(-(roff[c] + get4()) & -16); + FORC3 { + fseek (ifp, data_offset+roff[c], SEEK_SET); + getbits(-1); + vpred[0][0] = vpred[0][1] = vpred[1][0] = vpred[1][1] = 512; + for (row=0; row < height; row++) { + for (col=0; col < width; col++) { + diff = ljpeg_diff(huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + image[row*width+col][c] = hpred[col & 1]; + } + } + } +} + +void CLASS foveon_load_camf() +{ + unsigned type, wide, high, i, j, row, col, diff; + ushort huff[258], vpred[2][2] = {{512,512},{512,512}}, hpred[2]; + + fseek (ifp, meta_offset, SEEK_SET); + type = get4(); get4(); get4(); + wide = get4(); + high = get4(); + if (type == 2) { + fread (meta_data, 1, meta_length, ifp); + for (i=0; i < meta_length; i++) { + high = (high * 1597 + 51749) % 244944; + wide = high * (INT64) 301593171 >> 24; + meta_data[i] ^= ((((high << 8) - wide) >> 1) + wide) >> 17; + } + } else if (type == 4) { + free (meta_data); + meta_data = (char *) malloc (meta_length = wide*high*3/2); + merror (meta_data, "foveon_load_camf()"); + foveon_huff (huff); + get4(); + getbits(-1); + for (j=row=0; row < high; row++) { + for (col=0; col < wide; col++) { + diff = ljpeg_diff(huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + if (col & 1) { + meta_data[j++] = hpred[0] >> 4; + meta_data[j++] = hpred[0] << 4 | hpred[1] >> 8; + meta_data[j++] = hpred[1]; + } + } + } + } else + fprintf (stderr,_("%s has unknown CAMF type %d.\n"), ifname, type); } const char * CLASS foveon_camf_param (const char *block, const char *param) @@ -2922,6 +3287,7 @@ void *dp; unsigned dim[3]; + if (!name) return 0; dp = foveon_camf_matrix (dim, name); if (!dp) return 0; memcpy (ptr, dp, size*4); @@ -3002,6 +3368,7 @@ if (verbose) fprintf (stderr,_("Foveon interpolation...\n")); + foveon_load_camf(); foveon_fixed (dscr, 4, "DarkShieldColRange"); foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); foveon_fixed (satlev, 3, "SaturationLevel"); @@ -3010,9 +3377,9 @@ foveon_fixed (chroma_dq, 3, "ChromaDQ"); foveon_fixed (color_dq, 3, foveon_camf_param ("IncludeBlocks", "ColorDQ") ? - "ColorDQ" : "ColorDTQCamRGB"); + "ColorDQ" : "ColorDQCamRGB"); if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) - foveon_fixed (&cfilt, 1, "ColumnFilter"); + foveon_fixed (&cfilt, 1, "ColumnFilter"); memset (ddft, 0, sizeof ddft); if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") @@ -3076,10 +3443,10 @@ black = (float (*)[3]) calloc (height, sizeof *black); 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]); + ((float *)ddft[0])[i] = ((float *)ddft[1])[i] + + row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]); FORC3 black[row][c] = - ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + + ( 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]; } @@ -3122,8 +3489,8 @@ 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]); + ((float *)ddft[0])[i] = ((float *)ddft[1])[i] + + row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]); pix = image[row*width]; memcpy (prev, pix, sizeof prev); frow = row / (height-1.0) * (dim[2]-1); @@ -3162,7 +3529,7 @@ free (sgrow); free (sgain); - if ((badpix = (unsigned int *) foveon_camf_matrix (dim, "BadPixels"))) { + if ((badpix = (unsigned *) 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]; @@ -3304,7 +3671,7 @@ } /* Smooth the image bottom-to-top and save at 1/4 scale */ - shrink = (short (*)[3]) calloc ((width/4) * (height/4), sizeof *shrink); + shrink = (short (*)[3]) calloc ((height/4), (width/4)*sizeof *shrink); merror (shrink, "foveon_interpolate()"); for (row = height/4; row--; ) for (col=0; col < width/4; col++) { @@ -3380,19 +3747,106 @@ /* RESTRICTED code ends here */ +void CLASS crop_masked_pixels() +{ + int row, col; + unsigned r, c, m, mblack[8], zero, val; + + if (load_raw == &CLASS phase_one_load_raw || + load_raw == &CLASS phase_one_load_raw_c) + phase_one_correct(); + if (fuji_width) { + for (row=0; row < raw_height-top_margin*2; row++) { + for (col=0; col < fuji_width << !fuji_layout; col++) { + if (fuji_layout) { + r = fuji_width - 1 - col + (row >> 1); + c = col + ((row+1) >> 1); + } else { + r = fuji_width - 1 + row - (col >> 1); + c = row + ((col+1) >> 1); + } + if (r < height && c < width) + BAYER(r,c) = RAW(row+top_margin,col+left_margin); + } + } + } else { + for (row=0; row < height; row++) + for (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) { + mask[0][1] = mask[1][1] += 2; + mask[0][3] -= 2; + goto sides; + } + if (load_raw == &CLASS canon_600_load_raw || + load_raw == &CLASS sony_load_raw || + (load_raw == &CLASS eight_bit_load_raw && strncmp(model,"DC2",3)) || + load_raw == &CLASS kodak_262_load_raw || + (load_raw == &CLASS packed_load_raw && (load_flags & 256))) { +sides: + mask[0][0] = mask[1][0] = top_margin; + mask[0][2] = mask[1][2] = top_margin+height; + mask[0][3] += left_margin; + mask[1][1] += left_margin+width; + mask[1][3] += raw_width; + } + if (load_raw == &CLASS nokia_load_raw) { + mask[0][2] = top_margin; + mask[0][3] = width; + } +mask_set: + memset (mblack, 0, sizeof mblack); + for (zero=m=0; m < 8; m++) + for (row=MAX(mask[m][0],0); row < MIN(mask[m][2],raw_height); row++) + for (col=MAX(mask[m][1],0); col < MIN(mask[m][3],raw_width); col++) { + c = FC(row-top_margin,col-left_margin); + mblack[c] += val = RAW(row,col); + mblack[4+c]++; + zero += !val; + } + if (load_raw == &CLASS canon_600_load_raw && width < raw_width) { + black = (mblack[0]+mblack[1]+mblack[2]+mblack[3]) / + (mblack[4]+mblack[5]+mblack[6]+mblack[7]) - 4; + canon_600_correct(); + } else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7]) { + FORC4 cblack[c] = mblack[c] / mblack[4+c]; + cblack[4] = cblack[5] = cblack[6] = 0; + } +} + +void CLASS remove_zeroes() +{ + unsigned row, col, tot, n, r, c; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) + if (BAYER(row,col) == 0) { + tot = n = 0; + for (r = row-2; r <= row+2; r++) + for (c = col-2; c <= col+2; c++) + if (r < height && c < width && + FC(r,c) == FC(row,col) && BAYER(r,c)) + tot += (n++,BAYER(r,c)); + if (n) BAYER(row,col) = tot/n; + } +} + /* Seach from the current directory up to the root looking for a ".badpixels" file, and fix those pixels now. */ -void CLASS bad_pixels (char *fname) +void CLASS bad_pixels (const char *cfname) { FILE *fp=0; - char *cp, line[128]; + char *fname, *cp, line[128]; int len, time, row, col, r, c, rad, tot, n, fixed=0; if (!filters) return; - if (fname) - fp = fopen (fname, "r"); + if (cfname) + fp = fopen (cfname, "r"); else { for (len=32 ; ; len *= 2) { fname = (char *) malloc (len); @@ -3428,7 +3882,7 @@ 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)) { + (r != row || c != col) && fcol(r,c) == fcol(row,col)) { tot += BAYER2(r,c); n++; } @@ -3443,7 +3897,7 @@ fclose (fp); } -void CLASS subtract (char *fname) +void CLASS subtract (const char *fname) { FILE *fp; int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; @@ -3480,17 +3934,54 @@ BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); } free (pixel); + fclose (fp); + memset (cblack, 0, sizeof cblack); black = 0; } -void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) +void CLASS gamma_curve (double pwr, double ts, int mode, int imax) { - double work[3][6], num; - int i, j, k; + int i; + double g[6], bnd[2]={0,0}, r; - for (i=0; i < 3; i++) { - for (j=0; j < 6; j++) - work[i][j] = j == i+3; + g[0] = pwr; + g[1] = ts; + g[2] = g[3] = g[4] = 0; + bnd[g[1] >= 1] = 1; + if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { + for (i=0; i < 48; i++) { + g[2] = (bnd[0] + bnd[1])/2; + if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; + else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; + } + g[3] = g[2] / g[1]; + if (g[0]) g[4] = g[2] * (1/g[0] - 1); + } + if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; + else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 + - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; + if (!mode--) { + memcpy (gamm, g, sizeof gamm); + return; + } + for (i=0; i < 0x10000; i++) { + curve[i] = 0xffff; + if ((r = (double) i / imax) < 1) + curve[i] = 0x10000 * ( mode + ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) + : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); + } +} + +void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) +{ + double work[3][6], num; + int i, j, k; + + for (i=0; i < 3; i++) { + for (j=0; j < 6; j++) + work[i][j] = j == i+3; for (j=0; j < 3; j++) for (k=0; k < size; k++) work[i][j] += in[k][i] * in[k][j]; @@ -3512,7 +4003,7 @@ out[i][j] += work[j][k+3] * in[i][k]; } -void CLASS cam_xyz_coeff (double cam_xyz[4][3]) +void CLASS cam_xyz_coeff (float rgb_cam[3][4], double cam_xyz[4][3]) { double cam_rgb[4][3], inverse[4][3], num; int i, j, k; @@ -3530,7 +4021,7 @@ pre_mul[i] = 1 / num; } pseudoinverse (cam_rgb, inverse, colors); - for (raw_color = i=0; i < 3; i++) + for (i=0; i < 3; i++) for (j=0; j < colors; j++) rgb_cam[i][j] = inverse[j][i]; } @@ -3541,31 +4032,7 @@ #define NSQ 24 // Coordinates of the GretagMacbeth ColorChecker squares // width, height, 1st_column, 1st_row - static const int cut[NSQ][4] = { - { 241, 231, 234, 274 }, - { 251, 235, 534, 274 }, - { 255, 239, 838, 272 }, - { 255, 240, 1146, 274 }, - { 251, 237, 1452, 278 }, - { 243, 238, 1758, 288 }, - { 253, 253, 218, 558 }, - { 255, 249, 524, 562 }, - { 261, 253, 830, 562 }, - { 260, 255, 1144, 564 }, - { 261, 255, 1450, 566 }, - { 247, 247, 1764, 576 }, - { 255, 251, 212, 862 }, - { 259, 259, 518, 862 }, - { 263, 261, 826, 864 }, - { 265, 263, 1138, 866 }, - { 265, 257, 1450, 872 }, - { 257, 255, 1762, 874 }, - { 257, 253, 212, 1164 }, - { 262, 251, 516, 1172 }, - { 263, 257, 826, 1172 }, - { 263, 255, 1136, 1176 }, - { 255, 252, 1452, 1182 }, - { 257, 253, 1760, 1180 } }; + int cut[NSQ][4]; // you must set these // ColorChecker Chart under 6500-kelvin illumination static const double gmb_xyY[NSQ][3] = { { 0.400, 0.350, 10.1 }, // Dark Skin @@ -3593,8 +4060,8 @@ { 0.310, 0.316, 9.0 }, // Neutral 3.5 { 0.310, 0.316, 3.1 } }; // Black double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; - double inverse[NSQ][3], cam_xyz[4][3], num; - int c, i, j, k, sq, row, col, count[4]; + double inverse[NSQ][3], cam_xyz[4][3], balance[4], num; + int c, i, j, k, sq, row, col, pass, count[4]; memset (gmb_cam, 0, sizeof gmb_cam); for (sq=0; sq < NSQ; sq++) { @@ -3603,7 +4070,8 @@ for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { c = FC(row,col); if (c >= colors) c -= 2; - gmb_cam[sq][c] += BAYER(row,col); + gmb_cam[sq][c] += BAYER2(row,col); + BAYER2(row,col) = black + (BAYER2(row,col)-black)/2; count[c]++; } FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; @@ -3613,11 +4081,16 @@ (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; } pseudoinverse (gmb_xyz, inverse, NSQ); - for (i=0; i < colors; i++) - for (j=0; j < 3; j++) - for (cam_xyz[i][j] = k=0; k < NSQ; k++) - cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; - cam_xyz_coeff (cam_xyz); + for (pass=0; pass < 2; pass++) { + for (raw_color = i=0; i < colors; i++) + for (j=0; j < 3; j++) + for (cam_xyz[i][j] = k=0; k < NSQ; k++) + cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; + cam_xyz_coeff (rgb_cam, cam_xyz); + FORCC balance[c] = pre_mul[c] * gmb_cam[20][c]; + for (sq=0; sq < NSQ; sq++) + FORCC gmb_cam[sq][c] *= balance[c]; + } if (verbose) { printf (" { \"%s %s\", %d,\n\t{", make, model, black); num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); @@ -3643,7 +4116,7 @@ void CLASS wavelet_denoise() { float *fimg=0, *temp, thold, mul[2], avg, diff; - int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast; + int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ushort *window[4]; static const float noise[] = { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; @@ -3653,6 +4126,7 @@ while (maximum << scale < 0x10000) scale++; maximum <<= --scale; black <<= scale; + FORC4 cblack[c] <<= scale; if ((size = iheight*iwidth) < 0x15550000) fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); merror (fimg, "wavelet_denoise()"); @@ -3660,12 +4134,12 @@ if ((nc = colors) == 3 && filters) nc++; FORC(nc) { /* denoise R,G1,B,G3 individually */ for (i=0; i < size; i++) - fimg[i] = sqrt((unsigned) (image[i][c] << (scale+16))); + fimg[i] = 256 * sqrt(image[i][c] << scale); for (hpass=lev=0; lev < 5; lev++) { lpass = size*((lev & 1)+1); for (row=0; row < iheight; row++) { hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); - for (col=0; col < iwidth; col++) + for (col=0; col < iwidth; col++) fimg[lpass + row*iwidth + col] = temp[col] * 0.25; } for (col=0; col < iwidth; col++) { @@ -3687,8 +4161,10 @@ image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); } if (filters && colors == 3) { /* pull G1 and G3 closer together */ - for (row=0; row < 2; row++) + for (row=0; row < 2; row++) { mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; + blk[row] = cblack[FC(row,0) | 1]; + } for (i=0; i < 4; i++) window[i] = (ushort *) fimg + width*i; for (wlast=-1, row=1; row < height-1; row++) { @@ -3701,8 +4177,8 @@ thold = threshold/512; for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { avg = ( window[0][col-1] + window[0][col+1] + - window[2][col-1] + window[2][col+1] - black*4 ) - * mul[row & 1] + (window[1][col] - black) * 0.5 + black; + window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) + * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; avg = avg < 0 ? 0 : sqrt(avg); diff = sqrt(BAYER(row,col)) - avg; if (diff < -thold) diff += thold; @@ -3736,12 +4212,12 @@ for (x=col; x < col+8 && x < right; x++) FORC4 { if (filters) { - c = FC(y,x); - val = BAYER(y,x); + c = fcol(y,x); + val = BAYER2(y,x); } else val = image[y*width+x][c]; if (val > maximum-25) goto skip_block; - if ((val -= black) < 0) val = 0; + if ((val -= cblack[c]) < 0) val = 0; sum[c] += val; sum[c+4]++; if (filters) break; @@ -3756,7 +4232,7 @@ for (row=0; row < 8; row++) for (col=0; col < 8; col++) { c = FC(row,col); - if ((val = white[row][col] - black) > 0) + if ((val = white[row][col] - cblack[c]) > 0) sum[c] += val; sum[c+4]++; } @@ -3767,6 +4243,7 @@ else fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname); } + if (pre_mul[1] == 0) pre_mul[1] = 1; if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; dark = black; sat = maximum; @@ -3786,13 +4263,20 @@ FORC4 fprintf (stderr, " %f", pre_mul[c]); fputc ('\n', stderr); } + if (filters > 1000 && (cblack[4]+1)/2 == 1 && (cblack[5]+1)/2 == 1) { + FORC4 cblack[FC(c/2,c%2)] += + cblack[6 + c/2 % cblack[4] * cblack[5] + c%2 % cblack[5]]; + cblack[4] = cblack[5] = 0; + } size = iheight*iwidth; for (i=0; i < size*4; i++) { - val = image[0][i]; - if (!val) continue; - val -= black; + if (!(val = ((ushort *)image)[i])) continue; + if (cblack[4] && cblack[5]) + val -= cblack[6 + i/4 / iwidth % cblack[4] * cblack[5] + + i/4 % iwidth % cblack[5]]; + val -= cblack[i & 3]; val *= scale_mul[i & 3]; - image[0][i] = CLIP(val); + ((ushort *)image)[i] = CLIP(val); } if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { if (verbose) @@ -3831,12 +4315,24 @@ if (half_size) { height = iheight; width = iwidth; + if (filters == 9) { + for (row=0; row < 3; row++) + for (col=1; col < 4; col++) + if (!(image[row*width+col][0] | image[row*width+col][2])) + goto break2; break2: + for ( ; row < height; row+=3) + for (col=(col-1)%3+1; col < width-1; col+=3) { + img = image + row*width+col; + for (c=0; c < 3; c+=2) + img[0][c] = (img[-1][c] + img[1][c]) >> 1; + } + } } else { - img = (ushort (*)[4]) calloc (height*width, sizeof *img); - merror (img, "unshrink()"); + img = (ushort (*)[4]) calloc (height, width*sizeof *img); + merror (img, "pre_interpolate()"); for (row=0; row < height; row++) for (col=0; col < width; col++) { - c = fc(row,col); + c = fcol(row,col); img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; } free (image); @@ -3844,8 +4340,9 @@ shrink = 0; } } - if (filters && colors == 3) { - if ((mix_green = four_color_rgb)) colors++; + if (filters > 1000 && colors == 3) { + mix_green = four_color_rgb ^ half_size; + if (four_color_rgb | half_size) colors++; else { for (row = FC(1,0) >> 1; row < height; row+=2) for (col = FC(row,1) & 1; col < width; col+=2) @@ -3868,11 +4365,11 @@ for (y=row-1; y != row+2; y++) for (x=col-1; x != col+2; x++) if (y < height && x < width) { - f = fc(y,x); + f = fcol(y,x); sum[f] += image[y*width+x][f]; sum[f+4]++; } - f = fc(row,col); + f = fcol(row,col); FORCC if (c != f && sum[c+4]) image[row*width+col][c] = sum[c] / sum[c+4]; } @@ -3880,29 +4377,31 @@ void CLASS lin_interpolate() { - int code[16][16][32], *ip, sum[4]; - int c, i, x, y, row, col, shift, color; + 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 < 16; row++) - for (col=0; col < 16; col++) { - ip = code[row][col]; + 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); - if (shift == 2) continue; - color = fc(row+y,col+x); + 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 != fc(row,col)) { + if (c != f) { *ip++ = c; *ip++ = 256 / sum[c]; } @@ -3910,9 +4409,9 @@ for (row=1; row < height-1; row++) for (col=1; col < width-1; col++) { pix = image[row*width+col]; - ip = code[row & 15][col & 15]; + ip = code[row % size][col % size]; memset (sum, 0, sizeof sum); - for (i=8; i--; ip+=3) + 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; @@ -3924,66 +4423,60 @@ "Interpolation using a Threshold-based variable number of gradients" - described in http://scien.stanford.edu/class/psych221/projects/99/tingchen/algodep/vargra.html + 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() { - struct interpolate_terms { - signed char y1, x1, y2, x2, weight; - unsigned char grads; - }; - static const struct interpolate_terms 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} - }; - const struct interpolate_terms *cpt; - signed char *cp; - signed char chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, + -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, + -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, + -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, + -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, + -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, + -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, + -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, + -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, + -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, + -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, + -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, + -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, + +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, + +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, + +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, + +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, + +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, + +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, + +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, + +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, + +1,+0,+2,+1,0,0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; ushort (*brow[5])[4], *pix; - int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; + int 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 = 15; - ip = (int *) calloc ((prow+1)*(pcol+1), 1280); + 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++) { + for (row=0; row < prow; row++) /* Precalculate for VNG */ + for (col=0; col < pcol; col++) { code[row][col] = ip; - for (cpt=&terms[0], t=0; t < 64, cpt = &terms[t]; t++) { - y1 = cpt->y1; x1 = cpt->x1; - y2 = cpt->y2; x2 = cpt->x2; - weight = cpt->weight; - grads = cpt->grads; - 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; + 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; @@ -3996,8 +4489,8 @@ for (cp=chood, g=0; g < 8; g++) { y = *cp++; x = *cp++; *ip++ = (y*width + x) * 4; - color = fc(row,col); - if (fc(row+y,col+x) != color && fc(row+y*2,col+x*2) == color) + 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; @@ -4010,7 +4503,7 @@ 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]; + 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]; @@ -4033,7 +4526,7 @@ } thold = gmin + (gmax >> 1); memset (sum, 0, sizeof sum); - color = fc(row,col); + color = fcol(row,col); for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ if (gval[g] <= thold) { FORCC @@ -4067,9 +4560,8 @@ */ void CLASS ppg_interpolate() { - int gr[4], dir[5] = { 1, width, -1, -width, 1 }; - int row, col, avg, diff[2], guess[2], c, d, i; - static const short sort[] = { 0,2,1,3,0,1,2,3 }; + int dir[5] = { 1, width, -1, -width, 1 }; + int row, col, diff[2], guess[2], c, d, i; ushort (*pix)[4]; border_interpolate(3); @@ -4079,20 +4571,6 @@ 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 (avg=i=0; i < 4; i++) - avg += gr[i] = pix[dir[i]][1] << 2; - avg >>= 2; - for (i=0; i < 8; i+=2) - if (gr[sort[i]] > gr[sort[i+1]]) - SWAP(gr[sort[i]],gr[sort[i+1]]) - for (d=0; d < 4; d++) { - for (i=-2; i < 2; i++) - if (pix[i*dir[d] + (i+1)*dir[d+1]][1] <= avg) break; - if (i == 2) { - pix[0][1] = (gr[1]+gr[2]) >> 3; - goto next_pixel; - } - } 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]; @@ -4104,7 +4582,6 @@ } d = dir[i = diff[0] > diff[1]]; pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); -next_pixel: ; } /* Calculate red and blue for each green pixel: */ for (row=1; row < height-1; row++) @@ -4132,36 +4609,288 @@ } } +void CLASS cielab (ushort rgb[3], short lab[3]) +{ + int c, i, j, k; + float r, xyz[3]; + static float cbrt[0x10000], xyz_cam[3][4]; + + if (!rgb) { + for (i=0; i < 0x10000; i++) { + r = i / 65535.0; + cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; + } + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (xyz_cam[i][j] = k=0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; + return; + } + xyz[0] = xyz[1] = xyz[2] = 0.5; + FORCC { + xyz[0] += xyz_cam[0][c] * rgb[c]; + xyz[1] += xyz_cam[1][c] * rgb[c]; + xyz[2] += xyz_cam[2][c] * rgb[c]; + } + xyz[0] = cbrt[CLIP((int) xyz[0])]; + xyz[1] = cbrt[CLIP((int) xyz[1])]; + xyz[2] = cbrt[CLIP((int) xyz[2])]; + lab[0] = 64 * (116 * xyz[1] - 16); + lab[1] = 64 * 500 * (xyz[0] - xyz[1]); + lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +} + +#define TS 512 /* Tile Size */ +#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] + +/* + Frank Markesteijn's algorithm for Fuji X-Trans sensors + */ +void CLASS xtrans_interpolate (int passes) +{ + int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; + int val, ndir, pass, hm[8], avg[4], color[3][8]; + static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, + patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, + { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, + dir[4] = { 1,TS,TS+1,TS-1 }; + short allhex[3][3][2][8], *hex; + ushort min, max, sgrow, sgcol; + ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; + short (*lab) [TS][3], (*lix)[3]; + float (*drv)[TS][TS], diff[6], tr; + char (*homo)[TS][TS], *buffer; + + if (verbose) + fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); + + cielab (0,0); + ndir = 4 << (passes > 1); + buffer = (char *) malloc (TS*TS*(ndir*11+6)); + merror (buffer, "xtrans_interpolate()"); + rgb = (ushort(*)[TS][TS][3]) buffer; + lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); + drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); + homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); + +/* Map a green hexagon around each non-green pixel and vice versa: */ + for (row=0; row < 3; row++) + for (col=0; col < 3; col++) + for (ng=d=0; d < 10; d+=2) { + g = fcol(row,col) == 1; + if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; + if (ng == 4) { sgrow = row; sgcol = col; } + if (ng == g+1) FORC(8) { + v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; + h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; + allhex[row][col][0][c^(g*2 & d)] = h + v*width; + allhex[row][col][1][c^(g*2 & d)] = h + v*TS; + } + } + +/* Set green1 and green3 to the minimum and maximum allowed values: */ + for (row=2; row < height-2; row++) + for (min=~(max=0), col=2; col < width-2; col++) { + if (fcol(row,col) == 1 && (min=~(max=0))) continue; + pix = image + row*width + col; + hex = allhex[row % 3][col % 3][0]; + if (!max) FORC(6) { + val = pix[hex[c]][1]; + if (min > val) min = val; + if (max < val) max = val; + } + pix[0][1] = min; + pix[0][3] = max; + switch ((row-sgrow) % 3) { + case 1: if (row < height-3) { row++; col--; } break; + case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; + } + } + + for (top=3; top < height-19; top += TS-16) + for (left=3; left < width-19; left += TS-16) { + mrow = MIN (top+TS, height-3); + mcol = MIN (left+TS, width-3); + for (row=top; row < mrow; row++) + for (col=left; col < mcol; col++) + memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); + FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); + +/* Interpolate green horizontally, vertically, and along both diagonals: */ + for (row=top; row < mrow; row++) + for (col=left; col < mcol; col++) { + if ((f = fcol(row,col)) == 1) continue; + pix = image + row*width + col; + hex = allhex[row % 3][col % 3][0]; + color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - + 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); + color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + + 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); + FORC(2) color[1][2+c] = + 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * + (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); + FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = + LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); + } + + for (pass=0; pass < passes; pass++) { + if (pass == 1) + memcpy (rgb+=4, buffer, 4*sizeof *rgb); + +/* Recalculate green from interpolated values of closer pixels: */ + if (pass) { + for (row=top+2; row < mrow-2; row++) + for (col=left+2; col < mcol-2; col++) { + if ((f = fcol(row,col)) == 1) continue; + pix = image + row*width + col; + hex = allhex[row % 3][col % 3][1]; + for (d=3; d < 6; d++) { + rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; + val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] + - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; + rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); + } + } + } + +/* Interpolate red and blue values for solitary green pixels: */ + for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) + for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { + rix = &rgb[0][row-top][col-left]; + h = fcol(row,col+1); + memset (diff, 0, sizeof diff); + for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { + for (c=0; c < 2; c++, h^=2) { + g = 2*rix[0][1] - rix[i<<c][1] - rix[-i<<c][1]; + color[h][d] = g + rix[i<<c][h] + rix[-i<<c][h]; + if (d > 1) + diff[d] += SQR (rix[i<<c][1] - rix[-i<<c][1] + - rix[i<<c][h] + rix[-i<<c][h]) + SQR(g); + } + if (d > 1 && (d & 1)) + if (diff[d-1] < diff[d]) + FORC(2) color[c*2][d] = color[c*2][d-1]; + if (d < 2 || (d & 1)) { + FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); + rix += TS*TS; + } + } + } + +/* Interpolate red for blue pixels and vice versa: */ + for (row=top+3; row < mrow-3; row++) + for (col=left+3; col < mcol-3; col++) { + if ((f = 2-fcol(row,col)) == 1) continue; + rix = &rgb[0][row-top][col-left]; + c = (row-sgrow) % 3 ? TS:1; + h = 3 * (c ^ TS ^ 1); + for (d=0; d < 4; d++, rix += TS*TS) { + i = d > 1 || ((d ^ c) & 1) || + ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < + 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; + rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + + 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); + } + } + +/* Fill in red and blue for 2x2 blocks of green: */ + for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) + for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { + rix = &rgb[0][row-top][col-left]; + hex = allhex[row % 3][col % 3][1]; + for (d=0; d < ndir; d+=2, rix += TS*TS) + if (hex[d] + hex[d+1]) { + g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; + for (c=0; c < 4; c+=2) rix[0][c] = + CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); + } else { + g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; + for (c=0; c < 4; c+=2) rix[0][c] = + CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); + } + } + } + rgb = (ushort(*)[TS][TS][3]) buffer; + mrow -= top; + mcol -= left; + +/* Convert to CIELab and differentiate in all directions: */ + for (d=0; d < ndir; d++) { + for (row=2; row < mrow-2; row++) + for (col=2; col < mcol-2; col++) + cielab (rgb[d][row][col], lab[row][col]); + for (f=dir[d & 3],row=3; row < mrow-3; row++) + for (col=3; col < mcol-3; col++) { + lix = &lab[row][col]; + g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; + drv[d][row][col] = SQR(g) + + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) + + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); + } + } + +/* Build homogeneity maps from the derivatives: */ + memset(homo, 0, ndir*TS*TS); + for (row=4; row < mrow-4; row++) + for (col=4; col < mcol-4; col++) { + for (tr=FLT_MAX, d=0; d < ndir; d++) + if (tr > drv[d][row][col]) + tr = drv[d][row][col]; + tr *= 8; + for (d=0; d < ndir; d++) + for (v=-1; v <= 1; v++) + for (h=-1; h <= 1; h++) + if (drv[d][row+v][col+h] <= tr) + homo[d][row][col]++; + } + +/* Average the most homogenous pixels for the final result: */ + if (height-top < TS+4) mrow = height-top+2; + if (width-left < TS+4) mcol = width-left+2; + for (row = MIN(top,8); row < mrow-8; row++) + for (col = MIN(left,8); col < mcol-8; col++) { + for (d=0; d < ndir; d++) + for (hm[d]=0, v=-2; v <= 2; v++) + for (h=-2; h <= 2; h++) + hm[d] += homo[d][row+v][col+h]; + for (d=0; d < ndir-4; d++) + if (hm[d] < hm[d+4]) hm[d ] = 0; else + if (hm[d] > hm[d+4]) hm[d+4] = 0; + for (max=hm[0],d=1; d < ndir; d++) + if (max < hm[d]) max = hm[d]; + max -= max >> 3; + memset (avg, 0, sizeof avg); + for (d=0; d < ndir; d++) + if (hm[d] >= max) { + FORC3 avg[c] += rgb[d][row][col][c]; + avg[3]++; + } + FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; + } + } + free(buffer); + border_interpolate(8); +} +#undef fcol + /* Adaptive Homogeneity-Directed interpolation is based on the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. */ -#define TS 256 /* Tile Size */ - void CLASS ahd_interpolate() { - int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; - ushort (*pix)[4], (*rix)[3]; + 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; - float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; - ushort (*rgb)[TS][TS][3]; + 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")); - for (i=0; i < 0x10000; i++) { - r = i / 65535.0; - cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; - } - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (xyz_cam[i][j] = k=0; k < 3; k++) - xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; - + cielab (0,0); border_interpolate(5); - buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ + 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); @@ -4171,7 +4900,7 @@ for (left=2; left < width-5; left += TS-6) { /* Interpolate green horizontally and vertically: */ - for (row = top; row < top+TS && row < height-2; row++) { + 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; @@ -4205,18 +4934,7 @@ rix[0][c] = CLIP(val); c = FC(row,col); rix[0][c] = pix[0][c]; - xyz[0] = xyz[1] = xyz[2] = 0.5; - FORCC { - xyz[0] += xyz_cam[0][c] * rix[0][c]; - xyz[1] += xyz_cam[1][c] * rix[0][c]; - xyz[2] += xyz_cam[2][c] * rix[0][c]; - } - xyz[0] = cbrt[CLIP((int) xyz[0])]; - xyz[1] = cbrt[CLIP((int) xyz[1])]; - xyz[2] = cbrt[CLIP((int) xyz[2])]; - lix[0][0] = 64 * (116 * xyz[1] - 16); - lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]); - lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]); + cielab (rix[0],lix[0]); } /* Build homogeneity maps from the CIELab images: */ memset (homo, 0, 2*TS*TS); @@ -4263,7 +4981,7 @@ } #undef TS -void CLASS median_filter () +void CLASS median_filter() { ushort (*pix)[4]; int pass, c, i, j, k, med[9]; @@ -4346,7 +5064,7 @@ if (pre_mul[kc] < pre_mul[c]) kc = c; high = height / SCALE; wide = width / SCALE; - map = (float *) calloc (high*wide, sizeof *map); + map = (float *) calloc (high, wide*sizeof *map); merror (map, "recover_highlights()"); FORCC if (c != kc) { memset (map, 0, high*wide*sizeof *map); @@ -4413,7 +5131,7 @@ *type = get2(); *len = get4(); *save = ftell(ifp) + 4; - if (*len * ("11124811248488"[*type < 14 ? *type:0]-'0') > 4) + if (*len * ("11124811248484"[*type < 14 ? *type:0]-'0') > 4) fseek (ifp, get4()+base, SEEK_SET); } @@ -4470,12 +5188,13 @@ unsigned offset=0, entries, tag, type, len, save, c; unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; uchar buf97[324], ci, cj, ck; - short sorder=order; + short morder, sorder=order; char buf[10]; /* The MakerNote might have its own TIFF header (possibly with its own byte-order!), or it might just be a table. */ + if (!strcmp(make,"Nokia")) return; fread (buf, 1, 10, ifp); if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ !strncmp (buf,"VER" ,3) || @@ -4499,14 +5218,18 @@ if (get2() != 42) goto quit; offset = get4(); fseek (ifp, offset-8, SEEK_CUR); - } else if (!strcmp (buf,"OLYMPUS")) { + } else if (!strcmp (buf,"OLYMPUS") || + !strcmp (buf,"PENTAX ")) { base = ftell(ifp)-10; fseek (ifp, -2, SEEK_CUR); - order = get2(); get2(); - } else if (!strncmp (buf,"FUJIFILM",8) || - !strncmp (buf,"SONY",4) || + order = get2(); + if (buf[0] == 'O') get2(); + } else if (!strncmp (buf,"SONY",4) || !strcmp (buf,"Panasonic")) { - order = 0x4949; + goto nf; + } else if (!strncmp (buf,"FUJIFILM",8)) { + base = ftell(ifp)-10; +nf: order = 0x4949; fseek (ifp, 2, SEEK_CUR); } else if (!strcmp (buf,"OLYMP") || !strcmp (buf,"LEICA") || @@ -4516,31 +5239,52 @@ else if (!strcmp (buf,"AOC") || !strcmp (buf,"QVC")) fseek (ifp, -4, SEEK_CUR); - else fseek (ifp, -10, SEEK_CUR); - + else { + fseek (ifp, -10, SEEK_CUR); + if (!strncmp(make,"SAMSUNG",7)) + base = ftell(ifp); + } entries = get2(); if (entries > 1000) return; + morder = order; while (entries--) { + order = morder; tiff_get (base, &tag, &type, &len, &save); tag |= uptag << 16; - if (tag == 2 && strstr(make,"NIKON")) + if (tag == 2 && strstr(make,"NIKON") && !iso_speed) iso_speed = (get2(),get2()); if (tag == 4 && len > 26 && len < 35) { - iso_speed = 50 * pow (2, (get4(),get2())/32.0 - 4); - if ((i=(get2(),get2())) != 0x7fff) + if ((i=(get4(),get2())) != 0x7fff && !iso_speed) + iso_speed = 50 * pow (2, i/32.0 - 4); + if ((i=(get2(),get2())) != 0x7fff && !aperture) aperture = pow (2, i/64.0); - if ((i=get2()) != 0xffff) + if ((i=get2()) != 0xffff && !shutter) shutter = pow (2, (short) i/-32.0); wbi = (get2(),get2()); shot_order = (get2(),get2()); } + if ((tag == 4 || tag == 0x114) && !strncmp(make,"KONICA",6)) { + fseek (ifp, tag == 4 ? 140:160, SEEK_CUR); + switch (get2()) { + case 72: flip = 0; break; + case 76: flip = 6; break; + case 82: flip = 5; break; + } + } + if (tag == 7 && type == 2 && len > 20) + fgets (model2, 64, ifp); if (tag == 8 && type == 4) shot_order = get4(); if (tag == 9 && !strcmp(make,"Canon")) fread (artist, 64, 1, ifp); - if (tag == 0xc && len == 4) { - cam_mul[0] = getreal(type); - cam_mul[2] = getreal(type); + if (tag == 0xc && len == 4) + FORC3 cam_mul[(c << 1 | c >> 1) & 3] = getreal(type); + if (tag == 0xd && type == 7 && get2() == 0xaaaa) { + for (c=i=2; (ushort) c != 0xbbbb && i < len; i++) + c = c << 8 | fgetc(ifp); + while ((i+=4) < len-5) + if (get4() == 257 && (i=len) && (c = (get4(),fgetc(ifp))) < 3) + flip = "065"[c]-'0'; } if (tag == 0x10 && type == 4) unique_id = get4(); @@ -4548,9 +5292,18 @@ fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base); } - if (tag == 0x14 && len == 2560 && type == 7) { - fseek (ifp, 1248, SEEK_CUR); - goto get2_256; + if (tag == 0x14 && type == 7) { + if (len == 2560) { + fseek (ifp, 1248, SEEK_CUR); + goto get2_256; + } + fread (buf, 1, 10, ifp); + if (!strncmp(buf,"NRW ",4)) { + fseek (ifp, strcmp(buf+4,"0100") ? 46:1546, SEEK_CUR); + cam_mul[0] = get4() << 2; + cam_mul[1] = get4() + get4(); + cam_mul[2] = get4() << 2; + } } if (tag == 0x15 && type == 2 && is_raw) fread (model, 64, 1, ifp); @@ -4561,6 +5314,13 @@ if (tag == 0x1d) while ((c = fgetc(ifp)) && c != EOF) serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); + if (tag == 0x29 && type == 1) { + c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; + fseek (ifp, 8 + c*32, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); + } + if (tag == 0x3d && type == 3 && len == 4) + FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_bps); if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); @@ -4568,11 +5328,6 @@ raw_width = get2(); filters = 0x61616161; } - if (tag == 0x29 && type == 1) { - c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; - fseek (ifp, 8 + c*32, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); - } if ((tag == 0x81 && type == 7) || (tag == 0x100 && type == 7) || (tag == 0x280 && type == 1)) { @@ -4587,51 +5342,55 @@ meta_offset = ftell(ifp); if (tag == 0x97) { for (i=0; i < 4; i++) - ver97 = (ver97 << 4) + fgetc(ifp)-'0'; + ver97 = ver97 * 10 + fgetc(ifp)-'0'; switch (ver97) { - case 0x100: + case 100: fseek (ifp, 68, SEEK_CUR); FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); break; - case 0x102: + case 102: fseek (ifp, 6, SEEK_CUR); - goto get2_rggb; - case 0x103: + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + break; + case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); } - if (ver97 >> 8 == 2) { - if (ver97 != 0x205) fseek (ifp, 280, SEEK_CUR); + if (ver97 >= 200) { + if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); fread (buf97, 324, 1, ifp); } } + if (tag == 0xa1 && type == 7) { + order = 0x4949; + fseek (ifp, 140, SEEK_CUR); + FORC3 cam_mul[c] = get4(); + } if (tag == 0xa4 && type == 3) { fseek (ifp, wbi*48, SEEK_CUR); FORC3 cam_mul[c] = get2(); } - if (tag == 0xa7 && ver97 >> 8 == 2) { + if (tag == 0xa7 && (unsigned) (ver97-200) < 17) { ci = xlat[0][serial & 0xff]; cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)]; ck = 0x60; for (i=0; i < 324; i++) buf97[i] ^= (cj += ci * ck++); - FORC4 cam_mul[c ^ (c >> 1)] = - sget2 (buf97 + (ver97 == 0x205 ? 14:6) + c*2); - if (ver97 == 0x209) - FORC4 cam_mul[c ^ (c >> 1) ^ 1] = - sget2 (buf97 + 10 + c*2); + i = "66666>666;6A;:;55"[ver97-200] - '0'; + FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = + sget2 (buf97 + (i & -2) + c*2); } if (tag == 0x200 && len == 3) shot_order = (get4(),get4()); if (tag == 0x200 && len == 4) - black = (get2()+get2()+get2()+get2())/4; + FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) - goto get2_rggb; - if (tag == 0x401 && len == 4) { - black = (get4()+get4()+get4()+get4())/4; - } + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + if (tag == 0x220 && type == 7) + meta_offset = ftell(ifp); + if (tag == 0x401 && type == 4 && len == 4) + FORC4 cblack[c ^ c >> 1] = get4(); if (tag == 0xe01) { /* Nikon Capture Note */ - type = order; order = 0x4949; fseek (ifp, 22, SEEK_CUR); for (offset=22; offset+22 < len; offset += 22+i) { @@ -4641,7 +5400,6 @@ if (tag == 0x76a43207) flip = get2(); else fseek (ifp, i, SEEK_CUR); } - order = type; } if (tag == 0xe80 && len == 256 && type == 7) { fseek (ifp, 48, SEEK_CUR); @@ -4660,8 +5418,7 @@ for (i=0; i < 3; i++) FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; if ((tag == 0x1012 || tag == 0x20400600) && len == 4) - for (black = i=0; i < 4; i++) - black += get2() << 2; + FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x1017 || tag == 0x20400100) cam_mul[0] = get2() / 256.0; if (tag == 0x1018 || tag == 0x20400100) @@ -4672,22 +5429,34 @@ cam_mul[0] = get2() / 256.0; cam_mul[2] = get2() / 256.0; } - if (tag == 0x2020) + if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) + fseek (ifp, get4()+base, SEEK_SET); + if (tag == 0x2020 && !strncmp(buf,"OLYMP",5)) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); if (tag == 0xb028) { - fseek (ifp, get4(), SEEK_SET); + fseek (ifp, get4()+base, SEEK_SET); parse_thumb_note (base, 136, 137); } - if (tag == 0x4001 && type == 3) { - i = len == 582 ? 50 : len == 653 ? 68 : 126; + if (tag == 0x4001 && len > 500) { + i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; fseek (ifp, i, SEEK_CUR); -get2_rggb: FORC4 cam_mul[c ^ (c >> 1)] = get2(); - fseek (ifp, 22, SEEK_CUR); - FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + for (i+=18; i <= len; i+=10) { + get2(); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + if (sraw_mul[1] == 1170) break; + } } + if (tag == 0x4021 && get4() && get4()) + FORC4 cam_mul[c] = 1024; + if (tag == 0xa021) + FORC4 cam_mul[c ^ (c >> 1)] = get4(); + if (tag == 0xa028) + FORC4 cam_mul[c ^ (c >> 1)] -= get4(); + if (tag == 0xb001) + unique_id = get2(); next: fseek (ifp, save, SEEK_SET); } @@ -4716,6 +5485,7 @@ return; t.tm_year -= 1900; t.tm_mon -= 1; + t.tm_isdst = -1; if (mktime(&t) > 0) timestamp = mktime(&t); } @@ -4725,17 +5495,19 @@ unsigned kodak, entries, tag, type, len, save, c; double expo; - kodak = !strncmp(make,"EASTMAN",7); + kodak = !strncmp(make,"EASTMAN",7) && tiff_nifds < 3; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); switch (tag) { - case 33434: shutter = getreal(type); break; + case 33434: tiff_ifd[tiff_nifds-1].shutter = + shutter = getreal(type); break; case 33437: aperture = getreal(type); break; case 34855: iso_speed = get2(); break; case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128) + tiff_ifd[tiff_nifds-1].shutter = shutter = pow (2, expo); break; case 37378: aperture = pow (2, getreal(type)/2); break; case 37386: focal_len = getreal(type); break; @@ -4793,7 +5565,9 @@ static const char *mod[] = { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", - "Aptus 54S","Aptus 65S","Aptus 75S" }; + "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7", + "AFi-II 7","Aptus-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]; fseek (ifp, offset, SEEK_SET); @@ -4818,12 +5592,12 @@ } if (!strcmp(data,"icc_camera_to_tone_matrix")) { for (i=0; i < 9; i++) - romm_cam[0][i] = int_to_float(get4()); + ((float *)romm_cam)[i] = int_to_float(get4()); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_color_matrix")) { for (i=0; i < 9; i++) - fscanf (ifp, "%f", &romm_cam[0][i]); + fscanf (ifp, "%f", (float *)romm_cam + i); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_number_of_planes")) @@ -4843,6 +5617,8 @@ FORC4 fscanf (ifp, "%d", neut+c); FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; } + if (!strcmp(data,"Rows_data")) + load_flags = get4(); parse_mos (from); fseek (ifp, skip+from, SEEK_SET); } @@ -4865,7 +5641,8 @@ { unsigned entries, tag, type, len, save; int i, c, wbi=-2, wbtemp=6500; - float mul[3], num; + float mul[3]={1,1,1}, num; + static const int wbtag[] = { 64037,64040,64039,64041,-1,-1,64042 }; entries = get2(); if (entries > 1024) return; @@ -4878,6 +5655,8 @@ wbi = -2; } if (tag == 2118) wbtemp = getint(type); + if (tag == 2120 + wbi && wbi >= 0) + FORC3 cam_mul[c] = 2048.0 / getreal(type); if (tag == 2130 + wbi) FORC3 mul[c] = getreal(type); if (tag == 2140 + wbi && wbi >= 0) @@ -4888,11 +5667,17 @@ } if (tag == 2317) linear_table (len); if (tag == 6020) iso_speed = getint(type); + if (tag == 64013) wbi = fgetc(ifp); + if ((unsigned) wbi < 7 && tag == wbtag[wbi]) + FORC3 cam_mul[c] = get4(); + if (tag == 64019) width = getint(type); + if (tag == 64020) height = (getint(type)+1) & -2; fseek (ifp, save, SEEK_SET); } } void CLASS parse_minolta (int base); +int CLASS parse_tiff (int base); int CLASS parse_tiff_ifd (int base) { @@ -4900,7 +5685,7 @@ int ifd, use_cm=0, cfa, i, j, c, ima_len=0; char software[64], *cbuf, *cp; uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; - double dblack, cc[4][4], cm[4][3], cam_xyz[4][3], num; + double cc[4][4], cm[4][3], cam_xyz[4][3], num; double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; unsigned sony_curve[] = { 0,0,0,0,0,4095 }; unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; @@ -4918,6 +5703,10 @@ while (entries--) { tiff_get (base, &tag, &type, &len, &save); switch (tag) { + case 5: width = get2(); break; + case 6: height = get2(); break; + case 7: width += get2(); break; + case 9: if ((i = get2())) filters = i; break; case 17: case 18: if (type == 3 && len == 1) cam_mul[(tag-17)*2] = get2() / 256.0; @@ -4925,8 +5714,12 @@ case 23: if (type == 3) iso_speed = get2(); break; + case 28: case 29: case 30: + cblack[tag-28] = get2(); + cblack[3] = cblack[1]; + break; case 36: case 37: case 38: - cam_mul[tag-0x24] = get2(); + cam_mul[tag-36] = get2(); break; case 39: if (len < 50 || cam_mul[0]) break; @@ -4938,18 +5731,30 @@ thumb_offset = ftell(ifp) - 2; thumb_length = len; break; - case 2: case 256: /* ImageWidth */ + case 61440: /* Fuji HS10 table */ + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base); + break; + case 2: case 256: case 61441: /* ImageWidth */ tiff_ifd[ifd].width = getint(type); break; - case 3: case 257: /* ImageHeight */ + case 3: case 257: case 61442: /* ImageHeight */ tiff_ifd[ifd].height = getint(type); break; case 258: /* BitsPerSample */ + case 61443: tiff_ifd[ifd].samples = len & 7; - tiff_ifd[ifd].bps = get2(); + if ((tiff_ifd[ifd].bps = getint(type)) > 32) + tiff_ifd[ifd].bps = 8; + if (tiff_bps < tiff_ifd[ifd].bps) + tiff_bps = tiff_ifd[ifd].bps; + break; + case 61446: + raw_height = 0; + load_flags = get4() ? 24:80; break; case 259: /* Compression */ - tiff_ifd[ifd].comp = get2(); + tiff_ifd[ifd].comp = getint(type); break; case 262: /* PhotometricInterpretation */ tiff_ifd[ifd].phint = get2(); @@ -4963,21 +5768,35 @@ case 272: /* Model */ fgets (model, 64, ifp); break; + case 280: /* Panasonic RW2 offset */ + if (type != 4) break; + load_raw = &CLASS panasonic_load_raw; + load_flags = 0x2008; case 273: /* StripOffset */ - case 513: + case 513: /* JpegIFOffset */ + case 61447: tiff_ifd[ifd].offset = get4()+base; - if (!tiff_ifd[ifd].bps) { + if (!tiff_ifd[ifd].bps && tiff_ifd[ifd].offset > 0) { fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { tiff_ifd[ifd].comp = 6; - tiff_ifd[ifd].width = jh.wide << (jh.clrs == 2); + tiff_ifd[ifd].width = jh.wide; tiff_ifd[ifd].height = jh.high; tiff_ifd[ifd].bps = jh.bits; tiff_ifd[ifd].samples = jh.clrs; + if (!(jh.sraw || (jh.clrs & 1))) + tiff_ifd[ifd].width *= jh.clrs; + if ((tiff_ifd[ifd].width > 4*tiff_ifd[ifd].height) & ~jh.clrs) { + tiff_ifd[ifd].width /= 2; + tiff_ifd[ifd].height *= 2; + } + i = order; + parse_tiff (tiff_ifd[ifd].offset + 12); + order = i; } } break; - case 274: /* Qt::Orientation */ + case 274: /* Orientation */ tiff_ifd[ifd].flip = "50132467"[get2() & 7]-'0'; break; case 277: /* SamplesPerPixel */ @@ -4985,12 +5804,17 @@ break; case 279: /* StripByteCounts */ case 514: + case 61448: tiff_ifd[ifd].bytes = get4(); break; - case 305: /* Software */ + case 61454: + FORC3 cam_mul[(4-c) % 3] = getint(type); + break; + case 305: case 11: /* Software */ fgets (software, 64, ifp); if (!strncmp(software,"Adobe",5) || !strncmp(software,"dcraw",5) || + !strncmp(software,"UFRaw",5) || !strncmp(software,"Bibble",6) || !strncmp(software,"Nikon Scan",10) || !strcmp (software,"Digital Photo Professional")) @@ -5003,13 +5827,15 @@ fread (artist, 64, 1, ifp); break; case 322: /* TileWidth */ - tile_width = getint(type); + tiff_ifd[ifd].tile_width = getint(type); break; case 323: /* TileLength */ - tile_length = getint(type); + tiff_ifd[ifd].tile_length = getint(type); break; case 324: /* TileOffsets */ tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); + if (len == 1) + tiff_ifd[ifd].tile_width = tiff_ifd[ifd].tile_length = 0; if (len == 4) { load_raw = &CLASS sinar_4shot_load_raw; is_raw = 5; @@ -5017,6 +5843,7 @@ break; case 330: /* SubIFDs */ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { + load_raw = &CLASS sony_arw_load_raw; data_offset = get4()+base; ifd++; break; } @@ -5047,14 +5874,27 @@ case 29443: FORC4 cam_mul[c ^ (c < 2)] = get2(); break; + case 29459: + FORC4 cam_mul[c] = get2(); + i = (cam_mul[1] == 1024 && cam_mul[2] == 1024) << 1; + SWAP (cam_mul[i],cam_mul[i+1]) + break; case 33405: /* Model2 */ fgets (model2, 64, ifp); break; + case 33421: /* CFARepeatPatternDim */ + if (get2() == 6 && get2() == 6) + filters = 9; + break; case 33422: /* CFAPattern */ + if (filters == 9) { + FORC(36) ((char *)xtrans)[c] = fgetc(ifp) & 3; + break; + } case 64777: /* Kodak P-series */ if ((plen=len) > 16) plen = 16; fread (cfa_pat, 1, plen, ifp); - for (colors=cfa=i=0; i < plen; i++) { + for (colors=cfa=i=0; i < plen && colors < 4; i++) { colors += !(cfa & (1 << cfa_pat[i])); cfa |= 1 << cfa_pat[i]; } @@ -5062,11 +5902,12 @@ if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ goto guess_cfa_pc; case 33424: + case 65024: fseek (ifp, get4()+base, SEEK_SET); parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ - shutter = getreal(type); + tiff_ifd[ifd].shutter = shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); @@ -5119,13 +5960,24 @@ FORC3 rgb_cam[i][c] = getreal(type); } break; + case 40976: + strip_offset = get4(); + switch (tiff_ifd[ifd].comp) { + case 32770: load_raw = &CLASS samsung_load_raw; break; + case 32772: load_raw = &CLASS samsung2_load_raw; break; + case 32773: load_raw = &CLASS samsung3_load_raw; break; + } + break; case 46275: /* Imacon tags */ strcpy (make, "Imacon"); data_offset = ftell(ifp); ima_len = len; break; case 46279: - fseek (ifp, 78, SEEK_CUR); + if (!ima_len) break; + fseek (ifp, 38, SEEK_CUR); + case 46274: + fseek (ifp, 40, SEEK_CUR); raw_width = get4(); raw_height = get4(); left_margin = get4() & 7; @@ -5143,7 +5995,9 @@ flip = (get2() >> 7) * 90; if (width * height * 6 == ima_len) { if (flip % 180 == 90) SWAP(width,height); - filters = flip = 0; + raw_width = width; + raw_height = height; + left_margin = top_margin = filters = flip = 0; } sprintf (model, "Ixpress %d-Mp", height*width/1000000); load_raw = &CLASS imacon_full_load_raw; @@ -5162,6 +6016,9 @@ sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); free (cbuf); break; + case 50458: + if (!make[0]) strcpy (make, "Hasselblad"); + break; case 50459: /* Hasselblad tag */ i = order; j = ftell(ifp); @@ -5175,8 +6032,19 @@ break; case 50706: /* DNGVersion */ FORC4 dng_version = (dng_version << 8) + fgetc(ifp); + if (!make[0]) strcpy (make, "DNG"); + is_raw = 1; + break; + case 50708: /* UniqueCameraModel */ + if (model[0]) break; + fgets (make, 64, ifp); + if ((cp = strchr(make,' '))) { + strcpy(model,cp+1); + *cp = 0; + } break; case 50710: /* CFAPlaneColor */ + if (filters == 9) break; if (len > 4) len = 4; colors = len; fread (cfa_pc, 1, colors, ifp); @@ -5185,23 +6053,35 @@ cdesc[c] = 0; for (i=16; i--; ) filters = filters << 2 | tab[cfa_pat[i % plen]]; + filters -= !filters; break; case 50711: /* CFALayout */ - if (get2() == 2) { - fuji_width = 1; - filters = 0x49494949; - } + if (get2() == 2) fuji_width = 1; break; case 291: case 50712: /* LinearizationTable */ linear_table (len); break; + case 50713: /* BlackLevelRepeatDim */ + cblack[4] = get2(); + cblack[5] = get2(); + if (cblack[4] * cblack[5] > sizeof cblack / sizeof *cblack - 6) + cblack[4] = cblack[5] = 1; + break; + case 61450: + cblack[4] = cblack[5] = MIN(sqrt(len),64); case 50714: /* BlackLevel */ + if (!(cblack[4] * cblack[5])) + cblack[4] = cblack[5] = 1; + FORC (cblack[4] * cblack[5]) + cblack[6+c] = getreal(type); + black = 0; + break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ - for (dblack=i=0; i < len; i++) - dblack += getreal(type); - black += dblack/len + 0.5; + for (num=i=0; i < (len & 0xffff); i++) + num += getreal(type); + black += num/len + 0.5; break; case 50717: /* WhiteLevel */ maximum = getint(type); @@ -5220,6 +6100,7 @@ case 50724: /* CameraCalibration2 */ for (i=0; i < colors; i++) FORCC cc[i][c] = getreal(type); + break; case 50727: /* AnalogBalance */ FORCC ab[c] = getreal(type); break; @@ -5247,12 +6128,24 @@ height = getint(type) - top_margin; width = getint(type) - left_margin; break; + case 50830: /* MaskedAreas */ + for (i=0; i < len && i < 32; i++) + ((int *)mask)[i] = getint(type); + black = 0; + break; + case 51009: /* OpcodeList2 */ + meta_offset = ftell(ifp); + break; case 64772: /* Kodak P-series */ + if (len < 13) break; fseek (ifp, 16, SEEK_CUR); data_offset = get4(); fseek (ifp, 28, SEEK_CUR); data_offset += get4(); - load_raw = &CLASS packed_12_load_raw; + load_raw = &CLASS packed_load_raw; + break; + case 65026: + if (type == 2) fgets (model2, 64, ifp); } fseek (ifp, save, SEEK_SET); } @@ -5276,7 +6169,7 @@ FORCC for (i=0; i < 3; i++) for (cam_xyz[c][i]=j=0; j < colors; j++) cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; - cam_xyz_coeff (cam_xyz); + cam_xyz_coeff (cmatrix, cam_xyz); } if (asn[0]) { cam_mul[3] = 0; @@ -5287,21 +6180,26 @@ return 0; } -void CLASS parse_tiff (int base) +int CLASS parse_tiff (int base) { - int doff, max_samp=0, raw=-1, thm=-1, i; - struct jhead jh; + int doff; fseek (ifp, base, SEEK_SET); order = get2(); - if (order != 0x4949 && order != 0x4d4d) return; + if (order != 0x4949 && order != 0x4d4d) return 0; get2(); - memset (tiff_ifd, 0, sizeof tiff_ifd); - tiff_nifds = 0; while ((doff = get4())) { fseek (ifp, doff+base, SEEK_SET); if (parse_tiff_ifd (base)) break; } + return 1; +} + +void CLASS apply_tiff() +{ + int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; + struct jhead jh; + thumb_misc = 16; if (thumb_offset) { fseek (ifp, thumb_offset, SEEK_SET); @@ -5311,12 +6209,25 @@ thumb_height = jh.high; } } + for (i=tiff_nifds; i--; ) { + if (tiff_ifd[i].shutter) + shutter = tiff_ifd[i].shutter; + tiff_ifd[i].shutter = shutter; + } for (i=0; i < tiff_nifds; i++) { if (max_samp < tiff_ifd[i].samples) max_samp = tiff_ifd[i].samples; if (max_samp > 3) max_samp = 3; + os = raw_width*raw_height; + ns = tiff_ifd[i].width*tiff_ifd[i].height; + if (tiff_bps) { + os *= tiff_bps; + ns *= tiff_ifd[i].bps; + } if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && - tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { + (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && + ns && ((ns > os && (ties = 1)) || + (ns == os && shot_select == ties++))) { raw_width = tiff_ifd[i].width; raw_height = tiff_ifd[i].height; tiff_bps = tiff_ifd[i].bps; @@ -5324,60 +6235,105 @@ data_offset = tiff_ifd[i].offset; tiff_flip = tiff_ifd[i].flip; tiff_samples = tiff_ifd[i].samples; + tile_width = tiff_ifd[i].tile_width; + tile_length = tiff_ifd[i].tile_length; + shutter = tiff_ifd[i].shutter; raw = i; } } - fuji_width *= (raw_width+1)/2; - if (tiff_ifd[0].flip) tiff_flip = tiff_ifd[0].flip; + if (is_raw == 1 && ties) is_raw = ties; + if (!tile_width ) tile_width = INT_MAX; + if (!tile_length) tile_length = INT_MAX; + for (i=tiff_nifds; i--; ) + if (tiff_ifd[i].flip) tiff_flip = tiff_ifd[i].flip; if (raw >= 0 && !load_raw) switch (tiff_compress) { + case 32767: + if (tiff_ifd[raw].bytes == raw_width*raw_height) { + tiff_bps = 12; + maximum = 4095; + load_raw = &CLASS sony_arw2_load_raw; break; + } + if (tiff_ifd[raw].bytes*8 != raw_width*raw_height*tiff_bps) { + raw_height += 8; + load_raw = &CLASS sony_arw_load_raw; break; + } + load_flags = 79; + case 32769: + load_flags++; + case 32770: + case 32773: goto slr; case 0: case 1: + if (!strncmp(make,"OLYMPUS",7) && + tiff_ifd[raw].bytes*2 == raw_width*raw_height*3) + load_flags = 24; + if (!strcmp(make,"SONY") && tiff_bps < 14 && + tiff_ifd[raw].bytes == raw_width*raw_height*2) + tiff_bps = 14; + if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { + load_flags = 81; + tiff_bps = 12; + } slr: switch (tiff_bps) { case 8: load_raw = &CLASS eight_bit_load_raw; break; - case 12: load_raw = &CLASS packed_12_load_raw; - if (!strncmp(make,"NIKON",5)) - load_raw = &CLASS nikon_load_raw; - if (strncmp(make,"PENTAX",6)) break; - case 14: - case 16: load_raw = &CLASS unpacked_load_raw; break; - } - if (tiff_ifd[raw].bytes * 5 == raw_width * raw_height * 8) - load_raw = &CLASS olympus_e300_load_raw; - if (tiff_bps == 12 && tiff_ifd[raw].phint == 2) - load_raw = &CLASS olympus_cseries_load_raw; + case 12: if (tiff_ifd[raw].phint == 2) + load_flags = 6; + load_raw = &CLASS packed_load_raw; break; + case 14: load_raw = &CLASS packed_load_raw; + if (tiff_ifd[raw].bytes*4 == raw_width*raw_height*7) break; + load_flags = 0; + case 16: load_raw = &CLASS unpacked_load_raw; + if (!strncmp(make,"OLYMPUS",7) && + tiff_ifd[raw].bytes*7 > raw_width*raw_height) + load_raw = &CLASS olympus_load_raw; + } + if (filters == 9 && tiff_ifd[raw].bytes*8 < raw_width*raw_height*tiff_bps) + load_raw = &CLASS fuji_xtrans_load_raw; break; case 6: case 7: case 99: load_raw = &CLASS lossless_jpeg_load_raw; break; case 262: load_raw = &CLASS kodak_262_load_raw; break; - case 32767: - load_raw = &CLASS sony_arw2_load_raw; break; - case 32769: - load_raw = &CLASS nikon_load_raw; break; - case 32773: - load_raw = &CLASS packed_12_load_raw; break; case 34713: - load_raw = &CLASS nikon_compressed_load_raw; break; + if ((raw_width+9)/10*16*raw_height == tiff_ifd[raw].bytes) { + load_raw = &CLASS packed_load_raw; + load_flags = 1; + } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes*2) { + load_raw = &CLASS packed_load_raw; + if (model[0] == 'N') load_flags = 80; + } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes) { + load_raw = &CLASS nikon_yuv_load_raw; + gamma_curve (1/2.4, 12.92, 1, 4095); + memset (cblack, 0, sizeof cblack); + filters = 0; + } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) { + load_raw = &CLASS unpacked_load_raw; + load_flags = 4; + order = 0x4d4d; + } else + load_raw = &CLASS nikon_load_raw; break; case 65535: - load_raw = &CLASS pentax_k10_load_raw; break; + load_raw = &CLASS pentax_load_raw; break; case 65000: switch (tiff_ifd[raw].phint) { case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; case 32803: load_raw = &CLASS kodak_65000_load_raw; } - case 32867: break; + case 32867: case 34892: break; default: is_raw = 0; } - if (!dng_version && tiff_samples == 3) - if (tiff_ifd[raw].bytes && tiff_bps != 14 && tiff_bps != 2048) + if (!dng_version) + if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && + (tiff_compress & -16) != 32768) + || (tiff_bps == 8 && strncmp(make,"Phase",5) && + !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) is_raw = 0; - if (!dng_version && tiff_bps == 8 && tiff_compress == 1 && - tiff_ifd[raw].phint == 1) is_raw = 0; for (i=0; i < tiff_nifds; i++) if (i != raw && tiff_ifd[i].samples == max_samp && - tiff_ifd[i].width * tiff_ifd[i].height / SQR(tiff_ifd[i].bps+1) > - thumb_width * thumb_height / SQR(thumb_misc+1)) { + tiff_ifd[i].width * tiff_ifd[i].height / (SQR(tiff_ifd[i].bps)+1) > + thumb_width * thumb_height / (SQR(thumb_misc)+1) + && tiff_ifd[i].comp != 34892) { thumb_width = tiff_ifd[i].width; thumb_height = tiff_ifd[i].height; thumb_offset = tiff_ifd[i].offset; @@ -5392,10 +6348,12 @@ write_thumb = &CLASS layer_thumb; break; case 1: - if (tiff_ifd[thm].bps > 8) - thumb_load_raw = &CLASS kodak_thumb_load_raw; - else + if (tiff_ifd[thm].bps <= 8) write_thumb = &CLASS ppm_thumb; + else if (!strcmp(make,"Imacon")) + write_thumb = &CLASS ppm16_thumb; + else + thumb_load_raw = &CLASS kodak_thumb_load_raw; break; case 65000: thumb_load_raw = tiff_ifd[thm].phint == 6 ? @@ -5425,7 +6383,7 @@ break; case 0x574247: /* WBG */ get4(); - i = strstr(model,"A200") ? 3:0; + i = strcmp(model,"DiMAGE A200") ? 0:3; FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); break; case 0x545457: /* TTW */ @@ -5446,7 +6404,8 @@ */ void CLASS parse_external_jpeg() { - char *file, *ext, *jname, *jfile, *jext; + const char *file, *ext; + char *jname, *jfile, *jext; FILE *save=ifp; ext = strrchr (ifname, '.'); @@ -5456,18 +6415,20 @@ file++; if (!ext || strlen(ext) != 4 || ext-file != 8) return; jname = (char *) malloc (strlen(ifname) + 1); - merror (jname, "parse_external()"); + merror (jname, "parse_external_jpeg()"); strcpy (jname, ifname); jfile = file - ifname + jname; jext = ext - ifname + jname; if (strcasecmp (ext, ".jpg")) { strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); - memcpy (jfile, file+4, 4); - memcpy (jfile+4, file, 4); + if (isdigit(*file)) { + memcpy (jfile, file+4, 4); + memcpy (jfile+4, file, 4); + } } else while (isdigit(*--jext)) { if (*jext != '9') { - (*jext)++; + (*jext)++; break; } *jext = '0'; @@ -5507,16 +6468,14 @@ bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } - white[row][col] = - bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); - vbits -= bpp; + white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); } } /* Parse a CIFF file, better known as Canon CRW format. */ -void CLASS parse_ciff (int offset, int length) +void CLASS parse_ciff (int offset, int length, int depth) { int tboff, nrecs, c, type, len, save, wbi=-1; ushort key[] = { 0x410, 0x45f3 }; @@ -5525,15 +6484,14 @@ tboff = get4() + offset; fseek (ifp, tboff, SEEK_SET); nrecs = get2(); - if (nrecs > 100) return; + if ((nrecs | depth) > 127) return; while (nrecs--) { type = get2(); len = get4(); save = ftell(ifp) + 4; fseek (ifp, offset+get4(), SEEK_SET); if ((((type >> 8) + 8) | 8) == 0x38) - parse_ciff (ftell(ifp), len); /* Parse a sub-table */ - + parse_ciff (ftell(ifp), len, depth+1); /* Parse a sub-table */ if (type == 0x0810) fread (artist, 64, 1, ifp); if (type == 0x080a) { @@ -5542,7 +6500,9 @@ fread (model, 64, 1, ifp); } if (type == 0x1810) { - fseek (ifp, 12, SEEK_CUR); + width = get4(); + height = get4(); + pixel_aspect = int_to_float(get4()); flip = get4(); } if (type == 0x1835) /* Get the decoder table */ @@ -5700,7 +6660,7 @@ fseek (ifp, base, SEEK_SET); order = get4() & 0xffff; if (get4() >> 8 != 0x526177) return; /* "Raw" */ - fseek (ifp, base+get4(), SEEK_SET); + fseek (ifp, get4()+base, SEEK_SET); entries = get4(); get4(); while (entries--) { @@ -5714,7 +6674,7 @@ case 0x100: flip = "0653"[data & 3]-'0'; break; case 0x106: for (i=0; i < 9; i++) - romm_cam[0][i] = getreal(11); + ((float *)romm_cam)[i] = getreal(11); romm_coeff (romm_cam); break; case 0x107: @@ -5735,8 +6695,10 @@ case 0x21a: ph1.tag_21a = data; break; case 0x21c: strip_offset = data+base; break; case 0x21d: ph1.black = data; break; - case 0x222: ph1.split_col = data - left_margin; break; - case 0x223: ph1.black_off = data+base; break; + case 0x222: ph1.split_col = data; break; + case 0x223: ph1.black_col = data+base; break; + case 0x224: ph1.split_row = data; break; + case 0x225: ph1.black_row = data+base; break; case 0x301: model[63] = 0; fread (model, 1, 63, ifp); @@ -5774,10 +6736,22 @@ } else if (tag == 0x121) { height = get2(); if ((width = get2()) == 4284) width += 3; - } else if (tag == 0x130) + } else if (tag == 0x130) { fuji_layout = fgetc(ifp) >> 7; - if (tag == 0x2ff0) + fuji_width = !(fgetc(ifp) & 8); + } else if (tag == 0x131) { + filters = 9; + FORC(36) xtrans_abs[0][35-c] = fgetc(ifp) & 3; + } else if (tag == 0x2ff0) { FORC4 cam_mul[c ^ 1] = get2(); + } else if (tag == 0xc000 && len > 20000) { + c = order; + order = 0x4949; + while ((tag = get4()) > raw_width); + width = tag; + height = get4(); + order = c; + } fseek (ifp, save+len, SEEK_SET); } height <<= fuji_layout; @@ -5795,7 +6769,7 @@ order = 0x4d4d; len = get2() - 2; save = ftell(ifp); - if (mark == 0xc0 || mark == 0xc3) { + if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { fgetc(ifp); raw_height = get2(); raw_width = get2(); @@ -5803,8 +6777,8 @@ order = get2(); hlen = get4(); if (get4() == 0x48454150) /* "HEAP" */ - parse_ciff (save+hlen, len-hlen); - parse_tiff (save+6); + parse_ciff (save+hlen, len-hlen, 0); + if (parse_tiff (save+6)) apply_tiff(); fseek (ifp, save+len, SEEK_SET); } return 1; @@ -5821,18 +6795,26 @@ order = 0x4949; fread (tag, 4, 1, ifp); size = get4(); + end = ftell(ifp) + size; if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { - end = ftell(ifp) + size; get4(); - while (ftell(ifp) < end) + while (ftell(ifp)+7 < end && !feof(ifp)) parse_riff(); + } else if (!memcmp(tag,"nctg",4)) { + while (ftell(ifp)+7 < end) { + i = get2(); + size = get2(); + if ((i+1) >> 1 == 10 && size == 20) + get_timestamp(0); + else fseek (ifp, size, SEEK_CUR); + } } else if (!memcmp(tag,"IDIT",4) && size < 64) { fread (date, 64, 1, ifp); date[size] = 0; memset (&t, 0, sizeof t); if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { - for (i=0; i < 12 && strcmp(mon[i],month); i++); + for (i=0; i < 12 && strcasecmp(mon[i],month); i++); t.tm_mon = i; t.tm_year -= 1900; if (mktime(&t) > 0) @@ -5842,6 +6824,92 @@ fseek (ifp, size, SEEK_CUR); } +void CLASS parse_crx (int end) +{ + unsigned i, save, size, tag, base; + static int index=0, wide, high, off, len; + + order = 0x4d4d; + while (ftell(ifp)+7 < end) { + save = ftell(ifp); + if ((size = get4()) < 8) break; + switch (tag = get4()) { + case 0x6d6f6f76: /* moov */ + case 0x7472616b: /* trak */ + case 0x6d646961: /* mdia */ + case 0x6d696e66: /* minf */ + case 0x7374626c: /* stbl */ + parse_crx (save+size); + break; + case 0x75756964: /* uuid */ + switch (i=get4()) { + case 0xeaf42b5e: fseek (ifp, 8, SEEK_CUR); + case 0x85c0b687: fseek (ifp, 12, SEEK_CUR); + parse_crx (save+size); + } + break; + case 0x434d5431: /* CMT1 */ + case 0x434d5432: /* CMT2 */ + base = ftell(ifp); + order = get2(); + fseek (ifp, 6, SEEK_CUR); + tag & 1 ? parse_tiff_ifd (base) : parse_exif (base); + order = 0x4d4d; + break; + case 0x746b6864: /* tkhd */ + fseek (ifp, 12, SEEK_CUR); + index = get4(); + fseek (ifp, 58, SEEK_CUR); + wide = get4(); + high = get4(); + break; + case 0x7374737a: /* stsz */ + len = (get4(),get4()); + break; + case 0x636f3634: /* co64 */ + fseek (ifp, 12, SEEK_CUR); + off = get4(); + switch (index) { + case 1: /* 1 = full size, 2 = 27% size */ + thumb_width = wide; + thumb_height = high; + thumb_length = len; + thumb_offset = off; + break; + case 3: + raw_width = wide; + raw_height = high; + data_offset = off; + load_raw = &CLASS canon_crx_load_raw; + } + break; + case 0x50525657: /* PRVW */ + fseek (ifp, 6, SEEK_CUR); + } + fseek (ifp, save+size, SEEK_SET); + } +} + +void CLASS parse_qt (int end) +{ + unsigned save, size; + char tag[4]; + + order = 0x4d4d; + while (ftell(ifp)+7 < end) { + save = ftell(ifp); + if ((size = get4()) < 8) return; + fread (tag, 4, 1, ifp); + if (!memcmp(tag,"moov",4) || + !memcmp(tag,"udta",4) || + !memcmp(tag,"CNTH",4)) + parse_qt (save+size); + if (!memcmp(tag,"CNDA",4)) + parse_jpeg (ftell(ifp)); + fseek (ifp, save+size, SEEK_SET); + } +} + void CLASS parse_smal (int offset, int fsize) { int ver; @@ -5910,6 +6978,35 @@ data_offset += (INT64) get4() << 32; } +void CLASS parse_redcine() +{ + unsigned i, len, rdvo; + + order = 0x4d4d; + is_raw = 0; + fseek (ifp, 52, SEEK_SET); + width = get4(); + height = get4(); + fseek (ifp, 0, SEEK_END); + fseek (ifp, -(i = ftello(ifp) & 511), SEEK_CUR); + if (get4() != i || get4() != 0x52454f42) { + fprintf (stderr,_("%s: Tail is missing, parsing from head...\n"), ifname); + fseek (ifp, 0, SEEK_SET); + while ((len = get4()) != EOF) { + if (get4() == 0x52454456) + if (is_raw++ == shot_select) + data_offset = ftello(ifp) - 8; + fseek (ifp, len-8, SEEK_CUR); + } + } else { + rdvo = get4(); + fseek (ifp, 12, SEEK_CUR); + is_raw = get4(); + fseeko (ifp, rdvo+8 + shot_select*4, SEEK_SET); + data_offset = get4(); + } +} + char * CLASS foveon_gets (int offset, char *str, int len) { int i; @@ -5942,16 +7039,25 @@ switch (tag) { case 0x47414d49: /* IMAG */ case 0x32414d49: /* IMA2 */ - fseek (ifp, 12, SEEK_CUR); + fseek (ifp, 8, SEEK_CUR); + pent = get4(); wide = get4(); high = get4(); if (wide > raw_width && high > raw_height) { + switch (pent) { + case 5: load_flags = 1; + case 6: load_raw = &CLASS foveon_sd_load_raw; break; + case 30: load_raw = &CLASS foveon_dp_load_raw; break; + default: load_raw = 0; + } raw_width = wide; raw_height = high; - data_offset = off+24; + data_offset = off+28; + is_foveon = 1; } fseek (ifp, off+28, SEEK_SET); - if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8) { + if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8 + && thumb_length < len-28) { thumb_offset = off+28; thumb_length = len-28; write_thumb = &CLASS jpeg_thumb; @@ -5964,10 +7070,8 @@ } break; case 0x464d4143: /* CAMF */ - meta_offset = off+24; + meta_offset = off+8; meta_length = len-28; - if (meta_length > 0x20000) - meta_length = 0x20000; break; case 0x504f5250: /* PROP */ pent = (get4(),get4()); @@ -5975,7 +7079,7 @@ off += pent*8 + 24; if ((unsigned) pent > 256) pent=256; for (i=0; i < pent*2; i++) - poff[0][i] = off + get4()*2; + ((int *)poff)[i] = off + get4()*2; for (i=0; i < pent; i++) { foveon_gets (poff[i][0], name, 64); foveon_gets (poff[i][1], value, 64); @@ -6002,384 +7106,1159 @@ } fseek (ifp, save, SEEK_SET); } - is_foveon = 1; } /* - Thanks to Adobe for providing these excellent CAM -> XYZ matrices! + All matrices are from Adobe DNG Converter unless otherwise noted. */ -void CLASS adobe_coeff (char *make, char *model) +void CLASS adobe_coeff (const char *make, const char *model) { static const struct { const char *prefix; - short black, trans[12]; + short black, maximum, trans[12]; } table[] = { - { "Apple QuickTake", 0, /* DJC */ - { 17576,-3191,-3318,5210,6733,-1942,9031,1280,-124 } }, - { "Canon EOS D2000", 0, + { "AgfaPhoto DC-833m", 0, 0, /* DJC */ + { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, + { "Apple QuickTake", 0, 0, /* DJC */ + { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, + { "Canon EOS D2000", 0, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, - { "Canon EOS D6000", 0, + { "Canon EOS D6000", 0, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, - { "Canon EOS D30", 0, + { "Canon EOS D30", 0, 0, { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, - { "Canon EOS D60", 0, + { "Canon EOS D60", 0, 0xfa0, { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, - { "Canon EOS 5D", 0, + { "Canon EOS 5DS", 0, 0x3c96, + { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, + { "Canon EOS 5D Mark IV", 0, 0, + { 6446,-366,-864,-4436,12204,2513,-952,2496,6348 } }, + { "Canon EOS 5D Mark III", 0, 0x3c80, + { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, + { "Canon EOS 5D Mark II", 0, 0x3cf0, + { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, + { "Canon EOS 5D", 0, 0xe6c, { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, - { "Canon EOS 20Da", 0, + { "Canon EOS 6D Mark II", 0, 0, + { 6875,-970,-932,-4691,12459,2501,-874,1953,5809 } }, + { "Canon EOS 6D", 0, 0x3c82, + { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { "Canon EOS 7D Mark II", 0, 0x3510, + { 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 } }, + { "Canon EOS 7D", 0, 0x3510, + { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, + { "Canon EOS 10D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 20Da", 0, 0, { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, - { "Canon EOS 20D", 0, + { "Canon EOS 20D", 0, 0xfff, { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, - { "Canon EOS 30D", 0, + { "Canon EOS 30D", 0, 0, { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, - { "Canon EOS 40D", 0, + { "Canon EOS 40D", 0, 0x3f60, { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, - { "Canon EOS 350D", 0, + { "Canon EOS 50D", 0, 0x3d93, + { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, + { "Canon EOS 60D", 0, 0x2ff7, + { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, + { "Canon EOS 70D", 0, 0x3bc7, + { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { "Canon EOS 77D", 0, 0, + { 7377,-742,-998,-4235,11981,2549,-673,1918,5538 } }, + { "Canon EOS 80D", 0, 0, + { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } }, + { "Canon EOS 100D", 0, 0x350f, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 200D", 0, 0, + { 7377,-742,-998,-4235,11981,2549,-673,1918,5538 } }, + { "Canon EOS 300D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 350D", 0, 0xfff, { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, - { "Canon EOS 400D", 0, + { "Canon EOS 400D", 0, 0xe8e, { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, - { "Canon EOS-1Ds Mark III", 0, + { "Canon EOS 450D", 0, 0x390d, + { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, + { "Canon EOS 500D", 0, 0x3479, + { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, + { "Canon EOS 550D", 0, 0x3dd7, + { 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 } }, + { "Canon EOS 600D", 0, 0x3510, + { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { "Canon EOS 650D", 0, 0x354d, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 700D", 0, 0x3c00, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 750D", 0, 0x368e, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS 760D", 0, 0x350f, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS 800D", 0, 0, + { 6970,-512,-968,-4425,12161,2553,-739,1982,5601 } }, + { "Canon EOS 1000D", 0, 0xe43, + { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, + { "Canon EOS 1100D", 0, 0x3510, + { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, + { "Canon EOS 1200D", 0, 0x37c2, + { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { "Canon EOS 1300D", 0, 0x3510, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { "Canon EOS 1500D", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS 3000D", 0, 0, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { "Canon EOS M6", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS M5", 0, 0, /* also M50 */ + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS M3", 0, 0, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS M100", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS M10", 0, 0, + { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, + { "Canon EOS M", 0, 0, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS-1Ds Mark III", 0, 0x3bb0, { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, - { "Canon EOS-1Ds Mark II", 0, + { "Canon EOS-1Ds Mark II", 0, 0xe80, { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, - { "Canon EOS-1D Mark II N", 0, - { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, - { "Canon EOS-1D Mark III", 0, + { "Canon EOS-1D Mark IV", 0, 0x3bb0, + { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, + { "Canon EOS-1D Mark III", 0, 0x3bb0, { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, - { "Canon EOS-1D Mark II", 0, + { "Canon EOS-1D Mark II N", 0, 0xe80, + { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, + { "Canon EOS-1D Mark II", 0, 0xe80, { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, - { "Canon EOS-1DS", 0, + { "Canon EOS-1DS", 0, 0xe20, { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, - { "Canon EOS-1D", 0, + { "Canon EOS-1D C", 0, 0x3c4e, + { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { "Canon EOS-1D X Mark II", 0, 0, + { 7596,-978,-967,-4808,12571,2503,-1398,2567,5752 } }, + { "Canon EOS-1D X", 0, 0x3c4e, + { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { "Canon EOS-1D", 0, 0xe20, { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, - { "Canon EOS", 0, - { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, - { "Canon PowerShot A50", 0, + { "Canon EOS C500", 853, 0, /* DJC */ + { 17851,-10604,922,-7425,16662,763,-3660,3636,22278 } }, + { "Canon PowerShot A530", 0, 0, + { 0 } }, /* don't want the A5 matrix */ + { "Canon PowerShot A50", 0, 0, { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, - { "Canon PowerShot A5", 0, + { "Canon PowerShot A5", 0, 0, { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, - { "Canon PowerShot G1", 0, + { "Canon PowerShot G10", 0, 0, + { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, + { "Canon PowerShot G11", 0, 0, + { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, + { "Canon PowerShot G12", 0, 0, + { 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 } }, + { "Canon PowerShot G15", 0, 0, + { 7474,-2301,-567,-4056,11456,2975,-222,716,4181 } }, + { "Canon PowerShot G16", 0, 0, + { 8020,-2687,-682,-3704,11879,2052,-965,1921,5556 } }, + { "Canon PowerShot G1 X Mark III", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon PowerShot G1 X", 0, 0, + { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, + { "Canon PowerShot G1", 0, 0, { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, - { "Canon PowerShot G2", 0, + { "Canon PowerShot G2", 0, 0, { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, - { "Canon PowerShot G3", 0, + { "Canon PowerShot G3 X", 0, 0, + { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } }, + { "Canon PowerShot G3", 0, 0, { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, - { "Canon PowerShot G5", 0, + { "Canon PowerShot G5 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G5", 0, 0, { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, - { "Canon PowerShot G6", 0, + { "Canon PowerShot G6", 0, 0, { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, - { "Canon PowerShot G9", 0, + { "Canon PowerShot G7 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G9 X Mark II", 0, 0, + { 10056,-4131,-944,-2576,11143,1625,-238,1294,5179 } }, + { "Canon PowerShot G9 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G9", 0, 0, { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, - { "Canon PowerShot Pro1", 0, + { "Canon PowerShot Pro1", 0, 0, { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, - { "Canon PowerShot Pro70", 34, + { "Canon PowerShot Pro70", 34, 0, { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, - { "Canon PowerShot Pro90", 0, + { "Canon PowerShot Pro90", 0, 0, { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, - { "Canon PowerShot S30", 0, + { "Canon PowerShot S30", 0, 0, { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, - { "Canon PowerShot S40", 0, + { "Canon PowerShot S40", 0, 0, { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, - { "Canon PowerShot S45", 0, + { "Canon PowerShot S45", 0, 0, { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, - { "Canon PowerShot S50", 0, + { "Canon PowerShot S50", 0, 0, { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, - { "Canon PowerShot S60", 0, + { "Canon PowerShot S60", 0, 0, { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, - { "Canon PowerShot S70", 0, + { "Canon PowerShot S70", 0, 0, { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, - { "Canon PowerShot A610", 0, /* DJC */ + { "Canon PowerShot S90", 0, 0, + { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, + { "Canon PowerShot S95", 0, 0, + { 13440,-5896,-1279,-1236,9598,1931,-180,1001,4651 } }, + { "Canon PowerShot S100", 0, 0, + { 7968,-2565,-636,-2873,10697,2513,180,667,4211 } }, + { "Canon PowerShot S110", 0, 0, + { 8039,-2643,-654,-3783,11230,2930,-206,690,4194 } }, + { "Canon PowerShot S120", 0, 0, + { 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 } }, + { "Canon PowerShot SX1 IS", 0, 0, + { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, + { "Canon PowerShot SX50 HS", 0, 0, + { 12432,-4753,-1247,-2110,10691,1629,-412,1623,4926 } }, + { "Canon PowerShot SX60 HS", 0, 0, + { 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 } }, + { "Canon PowerShot A3300", 0, 0, /* DJC */ + { 10826,-3654,-1023,-3215,11310,1906,0,999,4960 } }, + { "Canon PowerShot A470", 0, 0, /* DJC */ + { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, + { "Canon PowerShot A610", 0, 0, /* DJC */ { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, - { "Canon PowerShot A620", 0, /* DJC */ + { "Canon PowerShot A620", 0, 0, /* DJC */ { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, - { "Canon PowerShot A640", 0, /* DJC */ + { "Canon PowerShot A630", 0, 0, /* DJC */ + { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, + { "Canon PowerShot A640", 0, 0, /* DJC */ { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, - { "Canon PowerShot A650", 0, /* DJC */ + { "Canon PowerShot A650", 0, 0, /* DJC */ { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, - { "Canon PowerShot S3 IS", 0, /* DJC */ + { "Canon PowerShot A720", 0, 0, /* DJC */ + { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, + { "Canon PowerShot S3 IS", 0, 0, /* DJC */ { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, - { "CINE 650", 0, + { "Canon PowerShot SX110 IS", 0, 0, /* DJC */ + { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, + { "Canon PowerShot SX220", 0, 0, /* DJC */ + { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, + { "Canon IXUS 160", 0, 0, /* DJC */ + { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } }, + { "Casio EX-S20", 0, 0, /* DJC */ + { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, + { "Casio EX-Z750", 0, 0, /* DJC */ + { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, + { "Casio EX-Z10", 128, 0xfff, /* DJC */ + { 9790,-3338,-603,-2321,10222,2099,-344,1273,4799 } }, + { "CINE 650", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, - { "CINE 660", 0, + { "CINE 660", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, - { "CINE", 0, + { "CINE", 0, 0, { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, - { "Contax N Digital", 0, + { "Contax N Digital", 0, 0xf1e, { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, - { "EPSON R-D1", 0, + { "DXO ONE", 0, 0, + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, + { "Epson R-D1", 0, 0, { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, - { "FUJIFILM FinePix E550", 0, + { "Fujifilm E550", 0, 0, { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, - { "FUJIFILM FinePix E900", 0, + { "Fujifilm E900", 0, 0, { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, - { "FUJIFILM FinePix F8", 0, - { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, - { "FUJIFILM FinePix F7", 0, + { "Fujifilm F5", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm F6", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm F77", 0, 0xfe9, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm F7", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, - { "FUJIFILM FinePix S20Pro", 0, + { "Fujifilm F8", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm GFX 50S", 0, 0, + { 11756,-4754,-874,-3056,11045,2305,-381,1457,6006 } }, + { "Fujifilm S100FS", 514, 0, + { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, + { "Fujifilm S1", 0, 0, + { 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 } }, + { "Fujifilm S20Pro", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, - { "FUJIFILM FinePix S2Pro", 128, + { "Fujifilm S20", 512, 0x3fff, + { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } }, + { "Fujifilm S2Pro", 128, 0xf15, { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, - { "FUJIFILM FinePix S3Pro", 0, + { "Fujifilm S3Pro", 0, 0x3dff, { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, - { "FUJIFILM FinePix S5Pro", 0, + { "Fujifilm S5Pro", 0, 0, { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, - { "FUJIFILM FinePix S5000", 0, + { "Fujifilm S5000", 0, 0, { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, - { "FUJIFILM FinePix S5100", 0, + { "Fujifilm S5100", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, - { "FUJIFILM FinePix S5500", 0, + { "Fujifilm S5500", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, - { "FUJIFILM FinePix S5200", 0, + { "Fujifilm S5200", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, - { "FUJIFILM FinePix S5600", 0, + { "Fujifilm S5600", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, - { "FUJIFILM FinePix S6", 0, + { "Fujifilm S6", 0, 0, { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, - { "FUJIFILM FinePix S7000", 0, + { "Fujifilm S7000", 0, 0, { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, - { "FUJIFILM FinePix S9000", 0, + { "Fujifilm S9000", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, - { "FUJIFILM FinePix S9500", 0, + { "Fujifilm S9500", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, - { "FUJIFILM FinePix S9100", 0, + { "Fujifilm S9100", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, - { "FUJIFILM FinePix S9600", 0, + { "Fujifilm S9600", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, - { "FUJIFILM IS-1", 0, + { "Fujifilm SL1000", 0, 0, + { 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 } }, + { "Fujifilm IS-1", 0, 0, { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, - { "Imacon Ixpress", 0, /* DJC */ + { "Fujifilm IS Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + { "Fujifilm HS10 HS11", 0, 0xf68, + { 12440,-3954,-1183,-1123,9674,1708,-83,1614,4086 } }, + { "Fujifilm HS2", 0, 0xfef, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm HS3", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm HS50EXR", 0, 0, + { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, + { "Fujifilm F900EXR", 0, 0, + { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, + { "Fujifilm X100F", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X100S", 0, 0, + { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, + { "Fujifilm X100T", 0, 0, + { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, + { "Fujifilm X100", 0, 0, + { 12161,-4457,-1069,-5034,12874,2400,-795,1724,6904 } }, + { "Fujifilm X10", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + { "Fujifilm X20", 0, 0, + { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, + { "Fujifilm X30", 0, 0, + { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } }, + { "Fujifilm X70", 0, 0, + { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } }, + { "Fujifilm X-Pro1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-Pro2", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X-A10", 0, 0, + { 11540,-4999,-991,-2949,10963,2278,-382,1049,5605 } }, + { "Fujifilm X-A20", 0, 0, + { 11540,-4999,-991,-2949,10963,2278,-382,1049,5605 } }, + { "Fujifilm X-A1", 0, 0, + { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } }, + { "Fujifilm X-A2", 0, 0, + { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, + { "Fujifilm X-A3", 0, 0, + { 12407,-5222,-1086,-2971,11116,2120,-294,1029,5284 } }, + { "Fujifilm X-A5", 0, 0, + { 11673,-4760,-1041,-3988,12058,2166,-771,1417,5569 } }, + { "Fujifilm X-E1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-E2S", 0, 0, + { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } }, + { "Fujifilm X-E2", 0, 0, + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, + { "Fujifilm X-E3", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X-H1", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X-M1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-S1", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + { "Fujifilm X-T1", 0, 0, /* also X-T10 */ + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, + { "Fujifilm X-T2", 0, 0, /* also X-T20 */ + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm XF1", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + { "Fujifilm XQ", 0, 0, /* XQ1 and XQ2 */ + { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, + { "GoPro HERO5 Black", 0, 0, + { 10344,-4210,-620,-2315,10625,1948,93,1058,5541 } }, + { "Imacon Ixpress", 0, 0, /* DJC */ { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, - { "KODAK NC2000", 0, + { "Kodak NC2000", 0, 0, { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, - { "Kodak DCS315C", 8, + { "Kodak DCS315C", 8, 0, { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, - { "Kodak DCS330C", 8, + { "Kodak DCS330C", 8, 0, { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, - { "KODAK DCS420", 0, + { "Kodak DCS420", 0, 0, { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, - { "KODAK DCS460", 0, + { "Kodak DCS460", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, - { "KODAK EOSDCS1", 0, + { "Kodak EOSDCS1", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, - { "KODAK EOSDCS3B", 0, + { "Kodak EOSDCS3B", 0, 0, { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, - { "Kodak DCS520C", 180, + { "Kodak DCS520C", 178, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, - { "Kodak DCS560C", 188, + { "Kodak DCS560C", 177, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, - { "Kodak DCS620C", 180, + { "Kodak DCS620C", 177, 0, { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, - { "Kodak DCS620X", 185, + { "Kodak DCS620X", 176, 0, { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, - { "Kodak DCS660C", 214, + { "Kodak DCS660C", 173, 0, { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, - { "Kodak DCS720X", 0, + { "Kodak DCS720X", 0, 0, { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, - { "Kodak DCS760C", 0, + { "Kodak DCS760C", 0, 0, { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, - { "Kodak DCS Pro SLR", 0, + { "Kodak DCS Pro SLR", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, - { "Kodak DCS Pro 14nx", 0, + { "Kodak DCS Pro 14nx", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, - { "Kodak DCS Pro 14", 0, + { "Kodak DCS Pro 14", 0, 0, { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, - { "Kodak ProBack645", 0, + { "Kodak ProBack645", 0, 0, { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, - { "Kodak ProBack", 0, + { "Kodak ProBack", 0, 0, { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, - { "KODAK P712", 0, + { "Kodak P712", 0, 0, { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, - { "KODAK P850", 0, + { "Kodak P850", 0, 0xf7c, { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, - { "KODAK P880", 0, + { "Kodak P880", 0, 0xfff, { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, - { "Leaf CMost", 0, + { "Kodak EasyShare Z980", 0, 0, + { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, + { "Kodak EasyShare Z981", 0, 0, + { 12729,-4717,-1188,-1367,9187,2582,274,860,4411 } }, + { "Kodak EasyShare Z990", 0, 0xfed, + { 11749,-4048,-1309,-1867,10572,1489,-138,1449,4522 } }, + { "Kodak EASYSHARE Z1015", 0, 0xef1, + { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, + { "Leaf CMost", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, - { "Leaf Valeo 6", 0, + { "Leaf Valeo 6", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, - { "Leaf Aptus 54S", 0, + { "Leaf Aptus 54S", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, - { "Leaf Aptus 65", 0, + { "Leaf Aptus 65", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, - { "Leaf Aptus 75", 0, + { "Leaf Aptus 75", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, - { "Leaf", 0, + { "Leaf", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, - { "Mamiya ZD", 0, + { "Mamiya ZD", 0, 0, { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, - { "Micron 2010", 110, /* DJC */ + { "Micron 2010", 110, 0, /* DJC */ { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, - { "Minolta DiMAGE 5", 0, + { "Minolta DiMAGE 5", 0, 0xf7d, { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, - { "Minolta DiMAGE 7Hi", 0, + { "Minolta DiMAGE 7Hi", 0, 0xf7d, { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, - { "Minolta DiMAGE 7", 0, + { "Minolta DiMAGE 7", 0, 0xf7d, { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, - { "Minolta DiMAGE A1", 0, + { "Minolta DiMAGE A1", 0, 0xf8b, { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, - { "MINOLTA DiMAGE A200", 0, + { "Minolta DiMAGE A200", 0, 0, { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, - { "Minolta DiMAGE A2", 0, + { "Minolta DiMAGE A2", 0, 0xf8f, { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, - { "Minolta DiMAGE Z2", 0, /* DJC */ + { "Minolta DiMAGE Z2", 0, 0, /* DJC */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, - { "MINOLTA DYNAX 5", 0, + { "Minolta DYNAX 5", 0, 0xffb, { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, - { "MINOLTA DYNAX 7", 0, + { "Minolta DYNAX 7", 0, 0xffb, { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, - { "NIKON D100", 0, + { "Motorola PIXL", 0, 0, /* DJC */ + { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, + { "Nikon D100", 0, 0, { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, - { "NIKON D1H", 0, + { "Nikon D1H", 0, 0, { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, - { "NIKON D1X", 0, + { "Nikon D1X", 0, 0, { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, - { "NIKON D1", 0, /* multiplied by 2.218750, 1.0, 1.148438 */ + { "Nikon D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, - { "NIKON D2H", 0, + { "Nikon D200", 0, 0xfbc, + { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, + { "Nikon D2H", 0, 0, { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, - { "NIKON D2X", 0, + { "Nikon D2X", 0, 0, { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, - { "NIKON D40X", 0, + { "Nikon D3000", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "Nikon D3100", 0, 0, + { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, + { "Nikon D3200", 0, 0xfb9, + { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, + { "Nikon D3300", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { "Nikon D3400", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { "Nikon D300", 0, 0, + { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, + { "Nikon D3X", 0, 0, + { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, + { "Nikon D3S", 0, 0, + { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, + { "Nikon D3", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "Nikon D40X", 0, 0, { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, - { "NIKON D40", 0, + { "Nikon D40", 0, 0, { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, - { "NIKON D50", 0, + { "Nikon D4S", 0, 0, + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + { "Nikon D4", 0, 0, + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + { "Nikon Df", 0, 0, + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + { "Nikon D5000", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, + { "Nikon D5100", 0, 0x3de6, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { "Nikon D5200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D5300", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { "Nikon D5500", 0, 0, + { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { "Nikon D5600", 0, 0, + { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { "Nikon D500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, + { "Nikon D50", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, - { "NIKON D70", 0, + { "Nikon D5", 0, 0, + { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } }, + { "Nikon D600", 0, 0x3e07, + { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, + { "Nikon D610", 0, 0, + { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, + { "Nikon D60", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "Nikon D7000", 0, 0, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { "Nikon D7100", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D7200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D7500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, + { "Nikon D750", 0, 0, + { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, + { "Nikon D700", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "Nikon D70", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, - { "NIKON D80", 0, + { "Nikon D850", 0, 0, + { 10405,-3755,-1270,-5461,13787,1793,-1040,2015,6785 } }, + { "Nikon D810", 0, 0, + { 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 } }, + { "Nikon D800", 0, 0, + { 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 } }, + { "Nikon D80", 0, 0, { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, - { "NIKON D200", 0, - { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, - { "NIKON D300", 0, - { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, - { "NIKON D3", 0, - { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, - { "NIKON E950", 0, /* DJC */ + { "Nikon D90", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, + { "Nikon E700", 0, 0x3dd, /* DJC */ + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, + { "Nikon E800", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, - { "NIKON E995", 0, /* copied from E5000 */ + { "Nikon E950", 0, 0x3dd, /* DJC */ + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, + { "Nikon E995", 0, 0, /* copied from E5000 */ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E2100", 0, /* copied from Z2, new white balance */ + { "Nikon E2100", 0, 0, /* copied from Z2, new white balance */ { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} }, - { "NIKON E2500", 0, + { "Nikon E2500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E4300", 0, /* copied from Minolta DiMAGE Z2 */ + { "Nikon E3200", 0, 0, /* DJC */ + { 9846,-2085,-1019,-3278,11109,2170,-774,2134,5745 } }, + { "Nikon E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, - { "NIKON E4500", 0, + { "Nikon E4500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E5000", 0, + { "Nikon E5000", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E5400", 0, + { "Nikon E5400", 0, 0, { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, - { "NIKON E5700", 0, + { "Nikon E5700", 0, 0, { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, - { "NIKON E8400", 0, + { "Nikon E8400", 0, 0, { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, - { "NIKON E8700", 0, + { "Nikon E8700", 0, 0, { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, - { "NIKON E8800", 0, + { "Nikon E8800", 0, 0, { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, - { "OLYMPUS C5050", 0, + { "Nikon COOLPIX A", 0, 0, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { "Nikon COOLPIX B700", 200, 0, + { 14387,-6014,-1299,-1357,9975,1616,467,1047,4744 } }, + { "Nikon COOLPIX P330", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon COOLPIX P340", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon COOLPIX P6000", 0, 0, + { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, + { "Nikon COOLPIX P7000", 0, 0, + { 11432,-3679,-1111,-3169,11239,2202,-791,1380,4455 } }, + { "Nikon COOLPIX P7100", 0, 0, + { 11053,-4269,-1024,-1976,10182,2088,-526,1263,4469 } }, + { "Nikon COOLPIX P7700", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon COOLPIX P7800", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon 1 V3", 0, 0, + { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, + { "Nikon 1 J4", 0, 0, + { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, + { "Nikon 1 J5", 0, 0, + { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } }, + { "Nikon 1 S2", 200, 0, + { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, + { "Nikon 1 V2", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { "Nikon 1 J3", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { "Nikon 1 AW1", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { "Nikon 1 ", 0, 0, /* J1, J2, S1, V1 */ + { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, + { "Olympus AIR A01", 0, 0, + { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } }, + { "Olympus C5050", 0, 0, { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, - { "OLYMPUS C5060", 0, + { "Olympus C5060", 0, 0, { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, - { "OLYMPUS C7070", 0, + { "Olympus C7070", 0, 0, { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, - { "OLYMPUS C70", 0, + { "Olympus C70", 0, 0, { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, - { "OLYMPUS C80", 0, + { "Olympus C80", 0, 0, { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, - { "OLYMPUS E-10", 0, + { "Olympus E-10", 0, 0xffc, { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, - { "OLYMPUS E-1", 0, + { "Olympus E-1", 0, 0, { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, - { "OLYMPUS E-20", 0, + { "Olympus E-20", 0, 0xffc, { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, - { "OLYMPUS E-300", 0, + { "Olympus E-300", 0, 0, { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, - { "OLYMPUS E-330", 0, + { "Olympus E-330", 0, 0, { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, - { "OLYMPUS E-3", 0, + { "Olympus E-30", 0, 0xfbc, + { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, + { "Olympus E-3", 0, 0xf99, { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, - { "OLYMPUS E-400", 0, + { "Olympus E-400", 0, 0, { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, - { "OLYMPUS E-410", 0, + { "Olympus E-410", 0, 0xf6a, { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, - { "OLYMPUS E-500", 0, + { "Olympus E-420", 0, 0xfd7, + { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, + { "Olympus E-450", 0, 0xfd2, + { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, + { "Olympus E-500", 0, 0, { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, - { "OLYMPUS E-510", 0, + { "Olympus E-510", 0, 0xf6a, { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, - { "OLYMPUS SP350", 0, + { "Olympus E-520", 0, 0xfd2, + { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, + { "Olympus E-5", 0, 0xeec, + { 11200,-3783,-1325,-4576,12593,2206,-695,1742,7504 } }, + { "Olympus E-600", 0, 0xfaf, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + { "Olympus E-620", 0, 0xfaf, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + { "Olympus E-P1", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { "Olympus E-P2", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { "Olympus E-P3", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { "Olympus E-P5", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PL1s", 0, 0, + { 11409,-3872,-1393,-4572,12757,2003,-709,1810,7415 } }, + { "Olympus E-PL1", 0, 0, + { 11408,-4289,-1215,-4286,12385,2118,-387,1467,7787 } }, + { "Olympus E-PL2", 0, 0xcf3, + { 15030,-5552,-1806,-3987,12387,1767,-592,1670,7023 } }, + { "Olympus E-PL3", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { "Olympus E-PL5", 0, 0xfcb, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PL6", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PL7", 0, 0, + { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, + { "Olympus E-PL8", 0, 0, + { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, + { "Olympus E-PL9", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PM1", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { "Olympus E-PM2", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-M10", 0, 0, /* also E-M10 Mark II & III */ + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-M1Mark II", 0, 0, + { 9383,-3170,-763,-2457,10702,2020,-384,1236,5552 } }, + { "Olympus E-M1", 0, 0, + { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, + { "Olympus E-M5MarkII", 0, 0, + { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } }, + { "Olympus E-M5", 0, 0xfe1, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus PEN-F", 0, 0, + { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } }, + { "Olympus SH-2", 0, 0, + { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, + { "Olympus SP350", 0, 0, { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, - { "OLYMPUS SP3", 0, + { "Olympus SP3", 0, 0, { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, - { "OLYMPUS SP500UZ", 0, + { "Olympus SP500UZ", 0, 0xfff, { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, - { "OLYMPUS SP510UZ", 0, + { "Olympus SP510UZ", 0, 0xffe, { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, - { "OLYMPUS SP550UZ", 0, + { "Olympus SP550UZ", 0, 0xffe, { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, - { "OLYMPUS SP560UZ", 0, + { "Olympus SP560UZ", 0, 0xff9, { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, - { "PENTAX *ist DL2", 0, + { "Olympus SP570UZ", 0, 0, + { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, + { "Olympus STYLUS1", 0, 0, + { 8360,-2420,-880,-3928,12353,1739,-1381,2416,5173 } }, + { "Olympus TG-4", 0, 0, + { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } }, + { "Olympus TG-5", 0, 0, + { 10899,-3833,-1082,-2112,10736,1575,-267,1452,5269 } }, + { "Olympus XZ-10", 0, 0, + { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + { "Olympus XZ-1", 0, 0, + { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, + { "Olympus XZ-2", 0, 0, + { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + { "OmniVision", 0, 0, /* DJC */ + { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, + { "Pentax *ist DL2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, - { "PENTAX *ist DL", 0, + { "Pentax *ist DL", 0, 0, { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, - { "PENTAX *ist DS2", 0, + { "Pentax *ist DS2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, - { "PENTAX *ist DS", 0, + { "Pentax *ist DS", 0, 0, { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, - { "PENTAX *ist D", 0, + { "Pentax *ist D", 0, 0, { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, - { "PENTAX K10D", 0, + { "Pentax K10D", 0, 0, { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, - { "PENTAX K1", 0, + { "Pentax K1", 0, 0, { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, - { "Panasonic DMC-FZ8", 0, + { "Pentax K20D", 0, 0, + { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, + { "Pentax K200D", 0, 0, + { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, + { "Pentax K2000", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "Pentax K-m", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "Pentax K-x", 0, 0, + { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, + { "Pentax K-r", 0, 0, + { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, + { "Pentax K-1", 0, 0, + { 8596,-2981,-639,-4202,12046,2431,-685,1424,6122 } }, + { "Pentax K-30", 0, 0, + { 8710,-2632,-1167,-3995,12301,1881,-981,1719,6535 } }, + { "Pentax K-3 II", 0, 0, + { 8626,-2607,-1155,-3995,12301,1881,-1039,1822,6925 } }, + { "Pentax K-3", 0, 0, + { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } }, + { "Pentax K-5 II", 0, 0, + { 8170,-2725,-639,-4440,12017,2744,-771,1465,6599 } }, + { "Pentax K-5", 0, 0, + { 8713,-2833,-743,-4342,11900,2772,-722,1543,6247 } }, + { "Pentax K-70", 0, 0, + { 8270,-2117,-1299,-4359,12953,1515,-1078,1933,5975 } }, + { "Pentax K-7", 0, 0, + { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, + { "Pentax K-S1", 0, 0, + { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } }, + { "Pentax K-S2", 0, 0, + { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } }, + { "Pentax KP", 0, 0, + { 8617,-3228,-1034,-4674,12821,2044,-803,1577,5728 } }, + { "Pentax Q-S1", 0, 0, + { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, + { "Pentax 645D", 0, 0x3e00, + { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, + { "Panasonic DMC-CM1", 15, 0, + { 8770,-3194,-820,-2871,11281,1803,-513,1552,4434 } }, + { "Panasonic DC-FZ80", 0, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-FZ8", 0, 0xf7f, { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, - { "Panasonic DMC-FZ18", 0, + { "Panasonic DMC-FZ18", 0, 0, { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, - { "Panasonic DMC-FZ30", 0, + { "Panasonic DMC-FZ28", 15, 0xf96, + { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, + { "Panasonic DMC-FZ2500", 15, 0, + { 7386,-2443,-743,-3437,11864,1757,-608,1660,4766 } }, + { "Panasonic DMC-FZ330", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, + { "Panasonic DMC-FZ300", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, + { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, - { "Panasonic DMC-FZ50", 0, /* aka "LEICA V-LUX1" */ + { "Panasonic DMC-FZ3", 15, 0, /* FZ35, FZ38 */ + { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, + { "Panasonic DMC-FZ4", 15, 0, /* FZ40, FZ45 */ + { 13639,-5535,-1371,-1698,9633,2430,316,1152,4108 } }, + { "Panasonic DMC-FZ50", 0, 0, + { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, + { "Panasonic DMC-FZ7", 15, 0, /* FZ70, FZ72 */ + { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } }, + { "Leica V-LUX1", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, - { "Panasonic DMC-L10", 0, + { "Panasonic DMC-L10", 15, 0xf96, { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, - { "Panasonic DMC-L1", 0, /* aka "LEICA DIGILUX 3" */ + { "Panasonic DMC-L1", 0, 0xf7f, { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, - { "Panasonic DMC-LC1", 0, /* aka "LEICA DIGILUX 2" */ + { "Leica DIGILUX 3", 0, 0xf7f, + { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, + { "Panasonic DMC-LC1", 0, 0, + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Leica DIGILUX 2", 0, 0, { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, - { "Panasonic DMC-LX1", 0, /* aka "LEICA D-LUX2" */ + { "Panasonic DMC-LX100", 15, 0, + { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, + { "Leica D-LUX (Typ 109)", 15, 0, + { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, + { "Panasonic DMC-LF1", 15, 0, + { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, + { "Leica C (Typ 112)", 15, 0, + { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, + { "Panasonic DMC-LX1", 0, 0xf7f, { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, - { "Panasonic DMC-LX2", 0, /* aka "LEICA D-LUX3" */ + { "Leica D-LUX2", 0, 0xf7f, + { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, + { "Panasonic DMC-LX2", 0, 0, + { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, + { "Leica D-LUX3", 0, 0, { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, - { "Phase One H 20", 0, /* DJC */ + { "Panasonic DMC-LX3", 15, 0, + { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, + { "Leica D-LUX 4", 15, 0, + { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, + { "Panasonic DMC-LX5", 15, 0, + { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, + { "Leica D-LUX 5", 15, 0, + { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, + { "Panasonic DMC-LX7", 15, 0, + { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, + { "Leica D-LUX 6", 15, 0, + { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, + { "Panasonic DMC-LX9", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DMC-FZ1000", 15, 0, + { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, + { "Leica V-LUX (Typ 114)", 15, 0, + { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, + { "Panasonic DMC-FZ100", 15, 0xfff, + { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, + { "Leica V-LUX 2", 15, 0xfff, + { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, + { "Panasonic DMC-FZ150", 15, 0xfff, + { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, + { "Leica V-LUX 3", 15, 0xfff, + { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, + { "Panasonic DMC-FZ200", 15, 0xfff, + { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, + { "Leica V-LUX 4", 15, 0xfff, + { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, + { "Panasonic DMC-FX150", 15, 0xfff, + { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, + { "Panasonic DMC-G10", 0, 0, + { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, + { "Panasonic DMC-G1", 15, 0xf94, + { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, + { "Panasonic DMC-G2", 15, 0xf3c, + { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, + { "Panasonic DMC-G3", 15, 0xfff, + { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, + { "Panasonic DMC-G5", 15, 0xfff, + { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, + { "Panasonic DMC-G6", 15, 0xfff, + { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, + { "Panasonic DMC-G7", 15, 0xfff, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-G8", 15, 0xfff, /* G8, G80, G81, G85 */ + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DC-G9", 15, 0xfff, + { 7685,-2375,-634,-3687,11700,2249,-748,1546,5111 } }, + { "Panasonic DMC-GF1", 15, 0xf92, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { "Panasonic DMC-GF2", 15, 0xfff, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { "Panasonic DMC-GF3", 15, 0xfff, + { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, + { "Panasonic DMC-GF5", 15, 0xfff, + { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, + { "Panasonic DMC-GF6", 15, 0, + { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, + { "Panasonic DMC-GF7", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GF8", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DC-GF9", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GH1", 15, 0xf92, + { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, + { "Panasonic DMC-GH2", 15, 0xf95, + { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, + { "Panasonic DMC-GH3", 15, 0, + { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, + { "Panasonic DMC-GH4", 15, 0, + { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } }, + { "Panasonic DC-GH5S", 15, 0, + { 6929,-2355,-708,-4192,12534,1828,-1097,1989,5195 } }, + { "Panasonic DC-GH5", 15, 0, + { 7641,-2336,-605,-3218,11299,2187,-485,1338,5121 } }, + { "Panasonic DMC-GM1", 15, 0, + { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } }, + { "Panasonic DMC-GM5", 15, 0, + { 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 } }, + { "Panasonic DMC-GX1", 15, 0, + { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, + { "Panasonic DMC-GX7", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GX85", 15, 0, + { 7771,-3020,-629,-4029,11950,2345,-821,1977,6119 } }, + { "Panasonic DMC-GX8", 15, 0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + { "Panasonic DC-GX9", 15, 0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + { "Panasonic DMC-ZS100", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DC-ZS200", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DMC-ZS40", 15, 0, + { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, + { "Panasonic DMC-ZS50", 15, 0, + { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, + { "Panasonic DMC-TZ82", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-ZS6", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-ZS70", 15, 0, + { 9052,-3117,-883,-3045,11346,1927,-205,1520,4730 } }, + { "Leica S (Typ 007)", 0, 0, + { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } }, + { "Leica X", 0, 0, /* X and X-U, both (Typ 113) */ + { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, + { "Leica Q (Typ 116)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, + { "Leica M (Typ 262)", 0, 0, + { 6653,-1486,-611,-4221,13303,929,-881,2416,7226 } }, + { "Leica SL (Typ 601)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, + { "Leica TL2", 0, 0, + { 5836,-1626,-647,-5384,13326,2261,-1207,2129,5861 } }, + { "Leica TL", 0, 0, + { 5463,-988,-364,-4634,12036,2946,-766,1389,6522 } }, + { "Leica CL", 0, 0, + { 7414,-2393,-840,-5127,13180,2138,-1585,2468,5064 } }, + { "Leica M10", 0, 0, + { 8249,-2849,-620,-5415,14756,565,-957,3074,6517 } }, + { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, - { "Phase One P 2", 0, + { "Phase One H 25", 0, 0, { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, - { "Phase One P 30", 0, + { "Phase One P 2", 0, 0, + { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, + { "Phase One P 30", 0, 0, { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, - { "Phase One P 45", 0, + { "Phase One P 45", 0, 0, { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, - { "SAMSUNG GX-1", 0, + { "Phase One P40", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { "Phase One P65", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { "Photron BC2-HD", 0, 0, /* DJC */ + { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } }, + { "Red One", 704, 0xffff, /* DJC */ + { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, + { "Ricoh GR II", 0, 0, + { 4630,-834,-423,-4977,12805,2417,-638,1467,6115 } }, + { "Ricoh GR", 0, 0, + { 3708,-543,-160,-5381,12254,3556,-1471,1929,8234 } }, + { "Samsung EX1", 0, 0x3e00, + { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, + { "Samsung EX2F", 0, 0x7ff, + { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, + { "Samsung EK-GN120", 0, 0, + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { "Samsung NX mini", 0, 0, + { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, + { "Samsung NX3300", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, + { "Samsung NX3000", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, + { "Samsung NX30", 0, 0, /* NX30, NX300, NX300M */ + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { "Samsung NX2000", 0, 0, + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { "Samsung NX2", 0, 0xfff, /* NX20, NX200, NX210 */ + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { "Samsung NX1000", 0, 0, + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { "Samsung NX1100", 0, 0, + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { "Samsung NX11", 0, 0, + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { "Samsung NX10", 0, 0, /* also NX100 */ + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { "Samsung NX500", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { "Samsung NX5", 0, 0, + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { "Samsung NX1", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { "Samsung WB2000", 0, 0xfff, + { 12093,-3557,-1155,-1000,9534,1733,-22,1787,4576 } }, + { "Samsung GX-1", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, - { "Sinar", 0, /* DJC */ + { "Samsung GX20", 0, 0, /* copied from Pentax K20D */ + { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, + { "Samsung S85", 0, 0, /* DJC */ + { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, + { "Sinar", 0, 0, /* DJC */ { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, - { "SONY DSC-F828", 491, + { "Sony DSC-F828", 0, 0, { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, - { "SONY DSC-R1", 512, + { "Sony DSC-R1", 0, 0, { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, - { "SONY DSC-V3", 0, + { "Sony DSC-V3", 0, 0, { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, - { "SONY DSLR-A100", 0, + { "Sony DSC-RX100M", 0, 0, /* M2, M3, M4, and M5 */ + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, + { "Sony DSC-RX100", 0, 0, + { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, + { "Sony DSC-RX10M4", 0, 0, + { 7699,-2566,-629,-2967,11270,1928,-378,1286,4807 } }, + { "Sony DSC-RX10", 0, 0, /* also RX10M2, RX10M3 */ + { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, + { "Sony DSC-RX1RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony DSC-RX1", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { "Sony DSC-RX0", 200, 0, + { 9396,-3507,-843,-2497,11111,1572,-343,1355,5089 } }, + { "Sony DSLR-A100", 0, 0xfeb, { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, - { "SONY DSLR-A200", 0, + { "Sony DSLR-A290", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "Sony DSLR-A2", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, - { "SONY DSLR-A350", 0, /* copied from above */ + { "Sony DSLR-A300", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, - { "SONY DSLR-A700", 254, - { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } } + { "Sony DSLR-A330", 0, 0, + { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, + { "Sony DSLR-A350", 0, 0xffc, + { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, + { "Sony DSLR-A380", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "Sony DSLR-A390", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "Sony DSLR-A450", 0, 0xfeb, + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { "Sony DSLR-A580", 0, 0xfeb, + { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { "Sony DSLR-A500", 0, 0xfeb, + { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, + { "Sony DSLR-A5", 0, 0xfeb, + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { "Sony DSLR-A700", 0, 0, + { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, + { "Sony DSLR-A850", 0, 0, + { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, + { "Sony DSLR-A900", 0, 0, + { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, + { "Sony ILCA-68", 0, 0, + { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, + { "Sony ILCA-77M2", 0, 0, + { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, + { "Sony ILCA-99M2", 0, 0, + { 6660,-1918,-471,-4613,12398,2485,-649,1433,6447 } }, + { "Sony ILCE-6", 0, 0, /* 6300, 6500 */ + { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, + { "Sony ILCE-7M2", 0, 0, + { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, + { "Sony ILCE-7M3", 0, 0, + { 7374,-2389,-551,-5435,13162,2519,-1006,1795,6552 } }, + { "Sony ILCE-7S", 0, 0, /* also ILCE-7SM2 */ + { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, + { "Sony ILCE-7RM3", 0, 0, + { 6640,-1847,-503,-5238,13010,2474,-993,1673,6527 } }, + { "Sony ILCE-7RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony ILCE-7R", 0, 0, + { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, + { "Sony ILCE-7", 0, 0, + { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, + { "Sony ILCE-9", 0, 0, + { 6389,-1703,-378,-4562,12265,2587,-670,1489,6550 } }, + { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony NEX-5N", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony NEX-5R", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-5T", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-3N", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-3", 138, 0, /* DJC */ + { 6907,-1256,-645,-4940,12621,2320,-1710,2581,6230 } }, + { "Sony NEX-5", 116, 0, /* DJC */ + { 6807,-1350,-342,-4216,11649,2567,-1089,2001,6420 } }, + { "Sony NEX-3", 0, 0, /* Adobe */ + { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, + { "Sony NEX-5", 0, 0, /* Adobe */ + { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, + { "Sony NEX-6", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-7", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A33", 0, 0, + { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, + { "Sony SLT-A35", 0, 0, + { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, + { "Sony SLT-A37", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A55", 0, 0, + { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { "Sony SLT-A57", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A58", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A65", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { "Sony SLT-A77", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { "Sony SLT-A99", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { "YI M1", 0, 0, + { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, }; double cam_xyz[4][3]; char name[130]; @@ -6388,11 +8267,13 @@ sprintf (name, "%s %s", make, model); for (i=0; i < sizeof table / sizeof *table; i++) if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { - if (table[i].black) - black = table[i].black; - for (j=0; j < 12; j++) - cam_xyz[0][j] = table[i].trans[j] / 10000.0; - cam_xyz_coeff (cam_xyz); + if (table[i].black) black = (ushort) table[i].black; + if (table[i].maximum) maximum = (ushort) table[i].maximum; + if (table[i].trans[0]) { + for (raw_color = j=0; j < 12; j++) + ((double *)cam_xyz)[j] = table[i].trans[j] / 10000.0; + cam_xyz_coeff (rgb_cam, cam_xyz); + } break; } } @@ -6436,100 +8317,336 @@ return sum[0] < sum[1] ? 0x4d4d : 0x4949; } +float CLASS find_green (int bps, int bite, int off0, int off1) +{ + UINT64 bitbuf=0; + int vbits, col, i, c; + ushort img[2][2064]; + double sum[]={0,0}; + + FORC(2) { + fseek (ifp, c ? off1:off0, SEEK_SET); + for (vbits=col=0; col < width; col++) { + for (vbits -= bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= (unsigned) (fgetc(ifp) << i); + } + img[c][col] = bitbuf << (64-bps-vbits) >> (64-bps); + } + } + FORC(width-1) { + sum[ c & 1] += ABS(img[0][c]-img[1][c+1]); + sum[~c & 1] += ABS(img[1][c]-img[0][c+1]); + } + return 100 * log(sum[0]/sum[1]); +} + /* Identify which camera created this file, and set global variables accordingly. */ void CLASS identify() { - char head[32], *cp; - unsigned hlen, fsize, i, c, is_canon; - struct jhead jh; + static const short pana[][6] = { + { 3130, 1743, 4, 0, -6, 0 }, + { 3130, 2055, 4, 0, -6, 0 }, + { 3130, 2319, 4, 0, -6, 0 }, + { 3170, 2103, 18, 0,-42, 20 }, + { 3170, 2367, 18, 13,-42,-21 }, + { 3177, 2367, 0, 0, -1, 0 }, + { 3304, 2458, 0, 0, -1, 0 }, + { 3330, 2463, 9, 0, -5, 0 }, + { 3330, 2479, 9, 0,-17, 4 }, + { 3370, 1899, 15, 0,-44, 20 }, + { 3370, 2235, 15, 0,-44, 20 }, + { 3370, 2511, 15, 10,-44,-21 }, + { 3690, 2751, 3, 0, -8, -3 }, + { 3710, 2751, 0, 0, -3, 0 }, + { 3724, 2450, 0, 0, 0, -2 }, + { 3770, 2487, 17, 0,-44, 19 }, + { 3770, 2799, 17, 15,-44,-19 }, + { 3880, 2170, 6, 0, -6, 0 }, + { 4060, 3018, 0, 0, 0, -2 }, + { 4290, 2391, 3, 0, -8, -1 }, + { 4330, 2439, 17, 15,-44,-19 }, + { 4508, 2962, 0, 0, -3, -4 }, + { 4508, 3330, 0, 0, -3, -6 }, + }; + static const ushort canon[][11] = { + { 1944, 1416, 0, 0, 48, 0 }, + { 2144, 1560, 4, 8, 52, 2, 0, 0, 0, 25 }, + { 2224, 1456, 48, 6, 0, 2 }, + { 2376, 1728, 12, 6, 52, 2 }, + { 2672, 1968, 12, 6, 44, 2 }, + { 3152, 2068, 64, 12, 0, 0, 16 }, + { 3160, 2344, 44, 12, 4, 4 }, + { 3344, 2484, 4, 6, 52, 6 }, + { 3516, 2328, 42, 14, 0, 0 }, + { 3596, 2360, 74, 12, 0, 0 }, + { 3744, 2784, 52, 12, 8, 12 }, + { 3944, 2622, 30, 18, 6, 2 }, + { 3948, 2622, 42, 18, 0, 2 }, + { 3984, 2622, 76, 20, 0, 2, 14 }, + { 4104, 3048, 48, 12, 24, 12 }, + { 4116, 2178, 4, 2, 0, 0 }, + { 4152, 2772, 192, 12, 0, 0 }, + { 4160, 3124, 104, 11, 8, 65 }, + { 4176, 3062, 96, 17, 8, 0, 0, 16, 0, 7, 0x49 }, + { 4192, 3062, 96, 17, 24, 0, 0, 16, 0, 0, 0x49 }, + { 4312, 2876, 22, 18, 0, 2 }, + { 4352, 2874, 62, 18, 0, 0 }, + { 4476, 2954, 90, 34, 0, 0 }, + { 4480, 3348, 12, 10, 36, 12, 0, 0, 0, 18, 0x49 }, + { 4480, 3366, 80, 50, 0, 0 }, + { 4496, 3366, 80, 50, 12, 0 }, + { 4768, 3516, 96, 16, 0, 0, 0, 16 }, + { 4832, 3204, 62, 26, 0, 0 }, + { 4832, 3228, 62, 51, 0, 0 }, + { 5108, 3349, 98, 13, 0, 0 }, + { 5120, 3318, 142, 45, 62, 0 }, + { 5280, 3528, 72, 52, 0, 0 }, + { 5344, 3516, 142, 51, 0, 0 }, + { 5344, 3584, 126,100, 0, 2 }, + { 5360, 3516, 158, 51, 0, 0 }, + { 5568, 3708, 72, 38, 0, 0 }, + { 5632, 3710, 96, 17, 0, 0, 0, 16, 0, 0, 0x49 }, + { 5712, 3774, 62, 20, 10, 2 }, + { 5792, 3804, 158, 51, 0, 0 }, + { 5920, 3950, 122, 80, 2, 0 }, + { 6096, 4051, 76, 35, 0, 0 }, + { 6096, 4056, 72, 34, 0, 0 }, + { 6288, 4056, 264, 36, 0, 0 }, + { 6384, 4224, 120, 44, 0, 0 }, + { 6880, 4544, 136, 42, 0, 0 }, + { 8896, 5920, 160, 64, 0, 0 }, + }; + static const struct { + ushort id; + char model[20]; + } unique[] = { + { 0x168, "EOS 10D" }, { 0x001, "EOS-1D" }, + { 0x175, "EOS 20D" }, { 0x174, "EOS-1D Mark II" }, + { 0x234, "EOS 30D" }, { 0x232, "EOS-1D Mark II N" }, + { 0x190, "EOS 40D" }, { 0x169, "EOS-1D Mark III" }, + { 0x261, "EOS 50D" }, { 0x281, "EOS-1D Mark IV" }, + { 0x287, "EOS 60D" }, { 0x167, "EOS-1DS" }, + { 0x325, "EOS 70D" }, + { 0x408, "EOS 77D" }, { 0x331, "EOS M" }, + { 0x350, "EOS 80D" }, { 0x328, "EOS-1D X Mark II" }, + { 0x346, "EOS 100D" }, + { 0x417, "EOS 200D" }, + { 0x170, "EOS 300D" }, { 0x188, "EOS-1Ds Mark II" }, + { 0x176, "EOS 450D" }, { 0x215, "EOS-1Ds Mark III" }, + { 0x189, "EOS 350D" }, { 0x324, "EOS-1D C" }, + { 0x236, "EOS 400D" }, { 0x269, "EOS-1D X" }, + { 0x252, "EOS 500D" }, { 0x213, "EOS 5D" }, + { 0x270, "EOS 550D" }, { 0x218, "EOS 5D Mark II" }, + { 0x286, "EOS 600D" }, { 0x285, "EOS 5D Mark III" }, + { 0x301, "EOS 650D" }, { 0x302, "EOS 6D" }, + { 0x326, "EOS 700D" }, { 0x250, "EOS 7D" }, + { 0x393, "EOS 750D" }, { 0x289, "EOS 7D Mark II" }, + { 0x347, "EOS 760D" }, { 0x406, "EOS 6D Mark II" }, + { 0x405, "EOS 800D" }, { 0x349, "EOS 5D Mark IV" }, + { 0x254, "EOS 1000D" }, + { 0x288, "EOS 1100D" }, + { 0x327, "EOS 1200D" }, { 0x382, "EOS 5DS" }, + { 0x404, "EOS 1300D" }, { 0x401, "EOS 5DS R" }, + { 0x422, "EOS 1500D" }, + { 0x432, "EOS 3000D" }, + }, sonique[] = { + { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, + { 0x101, "DSLR-A900" }, { 0x102, "DSLR-A700" }, + { 0x103, "DSLR-A200" }, { 0x104, "DSLR-A350" }, + { 0x105, "DSLR-A300" }, { 0x108, "DSLR-A330" }, + { 0x109, "DSLR-A230" }, { 0x10a, "DSLR-A290" }, + { 0x10d, "DSLR-A850" }, { 0x111, "DSLR-A550" }, + { 0x112, "DSLR-A500" }, { 0x113, "DSLR-A450" }, + { 0x116, "NEX-5" }, { 0x117, "NEX-3" }, + { 0x118, "SLT-A33" }, { 0x119, "SLT-A55V" }, + { 0x11a, "DSLR-A560" }, { 0x11b, "DSLR-A580" }, + { 0x11c, "NEX-C3" }, { 0x11d, "SLT-A35" }, + { 0x11e, "SLT-A65V" }, { 0x11f, "SLT-A77V" }, + { 0x120, "NEX-5N" }, { 0x121, "NEX-7" }, + { 0x123, "SLT-A37" }, { 0x124, "SLT-A57" }, + { 0x125, "NEX-F3" }, { 0x126, "SLT-A99V" }, + { 0x127, "NEX-6" }, { 0x128, "NEX-5R" }, + { 0x129, "DSC-RX100" }, { 0x12a, "DSC-RX1" }, + { 0x12e, "ILCE-3000" }, { 0x12f, "SLT-A58" }, + { 0x131, "NEX-3N" }, { 0x132, "ILCE-7" }, + { 0x133, "NEX-5T" }, { 0x134, "DSC-RX100M2" }, + { 0x135, "DSC-RX10" }, { 0x136, "DSC-RX1R" }, + { 0x137, "ILCE-7R" }, { 0x138, "ILCE-6000" }, + { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, + { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, + { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, + { 0x155, "DSC-RX100M4" },{ 0x156, "DSC-RX10M2" }, + { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, + { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, + { 0x161, "ILCA-68" }, { 0x162, "ILCA-99M2" }, + { 0x163, "DSC-RX10M3" }, { 0x164, "DSC-RX100M5" }, + { 0x165, "ILCE-6300" }, { 0x166, "ILCE-9" }, + { 0x168, "ILCE-6500" }, { 0x16a, "ILCE-7RM3" }, + { 0x16b, "ILCE-7M3" }, { 0x16c, "DSC-RX0" }, + { 0x16d, "DSC-RX10M4" }, + }; + static const char *orig, panalias[][12] = { + "@DC-FZ80", "DC-FZ82", "DC-FZ85", + "@DC-FZ81", "DC-FZ83", + "@DC-GF9", "DC-GX800", "DC-GX850", + "@DC-GF10", "DC-GF90", + "@DC-GX9", "DC-GX7MK3", + "@DC-ZS70", "DC-TZ90", "DC-TZ91", "DC-TZ92", "DC-TZ93", + "@DMC-FZ40", "DMC-FZ45", + "@DMC-FZ2500", "DMC-FZ2000", "DMC-FZH1", + "@DMC-G8", "DMC-G80", "DMC-G81", "DMC-G85", + "@DMC-GX85", "DMC-GX80", "DMC-GX7MK2", + "@DMC-LX9", "DMC-LX10", "DMC-LX15", + "@DMC-ZS40", "DMC-TZ60", "DMC-TZ61", + "@DMC-ZS50", "DMC-TZ70", "DMC-TZ71", + "@DMC-ZS60", "DMC-TZ80", "DMC-TZ81", "DMC-TZ85", + "@DMC-ZS100", "DMC-ZS110", "DMC-TZ100", "DMC-TZ101", "DMC-TZ110", "DMC-TX1", + "@DC-ZS200", "DC-TX2", "DC-TZ200", "DC-TZ202", "DC-TZ220", "DC-ZS220", + }; static const struct { - int fsize; - char make[12], model[19], withjpeg; + unsigned fsize; + ushort rw, rh; + uchar lm, tm, rm, bm, lf, cf, max, flags; + char make[10], model[20]; + ushort offset; } table[] = { - { 62464, "Kodak", "DC20" ,0 }, - { 124928, "Kodak", "DC20" ,0 }, - { 1652736, "Kodak", "DCS200" ,0 }, - { 4159302, "Kodak", "C330" ,0 }, - { 4162462, "Kodak", "C330" ,0 }, - { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */ - { 614400, "Kodak", "KAI-0340" ,0 }, - { 787456, "Creative", "PC-CAM 600" ,0 }, - { 1138688, "Minolta", "RD175" ,0 }, - { 3840000, "Foculus", "531C" ,0 }, - { 786432, "AVT", "F-080C" ,0 }, - { 1447680, "AVT", "F-145C" ,0 }, - { 1920000, "AVT", "F-201C" ,0 }, - { 5067304, "AVT", "F-510C" ,0 }, - { 10134608, "AVT", "F-510C" ,0 }, - { 16157136, "AVT", "F-810C" ,0 }, - { 1409024, "Sony", "XCD-SX910CR",0 }, - { 2818048, "Sony", "XCD-SX910CR",0 }, - { 3884928, "Micron", "2010" ,0 }, - { 6624000, "Pixelink", "A782" ,0 }, - { 13248000, "Pixelink", "A782" ,0 }, - { 6291456, "RoverShot","3320AF" ,0 }, - { 6553440, "Canon", "PowerShot A460",0 }, - { 6653280, "Canon", "PowerShot A530",0 }, - { 6573120, "Canon", "PowerShot A610",0 }, - { 9219600, "Canon", "PowerShot A620",0 }, - { 10341600, "Canon", "PowerShot A720",0 }, - { 10383120, "Canon", "PowerShot A630",0 }, - { 12945240, "Canon", "PowerShot A640",0 }, - { 15636240, "Canon", "PowerShot A650",0 }, - { 7710960, "Canon", "PowerShot S3 IS",0 }, - { 5939200, "OLYMPUS", "C770UZ" ,0 }, - { 1581060, "NIKON", "E900" ,1 }, /* or E900s,E910 */ - { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */ - { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */ - { 4771840, "NIKON", "E990" ,1 }, /* or E995, Oly C3030Z */ - { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */ - { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */ - { 5865472, "NIKON", "E4500" ,1 }, - { 7438336, "NIKON", "E5000" ,1 }, /* or E5700 */ - { 8998912, "NIKON", "COOLPIX S6" ,1 }, - { 1976352, "CASIO", "QV-2000UX" ,1 }, - { 3217760, "CASIO", "QV-3*00EX" ,1 }, - { 6218368, "CASIO", "QV-5700" ,1 }, - { 6054400, "CASIO", "QV-R41" ,1 }, - { 7530816, "CASIO", "QV-R51" ,1 }, - { 7684000, "CASIO", "QV-4000" ,1 }, - { 4948608, "CASIO", "EX-S100" ,1 }, - { 7542528, "CASIO", "EX-Z50" ,1 }, - { 7753344, "CASIO", "EX-Z55" ,1 }, - { 7426656, "CASIO", "EX-P505" ,1 }, - { 9313536, "CASIO", "EX-P600" ,1 }, - { 10979200, "CASIO", "EX-P700" ,1 }, - { 3178560, "PENTAX", "Optio S" ,1 }, - { 4841984, "PENTAX", "Optio S" ,1 }, - { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i, CASIO EX-Z4 */ - { 10702848, "PENTAX", "Optio 750Z" ,1 }, - { 12582980, "Sinar", "" ,0 }, - { 33292868, "Sinar", "" ,0 }, - { 44390468, "Sinar", "" ,0 } }; + { 786432,1024, 768, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-080C" }, + { 1447680,1392,1040, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-145C" }, + { 1920000,1600,1200, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-201C" }, + { 5067304,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C" }, + { 5067316,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C",12 }, + { 10134608,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C" }, + { 10134620,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C",12 }, + { 16157136,3272,2469, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-810C" }, + { 15980544,3264,2448, 0, 0, 0, 0, 8,0x61,0,1,"AgfaPhoto","DC-833m" }, + { 9631728,2532,1902, 0, 0, 0, 0,96,0x61,0,0,"Alcatel","5035D" }, + { 2868726,1384,1036, 0, 0, 0, 0,64,0x49,0,8,"Baumer","TXG14",1078 }, + { 5298000,2400,1766,12,12,44, 2, 8,0x94,0,2,"Canon","PowerShot SD300" }, + { 6553440,2664,1968, 4, 4,44, 4, 8,0x94,0,2,"Canon","PowerShot A460" }, + { 6573120,2672,1968,12, 8,44, 0, 8,0x94,0,2,"Canon","PowerShot A610" }, + { 6653280,2672,1992,10, 6,42, 2, 8,0x94,0,2,"Canon","PowerShot A530" }, + { 7710960,2888,2136,44, 8, 4, 0, 8,0x94,0,2,"Canon","PowerShot S3 IS" }, + { 9219600,3152,2340,36,12, 4, 0, 8,0x94,0,2,"Canon","PowerShot A620" }, + { 9243240,3152,2346,12, 7,44,13, 8,0x49,0,2,"Canon","PowerShot A470" }, + { 10341600,3336,2480, 6, 5,32, 3, 8,0x94,0,2,"Canon","PowerShot A720 IS" }, + { 10383120,3344,2484,12, 6,44, 6, 8,0x94,0,2,"Canon","PowerShot A630" }, + { 12945240,3736,2772,12, 6,52, 6, 8,0x94,0,2,"Canon","PowerShot A640" }, + { 15636240,4104,3048,48,12,24,12, 8,0x94,0,2,"Canon","PowerShot A650" }, + { 15467760,3720,2772, 6,12,30, 0, 8,0x94,0,2,"Canon","PowerShot SX110 IS" }, + { 15534576,3728,2778,12, 9,44, 9, 8,0x94,0,2,"Canon","PowerShot SX120 IS" }, + { 18653760,4080,3048,24,12,24,12, 8,0x94,0,2,"Canon","PowerShot SX20 IS" }, + { 19131120,4168,3060,92,16, 4, 1, 8,0x94,0,2,"Canon","PowerShot SX220 HS" }, + { 21936096,4464,3276,25,10,73,12, 8,0x16,0,2,"Canon","PowerShot SX30 IS" }, + { 24724224,4704,3504, 8,16,56, 8, 8,0x94,0,2,"Canon","PowerShot A3300 IS" }, + { 30858240,5248,3920, 8,16,56,16, 8,0x94,0,2,"Canon","IXUS 160" }, + { 1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX" }, + { 3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX" }, + { 6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700" }, + { 7816704,2867,2181, 0, 0,34,36, 0,0x16,0,1,"Casio","EX-Z60" }, + { 2937856,1621,1208, 0, 0, 1, 0, 0,0x94,7,13,"Casio","EX-S20" }, + { 4948608,2090,1578, 0, 0,32,34, 0,0x94,7,1,"Casio","EX-S100" }, + { 6054400,2346,1720, 2, 0,32, 0, 0,0x94,7,1,"Casio","QV-R41" }, + { 7426656,2568,1928, 0, 0, 0, 0, 0,0x94,0,1,"Casio","EX-P505" }, + { 7530816,2602,1929, 0, 0,22, 0, 0,0x94,7,1,"Casio","QV-R51" }, + { 7542528,2602,1932, 0, 0,32, 0, 0,0x94,7,1,"Casio","EX-Z50" }, + { 7562048,2602,1937, 0, 0,25, 0, 0,0x16,7,1,"Casio","EX-Z500" }, + { 7753344,2602,1986, 0, 0,32,26, 0,0x94,7,1,"Casio","EX-Z55" }, + { 9313536,2858,2172, 0, 0,14,30, 0,0x94,7,1,"Casio","EX-P600" }, + { 10834368,3114,2319, 0, 0,27, 0, 0,0x94,0,1,"Casio","EX-Z750" }, + { 10843712,3114,2321, 0, 0,25, 0, 0,0x94,0,1,"Casio","EX-Z75" }, + { 10979200,3114,2350, 0, 0,32,32, 0,0x94,7,1,"Casio","EX-P700" }, + { 12310144,3285,2498, 0, 0, 6,30, 0,0x94,0,1,"Casio","EX-Z850" }, + { 12489984,3328,2502, 0, 0,47,35, 0,0x94,0,1,"Casio","EX-Z8" }, + { 15499264,3754,2752, 0, 0,82, 0, 0,0x94,0,1,"Casio","EX-Z1050" }, + { 18702336,4096,3044, 0, 0,24, 0,80,0x94,7,1,"Casio","EX-ZR100" }, + { 7684000,2260,1700, 0, 0, 0, 0,13,0x94,0,1,"Casio","QV-4000" }, + { 787456,1024, 769, 0, 1, 0, 0, 0,0x49,0,0,"Creative","PC-CAM 600" }, + { 28829184,4384,3288, 0, 0, 0, 0,36,0x61,0,0,"DJI" }, + { 15151104,4608,3288, 0, 0, 0, 0, 0,0x94,0,0,"Matrix" }, + { 3840000,1600,1200, 0, 0, 0, 0,65,0x49,0,0,"Foculus","531C" }, + { 307200, 640, 480, 0, 0, 0, 0, 0,0x94,0,0,"Generic" }, + { 62464, 256, 244, 1, 1, 6, 1, 0,0x8d,0,0,"Kodak","DC20" }, + { 124928, 512, 244, 1, 1,10, 1, 0,0x8d,0,0,"Kodak","DC20" }, + { 1652736,1536,1076, 0,52, 0, 0, 0,0x61,0,0,"Kodak","DCS200" }, + { 4159302,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330" }, + { 4162462,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330",3160 }, + { 2247168,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" }, + { 3370752,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" }, + { 6163328,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603" }, + { 6166488,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603",3160 }, + { 460800, 640, 480, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, + { 9116448,2848,2134, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, + { 12241200,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP" }, + { 12272756,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP",31556 }, + { 18000000,4000,3000, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","12MP" }, + { 614400, 640, 480, 0, 3, 0, 0,64,0x94,0,0,"Kodak","KAI-0340" }, + { 15360000,3200,2400, 0, 0, 0, 0,96,0x16,0,0,"Lenovo","A820" }, + { 3884928,1608,1207, 0, 0, 0, 0,96,0x16,0,0,"Micron","2010",3212 }, + { 1138688,1534, 986, 0, 0, 0, 0, 0,0x61,0,0,"Minolta","RD175",513 }, + { 1581060,1305, 969, 0, 0,18, 6, 6,0x1e,4,1,"Nikon","E900" }, + { 2465792,1638,1204, 0, 0,22, 1, 6,0x4b,5,1,"Nikon","E950" }, + { 2940928,1616,1213, 0, 0, 0, 7,30,0x94,0,1,"Nikon","E2100" }, + { 4771840,2064,1541, 0, 0, 0, 1, 6,0xe1,0,1,"Nikon","E990" }, + { 4775936,2064,1542, 0, 0, 0, 0,30,0x94,0,1,"Nikon","E3700" }, + { 5865472,2288,1709, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E4500" }, + { 5869568,2288,1710, 0, 0, 0, 0, 6,0x16,0,1,"Nikon","E4300" }, + { 7438336,2576,1925, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E5000" }, + { 8998912,2832,2118, 0, 0, 0, 0,30,0x94,7,1,"Nikon","COOLPIX S6" }, + { 5939200,2304,1718, 0, 0, 0, 0,30,0x16,0,0,"Olympus","C770UZ" }, + { 3178560,2064,1540, 0, 0, 0, 0, 0,0x94,0,1,"Pentax","Optio S" }, + { 4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S" }, + { 6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4" }, + { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z" }, + { 4147200,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD" }, + { 4151666,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",8 }, + { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782" }, + { 6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF" }, + { 311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA" }, + { 16098048,3288,2448, 0, 0,24, 0, 9,0x94,0,1,"Samsung","S85" }, + { 16215552,3312,2448, 0, 0,48, 0, 9,0x94,0,1,"Samsung","S85" }, + { 20487168,3648,2808, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, + { 24000000,4000,3000, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, + { 12582980,3072,2048, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, + { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, + { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, + { 1409024,1376,1024, 0, 0, 1, 0, 0,0x49,0,0,"Sony","XCD-SX910CR" }, + { 2818048,1376,1024, 0, 0, 1, 0,97,0x49,0,0,"Sony","XCD-SX910CR" }, + { 17496000,4320,3240, 0, 0, 0,0,224,0x94,0,0,"Xiro","Xplorer V" }, + }; static const char *corp[] = - { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX", - "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar", "Phase One", - "SAMSUNG", "Mamiya" }; + { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", + "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", + "Nikon", "Nokia", "Olympus", "Ricoh", "Pentax", "Phase One", + "Samsung", "Sigma", "Sinar", "Sony", "YI" }; + char head[32], *cp; + int hlen, flen, fsize, zero_fsize=1, i, c; + struct jhead jh; - tiff_flip = flip = filters = -1; /* 0 is valid, so -1 is unknown */ + tiff_flip = flip = filters = UINT_MAX; /* unknown */ raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; maximum = height = width = top_margin = left_margin = 0; cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; iso_speed = shutter = aperture = focal_len = unique_id = 0; + tiff_nifds = 0; + memset (tiff_ifd, 0, sizeof tiff_ifd); memset (gpsdata, 0, sizeof gpsdata); + memset (cblack, 0, sizeof cblack); memset (white, 0, sizeof white); + memset (mask, 0, sizeof mask); thumb_offset = thumb_length = thumb_width = thumb_height = 0; load_raw = thumb_load_raw = 0; write_thumb = &CLASS jpeg_thumb; - data_offset = meta_length = tiff_bps = tiff_compress = 0; - kodak_cbpp = zero_after_ff = dng_version = 0; + data_offset = meta_offset = meta_length = tiff_bps = tiff_compress = 0; + kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; timestamp = shot_order = tiff_samples = black = is_foveon = 0; mix_green = profile_length = data_error = zero_is_bad = 0; - pixel_aspect = is_raw = raw_color = use_gamma = 1; - tile_width = tile_length = INT_MAX; + pixel_aspect = is_raw = raw_color = 1; + tile_width = tile_length = 0; for (i=0; i < 4; i++) { cam_mul[i] = i == 1; pre_mul[i] = i < 3; @@ -6537,26 +8654,24 @@ FORC3 rgb_cam[c][i] = c == i; } colors = 3; - tiff_bps = 12; - for (i=0; i < 0x4000; i++) curve[i] = i; + for (i=0; i < 0x10000; i++) curve[i] = i; order = get2(); hlen = get4(); fseek (ifp, 0, SEEK_SET); fread (head, 1, 32, ifp); fseek (ifp, 0, SEEK_END); - fsize = ftell(ifp); + flen = fsize = ftell(ifp); if ((cp = (char *) memmem (head, 32, "MMMM", 4)) || (cp = (char *) memmem (head, 32, "IIII", 4))) { parse_phase_one (cp-head); - if (cp-head) parse_tiff(0); + if (cp-head && parse_tiff(0)) apply_tiff(); } else if (order == 0x4949 || order == 0x4d4d) { if (!memcmp (head+6,"HEAPCCDR",8)) { data_offset = hlen; - parse_ciff (hlen, fsize - hlen); - } else { - parse_tiff(0); - } + parse_ciff (hlen, flen-hlen, 0); + load_raw = &CLASS canon_load_raw; + } else if (parse_tiff(0)) apply_tiff(); } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && !memcmp (head+6,"Exif",4)) { fseek (ifp, 4, SEEK_SET); @@ -6578,9 +8693,11 @@ } else if (!strcmp (head, "qktk")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 100"); + load_raw = &CLASS quicktake_100_load_raw; } else if (!strcmp (head, "qktn")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 150"); + load_raw = &CLASS kodak_radc_load_raw; } else if (!memcmp (head,"FUJIFILM",8)) { fseek (ifp, 84, SEEK_SET); thumb_offset = get4(); @@ -6593,12 +8710,24 @@ if (is_raw == 2 && shot_select) parse_fuji (i); } - fseek (ifp, 100, SEEK_SET); - data_offset = get4(); + fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); + parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); + apply_tiff(); + if (!load_raw) { + load_raw = &CLASS unpacked_load_raw; + tiff_bps = 14; + } } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); parse_riff(); + } else if (!memcmp (head+4,"ftypcrx ",8)) { + fseek (ifp, 0, SEEK_SET); + parse_crx (fsize); + } else if (!memcmp (head+4,"ftypqt ",9)) { + fseek (ifp, 0, SEEK_SET); + parse_qt (fsize); + is_raw = 0; } else if (!memcmp (head,"\0\001\0\001\0@",6)) { fseek (ifp, 6, SEEK_SET); fread (make, 1, 8, ifp); @@ -6608,8 +8737,53 @@ get2(); raw_width = get2(); raw_height = get2(); - load_raw = nokia_load_raw; + load_raw = &CLASS nokia_load_raw; + filters = 0x61616161; + } else if (!memcmp (head,"NOKIARAW",8)) { + strcpy (make, "NOKIA"); + order = 0x4949; + fseek (ifp, 300, SEEK_SET); + data_offset = get4(); + i = get4(); + width = get2(); + height = get2(); + switch (tiff_bps = i*8 / (width * height)) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 10: load_raw = &CLASS nokia_load_raw; + } + raw_height = height + (top_margin = i / (width * tiff_bps/8) - height); + mask[0][3] = 1; + filters = 0x61616161; + } else if (!memcmp (head,"ARRI",4)) { + order = 0x4949; + fseek (ifp, 20, SEEK_SET); + width = get4(); + height = get4(); + strcpy (make, "ARRI"); + fseek (ifp, 668, SEEK_SET); + fread (model, 1, 64, ifp); + data_offset = 4096; + load_raw = &CLASS packed_load_raw; + load_flags = 88; filters = 0x61616161; + } else if (!memcmp (head,"XPDS",4)) { + order = 0x4949; + fseek (ifp, 0x800, SEEK_SET); + fread (make, 1, 41, ifp); + raw_height = get2(); + raw_width = get2(); + fseek (ifp, 56, SEEK_CUR); + fread (model, 1, 30, ifp); + data_offset = 0x10000; + load_raw = &CLASS canon_rmf_load_raw; + gamma_curve (0, 12.25, 1, 1023); + } else if (!memcmp (head+4,"RED1",4)) { + strcpy (make, "Red"); + strcpy (model,"One"); + parse_redcine(); + load_raw = &CLASS redcine_load_raw; + gamma_curve (1/2.4, 12.92, 1, 4095); + filters = 0x49494949; } else if (!memcmp (head,"DSC-Image",9)) parse_rollei(); else if (!memcmp (head,"PWAD",4)) @@ -6620,22 +8794,67 @@ parse_foveon(); else if (!memcmp (head,"CI",2)) parse_cine(); - else - for (i=0; i < sizeof table / sizeof *table; i++) + if (make[0] == 0) + for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) if (fsize == table[i].fsize) { strcpy (make, table[i].make ); strcpy (model, table[i].model); - if (table[i].withjpeg) + flip = table[i].flags >> 2; + zero_is_bad = table[i].flags & 2; + if (table[i].flags & 1) parse_external_jpeg(); - } - if (make[0] == 0) parse_smal (0, fsize); - if (make[0] == 0) parse_jpeg (is_raw = 0); + data_offset = table[i].offset; + raw_width = table[i].rw; + raw_height = table[i].rh; + left_margin = table[i].lm; + top_margin = table[i].tm; + width = raw_width - left_margin - table[i].rm; + height = raw_height - top_margin - table[i].bm; + filters = 0x1010101 * table[i].cf; + colors = 4 - !((filters & filters >> 1) & 0x5555); + load_flags = table[i].lf; + switch (tiff_bps = (fsize-data_offset)*8 / (raw_width*raw_height)) { + case 6: + load_raw = &CLASS minolta_rd175_load_raw; break; + case 8: + load_raw = &CLASS eight_bit_load_raw; break; + case 10: case 12: + load_flags |= 512; + if (!strcmp(make,"Canon")) load_flags |= 256; + load_raw = &CLASS packed_load_raw; break; + case 16: + order = 0x4949 | 0x404 * (load_flags & 1); + tiff_bps -= load_flags >> 4; + tiff_bps -= load_flags = load_flags >> 1 & 7; + load_raw = &CLASS unpacked_load_raw; + } + maximum = (1 << tiff_bps) - (1 << table[i].max); + } + if (zero_fsize) fsize = 0; + if (make[0] == 0) parse_smal (0, flen); + if (make[0] == 0) { + parse_jpeg(0); + if (!(strncmp(model,"ov",2) && strncmp(model,"RP_OV",5)) && + !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; + } for (i=0; i < sizeof corp / sizeof *corp; i++) - if (strstr (make, corp[i])) /* Simplify company names */ - strcpy (make, corp[i]); - if (!strncmp (make,"KODAK",5)) - make[16] = model[16] = 0; + if (strcasestr (make, corp[i])) /* Simplify company names */ + strcpy (make, corp[i]); + if ((!strcmp(make,"Kodak") || !strcmp(make,"Leica")) && + ((cp = strcasestr(model," DIGITAL CAMERA")) || + (cp = strstr(model,"FILE VERSION")))) + *cp = 0; + if (!strncasecmp(model,"PENTAX",6)) + strcpy (make, "Pentax"); cp = make + strlen(make); /* Remove trailing spaces */ while (*--cp == ' ') *cp = 0; cp = model + strlen(model); @@ -6643,57 +8862,128 @@ i = strlen(make); /* Remove make from model */ if (!strncasecmp (model, make, i) && model[i++] == ' ') memmove (model, model+i, 64-i); + if (!strncmp (model,"FinePix ",8)) + strcpy (model, model+8); if (!strncmp (model,"Digital Camera ",15)) strcpy (model, model+15); desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; if (!is_raw) goto notraw; - if (!maximum) maximum = (1 << tiff_bps) - 1; if (!height) height = raw_height; if (!width) width = raw_width; - if (fuji_width) { - width = height + fuji_width; - height = width - 1; - pixel_aspect = 1; - } if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ { height = 2616; width = 3896; } - if (height == 3136 && width == 4864) /* Pentax K20D */ - { height = 3124; width = 4688; } + if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */ + { height = 3124; width = 4688; filters = 0x16161616; } + if (raw_height == 2868 && (!strcmp(model,"K-r") || !strcmp(model,"K-x"))) + { width = 4309; filters = 0x16161616; } + if (raw_height == 3136 && !strcmp(model,"K-7")) + { height = 3122; width = 4684; filters = 0x16161616; top_margin = 2; } + if (raw_height == 3284 && !strncmp(model,"K-5",3)) + { left_margin = 10; width = 4950; filters = 0x16161616; } + if (raw_height == 3300 && !strncmp(model,"K-50",4)) + { height = 3288, width = 4952; left_margin = 0; top_margin = 12; } + if (raw_height == 3664 && !strncmp(model,"K-S",3)) + { width = 5492; left_margin = 0; } + if (raw_height == 4032 && !strcmp(model,"K-3")) + { height = 4032; width = 6040; left_margin = 4; } + if (raw_height == 4060 && !strcmp(model,"KP")) + { height = 4032; width = 6032; left_margin = 52; top_margin = 28; } + if (raw_height == 4950 && !strcmp(model,"K-1")) + { height = 4932; width = 7380; left_margin = 4; top_margin = 18; } + if (raw_height == 5552 && !strcmp(model,"645D")) + { height = 5502; width = 7328; left_margin = 48; top_margin = 29; + filters = 0x61616161; } + if (height == 3014 && width == 4096) /* Ricoh GX200 */ + width = 4014; if (dng_version) { if (filters == UINT_MAX) filters = 0; - if (filters) is_raw = tiff_samples; - else colors = tiff_samples; - if (tiff_compress == 1) - load_raw = &CLASS adobe_dng_load_raw_nc; - if (tiff_compress == 7) - load_raw = &CLASS adobe_dng_load_raw_lj; + if (filters) is_raw *= tiff_samples; + else colors = tiff_samples; + switch (tiff_compress) { + case 0: + case 1: load_raw = &CLASS packed_dng_load_raw; break; + case 7: load_raw = &CLASS lossless_dng_load_raw; break; + case 34892: load_raw = &CLASS lossy_dng_load_raw; break; + default: load_raw = 0; + } goto dng_skip; } - if ((is_canon = !strcmp(make,"Canon"))) { - load_raw = memcmp (head+6,"HEAPCCDR",8) ? - &CLASS lossless_jpeg_load_raw : &CLASS canon_compressed_load_raw; - maximum = 0xfff; + if (!strcmp(make,"Canon") && !fsize && tiff_bps != 15) { + if (!load_raw) + load_raw = &CLASS lossless_jpeg_load_raw; + for (i=0; i < sizeof canon / sizeof *canon; i++) + if (raw_width == canon[i][0] && raw_height == canon[i][1]) { + width = raw_width - (left_margin = canon[i][2]); + height = raw_height - (top_margin = canon[i][3]); + width -= canon[i][4]; + height -= canon[i][5]; + mask[0][1] = canon[i][6]; + mask[0][3] = -canon[i][7]; + mask[1][1] = canon[i][8]; + mask[1][3] = -canon[i][9]; + if (canon[i][10]) filters = canon[i][10] * 0x01010101; + } + if ((unique_id | 0x20000) == 0x2720000) { + left_margin = 8; + top_margin = 16; + } + } + for (i=0; i < sizeof unique / sizeof *unique; i++) + if (unique_id == 0x80000000 + unique[i].id) { + adobe_coeff ("Canon", unique[i].model); + if (model[4] == 'K' && strlen(model) == 8) + strcpy (model, unique[i].model); + } + for (i=0; i < sizeof sonique / sizeof *sonique; i++) + if (unique_id == sonique[i].id) + strcpy (model, sonique[i].model); + for (i=0; i < sizeof panalias / sizeof *panalias; i++) + if (panalias[i][0] == '@') orig = panalias[i]+1; + else if (!strcmp(model,panalias[i])) + adobe_coeff ("Panasonic", orig); + if (!strcmp(make,"Nikon")) { + if (!load_raw) + load_raw = &CLASS packed_load_raw; + if (model[0] == 'E') + load_flags |= !data_offset << 2 | 2; } - if (!strcmp(make,"NIKON") && !load_raw) - load_raw = &CLASS nikon_load_raw; /* Set parameters based on camera name (for non-DNG files). */ + if (!strcmp(model,"KAI-0340") + && find_green (16, 16, 3840, 5120) < 25) { + height = 480; + top_margin = filters = 0; + strcpy (model,"C603"); + } + if (!strcmp(make,"Sony") && raw_width > 3888) + black = 128 << (tiff_bps - 12); if (is_foveon) { if (height*2 < width) pixel_aspect = 0.5; if (height > width) pixel_aspect = 2; filters = 0; - load_raw = &CLASS foveon_load_raw; simple_coeff(0); - } else if (is_canon && tiff_samples == 4) { + } else if (!strcmp(make,"Canon") && tiff_bps == 15) { + switch (width) { + case 3344: width -= 66; + case 3872: width -= 6; + } + if (height > width) { + SWAP(height,width); + SWAP(raw_height,raw_width); + } + if (width == 7200 && height == 3888) { + raw_width = width = 6480; + raw_height = height = 4320; + } filters = 0; + tiff_samples = colors = 3; load_raw = &CLASS canon_sraw_load_raw; } else if (!strcmp(model,"PowerShot 600")) { height = 613; width = 854; raw_width = 896; - pixel_aspect = 607/628.0; colors = 4; filters = 0xe1e4e1e4; load_raw = &CLASS canon_600_load_raw; @@ -6703,197 +8993,37 @@ width = 960; raw_width = 992; pixel_aspect = 256/235.0; - colors = 4; filters = 0x1e4e1e4e; - load_raw = &CLASS canon_a5_load_raw; + goto canon_a5; } else if (!strcmp(model,"PowerShot A50")) { height = 968; width = 1290; raw_width = 1320; - colors = 4; filters = 0x1b4e4b1e; - load_raw = &CLASS canon_a5_load_raw; + goto canon_a5; } else if (!strcmp(model,"PowerShot Pro70")) { height = 1024; width = 1552; - colors = 4; filters = 0x1e4b4e1b; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A460")) { - height = 1960; - width = 2616; - raw_height = 1968; - raw_width = 2664; - top_margin = 4; - left_margin = 4; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A530")) { - height = 1984; - width = 2620; - raw_height = 1992; - raw_width = 2672; - top_margin = 6; - left_margin = 10; - load_raw = &CLASS canon_a5_load_raw; - raw_color = 0; - } else if (!strcmp(model,"PowerShot A610")) { - if (canon_s2is()) strcpy (model+10, "S2 IS"); - height = 1960; - width = 2616; - raw_height = 1968; - raw_width = 2672; - top_margin = 8; - left_margin = 12; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A620")) { - height = 2328; - width = 3112; - raw_height = 2340; - raw_width = 3152; - top_margin = 12; - left_margin = 36; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A720")) { - height = 2472; - width = 3298; - raw_height = 2480; - raw_width = 3336; - top_margin = 5; - left_margin = 6; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A630")) { - height = 2472; - width = 3288; - raw_height = 2484; - raw_width = 3344; - top_margin = 6; - left_margin = 12; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A640")) { - height = 2760; - width = 3672; - raw_height = 2772; - raw_width = 3736; - top_margin = 6; - left_margin = 12; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A650")) { - height = 3024; - width = 4032; - raw_height = 3048; - raw_width = 4104; - top_margin = 12; - left_margin = 48; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot S3 IS")) { - height = 2128; - width = 2840; - raw_height = 2136; - raw_width = 2888; - top_margin = 8; - left_margin = 44; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot Pro90 IS")) { - width = 1896; +canon_a5: + colors = 4; + tiff_bps = 10; + load_raw = &CLASS packed_load_raw; + load_flags = 264; + } else if (!strcmp(model,"PowerShot Pro90 IS") || + !strcmp(model,"PowerShot G1")) { colors = 4; filters = 0xb4b4b4b4; - } else if (is_canon && raw_width == 2144) { - height = 1550; - width = 2088; - top_margin = 8; - left_margin = 4; - if (!strcmp(model,"PowerShot G1")) { - colors = 4; - filters = 0xb4b4b4b4; - } - } else if (is_canon && raw_width == 2224) { - height = 1448; - width = 2176; - top_margin = 6; - left_margin = 48; - } else if (is_canon && raw_width == 2376) { - height = 1720; - width = 2312; - top_margin = 6; - left_margin = 12; - } else if (is_canon && raw_width == 2672) { - height = 1960; - width = 2616; - top_margin = 6; - left_margin = 12; - } else if (is_canon && raw_width == 3152) { - height = 2056; - width = 3088; - top_margin = 12; - left_margin = 64; - if (unique_id == 0x80000170) - adobe_coeff ("Canon","EOS 300D"); - maximum = 0xfa0; - } else if (is_canon && raw_width == 3160) { - height = 2328; - width = 3112; - top_margin = 12; - left_margin = 44; - } else if (is_canon && raw_width == 3344) { - height = 2472; - width = 3288; - top_margin = 6; - left_margin = 4; + } else if (!strcmp(model,"PowerShot A610")) { + if (canon_s2is()) strcpy (model+10, "S2 IS"); + } else if (!strcmp(model,"PowerShot SX220 HS")) { + mask[1][3] = -4; } else if (!strcmp(model,"EOS D2000C")) { filters = 0x61616161; black = curve[200]; - } else if (is_canon && raw_width == 3516) { - top_margin = 14; - left_margin = 42; - if (unique_id == 0x80000189) - adobe_coeff ("Canon","EOS 350D"); - goto canon_cr2; - } else if (is_canon && raw_width == 3596) { - top_margin = 12; - left_margin = 74; - goto canon_cr2; - } else if (is_canon && raw_width == 3944) { - height = 2602; - width = 3908; - top_margin = 18; - left_margin = 30; - maximum = 0x3f60; - } else if (is_canon && raw_width == 3948) { - top_margin = 18; - left_margin = 42; - height -= 2; - if (unique_id == 0x80000236) - adobe_coeff ("Canon","EOS 400D"); - goto canon_cr2; - } else if (is_canon && raw_width == 3984) { - top_margin = 20; - left_margin = 76; - height -= 2; - maximum = 0x3bb0; - goto canon_cr2; - } else if (is_canon && raw_width == 4104) { - height = 3024; - width = 4032; - top_margin = 12; - left_margin = 48; - } else if (is_canon && raw_width == 4476) { - top_margin = 34; - left_margin = 90; - maximum = 0xe6c; - goto canon_cr2; - } else if (is_canon && raw_width == 5108) { - top_margin = 13; - left_margin = 98; - maximum = 0xe80; -canon_cr2: - height -= top_margin; - width -= left_margin; - } else if (is_canon && raw_width == 5712) { - height = 3752; - width = 5640; - top_margin = 20; - left_margin = 62; - maximum = 0x3bb0; + } else if (!strcmp(model,"EOS 80D")) { + top_margin -= 2; + height += 2; } else if (!strcmp(model,"D1")) { cam_mul[0] *= 256/527.0; cam_mul[2] *= 256/317.0; @@ -6901,62 +9031,71 @@ width -= 4; pixel_aspect = 0.5; } else if (!strcmp(model,"D40X") || - !strcmp(model,"D80")) { + !strcmp(model,"D60") || + !strcmp(model,"D80") || + !strcmp(model,"D3000")) { height -= 3; width -= 4; + } else if (!strcmp(model,"D3") || + !strcmp(model,"D3S") || + !strcmp(model,"D700")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"D3100")) { + width -= 28; + left_margin = 6; + } else if (!strcmp(model,"D5000") || + !strcmp(model,"D90")) { + width -= 42; + } else if (!strcmp(model,"D5100") || + !strcmp(model,"D7000") || + !strcmp(model,"COOLPIX A")) { + width -= 44; + } else if (!strcmp(model,"D3200") || + !strncmp(model,"D6",2) || + !strncmp(model,"D800",4)) { + width -= 46; + } else if (!strcmp(model,"D4") || + !strcmp(model,"Df")) { + width -= 52; + left_margin = 2; } else if (!strncmp(model,"D40",3) || !strncmp(model,"D50",3) || !strncmp(model,"D70",3)) { width--; } else if (!strcmp(model,"D100")) { - if (tiff_compress == 34713 && !nikon_is_compressed()) { - load_raw = &CLASS nikon_load_raw; + if (load_flags) raw_width = (width += 3) + 3; - } - maximum = 0xf44; } else if (!strcmp(model,"D200")) { left_margin = 1; width -= 4; - maximum = 0xfbc; filters = 0x94949494; } else if (!strncmp(model,"D2H",3)) { left_margin = 6; width -= 14; - } else if (!strcmp(model,"D2X")) { - width -= 8; - maximum = 0xf35; - } else if (!strcmp(model,"D3")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"D300")) { + } else if (!strncmp(model,"D2X",3)) { + if (width == 3264) width -= 32; + else width -= 8; + } else if (!strncmp(model,"D300",4)) { width -= 32; + } else if (!strncmp(model,"COOLPIX B",9)) { + load_flags = 24; + } else if (!strncmp(model,"COOLPIX P",9) && raw_width != 4032) { + load_flags = 24; + filters = 0x94949494; + if (model[9] == '7' && iso_speed >= 400) + black = 255; + } else if (!strncmp(model,"1 ",2)) { + height -= 2; } else if (fsize == 1581060) { - height = 963; - width = 1287; - raw_width = 1632; - load_raw = &CLASS nikon_e900_load_raw; - maximum = 0x3f4; - colors = 4; - filters = 0x1e1e1e1e; simple_coeff(3); pre_mul[0] = 1.2085; pre_mul[1] = 1.0943; pre_mul[3] = 1.1103; - } else if (fsize == 2465792) { - height = 1203; - width = 1616; - raw_width = 2048; - load_raw = &CLASS nikon_e900_load_raw; - maximum = 0x3dd; - colors = 4; - filters = 0x4b4b4b4b; - adobe_coeff ("NIKON","E950"); + } else if (fsize == 3178560) { + cam_mul[0] *= 4; + cam_mul[2] *= 4; } else if (fsize == 4771840) { - height = 1540; - width = 2064; - colors = 4; - filters = 0xe1e1e1e1; - load_raw = &CLASS nikon_load_raw; if (!timestamp && nikon_e995()) strcpy (model, "E995"); if (strcmp(model,"E995")) { @@ -6966,89 +9105,70 @@ pre_mul[1] = 1.246; pre_mul[2] = 1.018; } - } else if (!strcmp(model,"E2100")) { - if (!timestamp && !nikon_e2100()) goto cp_e2500; - height = 1206; - width = 1616; - load_raw = &CLASS nikon_e2100_load_raw; - } else if (!strcmp(model,"E2500")) { -cp_e2500: - strcpy (model, "E2500"); - height = 1204; - width = 1616; - colors = 4; - filters = 0x4b4b4b4b; + } else if (fsize == 2940928) { + if (!timestamp && !nikon_e2100()) + strcpy (model,"E2500"); + if (!strcmp(model,"E2500")) { + height -= 2; + load_flags = 6; + colors = 4; + filters = 0x4b4b4b4b; + } } else if (fsize == 4775936) { - height = 1542; - width = 2064; - load_raw = &CLASS nikon_e2100_load_raw; - pre_mul[0] = 1.818; - pre_mul[2] = 1.618; if (!timestamp) nikon_3700(); if (model[0] == 'E' && atoi(model+1) < 3700) filters = 0x49494949; if (!strcmp(model,"Optio 33WR")) { flip = 1; filters = 0x16161616; - pre_mul[0] = 1.331; - pre_mul[2] = 1.820; + } + if (make[0] == 'O') { + i = find_green (12, 32, 1188864, 3576832); + c = find_green (12, 32, 2383920, 2387016); + if (abs(i) < abs(c)) { + SWAP(i,c); + load_flags = 24; + } + if (i < 0) filters = 0x61616161; } } else if (fsize == 5869568) { - height = 1710; - width = 2288; - filters = 0x16161616; if (!timestamp && minolta_z2()) { strcpy (make, "Minolta"); strcpy (model,"DiMAGE Z2"); } - if (make[0] == 'M') - load_raw = &CLASS nikon_e2100_load_raw; - } else if (!strcmp(model,"E4500")) { - height = 1708; - width = 2288; - colors = 4; - filters = 0xb4b4b4b4; - } else if (fsize == 7438336) { - height = 1924; - width = 2576; - colors = 4; - filters = 0xb4b4b4b4; - } else if (fsize == 8998912) { - height = 2118; - width = 2832; - maximum = 0xf83; - load_raw = &CLASS nikon_e2100_load_raw; - } else if (!strcmp(model,"FinePix S5100") || - !strcmp(model,"FinePix S5500")) { - load_raw = &CLASS unpacked_load_raw; - maximum = 0x3e00; - } else if (!strcmp(make,"FUJIFILM")) { + load_flags = 6 + 24*(make[0] == 'M'); + } else if (fsize == 6291456) { + fseek (ifp, 0x300000, SEEK_SET); + if ((order = guess_byte_order(0x10000)) == 0x4d4d) { + height -= (top_margin = 16); + width -= (left_margin = 28); + maximum = 0xf5c0; + strcpy (make, "ISG"); + model[0] = 0; + } + } else if (!strcmp(make,"Fujifilm")) { if (!strcmp(model+7,"S2Pro")) { - strcpy (model+7," S2Pro"); + strcpy (model,"S2Pro"); height = 2144; width = 2880; flip = 6; - } else - maximum = 0x3e00; - if (is_raw == 2 && shot_select) - maximum = 0x2f00; - top_margin = (raw_height - height)/2; - left_margin = (raw_width - width )/2; - if (is_raw == 2) - data_offset += (shot_select > 0) * ( fuji_layout ? - (raw_width *= 2) : raw_height*raw_width*2 ); - fuji_width = width >> !fuji_layout; - width = (height >> fuji_layout) + fuji_width; - raw_height = height; - height = width - 1; - load_raw = &CLASS fuji_load_raw; - if (!(fuji_width & 1)) filters = 0x49494949; - } else if (!strcmp(model,"RD175")) { - height = 986; - width = 1534; - data_offset = 513; - filters = 0x61616161; - load_raw = &CLASS minolta_rd175_load_raw; + } + top_margin = (raw_height - height) >> 2 << 1; + left_margin = (raw_width - width ) >> 2 << 1; + if (width == 2848 || width == 3664) filters = 0x16161616; + if (width == 4032 || width == 4952 || width == 6032 || width == 8280) left_margin = 0; + if (width == 3328 && (width -= 66)) left_margin = 34; + if (width == 4936) left_margin = 4; + if (!strcmp(model,"HS50EXR") || + !strcmp(model,"F900EXR")) { + width += 2; + left_margin = 0; + filters = 0x16161616; + } + if (fuji_layout) raw_width *= is_raw; + if (filters == 9) + FORC(36) ((char *)xtrans)[c] = + xtrans_abs[(c/6+top_margin) % 6][(c+left_margin) % 6]; } else if (!strcmp(model,"KD-400Z")) { height = 1712; width = 2312; @@ -7056,21 +9176,20 @@ goto konica_400z; } else if (!strcmp(model,"KD-510Z")) { goto konica_510z; - } else if (!strcasecmp(make,"MINOLTA")) { - load_raw = &CLASS unpacked_load_raw; - maximum = 0xf7d; + } else if (!strcasecmp(make,"Minolta")) { + if (!load_raw && (maximum = 0xfff)) + load_raw = &CLASS unpacked_load_raw; if (!strncmp(model,"DiMAGE A",8)) { if (!strcmp(model,"DiMAGE A200")) filters = 0x49494949; - load_raw = &CLASS packed_12_load_raw; - maximum = model[8] == '1' ? 0xf8b : 0xfff; + tiff_bps = 12; + load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"ALPHA",5) || !strncmp(model,"DYNAX",5) || !strncmp(model,"MAXXUM",6)) { sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); adobe_coeff (make, model+20); - load_raw = &CLASS packed_12_load_raw; - maximum = 0xffb; + load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"DiMAGE G",8)) { if (model[8] == '4') { height = 1716; @@ -7091,127 +9210,69 @@ maximum = 0x3df; order = 0x4d4d; } + } else if (!strcmp(model,"*ist D")) { + load_raw = &CLASS unpacked_load_raw; + data_error = -1; } else if (!strcmp(model,"*ist DS")) { height -= 2; - } else if (!strcmp(model,"K20D")) { - filters = 0x16161616; - } else if (!strcmp(model,"Optio S")) { - if (fsize == 3178560) { - height = 1540; - width = 2064; - load_raw = &CLASS eight_bit_load_raw; - cam_mul[0] *= 4; - cam_mul[2] *= 4; - pre_mul[0] = 1.391; - pre_mul[2] = 1.188; - } else { - height = 1544; - width = 2068; - raw_width = 3136; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7c; - pre_mul[0] = 1.137; - pre_mul[2] = 1.453; - } - } else if (fsize == 6114240) { - height = 1737; - width = 2324; - raw_width = 3520; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7a; - pre_mul[0] = 1.980; - pre_mul[2] = 1.570; - } else if (!strcmp(model,"Optio 750Z")) { - height = 2302; - width = 3072; - load_raw = &CLASS nikon_e2100_load_raw; - } else if (!strcmp(model,"STV680 VGA")) { - height = 484; - width = 644; - load_raw = &CLASS eight_bit_load_raw; - flip = 2; - filters = 0x16161616; - black = 16; - pre_mul[0] = 1.097; - pre_mul[2] = 1.128; - } else if (!strcmp(model,"KAI-0340")) { - height = 477; - width = 640; + } else if (!strcmp(make,"Samsung") && raw_width == 4704) { + height -= top_margin = 8; + width -= 2 * (left_margin = 8); + load_flags = 256; + } else if (!strcmp(make,"Samsung") && raw_height == 3714) { + height -= top_margin = 18; + left_margin = raw_width - (width = 5536); + if (raw_width != 5600) + left_margin = top_margin = 0; + filters = 0x61616161; + colors = 3; + } else if (!strcmp(make,"Samsung") && raw_width == 5632) { order = 0x4949; - data_offset = 3840; - load_raw = &CLASS unpacked_load_raw; - pre_mul[0] = 1.561; - pre_mul[2] = 2.454; - } else if (!strcmp(model,"N95")) { - height = raw_height - (top_margin = 2); - } else if (!strcmp(model,"531C")) { - height = 1200; - width = 1600; - load_raw = &CLASS unpacked_load_raw; - filters = 0x49494949; - pre_mul[1] = 1.218; - } else if (!strcmp(model,"F-080C")) { - height = 768; - width = 1024; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"F-145C")) { - height = 1040; - width = 1392; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"F-201C")) { - height = 1200; - width = 1600; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"F-510C")) { - height = 1958; - width = 2588; - load_raw = fsize < 7500000 ? - &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; - maximum = 0xfff0; - } else if (!strcmp(model,"F-810C")) { - height = 2469; - width = 3272; - load_raw = &CLASS unpacked_load_raw; - maximum = 0xfff0; - } else if (!strcmp(model,"XCD-SX910CR")) { - height = 1024; - width = 1375; - raw_width = 1376; + height = 3694; + top_margin = 2; + width = 5574 - (left_margin = 32 + tiff_bps); + if (tiff_bps == 12) load_flags = 80; + } else if (!strcmp(make,"Samsung") && raw_width == 5664) { + height -= top_margin = 17; + left_margin = 96; + width = 5544; filters = 0x49494949; - maximum = 0x3ff; - load_raw = fsize < 2000000 ? - &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; - } else if (!strcmp(model,"2010")) { - height = 1207; - width = 1608; - order = 0x4949; - filters = 0x16161616; - data_offset = 3212; - maximum = 0x3ff; - load_raw = &CLASS unpacked_load_raw; - } else if (!strcmp(model,"A782")) { - height = 3000; - width = 2208; + } else if (!strcmp(make,"Samsung") && raw_width == 6496) { filters = 0x61616161; - load_raw = fsize < 10000000 ? - &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; - maximum = 0xffc0; - } else if (!strcmp(model,"3320AF")) { - height = 1536; - raw_width = width = 2048; - filters = 0x61616161; - load_raw = &CLASS unpacked_load_raw; - maximum = 0x3ff; - pre_mul[0] = 1.717; - pre_mul[2] = 1.138; - fseek (ifp, 0x300000, SEEK_SET); - if ((order = guess_byte_order(0x10000)) == 0x4d4d) { - height -= (top_margin = 16); - width -= (left_margin = 28); - maximum = 0xf5c0; - strcpy (make, "ISG"); - model[0] = 0; + black = 1 << (tiff_bps - 7); + } else if (!strcmp(model,"EX1")) { + order = 0x4949; + height -= 20; + top_margin = 2; + if ((width -= 6) > 3682) { + height -= 10; + width -= 46; + top_margin = 8; } + } else if (!strcmp(model,"WB2000")) { + order = 0x4949; + height -= 3; + top_margin = 2; + if ((width -= 10) > 3718) { + height -= 28; + width -= 56; + top_margin = 8; + } + } else if (strstr(model,"WB550")) { + strcpy (model, "WB550"); + } else if (!strcmp(model,"EX2F")) { + height = 3045; + width = 4070; + top_margin = 3; + order = 0x4949; + filters = 0x49494949; + load_raw = &CLASS unpacked_load_raw; + } else if (!strcmp(model,"STV680 VGA")) { + black = 16; + } else if (!strcmp(model,"N95")) { + height = raw_height - (top_margin = 2); + } else if (!strcmp(model,"640x480")) { + gamma_curve (0.45, 4.5, 1, 255); } else if (!strcmp(make,"Hasselblad")) { if (load_raw == &CLASS lossless_jpeg_load_raw) load_raw = &CLASS hasselblad_load_raw; @@ -7221,22 +9282,48 @@ top_margin = 4; left_margin = 7; filters = 0x61616161; - } - } else if (!strcmp(make,"Sinar")) { - if (!memcmp(head,"8BPS",4)) { - fseek (ifp, 14, SEEK_SET); - height = get4(); - width = get4(); + } else if (raw_width == 7410 || raw_width == 8282) { + height -= 84; + width -= 82; + top_margin = 4; + left_margin = 41; filters = 0x61616161; - data_offset = 68; + } else if (raw_width == 8384) { + height = 6208; + width = 8280; + top_margin = 96; + left_margin = 46; + } else if (raw_width == 9044) { + height = 6716; + width = 8964; + top_margin = 8; + left_margin = 40; + black += load_flags = 256; + maximum = 0x8101; + } else if (raw_width == 4090) { + strcpy (model, "V96C"); + height -= (top_margin = 6); + width -= (left_margin = 3) + 7; + filters = 0x61616161; + } + if (tiff_samples > 1) { + is_raw = tiff_samples+1; + if (!shot_select && !half_size) filters = 0; } + } else if (!strcmp(make,"Sinar")) { if (!load_raw) load_raw = &CLASS unpacked_load_raw; + if (is_raw > 1 && !shot_select && !half_size) filters = 0; maximum = 0x3fff; } else if (!strcmp(make,"Leaf")) { maximum = 0x3fff; + fseek (ifp, data_offset, SEEK_SET); + if (ljpeg_start (&jh, 1) && jh.bits == 15) + maximum = 0x1fff; if (tiff_samples > 1) filters = 0; - if (tiff_samples > 1 || tile_length < raw_height) + if (tiff_samples > 1 || tile_length < raw_height) { load_raw = &CLASS leaf_hdr_load_raw; + raw_width = tile_width; + } if ((width | height) == 2048) { if (tiff_samples == 1) { filters = 1; @@ -7269,133 +9356,69 @@ width -= 2 * (left_margin = 24); filters = 0x16161616; } - } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) { - maximum = 0xfff0; - if ((fsize-data_offset) / (width*8/7) == height) + } else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) { + if ((flen - data_offset) / (raw_width*8/7) == raw_height) load_raw = &CLASS panasonic_load_raw; - if (!load_raw) load_raw = &CLASS unpacked_load_raw; - switch (width) { - case 2568: - adobe_coeff ("Panasonic","DMC-LC1"); break; - case 3130: - left_margin = -14; - case 3170: - left_margin += 18; - width = 3096; - if (height > 2326) { - height = 2326; - top_margin = 13; - filters = 0x49494949; - } - maximum = 0xf7f0; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-FZ8"); break; - case 3177: - width -= 10; - filters = 0x49494949; - maximum = 0xf7fc; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-L1"); break; - case 3304: - width -= 16; - maximum = 0xf94c; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-FZ30"); break; - case 3330: - width = 3291; - left_margin = 9; - maximum = 0xf7f0; - goto fz18; - case 3370: - width = 3288; - left_margin = 15; -fz18: if (height > 2480) - height = 2480 - (top_margin = 10); - filters = 0x49494949; - zero_is_bad = 1; - break; - case 3690: - height += 36; - left_margin = -14; - filters = 0x49494949; - maximum = 0xf7f0; - case 3770: - width = 3672; - if ((height -= 39) == 2760) - top_margin = 15; - left_margin += 17; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-FZ50"); break; - case 3710: - width = 3682; - filters = 0x49494949; - break; - case 3880: - width -= 22; - left_margin = 6; - maximum = 0xf7f0; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-LX1"); break; - case 4290: - height += 38; - left_margin = -14; - filters = 0x49494949; - case 4330: - width = 4248; - if ((height -= 39) == 2400) - top_margin = 15; - left_margin += 17; - adobe_coeff ("Panasonic","DMC-LX2"); break; + if (!load_raw) { + load_raw = &CLASS unpacked_load_raw; + load_flags = 4; } + zero_is_bad = 1; + if ((height += 12) > raw_height) height = raw_height; + for (i=0; i < sizeof pana / sizeof *pana; i++) + if (raw_width == pana[i][0] && raw_height == pana[i][1]) { + left_margin = pana[i][2]; + top_margin = pana[i][3]; + width += pana[i][4]; + height += pana[i][5]; + } + 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; filters = 0x16161616; - load_raw = &CLASS nikon_e2100_load_raw; - } else if (!strcmp(make,"OLYMPUS")) { + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(make,"Olympus")) { height += height & 1; - filters = exif_cfa; - if (!strcmp(model,"E-1") || - !strcmp(model,"E-400")) { - maximum = 0xfff0; - } else if (!strcmp(model,"E-10") || - !strncmp(model,"E-20",4)) { - maximum = 0xffc0; - black <<= 2; - } else if (!strcmp(model,"E-300") || - !strcmp(model,"E-500")) { + if (exif_cfa) filters = exif_cfa; + if (width == 4100) width -= 4; + if (width == 4080) width -= 24; + if (width == 9280) { width -= 6; height -= 6; } + if (load_raw == &CLASS unpacked_load_raw) + load_flags = 4; + tiff_bps = 12; + if (!strcmp(model,"E-300") || + !strcmp(model,"E-500")) { width -= 20; if (load_raw == &CLASS unpacked_load_raw) { - maximum = 0xfc30; - black = 0; + maximum = 0xfc3; + memset (cblack, 0, sizeof cblack); } } else if (!strcmp(model,"E-330")) { width -= 30; if (load_raw == &CLASS unpacked_load_raw) - maximum = 0xf790; - } else if (!strcmp(model,"E-3")) { - maximum = 0xf99; - goto e410; - } else if (!strcmp(model,"E-410") || - !strcmp(model,"E-510")) { - maximum = 0xf6a; -e410: load_raw = &CLASS olympus_e410_load_raw; - black >>= 4; + maximum = 0xf79; } else if (!strcmp(model,"SP550UZ")) { - thumb_length = fsize - (thumb_offset = 0xa39800); + thumb_length = flen - (thumb_offset = 0xa39800); thumb_height = 480; thumb_width = 640; + } else if (!strcmp(model,"TG-4")) { + width -= 16; + } else if (!strcmp(model,"TG-5")) { + width -= 6; } } else if (!strcmp(model,"N Digital")) { height = 2047; width = 3072; filters = 0x61616161; data_offset = 0x1a00; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf1e; + load_raw = &CLASS packed_load_raw; } else if (!strcmp(model,"DSC-F828")) { width = 3288; left_margin = 5; + mask[1][3] = -17; data_offset = 862144; load_raw = &CLASS sony_load_raw; filters = 0x9c9c9c9c; @@ -7404,82 +9427,94 @@ } else if (!strcmp(model,"DSC-V3")) { width = 3109; left_margin = 59; + mask[0][1] = 9; data_offset = 787392; load_raw = &CLASS sony_load_raw; - } else if (!strcmp(make,"SONY") && raw_width == 3984) { - adobe_coeff ("SONY","DSC-R1"); + } else if (!strcmp(make,"Sony") && raw_width == 3984) { width = 3925; order = 0x4d4d; + } else if (!strcmp(make,"Sony") && raw_width == 4288) { + width -= 32; + } else if (!strcmp(make,"Sony") && raw_width == 4600) { + if (!strcmp(model,"DSLR-A350")) + height -= 4; + black = 0; + } else if (!strcmp(make,"Sony") && raw_width == 4928) { + if (height < 3280) width -= 8; + } else if (!strcmp(make,"Sony") && raw_width == 5504) { + width -= height > 3664 ? 8 : 32; + if (!strncmp(model,"DSC",3)) + black = 200 << (tiff_bps - 12); + } else if (!strcmp(make,"Sony") && raw_width == 6048) { + width -= 24; + if (strstr(model,"RX1") || strstr(model,"A99")) + width -= 6; + } else if (!strcmp(make,"Sony") && raw_width == 7392) { + width -= 30; + } else if (!strcmp(make,"Sony") && raw_width == 8000) { + width -= 32; } else if (!strcmp(model,"DSLR-A100")) { - height--; - load_raw = &CLASS sony_arw_load_raw; - maximum = 0xfeb; - } else if (!strcmp(model,"DSLR-A200")) { - height = raw_height += 8; - load_raw = &CLASS sony_arw_load_raw; - } else if (!strcmp(model,"DSLR-A350")) { - height = (raw_height += 8) - 4; - load_raw = &CLASS sony_arw_load_raw; - maximum = 0x1ffe; - } else if (!strncmp(model,"P850",4)) { - maximum = 0xf7c; - } else if (!strcmp(model,"C330")) { - height = 1744; - width = 2336; - raw_height = 1779; - raw_width = 2338; - top_margin = 33; - left_margin = 1; + if (width == 3880) { + height--; + width = ++raw_width; + } else { + height -= 4; + width -= 4; + order = 0x4d4d; + load_flags = 2; + } + filters = 0x61616161; + } else if (!strcmp(model,"PIXL")) { + height -= top_margin = 4; + width -= left_margin = 32; + gamma_curve (0, 7, 1, 255); + } else if (!strcmp(model,"C603") || !strcmp(model,"C330") + || !strcmp(model,"12MP")) { order = 0x4949; - if ((data_offset = fsize - raw_height*raw_width)) { - fseek (ifp, 168, SEEK_SET); + if (filters && data_offset) { + fseek (ifp, data_offset < 4096 ? 168 : 5252, SEEK_SET); read_shorts (curve, 256); - } else use_gamma = 0; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcasecmp(make,"KODAK")) { + } else gamma_curve (0, 3.875, 1, 255); + load_raw = filters ? &CLASS eight_bit_load_raw : + strcmp(model,"C330") ? &CLASS kodak_c603_load_raw : + &CLASS kodak_c330_load_raw; + load_flags = tiff_bps > 16; + tiff_bps = 8; + } else if (!strncasecmp(model,"EasyShare",9)) { + data_offset = data_offset < 0x15000 ? 0x15000 : 0x17000; + load_raw = &CLASS packed_load_raw; + } else if (!strcasecmp(make,"Kodak")) { if (filters == UINT_MAX) filters = 0x61616161; - if (!strncmp(model,"NC2000",6)) { + if (!strncmp(model,"NC2000",6) || + !strncmp(model,"EOSDCS",6) || + !strncmp(model,"DCS4",4)) { width -= 4; left_margin = 2; - } else if (!strcmp(model,"EOSDCS3B")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"EOSDCS1")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS420")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS460")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS460A")) { - width -= 4; - left_margin = 2; - colors = 1; - filters = 0; + if (model[6] == ' ') model[6] = 0; + if (!strcmp(model,"DCS460A")) goto bw; } else if (!strcmp(model,"DCS660M")) { black = 214; - colors = 1; - filters = 0; + goto bw; } else if (!strcmp(model,"DCS760M")) { - colors = 1; +bw: colors = 1; filters = 0; } + if (!strcmp(model+4,"20X")) + strcpy (cdesc, "MYCY"); if (strstr(model,"DC25")) { strcpy (model, "DC25"); data_offset = 15424; } if (!strncmp(model,"DC2",3)) { - height = 242; - if (fsize < 100000) { + raw_height = 2 + (height = 242); + if (flen < 100000) { raw_width = 256; width = 249; pixel_aspect = (4.0*height) / (3.0*width); } else { raw_width = 512; width = 501; pixel_aspect = (493.0*height) / (373.0*width); } - data_offset += raw_width + 1; + top_margin = left_margin = 1; colors = 4; filters = 0x8d8d8d8d; simple_coeff(1); @@ -7493,6 +9528,7 @@ width = 768; data_offset = 1152; load_raw = &CLASS kodak_radc_load_raw; + tiff_bps = 12; } else if (strstr(model,"DC50")) { strcpy (model, "DC50"); height = 512; @@ -7512,10 +9548,6 @@ thumb_offset = 6144; thumb_misc = 360; write_thumb = &CLASS layer_thumb; - height = 1024; - width = 1536; - data_offset = 79872; - load_raw = &CLASS eight_bit_load_raw; black = 17; } } else if (!strcmp(model,"Fotoman Pixtura")) { @@ -7525,17 +9557,17 @@ load_raw = &CLASS kodak_radc_load_raw; filters = 0x61616161; simple_coeff(2); - } else if (!strcmp(model,"QuickTake 100")) { - data_offset = 736; - load_raw = &CLASS quicktake_100_load_raw; - goto qt_common; - } else if (!strcmp(model,"QuickTake 150")) { - data_offset = 738 - head[5]; + } else if (!strncmp(model,"QuickTake",9)) { if (head[5]) strcpy (model+10, "200"); - load_raw = &CLASS kodak_radc_load_raw; -qt_common: - height = 480; - width = 640; + fseek (ifp, 544, SEEK_SET); + height = get2(); + width = get2(); + data_offset = (get4(),get2()) == 30 ? 738:736; + if (height > width) { + SWAP(height,width); + fseek (ifp, data_offset-6, SEEK_SET); + flip = ~get2() & 3 ? 5:6; + } filters = 0x61616161; } else if (!strcmp(make,"Rollei") && !load_raw) { switch (raw_width) { @@ -7553,100 +9585,10 @@ } filters = 0x16161616; load_raw = &CLASS rollei_load_raw; - pre_mul[0] = 1.8; - pre_mul[2] = 1.3; - } else if (!strcmp(model,"PC-CAM 600")) { - height = 768; - data_offset = width = 1024; - filters = 0x49494949; - load_raw = &CLASS eight_bit_load_raw; - pre_mul[0] = 1.14; - pre_mul[2] = 2.73; - } else if (!strcmp(model,"QV-2000UX")) { - height = 1208; - width = 1632; - data_offset = width * 2; - load_raw = &CLASS eight_bit_load_raw; - } else if (fsize == 3217760) { - height = 1546; - width = 2070; - raw_width = 2080; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"QV-4000")) { - height = 1700; - width = 2260; - load_raw = &CLASS unpacked_load_raw; - maximum = 0xffff; - } else if (!strcmp(model,"QV-5700")) { - height = 1924; - width = 2576; - load_raw = &CLASS casio_qv5700_load_raw; - } else if (!strcmp(model,"QV-R41")) { - height = 1720; - width = 2312; - raw_width = 3520; - left_margin = 2; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7f; - } else if (!strcmp(model,"QV-R51")) { - height = 1926; - width = 2580; - raw_width = 3904; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7f; - pre_mul[0] = 1.340; - pre_mul[2] = 1.672; - } else if (!strcmp(model,"EX-S100")) { - height = 1544; - width = 2058; - raw_width = 3136; - load_raw = &CLASS packed_12_load_raw; - pre_mul[0] = 1.631; - pre_mul[2] = 1.106; - } else if (!strcmp(model,"EX-Z50")) { - height = 1931; - width = 2570; - raw_width = 3904; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7f; - pre_mul[0] = 2.529; - pre_mul[2] = 1.185; - } else if (!strcmp(model,"EX-Z55")) { - height = 1960; - width = 2570; - raw_width = 3904; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7f; - pre_mul[0] = 1.520; - pre_mul[2] = 1.316; - } else if (!strcmp(model,"EX-P505")) { - height = 1928; - width = 2568; - raw_width = 3852; - load_raw = &CLASS packed_12_load_raw; - pre_mul[0] = 2.07; - pre_mul[2] = 1.88; - } else if (fsize == 9313536) { /* EX-P600 or QV-R61 */ - height = 2142; - width = 2844; - raw_width = 4288; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7f; - pre_mul[0] = 1.797; - pre_mul[2] = 1.219; - } else if (!strcmp(model,"EX-P700")) { - height = 2318; - width = 3082; - raw_width = 4672; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7f; - pre_mul[0] = 1.758; - pre_mul[2] = 1.504; } if (!model[0]) sprintf (model, "%dx%d", width, height); if (filters == UINT_MAX) filters = 0x94949494; - if (raw_color) adobe_coeff (make, model); if (thumb_offset && !thumb_height) { fseek (ifp, thumb_offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { @@ -7655,31 +9597,58 @@ } } dng_skip: - if (!load_raw || height < 22) is_raw = 0; -#ifdef HAVE_JPEG - if (load_raw == kodak_jpeg_load_raw) { - fprintf (stderr,_("%s: You must link dcraw with libjpeg!!\n"), ifname); + if ((use_camera_matrix & (use_camera_wb || dng_version)) + && cmatrix[0][0] > 0.125) { + memcpy (rgb_cam, cmatrix, sizeof cmatrix); + raw_color = 0; + } + if (raw_color) adobe_coeff (make, model); + if (load_raw == &CLASS kodak_radc_load_raw) + if (raw_color) adobe_coeff ("Apple","Quicktake"); + if (fuji_width) { + fuji_width = width >> !fuji_layout; + filters = fuji_width & 1 ? 0x94949494 : 0x49494949; + width = (height >> fuji_layout) + fuji_width; + height = width - 1; + pixel_aspect = 1; + } else { + if (raw_height < height) raw_height = height; + if (raw_width < width ) raw_width = width; + } + if (!tiff_bps) tiff_bps = 12; + if (!maximum) maximum = (1 << tiff_bps) - 1; + if (!load_raw || height < 22 || width < 22 || + tiff_bps > 16 || tiff_samples > 6 || colors > 4) + is_raw = 0; +#ifdef NO_JASPER + if (load_raw == &CLASS redcine_load_raw) { + fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), + ifname, "libjasper"); + is_raw = 0; + } +#endif +#ifdef NO_JPEG + if (load_raw == &CLASS kodak_jpeg_load_raw || + load_raw == &CLASS lossy_dng_load_raw) { + fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), + ifname, "libjpeg"); is_raw = 0; } #endif if (!cdesc[0]) - strcpy (cdesc, colors == 3 ? "RGB":"GMCY"); + strcpy (cdesc, colors == 3 ? "RGBG":"GMCY"); if (!raw_height) raw_height = height; if (!raw_width ) raw_width = width; - if (filters && colors == 3) - for (i=0; i < 32; i+=4) { - if ((filters >> i & 15) == 9) - filters |= 2 << i; - if ((filters >> i & 15) == 6) - filters |= 8 << i; - } + if (filters > 999 && colors == 3) + filters |= ((filters >> 2 & 0x22222222) | + (filters << 2 & 0x88888888)) & filters << 1; notraw: - if (flip == -1) flip = tiff_flip; - if (flip == -1) flip = 0; + if (flip == UINT_MAX) flip = tiff_flip; + if (flip == UINT_MAX) flip = 0; } #ifndef NO_LCMS -void CLASS apply_profile (char *input, char *output) +void CLASS apply_profile (const char *input, const char *output) { char *prof; cmsHPROFILE hInProfile=0, hOutProfile=0; @@ -7687,9 +9656,6 @@ FILE *fp; unsigned size; -#if LCMS_VERSION < 2000 - cmsErrorAction (LCMS_ERROR_SHOW); -#endif if (strcmp (input, "embed")) hInProfile = cmsOpenProfileFromFile (input, "r"); else if (profile_length) { @@ -7755,10 +9721,14 @@ { { 0.529317, 0.330092, 0.140588 }, { 0.098368, 0.873465, 0.028169 }, { 0.016879, 0.117663, 0.865457 } }; + static const double aces_rgb[3][3] = + { { 0.432996, 0.375380, 0.189317 }, + { 0.089427, 0.816523, 0.102989 }, + { 0.019165, 0.118150, 0.941914 } }; static const double (*out_rgb[])[3] = - { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; + { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb, aces_rgb }; static const char *name[] = - { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; + { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; static const unsigned phead[] = { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; @@ -7776,9 +9746,10 @@ 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; + output_color < 1 || output_color > 6; if (!raw_color) { oprof = (unsigned *) calloc (phead[0], 1); merror (oprof, "convert_to_rgb()"); @@ -7793,12 +9764,7 @@ memcpy (oprof+32, pbody, sizeof pbody); oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); - if (output_bps == 8) -#ifdef SRGB_GAMMA - pcurve[3] = 0x2330000; -#else - pcurve[3] = 0x1f00000; -#endif + 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); @@ -7806,7 +9772,7 @@ 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; + 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]); @@ -7834,7 +9800,7 @@ FORC3 img[c] = CLIP((int) out[c]); } else if (document_mode) - img[0] = img[FC(row,col)]; + img[0] = img[fcol(row,col)]; FORCC histogram[c][img[c] >> 3]++; } if (colors == 4 && output_color) colors = 3; @@ -7856,7 +9822,7 @@ step = sqrt(0.5); wide = fuji_width / step; high = (height - fuji_width) / step; - img = (ushort (*)[4]) calloc (wide*high, sizeof *img); + img = (ushort (*)[4]) calloc (high, wide*sizeof *img); merror (img, "fuji_rotate()"); for (row=0; row < high; row++) @@ -7889,7 +9855,7 @@ 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); + 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); @@ -7901,7 +9867,7 @@ height = newdim; } else { newdim = width * pixel_aspect + 0.5; - img = (ushort (*)[4]) calloc (height*newdim, sizeof *img); + 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); @@ -7924,33 +9890,6 @@ return row * iwidth + col; } -void CLASS gamma_lut (uchar lut[0x10000]) -{ - int perc, c, val, total, i; - float white=0, r; - - perc = width * height * 0.01; /* 99th percentile white level */ - if (fuji_width) perc /= 2; - if ((highlight & ~2) || no_auto_bright) perc = -1; - FORCC { - for (val=0x2000, total=0; --val > 32; ) - if ((total += histogram[c][val]) > perc) break; - if (white < val) white = val; - } - white *= 8 / bright; - for (i=0; i < 0x10000; i++) { - r = i / white; - val = 256 * ( !use_gamma ? r : -#ifdef SRGB_GAMMA - r <= 0.00304 ? r*12.92 : pow(r,2.5/6)*1.055-0.055 ); -#else - r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 ); -#endif - if (val > 255) val = 255; - lut[i] = val; - } -} - struct tiff_tag { ushort tag, type; int count; @@ -7973,21 +9912,25 @@ char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; -void CLASS tiff_set (ushort *ntag, +void CLASS tiff_set (struct tiff_hdr *th, 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) + tt->val.i = val; + if (type == 1 && count <= 4) FORC(4) tt->val.c[c] = val >> (c << 3); - else if (type == 3 && count <= 2) + else if (type == 2) { + count = strnlen((char *)th + val, count-1) + 1; + if (count <= 4) + FORC(4) tt->val.c[c] = ((char *)th)[val+c]; + } else if (type == 3 && count <= 2) FORC(2) tt->val.s[c] = val >> (c << 4); - else tt->val.i = val; + tt->count = count; + tt->type = type; + tt->tag = tag; } #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) @@ -8001,55 +9944,6 @@ 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; @@ -8059,14 +9953,63 @@ strncpy (th->desc, desc, 512); strncpy (th->make, make, 64); strncpy (th->model, model, 64); - strcpy (th->soft, "dcraw v" DCRAW_VERSION); - t = gmtime (×tamp); + 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); + if (full) { + tiff_set (th, &th->ntag, 254, 4, 1, 0); + tiff_set (th, &th->ntag, 256, 4, 1, width); + tiff_set (th, &th->ntag, 257, 4, 1, height); + tiff_set (th, &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, &th->ntag, 259, 3, 1, 1); + tiff_set (th, &th->ntag, 262, 3, 1, 1 + (colors > 1)); + } + tiff_set (th, &th->ntag, 270, 2, 512, TOFF(th->desc)); + tiff_set (th, &th->ntag, 271, 2, 64, TOFF(th->make)); + tiff_set (th, &th->ntag, 272, 2, 64, TOFF(th->model)); + if (full) { + if (oprof) psize = ntohl(oprof[0]); + tiff_set (th, &th->ntag, 273, 4, 1, sizeof *th + psize); + tiff_set (th, &th->ntag, 277, 3, 1, colors); + tiff_set (th, &th->ntag, 278, 4, 1, height); + tiff_set (th, &th->ntag, 279, 4, 1, height*width*colors*output_bps/8); + } else + tiff_set (th, &th->ntag, 274, 3, 1, "12435867"[flip]-'0'); + tiff_set (th, &th->ntag, 282, 5, 1, TOFF(th->rat[0])); + tiff_set (th, &th->ntag, 283, 5, 1, TOFF(th->rat[2])); + tiff_set (th, &th->ntag, 284, 3, 1, 1); + tiff_set (th, &th->ntag, 296, 3, 1, 2); + tiff_set (th, &th->ntag, 305, 2, 32, TOFF(th->soft)); + tiff_set (th, &th->ntag, 306, 2, 20, TOFF(th->date)); + tiff_set (th, &th->ntag, 315, 2, 64, TOFF(th->artist)); + tiff_set (th, &th->ntag, 34665, 4, 1, TOFF(th->nexif)); + if (psize) tiff_set (th, &th->ntag, 34675, 7, psize, sizeof *th); + tiff_set (th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4])); + tiff_set (th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6])); + tiff_set (th, &th->nexif, 34855, 3, 1, iso_speed); + tiff_set (th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8])); + if (gpsdata[1]) { + tiff_set (th, &th->ntag, 34853, 4, 1, TOFF(th->ngps)); + tiff_set (th, &th->ngps, 0, 1, 4, 0x202); + tiff_set (th, &th->ngps, 1, 2, 2, gpsdata[29]); + tiff_set (th, &th->ngps, 2, 5, 3, TOFF(th->gps[0])); + tiff_set (th, &th->ngps, 3, 2, 2, gpsdata[30]); + tiff_set (th, &th->ngps, 4, 5, 3, TOFF(th->gps[6])); + tiff_set (th, &th->ngps, 5, 1, 1, gpsdata[31]); + tiff_set (th, &th->ngps, 6, 5, 1, TOFF(th->gps[18])); + tiff_set (th, &th->ngps, 7, 5, 3, TOFF(th->gps[12])); + tiff_set (th, &th->ngps, 18, 2, 12, TOFF(th->gps[20])); + tiff_set (th, &th->ngps, 29, 2, 12, TOFF(th->gps[23])); + memcpy (th->gps, gpsdata, sizeof th->gps); + } } -void CLASS jpeg_thumb (FILE *tfp) +void CLASS jpeg_thumb() { char *thumb; ushort exif[5]; @@ -8075,26 +10018,36 @@ thumb = (char *) malloc (thumb_length); merror (thumb, "jpeg_thumb()"); fread (thumb, 1, thumb_length, ifp); - fputc (0xff, tfp); - fputc (0xd8, tfp); + 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, tfp); + fwrite (exif, 1, sizeof exif, ofp); tiff_head (&th, 0); - fwrite (&th, 1, sizeof th, tfp); + fwrite (&th, 1, sizeof th, ofp); } - fwrite (thumb+2, 1, thumb_length-2, tfp); + fwrite (thumb+2, 1, thumb_length-2, ofp); free (thumb); } -void CLASS write_ppm_tiff (FILE *ofp) +void CLASS write_ppm_tiff() { struct tiff_hdr th; - uchar *ppm, lut[0x10000]; + 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); @@ -8113,16 +10066,14 @@ else fprintf (ofp, "P%d\n%d %d\n%d\n", colors/2+5, width, height, (1 << output_bps)-1); - - if (output_bps == 8) gamma_lut (lut); 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] = lut[image[soff][c]]; - else FORCC ppm2[col*colors+c] = image[soff][c]; + 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); @@ -8130,22 +10081,21 @@ free (ppm); } -int CLASS main (int argc, char **argv) +int CLASS main (int argc, const char **argv) { - int arg, status=0; + 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, quality, i, c; - char opm, opt, *ofname, *sp, *cp, *bpfile=0, *dark_frame=0; - const char *write_ext; + 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; - FILE *ofp; #ifndef NO_LCMS - char *cam_profile=0, *out_profile=0; + const char *cam_profile=0, *out_profile=0; #endif #ifndef LOCALTIME - putenv ("TZ=UTC"); + putenv ((char *) "TZ=UTC"); #endif #ifdef LOCALEDIR setlocale (LC_CTYPE, ""); @@ -8155,7 +10105,7 @@ #endif if (argc == 1) { - printf(_("\nRaw photo decoder \"dcraw\" v%s"), VERSION); + 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")); @@ -8177,7 +10127,7 @@ 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)")); + puts(_("-o [0-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)")); #ifndef NO_LCMS puts(_("-o <file> Apply output ICC profile from file")); puts(_("-p <file> Apply camera ICC profile from file or \"embed\"")); @@ -8187,12 +10137,14 @@ 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(_("-4 Write 16-bit linear instead of 8-bit with gamma")); + 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; @@ -8200,8 +10152,8 @@ argv[argc] = ""; for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { opt = argv[arg++][1]; - if ((cp = strchr (sp="nbrkStqmHAC", opt))) - for (i=0; i < "11411111142"[cp-sp]-'0'; i++) + 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; @@ -8213,6 +10165,9 @@ 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; @@ -8239,25 +10194,27 @@ case 'i': identify_only = 1; break; case 'c': write_to_stdout = 1; break; case 'v': verbose = 1; break; - case 'h': half_size = 1; /* "-h" implies "-f" */ + 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 = (opm == '+'); break; - case 'D': - case 'd': document_mode = 1 + (opt == 'D'); + 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': output_bps = 16; 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 (use_camera_matrix < 0) - use_camera_matrix = use_camera_wb; if (arg == argc) { fprintf (stderr,_("No files to process.\n")); return 1; @@ -8276,6 +10233,7 @@ } for ( ; arg < argc; arg++) { status = 1; + raw_image = 0; image = 0; oprof = 0; meta_data = ofname = 0; @@ -8323,6 +10281,7 @@ height = thumb_height; width = thumb_width; filters = 0; + colors = 3; } else { fseek (ifp, thumb_offset, SEEK_SET); write_fun = write_thumb; @@ -8336,8 +10295,7 @@ if (identify_only && verbose && make[0]) { printf (_("\nFilename: %s\n"), ifname); printf (_("Timestamp: %s"), ctime(×tamp)); - printf (_("Camera: %s\n"), make); - printf (_("Model: %s\n"), model); + printf (_("Camera: %s %s\n"), make, model); if (artist[0]) printf (_("Owner: %s\n"), artist); if (dng_version) { @@ -8362,12 +10320,19 @@ } else if (!is_raw) fprintf (stderr,_("Cannot decode file %s\n"), ifname); if (!is_raw) goto next; - shrink = filters && - (half_size || threshold || aber[0] != 1 || aber[2] != 1); + 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; @@ -8384,10 +10349,15 @@ printf (_("Output size: %4d x %d\n"), iwidth, iheight); printf (_("Raw colors: %d"), colors); if (filters) { + int fhigh = 2, fwide = 2; + if ((filters ^ (filters >> 8)) & 0xff) fhigh = 4; + if ((filters ^ (filters >> 16)) & 0xffff) fhigh = 8; + if (filters == 1) fhigh = fwide = 16; + if (filters == 9) fhigh = fwide = 6; printf (_("\nFilter pattern: ")); - if (!cdesc[3]) cdesc[3] = 'G'; - for (i=0; i < 16; i++) - putchar (cdesc[fc(i >> 1,i & 1)]); + for (i=0; i < fhigh; i++) + for (c = i && putchar('/') && 0; c < fwide; c++) + putchar (cdesc[fcol(i,c)]); } printf (_("\nDaylight multipliers:")); FORCC printf (" %f", pre_mul[c]); @@ -8402,16 +10372,17 @@ fclose(ifp); continue; } - if (use_camera_matrix && cmatrix[0][0] > 0.25) { - memcpy (rgb_cam, cmatrix, sizeof cmatrix); - raw_color = 0; - } - image = (ushort (*)[4]) calloc (iheight*iwidth, sizeof *image); - merror (image, "main()"); 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); @@ -8419,28 +10390,62 @@ fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"), ifname, shot_select); fseeko (ifp, data_offset, SEEK_SET); - (*load_raw)(); + 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 && !document_mode) foveon_interpolate(); - if (!is_foveon && document_mode < 2) scale_colors(); + 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) + else if (quality == 2 && filters > 1000) ppg_interpolate(); - else ahd_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++) @@ -8483,7 +10488,7 @@ } if (verbose) fprintf (stderr,_("Writing data to %s ...\n"), ofname); - (*write_fun)(ofp); + (*write_fun)(); fclose(ifp); if (ofp != stdout) fclose(ofp); cleanup: diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libkdcraw/kdcraw.cpp libkdcraw/libkdcraw/libkdcraw/kdcraw.cpp --- libkdcraw-wrk/libkdcraw/libkdcraw/kdcraw.cpp 2022-11-07 08:15:53.610821808 +0300 +++ libkdcraw/libkdcraw/libkdcraw/kdcraw.cpp 2022-11-07 07:46:31.726795008 +0300 @@ -173,7 +173,8 @@ raw.imgdata.params.half_size = 1; // Half-size color image (3x faster than -q). // NOTE: new magic option introduced by LibRaw 0.7.0 to to make better noise filtration. - raw.imgdata.params.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; + //not with us in libraw 0.14+ + //raw.imgdata.params.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; int ret = raw.open_file((const char*)(TQFile::encodeName(path))); if (ret != LIBRAW_SUCCESS) @@ -292,7 +293,7 @@ d->setProgress(0.3); raw.imgdata.params.output_bps = 16; - raw.imgdata.params.document_mode = 2; + //raw.imgdata.params.document_mode = 2; ret = raw.unpack(); if (ret != LIBRAW_SUCCESS) @@ -387,12 +388,13 @@ TQByteArray outputProfile = TQFile::encodeName(m_rawDecodingSettings.outputProfile); // NOTE: new magic option introduced by LibRaw 0.7.0 to to make better noise/etc filtration. - raw.imgdata.params.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; + //Not in 0.14 + //raw.imgdata.params.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; if (m_rawDecodingSettings.gamma16bit) { // 16 bits color depth auto-gamma is not implemented in dcraw. - raw.imgdata.params.gamma_16bit = 1; + //raw.imgdata.params.gamma_16bit = 1; } if (m_rawDecodingSettings.sixteenBitsImage) diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libkdcraw/kdcrawprivate.cpp libkdcraw/libkdcraw/libkdcraw/kdcrawprivate.cpp --- libkdcraw-wrk/libkdcraw/libkdcraw/kdcrawprivate.cpp 2022-11-07 08:15:53.610821808 +0300 +++ libkdcraw/libkdcraw/libkdcraw/kdcrawprivate.cpp 2022-11-07 07:46:31.726795008 +0300 @@ -135,7 +135,7 @@ { if (!raw->imgdata.idata.cdesc[3]) raw->imgdata.idata.cdesc[3] = 'G'; for (int i=0; i < 16; i++) - identify.filterPattern.append(raw->imgdata.idata.cdesc[raw->fc(i >> 1,i & 1)]); + identify.filterPattern.append(raw->imgdata.idata.cdesc[raw->FC(i >> 1,i & 1)]); } for(int c = 0 ; c < raw->imgdata.idata.colors ; c++) diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/CMakeLists.txt libkdcraw/libkdcraw/libraw/CMakeLists.txt --- libkdcraw-wrk/libkdcraw/libraw/CMakeLists.txt 2022-11-07 08:15:53.610821808 +0300 +++ libkdcraw/libkdcraw/libraw/CMakeLists.txt 2022-11-07 07:46:31.726795008 +0300 @@ -20,9 +20,10 @@ SOURCES src/libraw_cxx.cpp src/libraw_c_api.cpp + src/libraw_datastream.cpp internal/dcraw_common.cpp + internal/demosaic_packs.cpp internal/dcraw_fileio.cpp - internal/foveon.cpp LINK ${LCMS_LIBRARIES} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_common.cpp libkdcraw/libkdcraw/libraw/internal/dcraw_common.cpp --- libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_common.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/internal/dcraw_common.cpp 2022-11-07 07:46:31.726795008 +0300 @@ -1,8295 +1,68 @@ -/* - 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. -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define CLASS LibRaw:: -#include "libraw/libraw_types.h" -#define LIBRAW_LIBRARY_BUILD -#define LIBRAW_IO_REDEFINED -#include "libraw/libraw.h" -#include "internal/defines.h" -#include "internal/var_defines.h" - - -#ifndef __GLIBC__ -char *my_memmem (char *haystack, size_t haystacklen, - char *needle, size_t needlelen) -{ - char *c; - for (c = haystack; c <= haystack + haystacklen - needlelen; c++) - if (!memcmp (c, needle, needlelen)) - return c; - return 0; -} -#define memmem my_memmem -#endif - - -ushort CLASS sget2 (uchar *s) -{ - if (order == 0x4949) /* "II" means little-endian */ - return s[0] | s[1] << 8; - else /* "MM" means big-endian */ - return s[0] << 8 | s[1]; -} - -ushort CLASS get2() -{ - uchar str[2] = { 0xff,0xff }; - fread (str, 1, 2, ifp); - return sget2(str); -} - -unsigned CLASS sget4 (uchar *s) -{ - if (order == 0x4949) - return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; - else - return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; -} -#define sget4(s) sget4((uchar *)s) - -unsigned CLASS get4() -{ - uchar str[4] = { 0xff,0xff,0xff,0xff }; - fread (str, 1, 4, ifp); - return sget4(str); -} - -unsigned CLASS getint (int type) -{ - return type == 3 ? get2() : get4(); -} - -float CLASS int_to_float (int i) -{ - union { int i; float f; } u; - u.i = i; - return u.f; -} - -double CLASS getreal (int type) -{ - union { char c[8]; double d; } u; - int i, rev; - - switch (type) { - case 3: return (unsigned short) get2(); - case 4: return (unsigned int) get4(); - case 5: u.d = (unsigned int) get4(); - return u.d / (unsigned int) get4(); - case 8: return (signed short) get2(); - case 9: return (signed int) get4(); - case 10: u.d = (signed int) get4(); - return u.d / (signed int) get4(); - case 11: return int_to_float (get4()); - case 12: - rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); - for (i=0; i < 8; i++) - u.c[i ^ rev] = fgetc(ifp); - return u.d; - default: return fgetc(ifp); - } -} - -void CLASS read_shorts (ushort *pixel, int count) -{ - if (fread (pixel, 2, count, ifp) < count) derror(); - if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) - swab ((char*)pixel, (char*)pixel, count*2); -} -void CLASS canon_black (double dark[2]) -{ - int c, diff, row, col; - - if (raw_width < width+4) return; - FORC(2) dark[c] /= (raw_width-width-2) * height >> 1; -#ifdef LIBRAW_LIBRARY_BUILD - if(!( filtering_mode & LIBRAW_FILTERING_NOBLACKS) ) - { -#endif - if ((diff = dark[0] - dark[1])) - for (row=0; row < height; row++) - for (col=1; col < width; col+=2) - BAYER(row,col) += diff; -#ifdef LIBRAW_LIBRARY_BUILD - } -#endif - dark[1] += diff; - black = (dark[0] + dark[1] + 1) / 2; -} - -void CLASS canon_600_fixed_wb (int temp) -{ - static const short mul[4][5] = { - { 667, 358,397,565,452 }, - { 731, 390,367,499,517 }, - { 1119, 396,348,448,537 }, - { 1399, 485,431,508,688 } }; - int lo, hi, i; - float frac=0; - - for (lo=4; --lo; ) - if (*mul[lo] <= temp) break; - for (hi=0; hi < 3; hi++) - if (*mul[hi] >= temp) break; - if (lo != hi) - frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); - for (i=1; i < 5; i++) - pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif -} - -/* Return values: 0 = white 1 = near white 2 = not white */ -int CLASS canon_600_color (int ratio[2], int mar) -{ - int clipped=0, target, miss; - - if (flash_used) { - if (ratio[1] < -104) - { ratio[1] = -104; clipped = 1; } - if (ratio[1] > 12) - { ratio[1] = 12; clipped = 1; } - } else { - if (ratio[1] < -264 || ratio[1] > 461) return 2; - if (ratio[1] < -50) - { ratio[1] = -50; clipped = 1; } - if (ratio[1] > 307) - { ratio[1] = 307; clipped = 1; } - } - target = flash_used || ratio[1] < 197 - ? -38 - (398 * ratio[1] >> 10) - : -123 + (48 * ratio[1] >> 10); - if (target - mar <= ratio[0] && - target + 20 >= ratio[0] && !clipped) return 0; - miss = target - ratio[0]; - if (abs(miss) >= mar*4) return 2; - if (miss < -20) miss = -20; - if (miss > mar) miss = mar; - ratio[0] = target - miss; - return 1; -} - -void CLASS canon_600_auto_wb() -{ - int mar, row, col, i, j, st, count[] = { 0,0 }; - int test[8], total[2][8], ratio[2][2], stat[2]; - - memset (&total, 0, sizeof total); - i = canon_ev + 0.5; - if (i < 10) mar = 150; - else if (i > 12) mar = 20; - else mar = 280 - 20 * i; - if (flash_used) mar = 80; - for (row=14; row < height-14; row+=4) - for (col=10; col < width; col+=2) { - for (i=0; i < 8; i++) - test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = - BAYER(row+(i >> 1),col+(i & 1)); - for (i=0; i < 8; i++) - if (test[i] < 150 || test[i] > 1500) goto next; - for (i=0; i < 4; i++) - if (abs(test[i] - test[i+4]) > 50) goto next; - for (i=0; i < 2; i++) { - for (j=0; j < 4; j+=2) - ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; - stat[i] = canon_600_color (ratio[i], mar); - } - if ((st = stat[0] | stat[1]) > 1) goto next; - for (i=0; i < 2; i++) - if (stat[i]) - for (j=0; j < 2; j++) - test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; - for (i=0; i < 8; i++) - total[st][i] += test[i]; - count[st]++; -next: ; - } - if (count[0] | count[1]) { - st = count[0]*200 < count[1]; - for (i=0; i < 4; i++) - pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CALCULATED; -#endif - } -} - -void CLASS canon_600_coeff() -{ - static const short table[6][12] = { - { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, - { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, - { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, - { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, - { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, - { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; - int t=0, i, c; - float mc, yc; - - mc = pre_mul[1] / pre_mul[2]; - yc = pre_mul[3] / pre_mul[2]; - if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; - if (mc > 1.28 && mc <= 2) { - if (yc < 0.8789) t=3; - else if (yc <= 2) t=4; - } - if (flash_used) t=5; - for (raw_color = i=0; i < 3; i++) - FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.rgb_cam_state = LIBRAW_COLORSTATE_CALCULATED; -#endif -} - -void CLASS canon_600_load_raw() -{ - uchar data[1120], *dp; - ushort pixel[896], *pix; - int irow, row, col, val; - static const short mul[4][2] = - { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; - - for (irow=row=0; irow < height; irow++) { - if (fread (data, 1, raw_width*5/4, ifp) < raw_width*5/4) derror(); - for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8) { - pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); - pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); - pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); - pix[3] = (dp[4] << 2) + (dp[1] & 3); - pix[4] = (dp[5] << 2) + (dp[9] & 3); - pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); - pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); - pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); - } - for (col=0; col < width; col++) - BAYER(row,col) = pixel[col]; - for (col=width; col < raw_width; col++) - { - black += pixel[col]; -#ifdef LIBRAW_LIBRARY_BUILD - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = pixel[col]; -#endif - } - if ((row+=2) > height) row = 1; - } - if (raw_width > width) - black = black / ((raw_width - width) * height) - 4; - for (row=0; row < height; row++) - for (col=0; col < width; col++) { -#ifdef LIBRAW_LIBRARY_BUILD - if( filtering_mode & LIBRAW_FILTERING_NOBLACKS) - val = BAYER(row,col); - else -#endif - if ((val = BAYER(row,col) - black) < 0) val = 0; - val = val * mul[row & 3][col & 1] >> 9; - BAYER(row,col) = val; - } - canon_600_fixed_wb(1311); - canon_600_auto_wb(); - canon_600_coeff(); - maximum = (0x3ff - black) * 1109 >> 9; - black = 0; -} - -void CLASS remove_zeroes() -{ - unsigned row, col, tot, n, r, c; - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,0,2); -#endif - for (row=0; row < height; row++) - for (col=0; col < width; col++) - if (BAYER(row,col) == 0) { - tot = n = 0; - for (r = row-2; r <= row+2; r++) - for (c = col-2; c <= col+2; c++) - if (r < height && c < width && - FC(r,c) == FC(row,col) && BAYER(r,c)) - tot += (n++,BAYER(r,c)); - if (n) BAYER(row,col) = tot/n; - } -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,1,2); -#endif -} - -int CLASS canon_s2is() -{ - unsigned row; - - for (row=0; row < 100; row++) { - fseek (ifp, row*3340 + 3284, SEEK_SET); - if (getc(ifp) > 15) return 1; - } - return 0; -} - -void CLASS canon_a5_load_raw() -{ - ushort data[2565], *dp, pixel; - int vbits=0, buf=0, row, col, bc=0; - - order = 0x4949; - for (row=-top_margin; row < raw_height-top_margin; row++) { - read_shorts (dp=data, raw_width * 10 / 16); - for (col=-left_margin; col < raw_width-left_margin; col++) { - if ((vbits -= 10) < 0) - buf = (vbits += 16, (buf << 16) + *dp++); - pixel = buf >> vbits & 0x3ff; -#ifdef LIBRAW_LIBRARY_BUILD - ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin); - if(dfp) *dfp = pixel; -#endif - if ((unsigned) row < height && (unsigned) col < width) - BAYER(row,col) = pixel; - else if (col > 1-left_margin && col != width) - black += (bc++,pixel); - } - } - if (bc) black /= bc; - maximum = 0x3ff; - -#ifdef LIBRAW_LIBRARY_BUILD - if(!(filtering_mode & LIBRAW_FILTERING_NOZEROES)) -#endif - if (raw_width > 1600) remove_zeroes(); -} - -/* - getbits(-1) initializes the buffer - getbits(n) where 0 <= n <= 25 returns an n-bit integer - */ -unsigned CLASS getbits (int nbits) -{ -#ifdef LIBRAW_NOTHREADS - static unsigned bitbuf=0; - static int vbits=0, reset=0; -#else -#define bitbuf tls->getbits.bitbuf -#define vbits tls->getbits.vbits -#define reset tls->getbits.reset -#endif - unsigned c; - - if (nbits == -1) - return bitbuf = vbits = reset = 0; - if (nbits == 0 || reset) return 0; - while (vbits < nbits) { - if ((c = fgetc(ifp)) == EOF) derror(); - if ((reset = zero_after_ff && c == 0xff && fgetc(ifp))) return 0; - bitbuf = (bitbuf << 8) + (uchar) c; - vbits += 8; - } - vbits -= nbits; - return bitbuf << (32-nbits-vbits) >> (32-nbits); -#ifndef LIBRAW_NOTHREADS -#undef bitbuf -#undef vbits -#undef reset -#endif -} - -void CLASS init_decoder() -{ - memset (first_decode, 0, sizeof first_decode); - free_decode = first_decode; -} - -/* - Construct a decode tree according to the specification in *source. - The first 16 bytes specify how many codes should be 1-bit, 2-bit - 3-bit, etc. Bytes after that are the leaf values. - - For example, if the source is - - { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, - 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, - - then the code is - - 00 0x04 - 010 0x03 - 011 0x05 - 100 0x06 - 101 0x02 - 1100 0x07 - 1101 0x01 - 11100 0x08 - 11101 0x09 - 11110 0x00 - 111110 0x0a - 1111110 0x0b - 1111111 0xff - */ -uchar * CLASS make_decoder (const uchar *source, int level) -{ - struct decode *cur; -#ifndef LIBRAW_NOTHREADS -#define t_leaf tls->make_decoder_leaf -#else - static int t_leaf; -#endif - int i, next; - - if (level==0) t_leaf=0; - cur = free_decode++; - if (free_decode > first_decode+2048) { -#ifdef LIBRAW_LIBRARY_BUILD - throw LIBRAW_EXCEPTION_DECODE_RAW; -#else - fprintf (stderr,_("%s: decoder table overflow\n"), ifname); - longjmp (failure, 2); -#endif - } - for (i=next=0; i <= t_leaf && next < 16; ) - i += source[next++]; - if (i > t_leaf) { - if (level < next) { - cur->branch[0] = free_decode; - make_decoder (source, level+1); - cur->branch[1] = free_decode; - make_decoder (source, level+1); - } else - cur->leaf = source[16 + t_leaf++]; - } - return (uchar *) source + 16 + t_leaf; -#ifndef LIBRAW_NOTHREADS -#undef t_leaf -#endif -} - -void CLASS crw_init_tables (unsigned table) -{ - static const uchar first_tree[3][29] = { - { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, - 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, - { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, - 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, - { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, - 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, - }; - static const uchar second_tree[3][180] = { - { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, - 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, - 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, - 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, - 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, - 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, - 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, - 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, - 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, - 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, - 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, - 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, - 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, - 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, - 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, - { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, - 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, - 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, - 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, - 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, - 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, - 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, - 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, - 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, - 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, - 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, - 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, - 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, - 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, - 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, - { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, - 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, - 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, - 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, - 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, - 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, - 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, - 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, - 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, - 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, - 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, - 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, - 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, - 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, - 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } - }; - if (table > 2) table = 2; - init_decoder(); - make_decoder ( first_tree[table], 0); - second_decode = free_decode; - make_decoder (second_tree[table], 0); -} - -/* - Return 0 if the image starts with compressed data, - 1 if it starts with uncompressed low-order bits. - - In Canon compressed data, 0xff is always followed by 0x00. - */ -int CLASS canon_has_lowbits() -{ - uchar test[0x4000]; - int ret=1, i; - - fseek (ifp, 0, SEEK_SET); - fread (test, 1, sizeof test, ifp); - for (i=540; i < sizeof test - 1; i++) - if (test[i] == 0xff) { - if (test[i+1]) return 1; - ret=0; - } - return ret; -} - -void CLASS canon_compressed_load_raw() -{ - ushort *pixel, *prow; - int nblocks, lowbits, i, row, r, col, save, val; - unsigned irow, icol; - struct decode *decode, *dindex; - int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; - double dark[2] = { 0,0 }; - uchar c; - - crw_init_tables (tiff_compress); - pixel = (ushort *) calloc (raw_width*8, sizeof *pixel); - merror (pixel, "canon_compressed_load_raw()"); - lowbits = canon_has_lowbits(); - if (!lowbits) maximum = 0x3ff; - fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); - zero_after_ff = 1; - getbits(-1); - for (row=0; row < raw_height; row+=8) { - nblocks = MIN (8, raw_height-row) * raw_width >> 6; - for (block=0; block < nblocks; block++) { - memset (diffbuf, 0, sizeof diffbuf); - decode = first_decode; - for (i=0; i < 64; i++ ) { - for (dindex=decode; dindex->branch[0]; ) - dindex = dindex->branch[getbits(1)]; - leaf = dindex->leaf; - decode = second_decode; - if (leaf == 0 && i) break; - if (leaf == 0xff) continue; - i += leaf >> 4; - len = leaf & 15; - if (len == 0) continue; - diff = getbits(len); - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - if (i < 64) diffbuf[i] = diff; - } - diffbuf[0] += carry; - carry = diffbuf[0]; - for (i=0; i < 64; i++ ) { - if (pnum++ % raw_width == 0) - base[0] = base[1] = 512; - if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) - derror(); - } - } - if (lowbits) { - save = ftell(ifp); - fseek (ifp, 26 + row*raw_width/4, SEEK_SET); - for (prow=pixel, i=0; i < raw_width*2; i++) { - c = fgetc(ifp); - for (r=0; r < 8; r+=2, prow++) { - val = (*prow << 2) + ((c >> r) & 3); - if (raw_width == 2672 && val < 512) val += 2; - *prow = val; - } - } - fseek (ifp, save, SEEK_SET); - } - for (r=0; r < 8; r++) { - irow = row - top_margin + r; -#ifndef LIBRAW_LIBRARY_BUILD - if (irow >= height) continue; -#endif - for (col=0; col < raw_width; col++) { -#ifdef LIBRAW_LIBRARY_BUILD - ushort *dfp = get_masked_pointer(row+r,col); - if(dfp) *dfp = pixel[r*raw_width+col]; - if (irow >= height) continue; // skip for top/bottom rows -#endif - icol = col - left_margin; - if (icol < width) - BAYER(irow,icol) = pixel[r*raw_width+col]; - else if (col > 1) - dark[icol & 1] += pixel[r*raw_width+col]; - } - } - } - free (pixel); - canon_black (dark); -} - -int CLASS ljpeg_start (struct jhead *jh, int info_only) -{ - int c, tag, len; - uchar data[0x10000], *dp; - - if (!info_only) init_decoder(); - memset (jh, 0, sizeof *jh); - FORC(6) jh->huff[c] = free_decode; - jh->restart = INT_MAX; - fread (data, 2, 1, ifp); - if (data[1] != 0xd8) return 0; - do { - fread (data, 2, 2, ifp); - tag = data[0] << 8 | data[1]; - len = (data[2] << 8 | data[3]) - 2; - if (tag <= 0xff00) return 0; - fread (data, 1, len, ifp); - switch (tag) { - case 0xffc3: - jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; - case 0xffc0: - jh->bits = data[0]; - jh->high = data[1] << 8 | data[2]; - jh->wide = data[3] << 8 | data[4]; - jh->clrs = data[5] + jh->sraw; - if (len == 9 && !dng_version) getc(ifp); - break; - case 0xffc4: - if (info_only) break; - for (dp = data; dp < data+len && *dp < 4; ) { - jh->huff[*dp] = free_decode; - dp = make_decoder (++dp, 0); - } - break; - case 0xffda: - jh->psv = data[1+data[0]*2]; - jh->bits -= data[3+data[0]*2] & 15; - break; - case 0xffdd: - jh->restart = data[0] << 8 | data[1]; - } - } while (tag != 0xffda); - if (info_only) return 1; - if (jh->sraw) { - FORC(4) jh->huff[2+c] = jh->huff[1]; - FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; - } - jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); - merror (jh->row, "ljpeg_start()"); - return zero_after_ff = 1; -} - -int CLASS ljpeg_diff (struct decode *dindex) -{ - int len, diff; - - while (dindex->branch[0]) - dindex = dindex->branch[getbits(1)]; - len = dindex->leaf; - if (len == 16 && (!dng_version || dng_version >= 0x1010000)) - return -32768; - diff = getbits(len); - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - return diff; -} - -ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) -{ - int col, c, diff, pred, spred=0; - ushort mark=0, *row[3]; - - if (jrow * jh->wide % jh->restart == 0) { - FORC(6) jh->vpred[c] = 1 << (jh->bits-1); - if (jrow) - do mark = (mark << 8) + (c = fgetc(ifp)); - while (c != EOF && mark >> 4 != 0xffd); - getbits(-1); - } - FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); - for (col=0; col < jh->wide; col++) - FORC(jh->clrs) { - diff = ljpeg_diff (jh->huff[c]); - if (jh->sraw && c <= jh->sraw && (col | c)) - pred = spred; - else if (col) pred = row[0][-jh->clrs]; - else pred = (jh->vpred[c] += diff) - diff; - if (jrow && col) switch (jh->psv) { - case 1: break; - case 2: pred = row[1][0]; break; - case 3: pred = row[1][-jh->clrs]; break; - case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; - case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; - case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; - case 7: pred = (pred + row[1][0]) >> 1; break; - default: pred = 0; - } - if ((**row = pred + diff) >> jh->bits) derror(); - if (c <= jh->sraw) spred = **row; - row[0]++; row[1]++; - } - return row[2]; -} - -void CLASS lossless_jpeg_load_raw() -{ - int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0; - double dark[2] = { 0,0 }; - struct jhead jh; - int min=INT_MAX; - ushort *rp; - - if (!ljpeg_start (&jh, 0)) return; - jwide = jh.wide * jh.clrs; - - for (jrow=0; jrow < jh.high; jrow++) { - rp = ljpeg_row (jrow, &jh); - for (jcol=0; jcol < jwide; jcol++) { - val = *rp++; - if (jh.bits <= 12) -#ifdef LIBRAW_LIBRARY_BUILD - if( !(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)) -#endif - val = curve[val & 0xfff]; - if (cr2_slice[0]) { - jidx = jrow*jwide + jcol; - i = jidx / (cr2_slice[1]*jh.high); - if ((j = i >= cr2_slice[0])) - i = cr2_slice[0]; - jidx -= i * (cr2_slice[1]*jh.high); - row = jidx / cr2_slice[1+j]; - col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; - } - if (raw_width == 3984 && (col -= 2) < 0) - col += (row--,raw_width); -#ifdef LIBRAW_LIBRARY_BUILD - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = val; -#endif - if ((unsigned) (row-top_margin) < height) { - if ((unsigned) (col-left_margin) < width) { - BAYER(row-top_margin,col-left_margin) = val; - if (min > val) min = val; - } else if (col > 1) - dark[(col-left_margin) & 1] += val; - } - if (++col >= raw_width) - col = (row++,0); - } - } - free (jh.row); - canon_black (dark); - if (!strcasecmp(make,"KODAK")) - black = min; -} - -void CLASS canon_sraw_load_raw() -{ - struct jhead jh; - short *rp=0, (*ip)[4]; - int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; - int v[3]={0,0,0}, ver, hue; - char *cp; - - if (!ljpeg_start (&jh, 0)) return; - jwide = (jh.wide >>= 1) * jh.clrs; - - for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { - scol = ecol; - ecol += cr2_slice[1] * 2 / jh.clrs; - if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; - for (row=0; row < height; row += (jh.clrs >> 1) - 1) { - ip = (short (*)[4]) image + row*width; - for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { - if ((jcol %= jwide) == 0) - rp = (short *) ljpeg_row (jrow++, &jh); - if (col >= width) continue; - FORC (jh.clrs-2) - ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; - ip[col][1] = rp[jcol+jh.clrs-2] - 16384; - ip[col][2] = rp[jcol+jh.clrs-1] - 16384; - } - } - } - for (cp=model2; *cp && !isdigit(*cp); cp++); - sscanf (cp, "%d.%d.%d", v, v+1, v+2); - ver = (v[0]*1000 + v[1])*1000 + v[2]; - hue = (jh.sraw+1) << 2; - if (unique_id == 0x80000218 && ver > 1000006 && ver < 3000000) - hue = jh.sraw << 1; - ip = (short (*)[4]) image; - rp = ip[0]; - for (row=0; row < height; row++, ip+=width) { - if (row & (jh.sraw >> 1)) - for (col=0; col < width; col+=2) - for (c=1; c < 3; c++) - if (row == height-1) - ip[col][c] = ip[col-width][c]; - else ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; - for (col=1; col < width; col+=2) - for (c=1; c < 3; c++) - if (col == width-1) - ip[col][c] = ip[col-1][c]; - else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; - } - for ( ; rp < ip[0]; rp+=4) { - if (unique_id < 0x80000200) { - pix[0] = rp[0] + rp[2] - 512; - pix[2] = rp[0] + rp[1] - 512; - pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12) - 512; - } else { - rp[1] = (rp[1] << 2) + hue; - rp[2] = (rp[2] << 2) + hue; - pix[0] = rp[0] + (( 200*rp[1] + 22929*rp[2]) >> 14); - pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); - pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); - } - FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); - } - free (jh.row); - maximum = 0x3fff; -} - -void CLASS adobe_copy_pixel (int row, int col, ushort **rp) -{ - unsigned r, c; - - r = row -= top_margin; - c = col -= left_margin; - if (is_raw == 2 && shot_select) (*rp)++; - if (filters) { -#ifndef LIBRAW_LIBRARY_BUILD - if (fuji_width) { - r = row + fuji_width - 1 - (col >> 1); - c = row + ((col+1) >> 1); - } -#endif -#ifdef LIBRAW_LIBRARY_BUILD - ushort val = **rp; - if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)) - val = **rp < 0x1000 ? curve[**rp] : **rp; - if (r < height && c < width) - BAYER(r,c) = val; - else - { - ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin); - if(dfp) *dfp = val; - } -#else - if (r < height && c < width) - BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; -#endif - *rp += is_raw; - } else { - if (r < height && c < width) - FORC(tiff_samples) - image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c]; - *rp += tiff_samples; - } - if (is_raw == 2 && shot_select) (*rp)--; -} - -void CLASS adobe_dng_load_raw_lj() -{ - unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; - struct jhead jh; - ushort *rp; - - while (trow < raw_height) { - save = ftell(ifp); - if (tile_length < INT_MAX) - fseek (ifp, get4(), SEEK_SET); - if (!ljpeg_start (&jh, 0)) break; - jwide = jh.wide; - if (filters) jwide *= jh.clrs; - jwide /= is_raw; - for (row=col=jrow=0; jrow < jh.high; jrow++) { - rp = ljpeg_row (jrow, &jh); - for (jcol=0; jcol < jwide; jcol++) { - adobe_copy_pixel (trow+row, tcol+col, &rp); - if (++col >= tile_width || col >= raw_width) - row += 1 + (col = 0); - } - } - fseek (ifp, save+4, SEEK_SET); - if ((tcol += tile_width) >= raw_width) - trow += tile_length + (tcol = 0); - free (jh.row); - } -} - -void CLASS adobe_dng_load_raw_nc() -{ - ushort *pixel, *rp; - int row, col; - - pixel = (ushort *) calloc (raw_width * tiff_samples, sizeof *pixel); - merror (pixel, "adobe_dng_load_raw_nc()"); - for (row=0; row < raw_height; row++) { - if (tiff_bps == 16) - read_shorts (pixel, raw_width * tiff_samples); - else { - getbits(-1); - for (col=0; col < raw_width * tiff_samples; col++) - pixel[col] = getbits(tiff_bps); - } - for (rp=pixel, col=0; col < raw_width; col++) - adobe_copy_pixel (row, col, &rp); - } - free (pixel); -} - -void CLASS pentax_tree() -{ - ushort bit[2][13]; - struct decode *cur; - int c, i, j; - - init_decoder(); - FORC(13) bit[0][c] = get2(); - FORC(13) bit[1][c] = fgetc(ifp) & 15; - FORC(13) { - cur = first_decode; - for (i=0; i < bit[1][c]; i++) { - j = bit[0][c] >> (11-i) & 1; - if (!cur->branch[j]) cur->branch[j] = ++free_decode; - cur = cur->branch[j]; - } - cur->leaf = c; - } -} - -void CLASS pentax_k10_load_raw() -{ - int row, col, diff; - ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; - - getbits(-1); - for (row=0; row < raw_height; row++) - { -#ifndef LIBRAW_LIBRARY_BUILD - if(row >= height) break; -#endif - for (col=0; col < raw_width; col++) { - diff = ljpeg_diff (first_decode); - if (col < 2) hpred[col] = vpred[row & 1][col] += diff; - else hpred[col & 1] += diff; - if (col < width && row < height) - BAYER(row,col) = hpred[col & 1]; -#ifdef LIBRAW_LIBRARY_BUILD - else - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = hpred[col & 1]; - } - - if (col < width && row < height) -#endif - if (hpred[col & 1] >> 12) derror(); - } - } -} - -void CLASS nikon_compressed_load_raw() -{ - static const uchar nikon_tree[][32] = { - { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ - 5,4,3,6,2,7,1,0,8,9,11,10,12 }, - { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ - 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 }, - { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ - 5,4,6,3,7,2,8,1,9,0,10,11,12 }, - { 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ - 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 }, - { 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ - 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 }, - { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ - 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } }; - struct decode *dindex; - ushort ver0, ver1, vpred[2][2], hpred[2], csize; - int i, min, max, step=0, huff=0, split=0, row, col, len, shl, diff; - - fseek (ifp, meta_offset, SEEK_SET); - ver0 = fgetc(ifp); - ver1 = fgetc(ifp); - if (ver0 == 0x49 || ver1 == 0x58) - fseek (ifp, 2110, SEEK_CUR); - if (ver0 == 0x46) huff = 2; - if (tiff_bps == 14) huff += 3; - read_shorts (vpred[0], 4); - max = 1 << tiff_bps & 0x7fff; - if ((csize = get2()) > 1) - step = max / (csize-1); - if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { - for (i=0; i < csize; i++) - curve[i*step] = get2(); - for (i=0; i < max; i++) - curve[i] = ( curve[i-i%step]*(step-i%step) + - curve[i-i%step+step]*(i%step) ) / step; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.curve_state = LIBRAW_COLORSTATE_LOADED; -#endif - fseek (ifp, meta_offset+562, SEEK_SET); - split = get2(); - } else if (ver0 != 0x46 && csize <= 0x4001) - { - read_shorts (curve, max=csize); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.curve_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - while (curve[max-2] == curve[max-1]) max--; - init_decoder(); - make_decoder (nikon_tree[huff], 0); - fseek (ifp, data_offset, SEEK_SET); - getbits(-1); - for (min=row=0; row < height; row++) { - if (split && row == split) { - init_decoder(); - make_decoder (nikon_tree[huff+1], 0); - max += (min = 16) << 1; - } - for (col=0; col < raw_width; col++) { - for (dindex=first_decode; dindex->branch[0]; ) - dindex = dindex->branch[getbits(1)]; - len = dindex->leaf & 15; - shl = dindex->leaf >> 4; - diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - !shl; - if (col < 2) hpred[col] = vpred[row & 1][col] += diff; - else hpred[col & 1] += diff; - if ((ushort)(hpred[col & 1] + min) >= max) derror(); -#ifndef LIBRAW_LIBRARY_BUILD - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; -#else - ushort xval = hpred[col & 1]; - if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)) - xval = curve[LIM((short)xval,0,0x3fff)]; - if ((unsigned) (col-left_margin) < width) - { - BAYER(row,col-left_margin) = xval; - } - else - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = xval; - } -#endif - - } - } -} - -/* - Figure out if a NEF file is compressed. These fancy heuristics - are only needed for the D100, thanks to a bug in some cameras - that tags all images as "compressed". - */ -int CLASS nikon_is_compressed() -{ - uchar test[256]; - int i; - - fseek (ifp, data_offset, SEEK_SET); - fread (test, 1, 256, ifp); - for (i=15; i < 256; i+=16) - if (test[i]) return 1; - return 0; -} - -/* - Returns 1 for a Coolpix 995, 0 for anything else. - */ -int CLASS nikon_e995() -{ - int i, histo[256]; - const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; - - memset (histo, 0, sizeof histo); - fseek (ifp, -2000, SEEK_END); - for (i=0; i < 2000; i++) - histo[fgetc(ifp)]++; - for (i=0; i < 4; i++) - if (histo[often[i]] < 200) - return 0; - return 1; -} - -/* - Returns 1 for a Coolpix 2100, 0 for anything else. - */ -int CLASS nikon_e2100() -{ - uchar t[12]; - int i; - - fseek (ifp, 0, SEEK_SET); - for (i=0; i < 1024; i++) { - fread (t, 1, 12, ifp); - if (((t[2] & t[4] & t[7] & t[9]) >> 4 - & t[1] & t[6] & t[8] & t[11] & 3) != 3) - return 0; - } - return 1; -} - -void CLASS nikon_3700() -{ - int bits, i; - uchar dp[24]; - static const struct { - int bits; - char t_make[12], t_model[15]; - } table[] = { - { 0x00, "PENTAX", "Optio 33WR" }, - { 0x03, "NIKON", "E3200" }, - { 0x32, "NIKON", "E3700" }, - { 0x33, "OLYMPUS", "C740UZ" } }; - - fseek (ifp, 3072, SEEK_SET); - fread (dp, 1, 24, ifp); - bits = (dp[8] & 3) << 4 | (dp[20] & 3); - for (i=0; i < sizeof table / sizeof *table; i++) - if (bits == table[i].bits) { - strcpy (make, table[i].t_make ); - strcpy (model, table[i].t_model); - } -} - /* - Separates a Minolta DiMAGE Z2 from a Nikon E4300. - */ -int CLASS minolta_z2() -{ - int i, nz; - char tail[424]; - - fseek (ifp, -sizeof tail, SEEK_END); - fread (tail, 1, sizeof tail, ifp); - for (nz=i=0; i < sizeof tail; i++) - if (tail[i]) nz++; - return nz > 20; -} - -/* Here raw_width is in bytes, not pixels. */ -void CLASS nikon_e900_load_raw() -{ - int offset=0, irow, row, col; - - for (irow=0; irow < height; irow++) { - row = irow * 2 % height; - if (row == 1) - offset = - (-offset & -4096); - fseek (ifp, offset, SEEK_SET); - offset += raw_width; - getbits(-1); - for (col=0; col < width; col++) - BAYER(row,col) = getbits(10); - } -} - -/* - The Fuji Super CCD is just a Bayer grid rotated 45 degrees. - */ -void CLASS fuji_load_raw() -{ - ushort *pixel; -#ifndef LIBRAW_LIBRARY_BUILD - int wide, row, col, r, c; - - fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); - wide = fuji_width << !fuji_layout; - pixel = (ushort *) calloc (wide, sizeof *pixel); - merror (pixel, "fuji_load_raw()"); - for (row=0; row < raw_height; row++) { - read_shorts (pixel, wide); - fseek (ifp, 2*(raw_width - wide), SEEK_CUR); - for (col=0; col < wide; col++) { - if (fuji_layout) { - r = fuji_width - 1 - col + (row >> 1); - c = col + ((row+1) >> 1); - } else { - r = fuji_width - 1 + row - (col >> 1); - c = row + ((col+1) >> 1); - } - BAYER(r,c) = pixel[col]; - } - } - free (pixel); -#else - int row,col; - int wide, r, c; - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "fuji_load_raw()"); - for (row=0; row < raw_height; row++) { - read_shorts (pixel, raw_width); - for (col=0; col < raw_width; col++) { - if(col >= left_margin && col < width+left_margin - && row >= top_margin && row < height+top_margin) - { - int rrow = row-top_margin; - int ccol = col-left_margin; - if (fuji_layout) { - r = fuji_width - 1 - ccol + (rrow >> 1); - c = ccol + ((rrow+1) >> 1); - } else { - r = fuji_width - 1 + rrow - (ccol >> 1); - c = rrow + ((ccol+1) >> 1); - } - - image[((row-top_margin) >> shrink)*iwidth + ((col-left_margin) >> shrink)][FC(r,c)] = pixel[col]; - } - else - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = pixel[col]; - } - } - } - free (pixel); -#endif -} -void CLASS ppm_thumb (FILE *tfp) -{ - char *thumb; - thumb_length = thumb_width*thumb_height*3; - thumb = (char *) malloc (thumb_length); - merror (thumb, "ppm_thumb()"); - fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); - fread (thumb, 1, thumb_length, ifp); - fwrite (thumb, 1, thumb_length, tfp); - free (thumb); -} - -void CLASS layer_thumb (FILE *tfp) -{ - int i, c; - char *thumb, map[][4] = { "012","102" }; - - colors = thumb_misc >> 5 & 7; - thumb_length = thumb_width*thumb_height; - thumb = (char *) calloc (colors, thumb_length); - merror (thumb, "layer_thumb()"); - fprintf (tfp, "P%d\n%d %d\n255\n", - 5 + (colors >> 1), thumb_width, thumb_height); - fread (thumb, thumb_length, colors, ifp); - for (i=0; i < thumb_length; i++) - FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], tfp); - free (thumb); -} - -void CLASS rollei_thumb (FILE *tfp) -{ - unsigned i; - ushort *thumb; - - thumb_length = thumb_width * thumb_height; - thumb = (ushort *) calloc (thumb_length, 2); - merror (thumb, "rollei_thumb()"); - fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); - read_shorts (thumb, thumb_length); - for (i=0; i < thumb_length; i++) { - putc (thumb[i] << 3, tfp); - putc (thumb[i] >> 5 << 2, tfp); - putc (thumb[i] >> 11 << 3, tfp); - } - free (thumb); -} - -void CLASS rollei_load_raw() -{ - uchar pixel[10]; - unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; - - isix = raw_width * raw_height * 5 / 8; - while (fread (pixel, 1, 10, ifp) == 10) { - for (i=0; i < 10; i+=2) { - todo[i] = iten++; - todo[i+1] = pixel[i] << 8 | pixel[i+1]; - buffer = pixel[i] >> 2 | buffer << 6; - } - for ( ; i < 16; i+=2) { - todo[i] = isix++; - todo[i+1] = buffer >> (14-i)*5; - } - for (i=0; i < 16; i+=2) { - row = todo[i] / raw_width - top_margin; - col = todo[i] % raw_width - left_margin; - if (row < height && col < width) - BAYER(row,col) = (todo[i+1] & 0x3ff); -#ifdef LIBRAW_LIBRARY_BUILD - else - { - ushort *dfp = get_masked_pointer(todo[i] / raw_width,todo[i] % raw_width); - if(dfp) *dfp = (todo[i+1] & 0x3ff); - } -#endif - } - } - maximum = 0x3ff; -} - -int CLASS bayer (unsigned row, unsigned col) -{ - return (row < height && col < width) ? BAYER(row,col) : 0; -} - -void CLASS phase_one_flat_field (int is_float, int nc) -{ - ushort head[8]; - unsigned wide, y, x, c, rend, cend, row, col; - float *mrow, num, mult[4]; - - read_shorts (head, 8); - wide = head[2] / head[4]; - mrow = (float *) calloc (nc*wide, sizeof *mrow); - merror (mrow, "phase_one_flat_field()"); - for (y=0; y < head[3] / head[5]; y++) { - for (x=0; x < wide; x++) - for (c=0; c < nc; c+=2) { - num = is_float ? getreal(11) : get2()/32768.0; - if (y==0) mrow[c*wide+x] = num; - else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; - } - if (y==0) continue; - rend = head[1]-top_margin + y*head[5]; - for (row = rend-head[5]; row < height && row < rend; row++) { - for (x=1; x < wide; x++) { - for (c=0; c < nc; c+=2) { - mult[c] = mrow[c*wide+x-1]; - mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; - } - cend = head[0]-left_margin + x*head[4]; - for (col = cend-head[4]; col < width && col < cend; col++) { - c = nc > 2 ? FC(row,col) : 0; - if (!(c & 1)) { - c = BAYER(row,col) * mult[c]; - BAYER(row,col) = LIM(c,0,65535); - } - for (c=0; c < nc; c+=2) - mult[c] += mult[c+1]; - } - } - for (x=0; x < wide; x++) - for (c=0; c < nc; c+=2) - mrow[c*wide+x] += mrow[(c+1)*wide+x]; - } - } - free (mrow); -} - -void CLASS phase_one_correct() -{ - unsigned entries, tag, data, save, col, row, type; - int len, i, j, k, cip, val[4], dev[4], sum, max; - int head[9], diff, mindiff=INT_MAX, off_412=0; - static const signed char dir[12][2] = - { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, - {-2,-2}, {-2,2}, {2,-2}, {2,2} }; - float poly[8], num, cfrac, frac, mult[2], *yval[2]; - ushort t_curve[0x10000], *xval[2]; - - if (half_size || !meta_length) return; -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("Phase One correction...\n")); -#endif - fseek (ifp, meta_offset, SEEK_SET); - order = get2(); - fseek (ifp, 6, SEEK_CUR); - fseek (ifp, meta_offset+get4(), SEEK_SET); - entries = get4(); get4(); - while (entries--) { - tag = get4(); - len = get4(); - data = get4(); - save = ftell(ifp); - fseek (ifp, meta_offset+data, SEEK_SET); - if (tag == 0x419) { /* Polynomial curve */ - for (get4(), i=0; i < 8; i++) - poly[i] = getreal(11); - poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; - for (i=0; i < 0x10000; i++) { - num = (poly[5]*i + poly[3])*i + poly[1]; - t_curve[i] = LIM(num,0,65535); - } goto apply; /* apply to right half */ - } else if (tag == 0x41a) { /* Polynomial curve */ - for (i=0; i < 4; i++) - poly[i] = getreal(11); - for (i=0; i < 0x10000; i++) { - for (num=0, j=4; j--; ) - num = num * i + poly[j]; - t_curve[i] = LIM(num+i,0,65535); - } apply: /* apply to whole image */ - for (row=0; row < height; row++) - for (col = (tag & 1)*ph1.split_col; col < width; col++) - BAYER(row,col) = t_curve[BAYER(row,col)]; - } else if (tag == 0x400) { /* Sensor defects */ - while ((len -= 8) >= 0) { - col = get2() - left_margin; - row = get2() - top_margin; - type = get2(); get2(); - if (col >= width) continue; - if (type == 131) /* Bad column */ - for (row=0; row < height; row++) - if (FC(row,col) == 1) { - for (sum=i=0; i < 4; i++) - sum += val[i] = bayer (row+dir[i][0], col+dir[i][1]); - for (max=i=0; i < 4; i++) { - dev[i] = abs((val[i] << 2) - sum); - if (dev[max] < dev[i]) max = i; - } - BAYER(row,col) = (sum - val[max])/3.0 + 0.5; - } else { - for (sum=0, i=8; i < 12; i++) - sum += bayer (row+dir[i][0], col+dir[i][1]); - BAYER(row,col) = 0.5 + sum * 0.0732233 + - (bayer(row,col-2) + bayer(row,col+2)) * 0.3535534; - } - else if (type == 129) { /* Bad pixel */ - if (row >= height) continue; - j = (FC(row,col) != 1) * 4; - for (sum=0, i=j; i < j+8; i++) - sum += bayer (row+dir[i][0], col+dir[i][1]); - BAYER(row,col) = (sum + 4) >> 3; - } - } - } else if (tag == 0x401) { /* All-color flat fields */ - phase_one_flat_field (1, 2); - } else if (tag == 0x416 || tag == 0x410) { - phase_one_flat_field (0, 2); - } else if (tag == 0x40b) { /* Red+blue flat field */ - phase_one_flat_field (0, 4); - } else if (tag == 0x412) { - fseek (ifp, 36, SEEK_CUR); - diff = abs (get2() - ph1.tag_21a); - if (mindiff > diff) { - mindiff = diff; - off_412 = ftell(ifp) - 38; - } - } - fseek (ifp, save, SEEK_SET); - } - if (off_412) { - fseek (ifp, off_412, SEEK_SET); - for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; - yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); - merror (yval[0], "phase_one_correct()"); - yval[1] = (float *) (yval[0] + head[1]*head[3]); - xval[0] = (ushort *) (yval[1] + head[2]*head[4]); - xval[1] = (ushort *) (xval[0] + head[1]*head[3]); - get2(); - for (i=0; i < 2; i++) - for (j=0; j < head[i+1]*head[i+3]; j++) - yval[i][j] = getreal(11); - for (i=0; i < 2; i++) - for (j=0; j < head[i+1]*head[i+3]; j++) - xval[i][j] = get2(); - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - cfrac = (float) col * head[3] / raw_width; - cfrac -= cip = cfrac; - num = BAYER(row,col) * 0.5; - for (i=cip; i < cip+2; i++) { - for (k=j=0; j < head[1]; j++) - if (num < xval[0][k = head[1]*i+j]) break; - frac = (j == 0 || j == head[1]) ? 0 : - (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); - mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); - } - i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) - * (row + top_margin) + num) * 2; - BAYER(row,col) = LIM(i,0,65535); - } - free (yval[0]); - } -} - -void CLASS phase_one_load_raw() -{ - int row, col, a, b; - ushort *pixel, akey, bkey, mask; - - fseek (ifp, ph1.key_off, SEEK_SET); - akey = get2(); - bkey = get2(); - mask = ph1.format == 1 ? 0x5555:0x1354; -#ifndef LIBRAW_LIBRARY_BUILD - fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET); - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "phase_one_load_raw()"); - for (row=0; row < height; row++) { - read_shorts (pixel, raw_width); - for (col=0; col < raw_width; col+=2) { - a = pixel[col+0] ^ akey; - b = pixel[col+1] ^ bkey; - pixel[col+0] = (a & mask) | (b & ~mask); - pixel[col+1] = (b & mask) | (a & ~mask); - } - for (col=0; col < width; col++) - BAYER(row,col) = pixel[col+left_margin]; - } - free (pixel); -#else - fseek (ifp, data_offset, SEEK_SET); - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "phase_one_load_raw()"); - for (row=0; row < raw_height; row++) { - read_shorts (pixel, raw_width); - for (col=0; col < raw_width; col+=2) { - a = pixel[col+0] ^ akey; - b = pixel[col+1] ^ bkey; - pixel[col+0] = (a & mask) | (b & ~mask); - pixel[col+1] = (b & mask) | (a & ~mask); - } - for (col=0; col < raw_width; col++) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) - *dfp = pixel[col]; - else - BAYER(row,col-left_margin) = pixel[col]; - } - } - free (pixel); - if(!( filtering_mode & LIBRAW_FILTERING_NORAWCURVE) ) -#endif - phase_one_correct(); -} - -unsigned CLASS ph1_bits (int nbits) -{ -#ifndef LIBRAW_NOTHREADS -#define bitbuf tls->ph1_bits.bitbuf -#define vbits tls->ph1_bits.vbits -#else - static UINT64 bitbuf=0; - static int vbits=0; -#endif - if (nbits == -1) - return bitbuf = vbits = 0; - if (nbits == 0) return 0; - if ((vbits -= nbits) < 0) { - bitbuf = bitbuf << 32 | get4(); - vbits += 32; - } - return bitbuf << (64-nbits-vbits) >> (64-nbits); -#ifndef LIBRAW_NOTHREADS -#undef bitbuf -#undef vbits -#endif -} - -void CLASS phase_one_load_raw_c() -{ - static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; - int *offset, len[2], pred[2], row, col, i, j; - ushort *pixel; - short (*t_black)[2]; - - pixel = (ushort *) calloc (raw_width + raw_height*4, 2); - merror (pixel, "phase_one_load_raw_c()"); - offset = (int *) (pixel + raw_width); - fseek (ifp, strip_offset, SEEK_SET); - for (row=0; row < raw_height; row++) - offset[row] = get4(); - t_black = (short (*)[2]) offset + raw_height; - fseek (ifp, ph1.black_off, SEEK_SET); - if (ph1.black_off) - { - read_shorts ((ushort *) t_black[0], raw_height*2); -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.masked_pixels.ph1_black = (ushort (*)[2])calloc(raw_height*2,sizeof(ushort)); - merror (imgdata.masked_pixels.ph1_black, "phase_one_load_raw_c()"); - memmove(imgdata.masked_pixels.ph1_black,(ushort *) t_black[0],raw_height*2*sizeof(ushort)); -#endif - } - for (i=0; i < 256; i++) - curve[i] = i*i / 3.969 + 0.5; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.curve_state = LIBRAW_COLORSTATE_CALCULATED; -#endif - for (row=0; row < raw_height; row++) { - fseek (ifp, data_offset + offset[row], SEEK_SET); - ph1_bits(-1); - pred[0] = pred[1] = 0; - for (col=0; col < raw_width; col++) { - if (col >= (raw_width & -8)) - len[0] = len[1] = 14; - else if ((col & 7) == 0) - for (i=0; i < 2; i++) { - for (j=0; j < 5 && !ph1_bits(1); j++); - if (j--) len[i] = length[j*2 + ph1_bits(1)]; - } - if ((i = len[col & 1]) == 14) - pixel[col] = pred[col & 1] = ph1_bits(16); - else - pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); - if (pred[col & 1] >> 16) derror(); -#ifdef LIBRAW_LIBRARY_BUILD - if(!( filtering_mode & LIBRAW_FILTERING_NORAWCURVE) ) -#endif - if (ph1.format == 5 && pixel[col] < 256) - pixel[col] = curve[pixel[col]]; - } - if ((unsigned) (row-top_margin) < height) -#ifndef LIBRAW_LIBRARY_BUILD - for (col=0; col < width; col++) { - i = (pixel[col+left_margin] << 2) - - ph1.t_black + t_black[row][col >= ph1.split_col]; - if (i > 0) BAYER(row-top_margin,col) = i; - } -#else - { - for (col=0; col < raw_width; col++) { - if( filtering_mode & LIBRAW_FILTERING_NOBLACKS) - i = (pixel[col] << 2); - else - i = (pixel[col] << 2) - - ph1.t_black + t_black[row][(col /* - left_margin */) >= ph1.split_col]; // changed to fix Coffin's bug! - if(col >= left_margin && col < width+left_margin) - { - if (i > 0) BAYER(row-top_margin,col-left_margin) = i; - } - else - { - ushort *dfp = get_masked_pointer(row,col); - if(i>0 && dfp) *dfp = i; - } - } - } - else - { - // top-bottom fields - for (col=0; col < raw_width; col++) { - i = (pixel[col] << 2) - - ph1.t_black + t_black[row][(col+left_margin) >= ph1.split_col]; - if (i > 0) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = i; - } - } - } -#endif - } - free (pixel); -#ifdef LIBRAW_LIBRARY_BUILD - if(!( filtering_mode & LIBRAW_FILTERING_NORAWCURVE) ) -#endif - phase_one_correct(); - maximum = 0xfffc - ph1.t_black; -} - -void CLASS hasselblad_load_raw() -{ - struct jhead jh; - struct decode *dindex; - int row, col, pred[2], len[2], diff, i; - - if (!ljpeg_start (&jh, 0)) return; - free (jh.row); - order = 0x4949; - ph1_bits(-1); - for (row=-top_margin; row < raw_height-top_margin; row++) { - pred[0] = pred[1] = 0x8000; - for (col=-left_margin; col < raw_width-left_margin; col+=2) { - for (i=0; i < 2; i++) { - for (dindex=jh.huff[0]; dindex->branch[0]; ) - dindex = dindex->branch[ph1_bits(1)]; - len[i] = dindex->leaf; - } - for (i=0; i < 2; i++) { - diff = ph1_bits(len[i]); - if ((diff & (1 << (len[i]-1))) == 0) - diff -= (1 << len[i]) - 1; - if (diff == 65535) diff = -32768; - pred[i] += diff; - if (row >= 0 && row < height && (unsigned)(col+i) < width) - BAYER(row,col+i) = pred[i]; -#ifdef LIBRAW_LIBRARY_BUILD - else - { - ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin); - if(dfp) *dfp = pred[i]; - } -#endif - } - } - } - maximum = 0xffff; -} - -void CLASS leaf_hdr_load_raw() -{ - ushort *pixel; - unsigned tile=0, r, c, row, col; - - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "leaf_hdr_load_raw()"); - FORC(tiff_samples) - for (r=0; r < raw_height; r++) { - if (r % tile_length == 0) { - fseek (ifp, data_offset + 4*tile++, SEEK_SET); - fseek (ifp, get4() + 2*left_margin, SEEK_SET); - } - if (filters && c != shot_select) continue; - read_shorts (pixel, raw_width); - if ((row = r - top_margin) >= height) continue; - for (col=0; col < width; col++) - if (filters) BAYER(row,col) = pixel[col]; - else image[row*width+col][c] = pixel[col]; - } - free (pixel); - if (!filters) { - maximum = 0xffff; - raw_color = 1; - } -} - -void CLASS sinar_4shot_load_raw() -{ - ushort *pixel; - unsigned shot, row, col, r, c; - - if ((shot = shot_select) || half_size) { - if (shot) shot--; - if (shot > 3) shot = 3; - fseek (ifp, data_offset + shot*4, SEEK_SET); - fseek (ifp, get4(), SEEK_SET); - unpacked_load_raw(); - return; - } - free (image); - image = (ushort (*)[4]) - calloc ((iheight=height)*(iwidth=width), sizeof *image); - merror (image, "sinar_4shot_load_raw()"); - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "sinar_4shot_load_raw()"); - for (shot=0; shot < 4; shot++) { - fseek (ifp, data_offset + shot*4, SEEK_SET); - fseek (ifp, get4(), SEEK_SET); - for (row=0; row < raw_height; row++) { - read_shorts (pixel, raw_width); - if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; - for (col=0; col < raw_width; col++) { - if ((c = col-left_margin - (shot & 1)) >= width) continue; - image[r*width+c][FC(row,col)] = pixel[col]; - } - } - } - free (pixel); - shrink = filters = 0; -} - -void CLASS imacon_full_load_raw() -{ - int row, col; - - for (row=0; row < height; row++) - for (col=0; col < width; col++) - read_shorts (image[row*width+col], 3); -} - -void CLASS packed_12_load_raw() -{ - int vbits=0, rbits=0, irow, row, col; - UINT64 bitbuf=0; - - if (raw_width * 2 >= width * 3) { /* If raw_width is in bytes, */ - rbits = raw_width * 8; - raw_width = raw_width * 2 / 3; /* convert it to pixels and */ - rbits -= raw_width * 12; /* save the remainder. */ - } - order = load_flags & 1 ? 0x4949 : 0x4d4d; - for (irow=0; irow < height; irow++) { - row = irow; - if (load_flags & 2 && - (row = irow * 2 % height + irow / (height/2)) == 1 && - load_flags & 4) { - if (vbits=0, tiff_compress) - fseek (ifp, data_offset - (-width*height*3/4 & -2048), SEEK_SET); - else { - fseek (ifp, 0, SEEK_END); - fseek (ifp, ftell(ifp)/2, SEEK_SET); - } - } - for (col=0; col < raw_width; col++) { - if ((vbits -= 12) < 0) { - bitbuf = bitbuf << 32 | get4(); - vbits += 32; - } - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = bitbuf << (52-vbits) >> 52; -#ifdef LIBRAW_LIBRARY_BUILD - else - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = bitbuf << (52-vbits) >> 52; - } -#endif - if (load_flags & 8 && (col % 10) == 9) - if (vbits=0, bitbuf & 255) derror(); - } - vbits -= rbits; - } - if (!strcmp(make,"OLYMPUS")) black >>= 4; -} - -void CLASS unpacked_load_raw() -{ - ushort *pixel; - int row, col, bits=0; - - while (1 << ++bits < maximum); -#ifndef LIBRAW_LIBRARY_BUILD - fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); - pixel = (ushort *) calloc (width, sizeof *pixel); - merror (pixel, "unpacked_load_raw()"); - for (row=0; row < height; row++) { - read_shorts (pixel, width); - fseek (ifp, 2*(raw_width - width), SEEK_CUR); - for (col=0; col < width; col++) - if ((BAYER2(row,col) = pixel[col]) >> bits) derror(); - } - free (pixel); -#else - // fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "unpacked_load_raw()"); - for (row=0; row < raw_height; row++) { - read_shorts (pixel, raw_width); - //fseek (ifp, 2*(raw_width - width), SEEK_CUR); - for (col=0; col < raw_width; col++) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) - *dfp = pixel[col]; - else - { - if ((BAYER2(row-top_margin,col-left_margin) = pixel[col]) >> bits) derror(); - } - } - } - free (pixel); -#endif -} - -void CLASS nokia_load_raw() -{ - uchar *data, *dp; - ushort *pixel, *pix; - int dwide, row, c; - - dwide = raw_width * 5 / 4; - data = (uchar *) malloc (dwide + raw_width*2); - merror (data, "nokia_load_raw()"); - pixel = (ushort *) (data + dwide); - for (row=0; row < raw_height; row++) { - if (fread (data, 1, dwide, ifp) < dwide) derror(); - for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=5, pix+=4) - FORC4 pix[c] = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); - if (row < top_margin) -#ifdef LIBRAW_LIBRARY_BUILD - { - int col; - for(col=0;col<width;col++) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) - *dfp = pixel[col]; - } - FORC(width) black += pixel[c]; - } -#else - FORC(width) black += pixel[c]; -#endif - else - FORC(width) BAYER(row-top_margin,c) = pixel[c]; - } - free (data); - if (top_margin) black /= top_margin * width; - maximum = 0x3ff; -} - -unsigned CLASS pana_bits (int nbits) -{ -#ifndef LIBRAW_NOTHREADS -#define buf tls->pana_bits.buf -#define vbits tls->pana_bits.vbits -#else - static uchar buf[0x4000]; - static int vbits; -#endif - int byte; - - if (!nbits) return vbits=0; - if (!vbits) { - fread (buf+load_flags, 1, 0x4000-load_flags, ifp); - fread (buf, 1, load_flags, ifp); - } - vbits = (vbits - nbits) & 0x1ffff; - byte = vbits >> 3 ^ 0x3ff0; - return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits); -#ifndef LIBRAW_NOTHREADS -#undef buf -#undef vbits -#endif -} - -void CLASS panasonic_load_raw() -{ - int row, col, i, j, sh=0, pred[2], nonz[2]; - - pana_bits(0); - for (row=0; row < height; row++) - for (col=0; col < raw_width; col++) { - if ((i = col % 14) == 0) - pred[0] = pred[1] = nonz[0] = nonz[1] = 0; - if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); - if (nonz[i & 1]) { - if ((j = pana_bits(8))) { - if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) - pred[i & 1] &= ~(-1 << sh); - pred[i & 1] += j << sh; - } - } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) - pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); - if (col < width) - if ((BAYER(row,col) = pred[col & 1]) > 4098) derror(); -#ifdef LIBRAW_LIBRARY_BUILD - if(col>=width) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp)*dfp = pred[col & 1]; - } -#endif - } -} - -void CLASS olympus_e300_load_raw() -{ - uchar *data, *dp; - ushort *pixel, *pix; - int dwide, row, col; - - dwide = raw_width * 16 / 10; -#ifndef LIBRAW_LIBRARY_BUILD - fseek (ifp, dwide*top_margin, SEEK_CUR); -#endif - data = (uchar *) malloc (dwide + raw_width*2); - merror (data, "olympus_e300_load_raw()"); - pixel = (ushort *) (data + dwide); -#ifndef LIBRAW_LIBRARY_BUILD - for (row=0; row < height; row++) -#else - for (row=0; row < raw_height; row++) -#endif - { - if (fread (data, 1, dwide, ifp) < dwide) derror(); - for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) { - if (((dp-data) & 15) == 15) - if (*dp++ && pix < pixel+width+left_margin) derror(); - pix[0] = dp[1] << 8 | dp[0]; - pix[1] = dp[2] << 4 | dp[1] >> 4; - } -#ifndef LIBRAW_LIBRARY_BUILD - for (col=0; col < width; col++) - BAYER(row,col) = (pixel[col+left_margin] & 0xfff); -#else - for (col=0; col < raw_width; col++) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) - *dfp = (pixel[col] & 0xfff); - else - BAYER(row-top_margin,col-left_margin) = (pixel[col] & 0xfff); - } - -#endif - } - free (data); - maximum >>= 4; - black >>= 4; -} - -void CLASS olympus_e410_load_raw() -{ - int row, col, nbits, sign, low, high, i, w, n, nw; - int acarry[2][3], *carry, pred, diff; - - fseek (ifp, 7, SEEK_CUR); - getbits(-1); - for (row=0; row < height; row++) { - memset (acarry, 0, sizeof acarry); - for (col=0; col < width; col++) { - carry = acarry[col & 1]; - i = 2 * (carry[2] < 3); - for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); - sign = getbits(1) * -1; - low = getbits(2); - for (high=0; high < 12; high++) - if (getbits(1)) break; - if (high == 12) - high = getbits(16-nbits) >> 1; - carry[0] = (high << nbits) | getbits(nbits); - diff = (carry[0] ^ sign) + carry[1]; - carry[1] = (diff*3 + carry[1]) >> 5; - carry[2] = carry[0] > 16 ? 0 : carry[2]+1; - if (row < 2 && col < 2) pred = 0; - else if (row < 2) pred = BAYER(row,col-2); - else if (col < 2) pred = BAYER(row-2,col); - else { - w = BAYER(row,col-2); - n = BAYER(row-2,col); - nw = BAYER(row-2,col-2); - if ((w < nw && nw < n) || (n < nw && nw < w)) { - if (ABS(w-nw) > 32 || ABS(n-nw) > 32) - pred = w + n - nw; - else pred = (w + n) >> 1; - } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; - } - if ((BAYER(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); - } - } -} - -void CLASS minolta_rd175_load_raw() -{ - uchar pixel[768]; - unsigned irow, box, row, col; - - for (irow=0; irow < 1481; irow++) { - if (fread (pixel, 1, 768, ifp) < 768) derror(); - box = irow / 82; - row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); - switch (irow) { - case 1477: case 1479: continue; - case 1476: row = 984; break; - case 1480: row = 985; break; - case 1478: row = 985; box = 1; - } - if ((box < 12) && (box & 1)) { - for (col=0; col < 1533; col++, row ^= 1) - if (col != 1) BAYER(row,col) = (col+1) & 2 ? - pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; - BAYER(row,1) = pixel[1] << 1; - BAYER(row,1533) = pixel[765] << 1; - } else - for (col=row & 1; col < 1534; col+=2) - BAYER(row,col) = pixel[col/2] << 1; - } - maximum = 0xff << 1; -} - -void CLASS casio_qv5700_load_raw() -{ - uchar data[3232], *dp; - ushort pixel[2576], *pix; - int row, col; - - for (row=0; row < height; row++) { - fread (data, 1, 3232, ifp); - for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) { - pix[0] = (dp[0] << 2) + (dp[1] >> 6); - pix[1] = (dp[1] << 4) + (dp[2] >> 4); - pix[2] = (dp[2] << 6) + (dp[3] >> 2); - pix[3] = (dp[3] << 8) + (dp[4] ); - } - for (col=0; col < width; col++) - BAYER(row,col) = (pixel[col] & 0x3ff); - } - maximum = 0x3fc; -} - -void CLASS quicktake_100_load_raw() -{ - uchar pixel[484][644]; - static const short gstep[16] = - { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; - static const short rstep[6][4] = - { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, - { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; - static const short t_curve[256] = - { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, - 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, - 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, - 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, - 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, - 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, - 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, - 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, - 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, - 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, - 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, - 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, - 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; - int rb, row, col, sharp, val=0; - - getbits(-1); - memset (pixel, 0x80, sizeof pixel); - for (row=2; row < height+2; row++) { - for (col=2+(row & 1); col < width+2; col+=2) { - val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + - pixel[row][col-2]) >> 2) + gstep[getbits(4)]; - pixel[row][col] = val = LIM(val,0,255); - if (col < 4) - pixel[row][col-2] = pixel[row+1][~row & 1] = val; - if (row == 2) - pixel[row-1][col+1] = pixel[row-1][col+3] = val; - } - pixel[row][col] = val; - } - for (rb=0; rb < 2; rb++) - for (row=2+rb; row < height+2; row+=2) - for (col=3-(row & 1); col < width+2; col+=2) { - if (row < 4 || col < 4) sharp = 2; - else { - val = ABS(pixel[row-2][col] - pixel[row][col-2]) - + ABS(pixel[row-2][col] - pixel[row-2][col-2]) - + ABS(pixel[row][col-2] - pixel[row-2][col-2]); - sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : - val < 32 ? 3 : val < 48 ? 4 : 5; - } - val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) - + rstep[sharp][getbits(2)]; - pixel[row][col] = val = LIM(val,0,255); - if (row < 4) pixel[row-2][col+2] = val; - if (col < 4) pixel[row+2][col-2] = val; - } - for (row=2; row < height+2; row++) - for (col=3-(row & 1); col < width+2; col+=2) { - val = ((pixel[row][col-1] + (pixel[row][col] << 2) + - pixel[row][col+1]) >> 1) - 0x100; - pixel[row][col] = LIM(val,0,255); - } - for (row=0; row < height; row++) - for (col=0; col < width; col++) - BAYER(row,col) = t_curve[pixel[row+2][col+2]]; - maximum = 0x3ff; -} - -const int * CLASS make_decoder_int (const int *source, int level) -{ - struct decode *cur; - - cur = free_decode++; - if (level < source[0]) { - cur->branch[0] = free_decode; - source = make_decoder_int (source, level+1); - cur->branch[1] = free_decode; - source = make_decoder_int (source, level+1); - } else { - cur->leaf = source[1]; - source += 2; - } - return source; -} - -int CLASS radc_token (int tree) -{ - int t; -#ifndef LIBRAW_NOTHREADS -#define dstart tls->radc_token.dstart -#define dindex tls->radc_token.dindex -#define s tls->radc_token.s - - static const int source[] = { -#else - static struct decode *dstart[18], *dindex; - static const int *s, source[] = { -#endif - 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, - 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, - 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, - 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, - 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, - 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, - 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, - 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, - 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, - 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, - 1,0, 2,2, 2,-2, - 1,-3, 1,3, - 2,-17, 2,-5, 2,5, 2,17, - 2,-7, 2,2, 2,9, 2,18, - 2,-18, 2,-9, 2,-2, 2,7, - 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, - 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, - 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 - }; - - if (free_decode == first_decode) - for (s=source, t=0; t < 18; t++) { - dstart[t] = free_decode; - s = make_decoder_int (s, 0); - } - if (tree == 18) { - if (kodak_cbpp == 243) - return (getbits(6) << 2) + 2; /* most DC50 photos */ - else - return (getbits(5) << 3) + 4; /* DC40, Fotoman Pixtura */ - } - for (dindex = dstart[tree]; dindex->branch[0]; ) - dindex = dindex->branch[getbits(1)]; - return dindex->leaf; - -#ifndef LIBRAW_NOTHREADS -#undef dstart -#undef dindex -#undef s -#endif -} - -#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) - -#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ -: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) - -void CLASS kodak_radc_load_raw() -{ - int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; - short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; - - init_decoder(); - getbits(-1); - for (i=0; i < sizeof(buf)/sizeof(short); i++) - buf[0][0][i] = 2048; - for (row=0; row < height; row+=4) { - FORC3 mul[c] = getbits(6); - FORC3 { - val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; - s = val > 65564 ? 10:12; - x = ~(-1 << (s-1)); - val <<= 12-s; - for (i=0; i < sizeof(buf[0])/sizeof(short); i++) - buf[c][0][i] = (buf[c][0][i] * val + x) >> s; - last[c] = mul[c]; - for (r=0; r <= !c; r++) { - buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; - for (tree=1, col=width/2; col > 0; ) { - if ((tree = radc_token(tree))) { - col -= 2; - if (tree == 8) - FORYX buf[c][y][x] = radc_token(tree+10) * mul[c]; - else - FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; - } else - do { - nreps = (col > 2) ? radc_token(9) + 1 : 1; - for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { - col -= 2; - FORYX buf[c][y][x] = PREDICTOR; - if (rep & 1) { - step = radc_token(10) << 4; - FORYX buf[c][y][x] += step; - } - } - } while (nreps == 9); - } - for (y=0; y < 2; y++) - for (x=0; x < width/2; x++) { - val = (buf[c][y+1][x] << 4) / mul[c]; - if (val < 0) val = 0; - if (c) BAYER(row+y*2+c-1,x*2+2-c) = val; - else BAYER(row+r*2+y,x*2+y) = val; - } - memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); - } - } - for (y=row; y < row+4; y++) - for (x=0; x < width; x++) - if ((x+y) & 1) { - r = x ? x-1 : x+1; - s = x+1 < width ? x+1 : x-1; - val = (BAYER(y,x)-2048)*2 + (BAYER(y,r)+BAYER(y,s))/2; - if (val < 0) val = 0; - BAYER(y,x) = val; - } - } - maximum = 0xfff; - use_gamma = 0; -} - -#undef FORYX -#undef PREDICTOR - -#ifdef NO_JPEG -void CLASS kodak_jpeg_load_raw() {} -#else - -METHODDEF(boolean) -fill_input_buffer (j_decompress_ptr cinfo) -{ -#ifndef LIBRAW_NOTHREADS -#define jpeg_buffer tls->jpeg_buffer -#else - static uchar jpeg_buffer[4096]; -#endif - size_t nbytes; - - nbytes = fread (jpeg_buffer, 1, 4096, ifp); - swab (jpeg_buffer, jpeg_buffer, nbytes); - cinfo->src->next_input_byte = jpeg_buffer; - cinfo->src->bytes_in_buffer = nbytes; - return TRUE; -#ifndef LIBRAW_NOTHREADS -#undef jpeg_buffer -#endif -} - -void CLASS kodak_jpeg_load_raw() -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - JSAMPARRAY buf; - JSAMPLE (*pixel)[3]; - int row, col; - - cinfo.err = jpeg_std_error (&jerr); - jpeg_create_decompress (&cinfo); - jpeg_stdio_src (&cinfo, ifp); - cinfo.src->fill_input_buffer = fill_input_buffer; - jpeg_read_header (&cinfo, TRUE); - jpeg_start_decompress (&cinfo); - if ((cinfo.output_width != width ) || - (cinfo.output_height*2 != height ) || - (cinfo.output_components != 3 )) { -#ifdef DCRAW_VERBOSE - fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname); -#endif - jpeg_destroy_decompress (&cinfo); -#ifdef LIBRAW_LIBRARY_BUILD - throw LIBRAW_EXCEPTION_DECODE_JPEG; -#else - longjmp (failure, 3); -#endif - } - buf = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); - - while (cinfo.output_scanline < cinfo.output_height) { - row = cinfo.output_scanline * 2; - jpeg_read_scanlines (&cinfo, buf, 1); - pixel = (JSAMPLE (*)[3]) buf[0]; - for (col=0; col < width; col+=2) { - BAYER(row+0,col+0) = pixel[col+0][1] << 1; - BAYER(row+1,col+1) = pixel[col+1][1] << 1; - BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; - BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; - } - } - jpeg_finish_decompress (&cinfo); - jpeg_destroy_decompress (&cinfo); - maximum = 0xff << 1; -} -#endif - -void CLASS kodak_dc120_load_raw() -{ - static const int mul[4] = { 162, 192, 187, 92 }; - static const int add[4] = { 0, 636, 424, 212 }; - uchar pixel[848]; - int row, shift, col; - - for (row=0; row < height; row++) { - if (fread (pixel, 1, 848, ifp) < 848) derror(); - shift = row * mul[row & 3] + add[row & 3]; - for (col=0; col < width; col++) - BAYER(row,col) = (ushort) pixel[(col + shift) % 848]; - } - maximum = 0xff; -} - -void CLASS eight_bit_load_raw() -{ - uchar *pixel; - unsigned row, col, val, lblack=0; - - pixel = (uchar *) calloc (raw_width, sizeof *pixel); - merror (pixel, "eight_bit_load_raw()"); -#ifndef LIBRAW_LIBRARY_BUILD - fseek (ifp, top_margin*raw_width, SEEK_CUR); - for (row=0; row < height; row++) { - if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); - for (col=0; col < raw_width; col++) { - val = curve[pixel[col]]; - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = val; - else lblack += val; - } - } -#else - for (row=0; row < raw_height; row++) { - if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); - for (col=0; col < raw_width; col++) { - if(filtering_mode & LIBRAW_FILTERING_NORAWCURVE) - { - val = pixel[col]; - if(val>maximum) maximum = val; - } - else - val = curve[pixel[col]]; - if((unsigned) (row-top_margin)< height) - { - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = val; - else - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = val; - lblack += val; - } - } - else // top/bottom margins - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = val; - } - } - } -#endif - - free (pixel); - if (raw_width > width+1) - black = lblack / ((raw_width - width) * height); - if (!strncmp(model,"DC2",3)) - black = 0; -#ifdef LIBRAW_LIBRARY_BUILD - if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)) -#endif - maximum = curve[0xff]; -} - -void CLASS kodak_yrgb_load_raw() -{ - uchar *pixel; - int row, col, y, cb, cr, rgb[3], c; - - pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); - merror (pixel, "kodak_yrgb_load_raw()"); - for (row=0; row < height; row++) { - if (~row & 1) - if (fread (pixel, raw_width, 3, ifp) < 3) derror(); - for (col=0; col < raw_width; col++) { - y = pixel[width*2*(row & 1) + col]; - cb = pixel[width + (col & -2)] - 128; - cr = pixel[width + (col & -2)+1] - 128; - rgb[1] = y-((cb + cr + 2) >> 2); - rgb[2] = rgb[1] + cb; - rgb[0] = rgb[1] + cr; - FORC3 image[row*width+col][c] = LIM(rgb[c],0,255); - } - } - free (pixel); - use_gamma = 0; -} - -void CLASS kodak_262_load_raw() -{ - static const uchar kodak_tree[2][26] = - { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, - { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; - struct decode *decode[2]; - uchar *pixel; - int *strip, ns, i, row, col, chess, pi=0, pi1, pi2, pred, val; - - init_decoder(); - for (i=0; i < 2; i++) { - decode[i] = free_decode; - make_decoder (kodak_tree[i], 0); - } - ns = (raw_height+63) >> 5; - pixel = (uchar *) malloc (raw_width*32 + ns*4); - merror (pixel, "kodak_262_load_raw()"); - strip = (int *) (pixel + raw_width*32); - order = 0x4d4d; - for (i=0; i < ns; i++) - strip[i] = get4(); - for (row=0; row < raw_height; row++) { - if ((row & 31) == 0) { - fseek (ifp, strip[row >> 5], SEEK_SET); - getbits(-1); - pi = 0; - } - for (col=0; col < raw_width; col++) { - chess = (row + col) & 1; - pi1 = chess ? pi-2 : pi-raw_width-1; - pi2 = chess ? pi-2*raw_width : pi-raw_width+1; - if (col <= chess) pi1 = -1; - if (pi1 < 0) pi1 = pi2; - if (pi2 < 0) pi2 = pi1; - if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; - pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; - pixel[pi] = val = pred + ljpeg_diff (decode[chess]); - if (val >> 8) derror(); -#ifdef LIBRAW_LIBRARY_BUILD - if(filtering_mode & LIBRAW_FILTERING_NORAWCURVE) - val = pixel[pi++]; - else - val = curve[pixel[pi++]]; -#else - val = curve[pixel[pi++]]; -#endif - if ((unsigned) (col-left_margin) < width) - BAYER(row,col-left_margin) = val; - else -#ifndef LIBRAW_LIBRARY_BUILD - black += val; -#else - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = val; - black += val; - } -#endif - } - } - free (pixel); - if (raw_width > width) - black /= (raw_width - width) * height; -} - -int CLASS kodak_65000_decode (short *out, int bsize) -{ - uchar c, blen[768]; - ushort raw[6]; - INT64 bitbuf=0; - int save, bits=0, i, j, len, diff; - - save = ftell(ifp); - bsize = (bsize + 3) & -4; - for (i=0; i < bsize; i+=2) { - c = fgetc(ifp); - if ((blen[i ] = c & 15) > 12 || - (blen[i+1] = c >> 4) > 12 ) { - fseek (ifp, save, SEEK_SET); - for (i=0; i < bsize; i+=8) { - read_shorts (raw, 6); - out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; - out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; - for (j=0; j < 6; j++) - out[i+2+j] = raw[j] & 0xfff; - } - return 1; - } - } - if ((bsize & 7) == 4) { - bitbuf = fgetc(ifp) << 8; - bitbuf += fgetc(ifp); - bits = 16; - } - for (i=0; i < bsize; i++) { - len = blen[i]; - if (bits < len) { - for (j=0; j < 32; j+=8) - bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); - bits += 32; - } - diff = bitbuf & (0xffff >> (16-len)); - bitbuf >>= len; - bits -= len; - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - out[i] = diff; - } - return 0; -} - -void CLASS kodak_65000_load_raw() -{ - short buf[256]; - int row, col, len, pred[2], ret, i; - - for (row=0; row < height; row++) - for (col=0; col < width; col+=256) { - pred[0] = pred[1] = 0; - len = MIN (256, width-col); - ret = kodak_65000_decode (buf, len); - for (i=0; i < len; i++) -#ifndef LIBRAW_LIBRARY_BUILD - if ((BAYER(row,col+i) = curve[ret ? buf[i] : - (pred[i & 1] += buf[i])]) >> 12) derror(); -#else - { - ushort val = ret ? buf[i] : (pred[i & 1] += buf[i]); - if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)) - val = curve[val]; - BAYER(row,col+i)=val; - if(curve[val]>>12) derror(); - } -#endif - } -} + Copyright 2008-2020 LibRaw LLC (info@libraw.org) -void CLASS kodak_ycbcr_load_raw() -{ - short buf[384], *bp; - int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; - ushort *ip; + * This file is provided for compatibility w/ old build scripts/tools: + * It includes multiple separate files that should be built separately + * if new build tools are used - for (row=0; row < height; row+=2) - for (col=0; col < width; col+=128) { - len = MIN (128, width-col); - kodak_65000_decode (buf, len*3); - y[0][1] = y[1][1] = cb = cr = 0; - for (bp=buf, i=0; i < len; i+=2, bp+=2) { - cb += bp[4]; - cr += bp[5]; - rgb[1] = -((cb + cr + 2) >> 2); - rgb[2] = rgb[1] + cb; - rgb[0] = rgb[1] + cr; - for (j=0; j < 2; j++) - for (k=0; k < 2; k++) { - if ((y[j][k] = y[j][k^1] + *bp++) >> 10) derror(); - ip = image[(row+j)*width + col+i+k]; -#ifndef LIBRAW_LIBRARY_BUILD - FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; -#else - if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)) - FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; - else - FORC3 ip[c] = y[j][k]+rgb[c];; -#endif - } - } - } -} + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: -void CLASS kodak_rgb_load_raw() -{ - short buf[768], *bp; - int row, col, len, c, i, rgb[3]; - ushort *ip=image[0]; +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). - for (row=0; row < height; row++) - for (col=0; col < width; col+=256) { - len = MIN (256, width-col); - kodak_65000_decode (buf, len*3); - memset (rgb, 0, sizeof rgb); - for (bp=buf, i=0; i < len; i++, ip+=4) - FORC3 if ((ip[c] = rgb[c] += *bp++) >> 12) derror(); - } -} +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). -void CLASS kodak_thumb_load_raw() -{ - int row, col; - colors = thumb_misc >> 5; - for (row=0; row < height; row++) - for (col=0; col < width; col++) - read_shorts (image[row*width+col], colors); - maximum = (1 << (thumb_misc & 31)) - 1; -} - -void CLASS sony_decrypt (unsigned *data, int len, int start, int key) -{ -#ifndef LIBRAW_NOTHREADS -#define pad tls->sony_decrypt.pad -#define p tls->sony_decrypt.p -#else - static unsigned pad[128], p; -#endif - - if (start) { - for (p=0; p < 4; p++) - pad[p] = key = key * 48828125 + 1; - pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; - for (p=4; p < 127; p++) - pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; - for (p=0; p < 127; p++) - pad[p] = htonl(pad[p]); - } - while (len--) - *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; -#ifndef LIBRAW_NOTHREADS -#undef pad -#undef p -#endif -} - -void CLASS sony_load_raw() -{ - uchar head[40]; - ushort *pixel; - unsigned i, key, row, col; - - fseek (ifp, 200896, SEEK_SET); - fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); - order = 0x4d4d; - key = get4(); - fseek (ifp, 164600, SEEK_SET); - fread (head, 1, 40, ifp); - sony_decrypt ((unsigned int *) head, 10, 1, key); - for (i=26; i-- > 22; ) - key = key << 8 | head[i]; - fseek (ifp, data_offset, SEEK_SET); - pixel = (ushort *) calloc (raw_width, sizeof *pixel); - merror (pixel, "sony_load_raw()"); - for (row=0; row < height; row++) { - if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); - sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key); -#ifdef LIBRAW_LIBRARY_BUILD - for (col=0; col < left_margin; col++) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = ntohs(pixel[col]); - } - for (col=left_margin+width; col < raw_width; col++) - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = ntohs(pixel[col]); - } -#endif - for (col=9; col < left_margin; col++) - black += ntohs(pixel[col]); - for (col=0; col < width; col++) - if ((BAYER(row,col) = ntohs(pixel[col+left_margin])) >> 14) - derror(); - } - free (pixel); - if (left_margin > 9) - black /= (left_margin-9) * height; - maximum = 0x3ff0; -} - -void CLASS sony_arw_load_raw() -{ - int col, row, len, diff, sum=0; - - getbits(-1); - for (col = raw_width; col--; ) - for (row=0; row < raw_height+1; row+=2) { - if (row == raw_height) row = 1; - len = 4 - getbits(2); - if (len == 3 && getbits(1)) len = 0; - if (len == 4) - while (len < 17 && !getbits(1)) len++; - diff = getbits(len); - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - if ((sum += diff) >> 12) derror(); - if (row < height) BAYER(row,col) = sum; -#ifdef LIBRAW_LIBRARY_BUILD - else - { - ushort *dfp = get_masked_pointer(row,col); - if(dfp) *dfp = sum; - } -#endif - } -} - -void CLASS sony_arw2_load_raw() -{ - uchar *data, *dp; - ushort pix[16]; - int row, col, val, max, min, imax, imin, sh, bit, i; - - data = (uchar *) malloc (raw_width*tiff_bps >> 3); - merror (data, "sony_arw2_load_raw()"); - for (row=0; row < height; row++) { - fread (data, 1, raw_width*tiff_bps >> 3, ifp); - if (tiff_bps == 8) { - for (dp=data, col=0; col < width-30; dp+=16) { - max = 0x7ff & (val = sget4(dp)); - min = 0x7ff & val >> 11; - imax = 0x0f & val >> 22; - imin = 0x0f & val >> 26; - for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); - for (bit=30, i=0; i < 16; i++) - if (i == imax) pix[i] = max; - else if (i == imin) pix[i] = min; - else { - pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; - if (pix[i] > 0x7ff) pix[i] = 0x7ff; - bit += 7; - } - for (i=0; i < 16; i++, col+=2) -#ifndef LIBRAW_LIBRARY_BUILD - BAYER(row,col) = curve[pix[i] << 1] >> 1; -#else - { - ushort val = pix[i]; - if(!(filtering_mode & LIBRAW_FILTERING_NORAWCURVE)) - val = curve[val<<1]>>1; - BAYER(row,col)=val; - } -#endif - col -= col & 1 ? 1:31; - } - } else if (tiff_bps == 12) - for (dp=data, col=0; col < width; dp+=3, col+=2) { - BAYER(row,col) = ((dp[1] << 8 | dp[0]) & 0xfff) << 1; - BAYER(row,col+1) = (dp[2] << 4 | dp[1] >> 4) << 1; - } - } - free (data); -} - -#define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) - -/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ -void CLASS smal_decode_segment (unsigned seg[2][2], int holes) -{ - uchar hist[3][13] = { - { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, - { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, - { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; - int low, high=0xff, carry=0, nbits=8; - int s, count, bin, next, i, sym[3]; - uchar diff, pred[]={0,0}; - ushort data=0, range=0; - unsigned pix, row, col; - - fseek (ifp, seg[0][1]+1, SEEK_SET); - getbits(-1); - for (pix=seg[0][0]; pix < seg[1][0]; pix++) { - for (s=0; s < 3; s++) { - data = data << nbits | getbits(nbits); - if (carry < 0) - carry = (nbits += carry+1) < 1 ? nbits-1 : 0; - while (--nbits >= 0) - if ((data >> nbits & 0xff) == 0xff) break; - if (nbits > 0) - data = ((data & ((1 << (nbits-1)) - 1)) << 1) | - ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits)); - if (nbits >= 0) { - data += getbits(1); - carry = nbits - 8; - } - count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); - for (bin=0; hist[s][bin+5] > count; bin++); - low = hist[s][bin+5] * (high >> 4) >> 2; - if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; - high -= low; - for (nbits=0; high << nbits < 128; nbits++); - range = (range+low) << nbits; - high <<= nbits; - next = hist[s][1]; - if (++hist[s][2] > hist[s][3]) { - next = (next+1) & hist[s][0]; - hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; - hist[s][2] = 1; - } - if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { - if (bin < hist[s][1]) - for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; - else if (next <= bin) - for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; - } - hist[s][1] = next; - sym[s] = bin; - } - diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); - if (sym[0] & 4) - diff = diff ? -diff : 0x80; - if (ftell(ifp) + 12 >= seg[1][1]) - diff = 0; - pred[pix & 1] += diff; - row = pix / raw_width - top_margin; - col = pix % raw_width - left_margin; - if (row < height && col < width) - BAYER(row,col) = pred[pix & 1]; -#ifdef LIBRAW_LIBRARY_BUILD - else - { - ushort *dfp = get_masked_pointer(row+top_margin,col+left_margin); - if(dfp) *dfp = pred[pix &1]; - } -#endif - if (!(pix & 1) && HOLE(row)) pix += 2; - } - maximum = 0xff; -} - -void CLASS smal_v6_load_raw() -{ - unsigned seg[2][2]; - - fseek (ifp, 16, SEEK_SET); - seg[0][0] = 0; - seg[0][1] = get2(); - seg[1][0] = raw_width * raw_height; - seg[1][1] = INT_MAX; - smal_decode_segment (seg, 0); - use_gamma = 0; -} - -int CLASS median4 (int *p) -{ - int min, max, sum, i; - - min = max = sum = p[0]; - for (i=1; i < 4; i++) { - sum += p[i]; - if (min > p[i]) min = p[i]; - if (max < p[i]) max = p[i]; - } - return (sum - min - max) >> 1; -} - -void CLASS fill_holes (int holes) -{ - int row, col, val[4]; - - for (row=2; row < height-2; row++) { - if (!HOLE(row)) continue; - for (col=1; col < width-1; col+=4) { - val[0] = BAYER(row-1,col-1); - val[1] = BAYER(row-1,col+1); - val[2] = BAYER(row+1,col-1); - val[3] = BAYER(row+1,col+1); - BAYER(row,col) = median4(val); - } - for (col=2; col < width-2; col+=4) - if (HOLE(row-2) || HOLE(row+2)) - BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1; - else { - val[0] = BAYER(row,col-2); - val[1] = BAYER(row,col+2); - val[2] = BAYER(row-2,col); - val[3] = BAYER(row+2,col); - BAYER(row,col) = median4(val); - } - } -} - -void CLASS smal_v9_load_raw() -{ - unsigned seg[256][2], offset, nseg, holes, i; - - fseek (ifp, 67, SEEK_SET); - offset = get4(); - nseg = fgetc(ifp); - fseek (ifp, offset, SEEK_SET); - for (i=0; i < nseg*2; i++) - seg[0][i] = get4() + data_offset*(i & 1); - fseek (ifp, 78, SEEK_SET); - holes = fgetc(ifp); - fseek (ifp, 88, SEEK_SET); - seg[nseg][0] = raw_height * raw_width; - seg[nseg][1] = get4() + data_offset; - for (i=0; i < nseg; i++) - smal_decode_segment (seg+i, holes); - if (holes) fill_holes (holes); -} - -void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) -{ - double work[3][6], num; - int i, j, k; - - for (i=0; i < 3; i++) { - for (j=0; j < 6; j++) - work[i][j] = j == i+3; - for (j=0; j < 3; j++) - for (k=0; k < size; k++) - work[i][j] += in[k][i] * in[k][j]; - } - for (i=0; i < 3; i++) { - num = work[i][i]; - for (j=0; j < 6; j++) - work[i][j] /= num; - for (k=0; k < 3; k++) { - if (k==i) continue; - num = work[k][i]; - for (j=0; j < 6; j++) - work[k][j] -= work[i][j] * num; - } - } - for (i=0; i < size; i++) - for (j=0; j < 3; j++) - for (out[i][j]=k=0; k < 3; k++) - out[i][j] += work[j][k+3] * in[i][k]; -} - -void CLASS cam_xyz_coeff (double cam_xyz[4][3]) -{ - double cam_rgb[4][3], inverse[4][3], num; - int i, j, k; - - for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ - for (j=0; j < 3; j++) - for (cam_rgb[i][j] = k=0; k < 3; k++) - cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; - - for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ - for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ - num += cam_rgb[i][j]; - for (j=0; j < 3; j++) - cam_rgb[i][j] /= num; - pre_mul[i] = 1 / num; - } - pseudoinverse (cam_rgb, inverse, colors); - for (raw_color = i=0; i < 3; i++) - for (j=0; j < colors; j++) - rgb_cam[i][j] = inverse[j][i]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; - color_flags.rgb_cam_state = LIBRAW_COLORSTATE_CONST; -#endif -} - -#ifdef COLORCHECK -void CLASS colorcheck() -{ -#define NSQ 24 -// Coordinates of the GretagMacbeth ColorChecker squares -// width, height, 1st_column, 1st_row - static const int cut[NSQ][4] = { - { 241, 231, 234, 274 }, - { 251, 235, 534, 274 }, - { 255, 239, 838, 272 }, - { 255, 240, 1146, 274 }, - { 251, 237, 1452, 278 }, - { 243, 238, 1758, 288 }, - { 253, 253, 218, 558 }, - { 255, 249, 524, 562 }, - { 261, 253, 830, 562 }, - { 260, 255, 1144, 564 }, - { 261, 255, 1450, 566 }, - { 247, 247, 1764, 576 }, - { 255, 251, 212, 862 }, - { 259, 259, 518, 862 }, - { 263, 261, 826, 864 }, - { 265, 263, 1138, 866 }, - { 265, 257, 1450, 872 }, - { 257, 255, 1762, 874 }, - { 257, 253, 212, 1164 }, - { 262, 251, 516, 1172 }, - { 263, 257, 826, 1172 }, - { 263, 255, 1136, 1176 }, - { 255, 252, 1452, 1182 }, - { 257, 253, 1760, 1180 } }; -// ColorChecker Chart under 6500-kelvin illumination - static const double gmb_xyY[NSQ][3] = { - { 0.400, 0.350, 10.1 }, // Dark Skin - { 0.377, 0.345, 35.8 }, // Light Skin - { 0.247, 0.251, 19.3 }, // Blue Sky - { 0.337, 0.422, 13.3 }, // Foliage - { 0.265, 0.240, 24.3 }, // Blue Flower - { 0.261, 0.343, 43.1 }, // Bluish Green - { 0.506, 0.407, 30.1 }, // Orange - { 0.211, 0.175, 12.0 }, // Purplish Blue - { 0.453, 0.306, 19.8 }, // Moderate Red - { 0.285, 0.202, 6.6 }, // Purple - { 0.380, 0.489, 44.3 }, // Yellow Green - { 0.473, 0.438, 43.1 }, // Orange Yellow - { 0.187, 0.129, 6.1 }, // Blue - { 0.305, 0.478, 23.4 }, // Green - { 0.539, 0.313, 12.0 }, // Red - { 0.448, 0.470, 59.1 }, // Yellow - { 0.364, 0.233, 19.8 }, // Magenta - { 0.196, 0.252, 19.8 }, // Cyan - { 0.310, 0.316, 90.0 }, // White - { 0.310, 0.316, 59.1 }, // Neutral 8 - { 0.310, 0.316, 36.2 }, // Neutral 6.5 - { 0.310, 0.316, 19.8 }, // Neutral 5 - { 0.310, 0.316, 9.0 }, // Neutral 3.5 - { 0.310, 0.316, 3.1 } }; // Black - double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; - double inverse[NSQ][3], cam_xyz[4][3], num; - int c, i, j, k, sq, row, col, count[4]; - - memset (gmb_cam, 0, sizeof gmb_cam); - for (sq=0; sq < NSQ; sq++) { - FORCC count[c] = 0; - for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) - for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { - c = FC(row,col); - if (c >= colors) c -= 2; - gmb_cam[sq][c] += BAYER(row,col); - count[c]++; - } - FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; - gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1]; - gmb_xyz[sq][1] = gmb_xyY[sq][2]; - gmb_xyz[sq][2] = gmb_xyY[sq][2] * - (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; - } - pseudoinverse (gmb_xyz, inverse, NSQ); - for (i=0; i < colors; i++) - for (j=0; j < 3; j++) - for (cam_xyz[i][j] = k=0; k < NSQ; k++) - cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; - cam_xyz_coeff (cam_xyz); -#ifdef DCRAW_VERBOSE - if (verbose) { - printf (" { \"%s %s\", %d,\n\t{", make, model, black); - num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); - FORCC for (j=0; j < 3; j++) - printf ("%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5)); - puts (" } },"); - } -#endif -#undef NSQ -} -#endif - -void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) -{ - int i; - for (i=0; i < sc; i++) - temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; - for (; i+sc < size; i++) - temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; - for (; i < size; i++) - temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; -} - -#ifndef _OPENMP -void CLASS wavelet_denoise() -{ - float *fimg=0, *temp, thold, mul[2], avg, diff; - int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast; - ushort *window[4]; - static const float noise[] = - { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; - -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); -#endif - - while (maximum << scale < 0x10000) scale++; - maximum <<= --scale; - black <<= scale; - if ((size = iheight*iwidth) < 0x15550000) - fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); - merror (fimg, "wavelet_denoise()"); - temp = fimg + size*3; - if ((nc = colors) == 3 && filters) nc++; - FORC(nc) { /* denoise R,G1,B,G3 individually */ - for (i=0; i < size; i++) - fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); - for (hpass=lev=0; lev < 5; lev++) { - lpass = size*((lev & 1)+1); - for (row=0; row < iheight; row++) { - hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); - for (col=0; col < iwidth; col++) - fimg[lpass + row*iwidth + col] = temp[col] * 0.25; - } - for (col=0; col < iwidth; col++) { - hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); - for (row=0; row < iheight; row++) - fimg[lpass + row*iwidth + col] = temp[row] * 0.25; - } - thold = threshold * noise[lev]; - for (i=0; i < size; i++) { - fimg[hpass+i] -= fimg[lpass+i]; - if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; - else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; - else fimg[hpass+i] = 0; - if (hpass) fimg[i] += fimg[hpass+i]; - } - hpass = lpass; - } - for (i=0; i < size; i++) - image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); - } - if (filters && colors == 3) { /* pull G1 and G3 closer together */ - for (row=0; row < 2; row++) - mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; - for (i=0; i < 4; i++) - window[i] = (ushort *) fimg + width*i; - for (wlast=-1, row=1; row < height-1; row++) { - while (wlast < row+1) { - for (wlast++, i=0; i < 4; i++) - window[(i+3) & 3] = window[i]; - for (col = FC(wlast,1) & 1; col < width; col+=2) - window[2][col] = BAYER(wlast,col); - } - thold = threshold/512; - for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { - avg = ( window[0][col-1] + window[0][col+1] + - window[2][col-1] + window[2][col+1] - black*4 ) - * mul[row & 1] + (window[1][col] - black) * 0.5 + black; - avg = avg < 0 ? 0 : sqrt(avg); - diff = sqrt((double)(BAYER(row,col))) - avg; - if (diff < -thold) diff += thold; - else if (diff > thold) diff -= thold; - else diff = 0; - BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); - } - } - } - free (fimg); -} -#else -void CLASS wavelet_denoise() -{ - float *fimg=0, *temp, thold, mul[2], avg, diff; - int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast; - ushort *window[4]; - static const float noise[] = - { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; - -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); -#endif - - while (maximum << scale < 0x10000) scale++; - maximum <<= --scale; - black <<= scale; - if ((size = iheight*iwidth) < 0x15550000) - fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); - merror (fimg, "wavelet_denoise()"); - temp = fimg + size*3; - if ((nc = colors) == 3 && filters) nc++; -#ifdef LIBRAW_LIBRARY_BUILD -#pragma omp parallel default(shared) private(i,col,row,thold,lev,lpass,hpass,temp) firstprivate(c,scale,size) -#endif - { - temp = (float*)malloc( (iheight + iwidth) * sizeof *fimg); - FORC(nc) { /* denoise R,G1,B,G3 individually */ -#ifdef LIBRAW_LIBRARY_BUILD -#pragma omp for -#endif - for (i=0; i < size; i++) - fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); - for (hpass=lev=0; lev < 5; lev++) { - lpass = size*((lev & 1)+1); -#ifdef LIBRAW_LIBRARY_BUILD -#pragma omp for -#endif - for (row=0; row < iheight; row++) { - hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); - for (col=0; col < iwidth; col++) - fimg[lpass + row*iwidth + col] = temp[col] * 0.25; - } -#ifdef LIBRAW_LIBRARY_BUILD -#pragma omp for -#endif - for (col=0; col < iwidth; col++) { - hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); - for (row=0; row < iheight; row++) - fimg[lpass + row*iwidth + col] = temp[row] * 0.25; - } - thold = threshold * noise[lev]; -#ifdef LIBRAW_LIBRARY_BUILD -#pragma omp for -#endif - for (i=0; i < size; i++) { - fimg[hpass+i] -= fimg[lpass+i]; - if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; - else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; - else fimg[hpass+i] = 0; - if (hpass) fimg[i] += fimg[hpass+i]; - } - hpass = lpass; - } -#ifdef LIBRAW_LIBRARY_BUILD -#pragma omp for -#endif - for (i=0; i < size; i++) - image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); - } - free(temp); - } /* end omp parallel */ -/* the following loops are hard to parallize, no idea yes, - * problem is wlast which is carrying dependency - * second part should be easyer, but did not yet get it right. - */ - if (filters && colors == 3) { /* pull G1 and G3 closer together */ - for (row=0; row < 2; row++) - mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; - for (i=0; i < 4; i++) - window[i] = (ushort *) fimg + width*i; - for (wlast=-1, row=1; row < height-1; row++) { - while (wlast < row+1) { - for (wlast++, i=0; i < 4; i++) - window[(i+3) & 3] = window[i]; - for (col = FC(wlast,1) & 1; col < width; col+=2) - window[2][col] = BAYER(wlast,col); - } - thold = threshold/512; - for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { - avg = ( window[0][col-1] + window[0][col+1] + - window[2][col-1] + window[2][col+1] - black*4 ) - * mul[row & 1] + (window[1][col] - black) * 0.5 + black; - avg = avg < 0 ? 0 : sqrt(avg); - diff = sqrt(BAYER(row,col)) - avg; - if (diff < -thold) diff += thold; - else if (diff > thold) diff -= thold; - else diff = 0; - BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); - } - } - } - free (fimg); -} - -#endif - -void CLASS scale_colors() -{ - unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; - int val, dark, sat; - double dsum[8], dmin, dmax; - float scale_mul[4], fr, fc; - ushort *img=0, *pix; - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,0,2); -#endif - - if (user_mul[0]) - memcpy (pre_mul, user_mul, sizeof pre_mul); - if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) { - memset (dsum, 0, sizeof dsum); - bottom = MIN (greybox[1]+greybox[3], height); - right = MIN (greybox[0]+greybox[2], width); - for (row=greybox[1]; row < bottom; row += 8) - for (col=greybox[0]; col < right; col += 8) { - memset (sum, 0, sizeof sum); - for (y=row; y < row+8 && y < bottom; y++) - for (x=col; x < col+8 && x < right; x++) - FORC4 { - if (filters) { - c = FC(y,x); - val = BAYER(y,x); - } else - val = image[y*width+x][c]; - if (val > maximum-25) goto skip_block; - if ((val -= black) < 0) val = 0; - sum[c] += val; - sum[c+4]++; - if (filters) break; - } - FORC(8) dsum[c] += sum[c]; -skip_block: ; - } - FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CALCULATED; -#endif - } - if (use_camera_wb && cam_mul[0] != -1) { - memset (sum, 0, sizeof sum); - for (row=0; row < 8; row++) - for (col=0; col < 8; col++) { - c = FC(row,col); - if ((val = white[row][col] - black) > 0) - sum[c] += val; - sum[c+4]++; - } - if (sum[0] && sum[1] && sum[2] && sum[3]) - { - FORC4 pre_mul[c] = (float) sum[c+4] / sum[c]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CALCULATED; -#endif - } - else if (cam_mul[0] && cam_mul[2]) - { - memcpy (pre_mul, cam_mul, sizeof pre_mul); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state =color_flags.pre_mul_state; -#endif - } - else - { -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB; -#endif -#ifdef DCRAW_VERBOSE - fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname); -#endif - } - } - if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; - dark = black; - sat = maximum; - if (threshold) wavelet_denoise(); - maximum -= black; - for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { - if (dmin > pre_mul[c]) - dmin = pre_mul[c]; - if (dmax < pre_mul[c]) - dmax = pre_mul[c]; - } - if (!highlight) dmax = dmin; - FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; -#ifdef DCRAW_VERBOSE - if (verbose) { - fprintf (stderr, - _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat); - FORC4 fprintf (stderr, " %f", pre_mul[c]); - fputc ('\n', stderr); - } -#endif - size = iheight*iwidth; - for (i=0; i < size*4; i++) { - val = image[0][i]; - if (!val) continue; - val -= black; - val *= scale_mul[i & 3]; - image[0][i] = CLIP(val); - } - if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { -#ifdef DCRAW_VERBOSE - if (verbose) - fprintf (stderr,_("Correcting chromatic aberration...\n")); -#endif - for (c=0; c < 4; c+=2) { - if (aber[c] == 1) continue; - img = (ushort *) malloc (size * sizeof *img); - merror (img, "scale_colors()"); - for (i=0; i < size; i++) - img[i] = image[i][c]; - for (row=0; row < iheight; row++) { - ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5; - if (ur > iheight-2) continue; - fr -= ur; - for (col=0; col < iwidth; col++) { - uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5; - if (uc > iwidth-2) continue; - fc -= uc; - pix = img + ur*iwidth + uc; - image[row*iwidth+col][c] = - (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) + - (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr; - } - } - free(img); - } - } -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,1,2); -#endif -} - -void CLASS pre_interpolate() -{ - ushort (*img)[4]; - int row, col, c; - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,0,2); -#endif - if (shrink) { - if (half_size) { - height = iheight; - width = iwidth; - } else { - img = (ushort (*)[4]) calloc (height*width, sizeof *img); - merror (img, "pre_interpolate()"); - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - c = fc(row,col); - img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; - } - free (image); - image = img; - shrink = 0; - } - } - if (filters && colors == 3) { - if ((mix_green = four_color_rgb)) colors++; - else { - for (row = FC(1,0) >> 1; row < height; row+=2) - for (col = FC(row,1) & 1; col < width; col+=2) - image[row*width+col][1] = image[row*width+col][3]; - filters &= ~((filters & 0x55555555) << 1); - } - } - if (half_size) filters = 0; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,1,2); -#endif -} - -void CLASS border_interpolate (int border) -{ - unsigned row, col, y, x, f, c, sum[8]; - - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - if (col==border && row >= border && row < height-border) - col = width-border; - memset (sum, 0, sizeof sum); - for (y=row-1; y != row+2; y++) - for (x=col-1; x != col+2; x++) - if (y < height && x < width) { - f = fc(y,x); - sum[f] += image[y*width+x][f]; - sum[f+4]++; - } - f = fc(row,col); - FORCC if (c != f && sum[c+4]) - image[row*width+col][c] = sum[c] / sum[c+4]; - } -} - -void CLASS lin_interpolate() -{ - int code[16][16][32], *ip, sum[4]; - int c, i, x, y, row, col, shift, color; - ushort *pix; - -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); -#endif - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3); -#endif - border_interpolate(1); - for (row=0; row < 16; row++) - for (col=0; col < 16; col++) { - ip = code[row][col]; - memset (sum, 0, sizeof sum); - for (y=-1; y <= 1; y++) - for (x=-1; x <= 1; x++) { - shift = (y==0) + (x==0); - if (shift == 2) continue; - color = fc(row+y,col+x); - *ip++ = (width*y + x)*4 + color; - *ip++ = shift; - *ip++ = color; - sum[color] += 1 << shift; - } - FORCC - if (c != fc(row,col)) { - *ip++ = c; - *ip++ = 256 / sum[c]; - } - } -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3); -#endif - for (row=1; row < height-1; row++) - for (col=1; col < width-1; col++) { - pix = image[row*width+col]; - ip = code[row & 15][col & 15]; - memset (sum, 0, sizeof sum); - for (i=8; i--; ip+=3) - sum[ip[2]] += pix[ip[0]] << ip[1]; - for (i=colors; --i; ip+=2) - pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; - } -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3); -#endif -} - -/* - This algorithm is officially called: - - "Interpolation using a Threshold-based variable number of gradients" - - described in http://scien.stanford.edu/class/psych221/projects/99/tingchen/algodep/vargra.html - - I've extended the basic idea to work with non-Bayer filter arrays. - Gradients are numbered clockwise from NW=0 to W=7. - */ -void CLASS vng_interpolate() -{ - struct interpolate_terms { - signed char y1, x1, y2, x2, weight; - unsigned char grads; - }; - static const interpolate_terms 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} - }; - const interpolate_terms *cpt; - signed char *cp; - signed char chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; - ushort (*brow[5])[4], *pix; - int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; - int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; - int g, diff, thold, num, c; - lin_interpolate(); -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("VNG interpolation...\n")); -#endif - - if (filters == 1) prow = pcol = 15; - ip = (int *) calloc ((prow+1)*(pcol+1), 1280); - merror (ip, "vng_interpolate()"); - for (row=0; row <= prow; row++) /* Precalculate for VNG */ - for (col=0; col <= pcol; col++) { - code[row][col] = ip; - for (cpt=&terms[0], t=0; t < 64, cpt = &terms[t]; t++) { - y1 = cpt->y1; x1 = cpt->x1; - y2 = cpt->y2; x2 = cpt->x2; - weight = cpt->weight; - grads = cpt->grads; - color = fc(row+y1,col+x1); - if (fc(row+y2,col+x2) != color) continue; - diag = (fc(row,col+1) == color && fc(row+1,col) == color) ? 2:1; - if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; - *ip++ = (y1*width + x1)*4 + color; - *ip++ = (y2*width + x2)*4 + color; - *ip++ = weight; - for (g=0; g < 8; g++) - if (grads & 1<<g) *ip++ = g; - *ip++ = -1; - } - *ip++ = INT_MAX; - for (cp=chood, g=0; g < 8; g++) { - y = *cp++; x = *cp++; - *ip++ = (y*width + x) * 4; - color = fc(row,col); - if (fc(row+y,col+x) != color && fc(row+y*2,col+x*2) == color) - *ip++ = (y*width + x) * 8 + color; - else - *ip++ = 0; - } - } - brow[4] = (ushort (*)[4]) calloc (width*3, sizeof **brow); - merror (brow[4], "vng_interpolate()"); - for (row=0; row < 3; row++) - brow[row] = brow[4] + row*width; - for (row=2; row < height-2; row++) { /* Do VNG interpolation */ -#ifdef LIBRAW_LIBRARY_BUILD - if(!((row-2)%256))RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,(row-2)/256+1,((height-3)/256)+1); -#endif - for (col=2; col < width-2; col++) { - pix = image[row*width+col]; - ip = code[row & prow][col & pcol]; - memset (gval, 0, sizeof gval); - while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */ - diff = ABS(pix[g] - pix[ip[1]]) << ip[2]; - gval[ip[3]] += diff; - ip += 5; - if ((g = ip[-1]) == -1) continue; - gval[g] += diff; - while ((g = *ip++) != -1) - gval[g] += diff; - } - ip++; - gmin = gmax = gval[0]; /* Choose a threshold */ - for (g=1; g < 8; g++) { - if (gmin > gval[g]) gmin = gval[g]; - if (gmax < gval[g]) gmax = gval[g]; - } - if (gmax == 0) { - memcpy (brow[2][col], pix, sizeof *image); - continue; - } - thold = gmin + (gmax >> 1); - memset (sum, 0, sizeof sum); - color = fc(row,col); - for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ - if (gval[g] <= thold) { - FORCC - if (c == color && ip[1]) - sum[c] += (pix[c] + pix[ip[1]]) >> 1; - else - sum[c] += pix[ip[0] + c]; - num++; - } - } - FORCC { /* Save to buffer */ - t = pix[color]; - if (c != color) - t += (sum[c] - sum[color]) / num; - brow[2][col][c] = CLIP(t); - } - } - if (row > 3) /* Write buffer to image */ - memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); - for (g=0; g < 4; g++) - brow[(g-1) & 3] = brow[g]; - } - memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); - memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); - free (brow[4]); - free (code[0][0]); -} - -/* - Patterned Pixel Grouping Interpolation by Alain Desbiolles */ -void CLASS ppg_interpolate() -{ - int dir[5] = { 1, width, -1, -width, 1 }; - int row, col, diff[2], guess[2], c, d, i; - ushort (*pix)[4]; - - border_interpolate(3); -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("PPG interpolation...\n")); -#endif - -/* Fill in the green layer with gradients and pattern recognition: */ -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3); -#endif - for (row=3; row < height-3; row++) - for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) { - pix = image + row*width+col; - for (i=0; (d=dir[i]) > 0; i++) { - guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - - pix[-2*d][c] - pix[2*d][c]; - diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + - ABS(pix[ 2*d][c] - pix[ 0][c]) + - ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + - ( ABS(pix[ 3*d][1] - pix[ d][1]) + - ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; - } - d = dir[i = diff[0] > diff[1]]; - pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); - } -/* Calculate red and blue for each green pixel: */ -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3); -#endif - for (row=1; row < height-1; row++) - for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { - pix = image + row*width+col; - for (i=0; (d=dir[i]) > 0; c=2-c, i++) - pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1] - - pix[-d][1] - pix[d][1]) >> 1); - } -/* Calculate blue for red pixels and vice versa: */ -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3); -#endif - for (row=1; row < height-1; row++) - for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { - pix = image + row*width+col; - for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { - diff[i] = ABS(pix[-d][c] - pix[d][c]) + - ABS(pix[-d][1] - pix[0][1]) + - ABS(pix[ d][1] - pix[0][1]); - guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] - - pix[-d][1] - pix[d][1]; - } - if (diff[0] != diff[1]) - pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); - else - pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); - } -} - -/* - Adaptive Homogeneity-Directed interpolation is based on - the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. - */ -#define TS 256 /* Tile Size */ -#ifndef _OPENMP -void CLASS ahd_interpolate() -{ - int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; - ushort (*pix)[4], (*rix)[3]; - static const int dir[4] = { -1, 1, -TS, TS }; - unsigned ldiff[2][4], abdiff[2][4], leps, abeps; - float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; - ushort (*rgb)[TS][TS][3]; - short (*lab)[TS][TS][3], (*lix)[3]; - char (*homo)[TS][TS], *buffer; - -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("AHD interpolation...\n")); -#endif - - for (i=0; i < 0x10000; i++) { - r = i / 65535.0; - cbrt[i] = r > 0.008856 ? pow((double)r,1/3.0) : 7.787*r + 16/116.0; - } - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (xyz_cam[i][j] = k=0; k < 3; k++) - xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; - - border_interpolate(5); - buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ - merror (buffer, "ahd_interpolate()"); - rgb = (ushort(*)[TS][TS][3]) buffer; - lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); - homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); - - for (top=2; top < height-5; top += TS-6) - { - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,(top-2)/(TS-6),(height-7)/(TS-6)+1); -#endif - for (left=2; left < width-5; left += TS-6) { - -/* Interpolate green horizontally and vertically: */ - for (row = top; row < top+TS && row < height-2; row++) { - col = left + (FC(row,left) & 1); - for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { - pix = image + row*width+col; - val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - - pix[-2][c] - pix[2][c]) >> 2; - rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); - val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - - pix[-2*width][c] - pix[2*width][c]) >> 2; - rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); - } - } -/* Interpolate red and blue, and convert to CIELab: */ - for (d=0; d < 2; d++) - for (row=top+1; row < top+TS-1 && row < height-3; row++) - for (col=left+1; col < left+TS-1 && col < width-3; col++) { - pix = image + row*width+col; - rix = &rgb[d][row-top][col-left]; - lix = &lab[d][row-top][col-left]; - if ((c = 2 - FC(row,col)) == 1) { - c = FC(row+1,col); - val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] - - rix[-1][1] - rix[1][1] ) >> 1); - rix[0][2-c] = CLIP(val); - val = pix[0][1] + (( pix[-width][c] + pix[width][c] - - rix[-TS][1] - rix[TS][1] ) >> 1); - } else - val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] - + pix[+width-1][c] + pix[+width+1][c] - - rix[-TS-1][1] - rix[-TS+1][1] - - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); - rix[0][c] = CLIP(val); - c = FC(row,col); - rix[0][c] = pix[0][c]; - xyz[0] = xyz[1] = xyz[2] = 0.5; - FORCC { - xyz[0] += xyz_cam[0][c] * rix[0][c]; - xyz[1] += xyz_cam[1][c] * rix[0][c]; - xyz[2] += xyz_cam[2][c] * rix[0][c]; - } - xyz[0] = cbrt[CLIP((int) xyz[0])]; - xyz[1] = cbrt[CLIP((int) xyz[1])]; - xyz[2] = cbrt[CLIP((int) xyz[2])]; - lix[0][0] = 64 * (116 * xyz[1] - 16); - lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]); - lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]); - } -/* Build homogeneity maps from the CIELab images: */ - memset (homo, 0, 2*TS*TS); - for (row=top+2; row < top+TS-2 && row < height-4; row++) { - tr = row-top; - for (col=left+2; col < left+TS-2 && col < width-4; col++) { - tc = col-left; - for (d=0; d < 2; d++) { - lix = &lab[d][tr][tc]; - for (i=0; i < 4; i++) { - ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); - abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) - + SQR(lix[0][2]-lix[dir[i]][2]); - } - } - leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), - MAX(ldiff[1][2],ldiff[1][3])); - abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), - MAX(abdiff[1][2],abdiff[1][3])); - for (d=0; d < 2; d++) - for (i=0; i < 4; i++) - if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) - homo[d][tr][tc]++; - } - } -/* Combine the most homogenous pixels for the final result: */ - for (row=top+3; row < top+TS-3 && row < height-5; row++) { - tr = row-top; - for (col=left+3; col < left+TS-3 && col < width-5; col++) { - tc = col-left; - for (d=0; d < 2; d++) - for (hm[d]=0, i=tr-1; i <= tr+1; i++) - for (j=tc-1; j <= tc+1; j++) - hm[d] += homo[d][i][j]; - if (hm[0] != hm[1]) - FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; - else - FORC3 image[row*width+col][c] = - (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; - } - } - } - } - free (buffer); -} -#else -void CLASS ahd_interpolate() -{ - int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; - ushort (*pix)[4], (*rix)[3]; - static const int dir[4] = { -1, 1, -TS, TS }; - unsigned ldiff[2][4], abdiff[2][4], leps, abeps; - float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; - ushort (*rgb)[TS][TS][3]; - short (*lab)[TS][TS][3], (*lix)[3]; - char (*homo)[TS][TS], *buffer; - -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("AHD interpolation...\n")); -#endif - - for (i=0; i < 0x10000; i++) { - r = i / 65535.0; - cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; - } - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (xyz_cam[i][j] = k=0; k < 3; k++) - xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; - - border_interpolate(5); - -#ifdef LIBRAW_LIBRARY_BUILD -#pragma omp parallel private(buffer,rgb,lab,homo,top,left,row,c,col,pix,val,d,rix,xyz,lix,tc,tr,ldiff,abdiff,leps,abeps,hm,i,j) firstprivate(cbrt) shared(xyz_cam) -#endif - { - buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ - merror (buffer, "ahd_interpolate()"); - rgb = (ushort(*)[TS][TS][3]) buffer; - lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); - homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); - -#pragma omp for schedule(dynamic) - for (top=2; top < height-5; top += TS-6){ -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,(top-2)/(TS-6)+1,(height-7)/(TS-6)+1); -#endif - for (left=2; left < width-5; left += TS-6) { - - /* Interpolate green horizontally and vertically: */ - for (row = top; row < top+TS && row < height-2; row++) { - col = left + (FC(row,left) & 1); - for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { - pix = image + row*width+col; - val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - - pix[-2][c] - pix[2][c]) >> 2; - rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); - val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - - pix[-2*width][c] - pix[2*width][c]) >> 2; - rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); - } - } - /* Interpolate red and blue, and convert to CIELab: */ - for (d=0; d < 2; d++) - for (row=top+1; row < top+TS-1 && row < height-3; row++) - for (col=left+1; col < left+TS-1 && col < width-3; col++) { - pix = image + row*width+col; - rix = &rgb[d][row-top][col-left]; - lix = &lab[d][row-top][col-left]; - if ((c = 2 - FC(row,col)) == 1) { - c = FC(row+1,col); - val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] - - rix[-1][1] - rix[1][1] ) >> 1); - rix[0][2-c] = CLIP(val); - val = pix[0][1] + (( pix[-width][c] + pix[width][c] - - rix[-TS][1] - rix[TS][1] ) >> 1); - } else - val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] - + pix[+width-1][c] + pix[+width+1][c] - - rix[-TS-1][1] - rix[-TS+1][1] - - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); - rix[0][c] = CLIP(val); - c = FC(row,col); - rix[0][c] = pix[0][c]; - xyz[0] = xyz[1] = xyz[2] = 0.5; - FORCC { - xyz[0] += xyz_cam[0][c] * rix[0][c]; - xyz[1] += xyz_cam[1][c] * rix[0][c]; - xyz[2] += xyz_cam[2][c] * rix[0][c]; - } - xyz[0] = cbrt[CLIP((int) xyz[0])]; - xyz[1] = cbrt[CLIP((int) xyz[1])]; - xyz[2] = cbrt[CLIP((int) xyz[2])]; - lix[0][0] = 64 * (116 * xyz[1] - 16); - lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]); - lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]); - } - /* Build homogeneity maps from the CIELab images: */ - memset (homo, 0, 2*TS*TS); - for (row=top+2; row < top+TS-2 && row < height-4; row++) { - tr = row-top; - for (col=left+2; col < left+TS-2 && col < width-4; col++) { - tc = col-left; - for (d=0; d < 2; d++) { - lix = &lab[d][tr][tc]; - for (i=0; i < 4; i++) { - ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); - abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) - + SQR(lix[0][2]-lix[dir[i]][2]); - } - } - leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), - MAX(ldiff[1][2],ldiff[1][3])); - abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), - MAX(abdiff[1][2],abdiff[1][3])); - for (d=0; d < 2; d++) - for (i=0; i < 4; i++) - if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) - homo[d][tr][tc]++; - } - } - /* Combine the most homogenous pixels for the final result: */ - for (row=top+3; row < top+TS-3 && row < height-5; row++) { - tr = row-top; - for (col=left+3; col < left+TS-3 && col < width-5; col++) { - tc = col-left; - for (d=0; d < 2; d++) - for (hm[d]=0, i=tr-1; i <= tr+1; i++) - for (j=tc-1; j <= tc+1; j++) - hm[d] += homo[d][i][j]; - if (hm[0] != hm[1]) - FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; - else - FORC3 image[row*width+col][c] = - (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; - } - } - } - } - free (buffer); - } -} - -#endif -#undef TS - -void CLASS median_filter() -{ - ushort (*pix)[4]; - int pass, c, i, j, k, med[9]; - static const uchar opt[] = /* Optimal 9-element median search */ - { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, - 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; - - for (pass=1; pass <= med_passes; pass++) { -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_MEDIAN_FILTER,pass-1,med_passes); -#endif -#ifdef DCRAW_VERBOSE - if (verbose) - fprintf (stderr,_("Median filter pass %d...\n"), pass); -#endif - for (c=0; c < 3; c+=2) { - for (pix = image; pix < image+width*height; pix++) - pix[0][3] = pix[0][c]; - for (pix = image+width; pix < image+width*(height-1); pix++) { - if ((pix-image+1) % width < 2) continue; - for (k=0, i = -width; i <= width; i += width) - for (j = i-1; j <= i+1; j++) - med[k++] = pix[j][3] - pix[j][1]; - for (i=0; i < sizeof opt; i+=2) - if (med[opt[i]] > med[opt[i+1]]) - SWAP (med[opt[i]] , med[opt[i+1]]); - pix[0][c] = CLIP(med[4] + pix[0][1]); - } - } - } -} - -void CLASS blend_highlights() -{ - int clip=INT_MAX, row, col, c, i, j; - static const float trans[2][4][4] = - { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, - { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; - static const float itrans[2][4][4] = - { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, - { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; - float cam[2][4], lab[2][4], sum[2], chratio; - - if ((unsigned) (colors-3) > 1) return; -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("Blending highlights...\n")); -#endif - FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,0,2); -#endif - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - FORCC if (image[row*width+col][c] > clip) break; - if (c == colors) continue; - FORCC { - cam[0][c] = image[row*width+col][c]; - cam[1][c] = MIN(cam[0][c],clip); - } - for (i=0; i < 2; i++) { - FORCC for (lab[i][c]=j=0; j < colors; j++) - lab[i][c] += trans[colors-3][c][j] * cam[i][j]; - for (sum[i]=0,c=1; c < colors; c++) - sum[i] += SQR(lab[i][c]); - } - chratio = sqrt(sum[1]/sum[0]); - for (c=1; c < colors; c++) - lab[0][c] *= chratio; - FORCC for (cam[0][c]=j=0; j < colors; j++) - cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; - FORCC image[row*width+col][c] = cam[0][c] / colors; - } -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,1,2); -#endif -} - -#define SCALE (4 >> shrink) -void CLASS recover_highlights() -{ - float *map, sum, wgt, grow; - int hsat[4], count, spread, change, val, i; - unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; - ushort *pixel; - static const signed char dir[8][2] = - { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; - -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); -#endif - - grow = pow (2.0, 4.0-highlight); - FORCC hsat[c] = 32000 * pre_mul[c]; - for (kc=0, c=1; c < colors; c++) - if (pre_mul[kc] < pre_mul[c]) kc = c; - high = height / SCALE; - wide = width / SCALE; - map = (float *) calloc (high*wide, sizeof *map); - merror (map, "recover_highlights()"); - FORCC if (c != kc) { -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,c-1,colors-1); -#endif - memset (map, 0, high*wide*sizeof *map); - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - sum = wgt = count = 0; - for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) - for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { - pixel = image[row*width+col]; - if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { - sum += pixel[c]; - wgt += pixel[kc]; - count++; - } - } - if (count == SCALE*SCALE) - map[mrow*wide+mcol] = sum / wgt; - } - for (spread = 32/grow; spread--; ) { - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - if (map[mrow*wide+mcol]) continue; - sum = count = 0; - for (d=0; d < 8; d++) { - y = mrow + dir[d][0]; - x = mcol + dir[d][1]; - if (y < high && x < wide && map[y*wide+x] > 0) { - sum += (1 + (d & 1)) * map[y*wide+x]; - count += 1 + (d & 1); - } - } - if (count > 3) - map[mrow*wide+mcol] = - (sum+grow) / (count+grow); - } - for (change=i=0; i < high*wide; i++) - if (map[i] < 0) { - map[i] = -map[i]; - change = 1; - } - if (!change) break; - } - for (i=0; i < high*wide; i++) - if (map[i] == 0) map[i] = 1; - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) - for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { - pixel = image[row*width+col]; - if (pixel[c] / hsat[c] > 1) { - val = pixel[kc] * map[mrow*wide+mcol]; - if (pixel[c] < val) pixel[c] = CLIP(val); - } - } - } - } - free (map); -} -#undef SCALE - -void CLASS tiff_get (unsigned base, - unsigned *tag, unsigned *type, unsigned *len, unsigned *save) -{ - *tag = get2(); - *type = get2(); - *len = get4(); - *save = ftell(ifp) + 4; - if (*len * ("11124811248488"[*type < 14 ? *type:0]-'0') > 4) - fseek (ifp, get4()+base, SEEK_SET); -} - -void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) -{ - unsigned entries, tag, type, len, save; - - entries = get2(); - while (entries--) { - tiff_get (base, &tag, &type, &len, &save); - if (tag == toff) thumb_offset = get4()+base; - if (tag == tlen) thumb_length = get4(); - fseek (ifp, save, SEEK_SET); - } -} - -void CLASS parse_makernote (int base, int uptag) -{ - static const uchar xlat[2][256] = { - { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, - 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, - 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, - 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, - 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, - 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, - 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, - 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, - 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, - 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, - 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, - 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, - 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, - 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, - 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, - 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, - { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, - 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, - 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, - 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, - 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, - 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, - 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, - 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, - 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, - 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, - 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, - 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, - 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, - 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, - 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, - 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; - unsigned offset=0, entries, tag, type, len, save, c; - unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; - uchar buf97[324], ci, cj, ck; - short sorder=order; - char buf[10]; -/* - The MakerNote might have its own TIFF header (possibly with - its own byte-order!), or it might just be a table. - */ - fread (buf, 1, 10, ifp); - if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ - !strncmp (buf,"VER" ,3) || - !strncmp (buf,"IIII",4) || - !strncmp (buf,"MMMM",4)) return; - if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */ - !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */ - order = 0x4d4d; - while ((i=ftell(ifp)) < data_offset && i < 16384) { - wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3]; - wb[3] = get2(); - if (wb[1] == 256 && wb[3] == 256 && - wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640) - FORC4 cam_mul[c] = wb[c]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - goto quit; - } - if (!strcmp (buf,"Nikon")) { - base = ftell(ifp); - order = get2(); - if (get2() != 42) goto quit; - offset = get4(); - fseek (ifp, offset-8, SEEK_CUR); - } else if (!strcmp (buf,"OLYMPUS")) { - base = ftell(ifp)-10; - fseek (ifp, -2, SEEK_CUR); - order = get2(); get2(); - } else if (!strncmp (buf,"FUJIFILM",8) || - !strncmp (buf,"SONY",4) || - !strcmp (buf,"Panasonic")) { - order = 0x4949; - fseek (ifp, 2, SEEK_CUR); - } else if (!strcmp (buf,"OLYMP") || - !strcmp (buf,"LEICA") || - !strcmp (buf,"Ricoh") || - !strcmp (buf,"EPSON")) - fseek (ifp, -2, SEEK_CUR); - else if (!strcmp (buf,"AOC") || - !strcmp (buf,"QVC")) - fseek (ifp, -4, SEEK_CUR); - else fseek (ifp, -10, SEEK_CUR); - - entries = get2(); - if (entries > 1000) return; - while (entries--) { - tiff_get (base, &tag, &type, &len, &save); - tag |= uptag << 16; - if (tag == 2 && strstr(make,"NIKON")) - iso_speed = (get2(),get2()); - if (tag == 4 && len > 26 && len < 35) { - if ((i=(get4(),get2())) != 0x7fff && !iso_speed) - iso_speed = 50 * pow (2, i/32.0 - 4); - if ((i=(get2(),get2())) != 0x7fff && !aperture) - aperture = pow (2, i/64.0); - if ((i=get2()) != 0xffff && !shutter) - shutter = pow (2, (short) i/-32.0); - wbi = (get2(),get2()); - shot_order = (get2(),get2()); - } - if (tag == 7 && type == 2 && len > 20) - fgets (model2, 64, ifp); - if (tag == 8 && type == 4) - shot_order = get4(); - if (tag == 9 && !strcmp(make,"Canon")) - fread (artist, 64, 1, ifp); - if (tag == 0xc && len == 4) { - cam_mul[0] = getreal(type); - cam_mul[2] = getreal(type); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (tag == 0x10 && type == 4) - unique_id = get4(); - if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) { - fseek (ifp, get4()+base, SEEK_SET); - parse_tiff_ifd (base); - } - if (tag == 0x14 && len == 2560 && type == 7) { - fseek (ifp, 1248, SEEK_CUR); - goto get2_256; - } - if (tag == 0x15 && type == 2 && is_raw) - fread (model, 64, 1, ifp); - if (strstr(make,"PENTAX")) { - if (tag == 0x1b) tag = 0x1018; - if (tag == 0x1c) tag = 0x1017; - } - if (tag == 0x1d) - while ((c = fgetc(ifp)) && c != EOF) - serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); - if (tag == 0x81 && type == 4) { - data_offset = get4(); - fseek (ifp, data_offset + 41, SEEK_SET); - raw_height = get2() * 2; - raw_width = get2(); - filters = 0x61616161; - } - if (tag == 0x29 && type == 1) { - c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; - fseek (ifp, 8 + c*32, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if ((tag == 0x81 && type == 7) || - (tag == 0x100 && type == 7) || - (tag == 0x280 && type == 1)) { - thumb_offset = ftell(ifp); - thumb_length = len; - } - if (tag == 0x88 && type == 4 && (thumb_offset = get4())) - thumb_offset += base; - if (tag == 0x89 && type == 4) - thumb_length = get4(); - if (tag == 0x8c || tag == 0x96) - meta_offset = ftell(ifp); - if (tag == 0x97) { - for (i=0; i < 4; i++) - ver97 = ver97 * 10 + fgetc(ifp)-'0'; - switch (ver97) { - case 100: - fseek (ifp, 68, SEEK_CUR); - FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 102: - fseek (ifp, 6, SEEK_CUR); - goto get2_rggb; - case 103: - fseek (ifp, 16, SEEK_CUR); - FORC4 cam_mul[c] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (ver97 >= 200) { - if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); - fread (buf97, 324, 1, ifp); - } - } - if (tag == 0xa4 && type == 3) { - fseek (ifp, wbi*48, SEEK_CUR); - FORC3 cam_mul[c] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (tag == 0xa7 && (unsigned) (ver97-200) < 12 && !cam_mul[0]) { - ci = xlat[0][serial & 0xff]; - cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)]; - ck = 0x60; - for (i=0; i < 324; i++) - buf97[i] ^= (cj += ci * ck++); - i = "66666>666;6A"[ver97-200] - '0'; - FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = - sget2 (buf97 + (i & -2) + c*2); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (tag == 0x200 && len == 3) - shot_order = (get4(),get4()); - if (tag == 0x200 && len == 4) - black = (get2()+get2()+get2()+get2())/4; - if (tag == 0x201 && len == 4) - goto get2_rggb; - if (tag == 0x220 && len == 53) { - fseek (ifp, 14, SEEK_CUR); - pentax_tree(); - } - if (tag == 0x401 && len == 4) { - black = (get4()+get4()+get4()+get4())/4; - } - if (tag == 0xe01) { /* Nikon Capture Note */ - type = order; - order = 0x4949; - fseek (ifp, 22, SEEK_CUR); - for (offset=22; offset+22 < len; offset += 22+i) { - tag = get4(); - fseek (ifp, 14, SEEK_CUR); - i = get4()-4; - if (tag == 0x76a43207) flip = get2(); - else fseek (ifp, i, SEEK_CUR); - } - order = type; - } - if (tag == 0xe80 && len == 256 && type == 7) { - fseek (ifp, 48, SEEK_CUR); - cam_mul[0] = get2() * 508 * 1.078 / 0x10000; - cam_mul[2] = get2() * 382 * 1.173 / 0x10000; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (tag == 0xf00 && type == 7) { - if (len == 614) - fseek (ifp, 176, SEEK_CUR); - else if (len == 734 || len == 1502) - fseek (ifp, 148, SEEK_CUR); - else goto next; - goto get2_256; - } - if ((tag == 0x1011 && len == 9) || tag == 0x20400200) - { - for (i=0; i < 3; i++) - FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cmatrix_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if ((tag == 0x1012 || tag == 0x20400600) && len == 4) - for (black = i=0; i < 4; i++) - black += get2() << 2; - if (tag == 0x1017 || tag == 0x20400100) - { - cam_mul[0] = get2() / 256.0; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (tag == 0x1018 || tag == 0x20400100) - { - cam_mul[2] = get2() / 256.0; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (tag == 0x2011 && len == 2) { -get2_256: - order = 0x4d4d; - cam_mul[0] = get2() / 256.0; - cam_mul[2] = get2() / 256.0; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if ((tag | 0x70) == 0x2070 && type == 4) - fseek (ifp, get4()+base, SEEK_SET); - if (tag == 0x2010 && type != 7) - load_raw = &CLASS olympus_e410_load_raw; - if (tag == 0x2020) - parse_thumb_note (base, 257, 258); - if (tag == 0x2040) - parse_makernote (base, 0x2040); - if (tag == 0xb028) { - fseek (ifp, get4(), SEEK_SET); - parse_thumb_note (base, 136, 137); - } - if (tag == 0x4001 && len > 500) { - i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; - fseek (ifp, i, SEEK_CUR); -get2_rggb: - FORC4 cam_mul[c ^ (c >> 1)] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - fseek (ifp, 22, SEEK_CUR); - FORC4 sraw_mul[c ^ (c >> 1)] = get2(); - } -next: - fseek (ifp, save, SEEK_SET); - } -quit: - order = sorder; -} - -/* - Since the TIFF DateTime string has no timezone information, - assume that the camera's clock was set to Universal Time. - */ -void CLASS get_timestamp (int reversed) -{ - struct tm t; - char str[20]; - int i; - - str[19] = 0; - if (reversed) - for (i=19; i--; ) str[i] = fgetc(ifp); - else - fread (str, 19, 1, ifp); - memset (&t, 0, sizeof t); - if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, - &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) - return; - t.tm_year -= 1900; - t.tm_mon -= 1; - if (mktime(&t) > 0) - timestamp = mktime(&t); -} - -void CLASS parse_exif (int base) -{ - unsigned kodak, entries, tag, type, len, save, c; - double expo; - - kodak = !strncmp(make,"EASTMAN",7); - entries = get2(); - while (entries--) { - tiff_get (base, &tag, &type, &len, &save); - switch (tag) { - case 33434: shutter = getreal(type); break; - case 33437: aperture = getreal(type); break; - case 34855: iso_speed = get2(); break; - case 36867: - case 36868: get_timestamp(0); break; - case 37377: if ((expo = -getreal(type)) < 128) - shutter = pow (2, expo); break; - case 37378: aperture = pow (2, getreal(type)/2); break; - case 37386: focal_len = getreal(type); break; - case 37500: parse_makernote (base, 0); break; - case 40962: if (kodak) raw_width = get4(); break; - case 40963: if (kodak) raw_height = get4(); break; - case 41730: - if (get4() == 0x20002) - for (exif_cfa=c=0; c < 8; c+=2) - exif_cfa |= fgetc(ifp) * 0x01010101 << c; - } - fseek (ifp, save, SEEK_SET); - } -} - -void CLASS parse_gps (int base) -{ - unsigned entries, tag, type, len, save, c; - - entries = get2(); - while (entries--) { - tiff_get (base, &tag, &type, &len, &save); - switch (tag) { - case 1: case 3: case 5: - gpsdata[29+tag/2] = getc(ifp); break; - case 2: case 4: case 7: - FORC(6) gpsdata[tag/3*6+c] = get4(); break; - case 6: - FORC(2) gpsdata[18+c] = get4(); break; - case 18: case 29: - fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp); - } - fseek (ifp, save, SEEK_SET); - } -} - -void CLASS romm_coeff (float romm_cam[3][3]) -{ - static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ - { { 2.034193, -0.727420, -0.306766 }, - { -0.228811, 1.231729, -0.002922 }, - { -0.008565, -0.153273, 1.161839 } }; - int i, j, k; - - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) - for (cmatrix[i][j] = k=0; k < 3; k++) - cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cmatrix_state = LIBRAW_COLORSTATE_CALCULATED; -#endif -} - -void CLASS parse_mos (int offset) -{ - char data[40]; - int skip, from, i, c, neut[4], planes=0, frot=0; - static const char *mod[] = - { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", - "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", - "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7" }; - float romm_cam[3][3]; - - fseek (ifp, offset, SEEK_SET); - while (1) { - if (get4() != 0x504b5453) break; - get4(); - fread (data, 1, 40, ifp); - skip = get4(); - from = ftell(ifp); - if (!strcmp(data,"JPEG_preview_data")) { - thumb_offset = from; - thumb_length = skip; - } - if (!strcmp(data,"icc_camera_profile")) { - profile_offset = from; - profile_length = skip; - } - if (!strcmp(data,"ShootObj_back_type")) { - fscanf (ifp, "%d", &i); - if ((unsigned) i < sizeof mod / sizeof (*mod)) - strcpy (model, mod[i]); - } - if (!strcmp(data,"icc_camera_to_tone_matrix")) { - for (i=0; i < 9; i++) - romm_cam[0][i] = int_to_float(get4()); - romm_coeff (romm_cam); - } - if (!strcmp(data,"CaptProf_color_matrix")) { - for (i=0; i < 9; i++) - fscanf (ifp, "%f", &romm_cam[0][i]); - romm_coeff (romm_cam); - } - if (!strcmp(data,"CaptProf_number_of_planes")) - fscanf (ifp, "%d", &planes); - if (!strcmp(data,"CaptProf_raw_data_rotation")) - fscanf (ifp, "%d", &flip); - if (!strcmp(data,"CaptProf_mosaic_pattern")) - FORC4 { - fscanf (ifp, "%d", &i); - if (i == 1) frot = c ^ (c >> 1); - } - if (!strcmp(data,"ImgProf_rotation_angle")) { - fscanf (ifp, "%d", &i); - flip = i - flip; - } - if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) { - FORC4 fscanf (ifp, "%d", neut+c); - FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - parse_mos (from); - fseek (ifp, skip+from, SEEK_SET); - } - if (planes) - filters = (planes == 1) * 0x01010101 * - (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3]; -} - -void CLASS linear_table (unsigned len) -{ - int i; - if (len > 0x1000) len = 0x1000; - read_shorts (curve, len); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.curve_state = LIBRAW_COLORSTATE_LOADED; -#endif - for (i=len; i < 0x1000; i++) - curve[i] = curve[i-1]; - maximum = curve[0xfff]; -} - -void CLASS parse_kodak_ifd (int base) -{ - unsigned entries, tag, type, len, save; - int i, c, wbi=-2, wbtemp=6500; - float mul[3], num; - - entries = get2(); - if (entries > 1024) return; - while (entries--) { - tiff_get (base, &tag, &type, &len, &save); - if (tag == 1020) wbi = getint(type); - if (tag == 1021 && len == 72) { /* WB set in software */ - fseek (ifp, 40, SEEK_CUR); - FORC3 cam_mul[c] = 2048.0 / get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - wbi = -2; - } - if (tag == 2118) wbtemp = getint(type); - if (tag == 2130 + wbi) - FORC3 mul[c] = getreal(type); - if (tag == 2140 + wbi && wbi >= 0) - { - FORC3 { - for (num=i=0; i < 4; i++) - num += getreal(type) * pow (wbtemp/100.0, i); - cam_mul[c] = 2048 / (num * mul[c]); - } -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (tag == 2317) linear_table (len); - if (tag == 6020) iso_speed = getint(type); - fseek (ifp, save, SEEK_SET); - } -} - -int CLASS parse_tiff_ifd (int base) -{ - unsigned entries, tag, type, len, plen=16, save; - int ifd, use_cm=0, cfa, i, j, c, ima_len=0; - char software[64], *cbuf, *cp; - uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; - double dblack, cc[4][4], cm[4][3], cam_xyz[4][3], num; - double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; - unsigned sony_curve[] = { 0,0,0,0,0,4095 }; - unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; - struct jhead jh; - FILE *sfp; - - if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) - return 1; - ifd = tiff_nifds++; - for (j=0; j < 4; j++) - for (i=0; i < 4; i++) - cc[j][i] = i == j; - entries = get2(); - if (entries > 512) return 1; - while (entries--) { - tiff_get (base, &tag, &type, &len, &save); - switch (tag) { - case 17: case 18: - if (type == 3 && len == 1) - { - cam_mul[(tag-17)*2] = get2() / 256.0; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - break; - case 23: - if (type == 3) iso_speed = get2(); - break; - case 36: case 37: case 38: - cam_mul[tag-0x24] = get2(); - break; - case 39: - if (len < 50 || cam_mul[0]) break; - fseek (ifp, 12, SEEK_CUR); - FORC3 cam_mul[c] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 46: - if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break; - thumb_offset = ftell(ifp) - 2; - thumb_length = len; - break; - case 2: case 256: /* ImageWidth */ - tiff_ifd[ifd].t_width = getint(type); - break; - case 3: case 257: /* ImageHeight */ - tiff_ifd[ifd].t_height = getint(type); - break; - case 258: /* BitsPerSample */ - tiff_ifd[ifd].samples = len & 7; - tiff_ifd[ifd].bps = get2(); - break; - case 259: /* Compression */ - tiff_ifd[ifd].comp = get2(); - break; - case 262: /* PhotometricInterpretation */ - tiff_ifd[ifd].phint = get2(); - break; - case 270: /* ImageDescription */ - fread (desc, 512, 1, ifp); - break; - case 271: /* Make */ - fgets (make, 64, ifp); - break; - case 272: /* Model */ - fgets (model, 64, ifp); - break; - case 280: /* Panasonic RW2 offset */ - if (type != 4) break; - load_raw = &CLASS panasonic_load_raw; - load_flags = 0x2008; - case 273: /* StripOffset */ - case 513: - tiff_ifd[ifd].offset = get4()+base; - if (!tiff_ifd[ifd].bps) { - fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); - if (ljpeg_start (&jh, 1)) { - tiff_ifd[ifd].comp = 6; - tiff_ifd[ifd].t_width = jh.wide << (jh.clrs == 2); - tiff_ifd[ifd].t_height = jh.high; - tiff_ifd[ifd].bps = jh.bits; - tiff_ifd[ifd].samples = jh.clrs; - } - } - break; - case 274: /* Qt::Orientation */ - tiff_ifd[ifd].t_flip = "50132467"[get2() & 7]-'0'; - break; - case 277: /* SamplesPerPixel */ - tiff_ifd[ifd].samples = getint(type) & 7; - break; - case 279: /* StripByteCounts */ - case 514: - tiff_ifd[ifd].bytes = get4(); - break; - case 305: case 11: /* Software */ - fgets (software, 64, ifp); - if (!strncmp(software,"Adobe",5) || - !strncmp(software,"dcraw",5) || - !strncmp(software,"UFRaw",5) || - !strncmp(software,"Bibble",6) || - !strncmp(software,"Nikon Scan",10) || - !strcmp (software,"Digital Photo Professional")) - is_raw = 0; - break; - case 306: /* DateTime */ - get_timestamp(0); - break; - case 315: /* Artist */ - fread (artist, 64, 1, ifp); - break; - case 322: /* TileWidth */ - tile_width = getint(type); - break; - case 323: /* TileLength */ - tile_length = getint(type); - break; - case 324: /* TileOffsets */ - tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); - if (len == 4) { - load_raw = &CLASS sinar_4shot_load_raw; - is_raw = 5; - } - break; - case 330: /* SubIFDs */ - if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].t_width == 3872) { - load_raw = &CLASS sony_arw_load_raw; - data_offset = get4()+base; - ifd++; break; - } - while (len--) { - i = ftell(ifp); - fseek (ifp, get4()+base, SEEK_SET); - if (parse_tiff_ifd (base)) break; - fseek (ifp, i+4, SEEK_SET); - } - break; - case 400: - strcpy (make, "Sarnoff"); - maximum = 0xfff; - break; - case 28688: - FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff; - for (i=0; i < 5; i++) - for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++) - curve[j] = curve[j-1] + (1 << i); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.curve_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 29184: sony_offset = get4(); break; - case 29185: sony_length = get4(); break; - case 29217: sony_key = get4(); break; - case 29264: - parse_minolta (ftell(ifp)); - raw_width = 0; - break; - case 29443: - FORC4 cam_mul[c ^ (c < 2)] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 29459: - FORC4 cam_mul[c ^ (c >> 1)] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 33405: /* Model2 */ - fgets (model2, 64, ifp); - break; - case 33422: /* CFAPattern */ - case 64777: /* Kodak P-series */ - if ((plen=len) > 16) plen = 16; - fread (cfa_pat, 1, plen, ifp); - for (colors=cfa=i=0; i < plen; i++) { - colors += !(cfa & (1 << cfa_pat[i])); - cfa |= 1 << cfa_pat[i]; - } - if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ - if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ - goto guess_cfa_pc; - case 33424: - fseek (ifp, get4()+base, SEEK_SET); - parse_kodak_ifd (base); - break; - case 33434: /* ExposureTime */ - shutter = getreal(type); - break; - case 33437: /* FNumber */ - aperture = getreal(type); - break; - case 34306: /* Leaf white balance */ - FORC4 cam_mul[c ^ 1] = 4096.0 / get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 34307: /* Leaf CatchLight color matrix */ - fread (software, 1, 7, ifp); - if (strncmp(software,"MATRIX",6)) break; - colors = 4; - for (raw_color = i=0; i < 3; i++) { - FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]); - if (!use_camera_wb) continue; - num = 0; - FORC4 num += rgb_cam[i][c]; - FORC4 rgb_cam[i][c] /= num; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.rgb_cam_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - break; - case 34310: /* Leaf metadata */ - parse_mos (ftell(ifp)); - case 34303: - strcpy (make, "Leaf"); - break; - case 34665: /* EXIF tag */ - fseek (ifp, get4()+base, SEEK_SET); - parse_exif (base); - break; - case 34853: /* GPSInfo tag */ - fseek (ifp, get4()+base, SEEK_SET); - parse_gps (base); - break; - case 34675: /* InterColorProfile */ - case 50831: /* AsShotICCProfile */ - profile_offset = ftell(ifp); - profile_length = len; - break; - case 37122: /* CompressedBitsPerPixel */ - kodak_cbpp = get4(); - break; - case 37386: /* FocalLength */ - focal_len = getreal(type); - break; - case 37393: /* ImageNumber */ - shot_order = getint(type); - break; - case 37400: /* old Kodak KDC tag */ - for (raw_color = i=0; i < 3; i++) { - getreal(type); - FORC3 rgb_cam[i][c] = getreal(type); - } -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.rgb_cam_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 46275: /* Imacon tags */ - strcpy (make, "Imacon"); - data_offset = ftell(ifp); - ima_len = len; - break; - case 46279: - if (!ima_len) break; - fseek (ifp, 78, SEEK_CUR); - raw_width = get4(); - raw_height = get4(); - left_margin = get4() & 7; - width = raw_width - left_margin - (get4() & 7); - top_margin = get4() & 7; - height = raw_height - top_margin - (get4() & 7); - if (raw_width == 7262) { - height = 5444; - width = 7244; - left_margin = 7; - } - fseek (ifp, 52, SEEK_CUR); - FORC3 cam_mul[c] = getreal(11); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - fseek (ifp, 114, SEEK_CUR); - flip = (get2() >> 7) * 90; - if (width * height * 6 == ima_len) { - if (flip % 180 == 90) SWAP(width,height); - filters = flip = 0; - } - sprintf (model, "Ixpress %d-Mp", height*width/1000000); - load_raw = &CLASS imacon_full_load_raw; - if (filters) { - if (left_margin & 1) filters = 0x61616161; - load_raw = &CLASS unpacked_load_raw; - } - maximum = 0xffff; - break; - case 50454: /* Sinar tag */ - case 50455: - if (!(cbuf = (char *) malloc(len))) break; - fread (cbuf, 1, len, ifp); - for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) - if (!strncmp (++cp,"Neutral ",8)) - { - sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - free (cbuf); - break; - case 50458: - if (!make[0]) strcpy (make, "Hasselblad"); - break; - case 50459: /* Hasselblad tag */ - i = order; - j = ftell(ifp); - c = tiff_nifds; - order = get2(); - fseek (ifp, j+(get2(),get4()), SEEK_SET); - parse_tiff_ifd (j); - maximum = 0xffff; - tiff_nifds = c; - order = i; - break; - case 50706: /* DNGVersion */ - FORC4 dng_version = (dng_version << 8) + fgetc(ifp); - if (!make[0]) strcpy (make, "DNG"); - is_raw = 1; - break; - case 50710: /* CFAPlaneColor */ - if (len > 4) len = 4; - colors = len; - fread (cfa_pc, 1, colors, ifp); -guess_cfa_pc: - FORCC tab[cfa_pc[c]] = c; - cdesc[c] = 0; - for (i=16; i--; ) - filters = filters << 2 | tab[cfa_pat[i % plen]]; - break; - case 50711: /* CFALayout */ - if (get2() == 2) { - fuji_width = 1; - filters = 0x49494949; - } - break; - case 291: - case 50712: /* LinearizationTable */ - linear_table (len); - break; - case 50714: /* BlackLevel */ - case 50715: /* BlackLevelDeltaH */ - case 50716: /* BlackLevelDeltaV */ - for (dblack=i=0; i < len; i++) - dblack += getreal(type); - black += dblack/len + 0.5; - break; - case 50717: /* WhiteLevel */ - maximum = getint(type); - break; - case 50718: /* DefaultScale */ - pixel_aspect = getreal(type); - pixel_aspect /= getreal(type); - break; - case 50721: /* ColorMatrix1 */ - case 50722: /* ColorMatrix2 */ - FORCC for (j=0; j < 3; j++) - cm[c][j] = getreal(type); - use_cm = 1; - break; - case 50723: /* CameraCalibration1 */ - case 50724: /* CameraCalibration2 */ - for (i=0; i < colors; i++) - FORCC cc[i][c] = getreal(type); - case 50727: /* AnalogBalance */ - FORCC ab[c] = getreal(type); - break; - case 50728: /* AsShotNeutral */ - FORCC asn[c] = getreal(type); - break; - case 50729: /* AsShotWhiteXY */ - xyz[0] = getreal(type); - xyz[1] = getreal(type); - xyz[2] = 1 - xyz[0] - xyz[1]; - FORC3 xyz[c] /= d65_white[c]; - break; - case 50740: /* DNGPrivateData */ - if (dng_version) break; - parse_minolta (j = get4()+base); - fseek (ifp, j, SEEK_SET); - parse_tiff_ifd (base); - break; - case 50752: - read_shorts (cr2_slice, 3); - break; - case 50829: /* ActiveArea */ - top_margin = getint(type); - left_margin = getint(type); - height = getint(type) - top_margin; - width = getint(type) - left_margin; - break; - case 64772: /* Kodak P-series */ - fseek (ifp, 16, SEEK_CUR); - data_offset = get4(); - fseek (ifp, 28, SEEK_CUR); - data_offset += get4(); - load_raw = &CLASS packed_12_load_raw; - } - fseek (ifp, save, SEEK_SET); - } - if (sony_length && (buf = (unsigned *) malloc(sony_length))) { - fseek (ifp, sony_offset, SEEK_SET); - fread (buf, sony_length, 1, ifp); - sony_decrypt (buf, sony_length/4, 1, sony_key); -#ifndef LIBRAW_LIBRARY_BUILD - sfp = ifp; - if ((ifp = tmpfile())) { - fwrite (buf, sony_length, 1, ifp); - fseek (ifp, 0, SEEK_SET); - parse_tiff_ifd (-sony_offset); - fclose (ifp); - } - ifp = sfp; -#else - if( !ifp->tempbuffer_open(buf,sony_length)) - { - parse_tiff_ifd(-sony_offset); - ifp->tempbuffer_close(); - } -#endif - free (buf); - } - for (i=0; i < colors; i++) - FORCC cc[i][c] *= ab[i]; - if (use_cm) { - FORCC for (i=0; i < 3; i++) - for (cam_xyz[c][i]=j=0; j < colors; j++) - cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; - cam_xyz_coeff (cam_xyz); - } - if (asn[0]) { - cam_mul[3] = 0; - FORCC cam_mul[c] = 1 / asn[c]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (!use_cm) - { - FORCC pre_mul[c] /= cc[c][c]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - - return 0; -} - -void CLASS parse_tiff (int base) -{ - int doff, max_samp=0, raw=-1, thm=-1, i; - struct jhead jh; - - fseek (ifp, base, SEEK_SET); - order = get2(); - if (order != 0x4949 && order != 0x4d4d) return; - get2(); - memset (tiff_ifd, 0, sizeof tiff_ifd); - tiff_nifds = 0; - while ((doff = get4())) { - fseek (ifp, doff+base, SEEK_SET); - if (parse_tiff_ifd (base)) break; - } - thumb_misc = 16; - if (thumb_offset) { - fseek (ifp, thumb_offset, SEEK_SET); - if (ljpeg_start (&jh, 1)) { - thumb_misc = jh.bits; - thumb_width = jh.wide; - thumb_height = jh.high; - } - } - for (i=0; i < tiff_nifds; i++) { - if (max_samp < tiff_ifd[i].samples) - max_samp = tiff_ifd[i].samples; - if (max_samp > 3) max_samp = 3; - if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && - tiff_ifd[i].t_width*tiff_ifd[i].t_height > raw_width*raw_height) { - raw_width = tiff_ifd[i].t_width; - raw_height = tiff_ifd[i].t_height; - tiff_bps = tiff_ifd[i].bps; - tiff_compress = tiff_ifd[i].comp; - data_offset = tiff_ifd[i].offset; - tiff_flip = tiff_ifd[i].t_flip; - tiff_samples = tiff_ifd[i].samples; - raw = i; - } - } - fuji_width *= (raw_width+1)/2; - if (tiff_ifd[0].t_flip) tiff_flip = tiff_ifd[0].t_flip; - if (raw >= 0 && !load_raw) - switch (tiff_compress) { - case 0: case 1: - switch (tiff_bps) { - case 8: load_raw = &CLASS eight_bit_load_raw; break; - case 12: load_raw = &CLASS packed_12_load_raw; - if (tiff_ifd[raw].phint == 2) - load_flags = 6; - if (strncmp(make,"PENTAX",6)) break; - case 14: - case 16: load_raw = &CLASS unpacked_load_raw; break; - } - if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) - load_raw = &CLASS olympus_e300_load_raw; - break; - case 6: case 7: case 99: - load_raw = &CLASS lossless_jpeg_load_raw; break; - case 262: - load_raw = &CLASS kodak_262_load_raw; break; - case 32767: - load_raw = &CLASS sony_arw2_load_raw; - if (tiff_ifd[raw].bytes*8 == raw_width*raw_height*tiff_bps) - break; - raw_height += 8; - load_raw = &CLASS sony_arw_load_raw; break; - case 32769: - load_flags = 8; - case 32773: - load_raw = &CLASS packed_12_load_raw; break; - case 34713: - load_raw = &CLASS nikon_compressed_load_raw; break; - case 65535: - load_raw = &CLASS pentax_k10_load_raw; break; - case 65000: - switch (tiff_ifd[raw].phint) { - case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; - case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; - case 32803: load_raw = &CLASS kodak_65000_load_raw; - } - case 32867: break; - default: is_raw = 0; - } - if (!dng_version && tiff_samples == 3) - if (tiff_ifd[raw].bytes && tiff_bps != 14 && tiff_bps != 2048) - is_raw = 0; - if (!dng_version && tiff_bps == 8 && tiff_compress == 1 && - tiff_ifd[raw].phint == 1) is_raw = 0; - if (tiff_bps == 8 && tiff_samples == 4) is_raw = 0; - for (i=0; i < tiff_nifds; i++) - if (i != raw && tiff_ifd[i].samples == max_samp && - tiff_ifd[i].t_width * tiff_ifd[i].t_height / SQR(tiff_ifd[i].bps+1) > - thumb_width * thumb_height / SQR(thumb_misc+1)) { - thumb_width = tiff_ifd[i].t_width; - thumb_height = tiff_ifd[i].t_height; - thumb_offset = tiff_ifd[i].offset; - thumb_length = tiff_ifd[i].bytes; - thumb_misc = tiff_ifd[i].bps; - thm = i; - } - if (thm >= 0) { - thumb_misc |= tiff_ifd[thm].samples << 5; - switch (tiff_ifd[thm].comp) { - case 0: - write_thumb = &CLASS layer_thumb; - break; - case 1: - if (tiff_ifd[thm].bps > 8) - thumb_load_raw = &CLASS kodak_thumb_load_raw; - else - write_thumb = &CLASS ppm_thumb; - break; - case 65000: - thumb_load_raw = tiff_ifd[thm].phint == 6 ? - &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw; - } - } -} - -void CLASS parse_minolta (int base) -{ - int save, tag, len, offset, high=0, wide=0, i, c; - short sorder=order; - - fseek (ifp, base, SEEK_SET); - if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; - order = fgetc(ifp) * 0x101; - offset = base + get4() + 8; - while ((save=ftell(ifp)) < offset) { - for (tag=i=0; i < 4; i++) - tag = tag << 8 | fgetc(ifp); - len = get4(); - switch (tag) { - case 0x505244: /* PRD */ - fseek (ifp, 8, SEEK_CUR); - high = get2(); - wide = get2(); - break; - case 0x574247: /* WBG */ - get4(); - i = strcmp(model,"DiMAGE A200") ? 0:3; - FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 0x545457: /* TTW */ - parse_tiff (ftell(ifp)); - data_offset = offset; - } - fseek (ifp, save+len+8, SEEK_SET); - } - raw_height = high; - raw_width = wide; - order = sorder; -} - -/* - Many cameras have a "debug mode" that writes JPEG and raw - at the same time. The raw file has no header, so try to - to open the matching JPEG file and read its metadata. - */ -void CLASS parse_external_jpeg() -{ - char *file, *ext, *jname, *jfile, *jext; -#ifndef LIBRAW_LIBRARY_BUILD - FILE *save=ifp; -#else - if(!ifp->fname()) - { - imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; - return; - } -#endif - - ext = strrchr (ifname, '.'); - file = strrchr (ifname, '/'); - if (!file) file = strrchr (ifname, '\\'); -#ifndef LIBRAW_LIBRARY_BUILD - if (!file) file = ifname-1; -#else - if (!file) file = (char*)ifname-1; -#endif - file++; - if (!ext || strlen(ext) != 4 || ext-file != 8) return; - jname = (char *) malloc (strlen(ifname) + 1); - merror (jname, "parse_external_jpeg()"); - strcpy (jname, ifname); - jfile = file - ifname + jname; - jext = ext - ifname + jname; - if (strcasecmp (ext, ".jpg")) { - strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); - if (isdigit(*file)) { - memcpy (jfile, file+4, 4); - memcpy (jfile+4, file, 4); - } - } else - while (isdigit(*--jext)) { - if (*jext != '9') { - (*jext)++; - break; - } - *jext = '0'; - } -#ifndef LIBRAW_LIBRARY_BUILD - if (strcmp (jname, ifname)) { - if ((ifp = fopen (jname, "rb"))) { -#ifdef DCRAW_VERBOSE - if (verbose) - fprintf (stderr,_("Reading metadata from %s ...\n"), jname); -#endif - parse_tiff (12); - thumb_offset = 0; - is_raw = 1; - fclose (ifp); - } - } -#else - if (strcmp (jname, ifname)) - { - if(!ifp->subfile_open(jname)) - { - parse_tiff (12); - thumb_offset = 0; - is_raw = 1; - ifp->subfile_close(); - } - else - imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; - } -#endif - if (!timestamp) - { -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; -#endif -#ifdef DCRAW_VERBOSE - fprintf (stderr,_("Failed to read metadata from %s\n"), jname); -#endif - } - free (jname); -#ifndef LIBRAW_LIBRARY_BUILD - ifp = save; -#endif -} - -/* - CIFF block 0x1030 contains an 8x8 white sample. - Load this into white[][] for use in scale_colors(). - */ -void CLASS ciff_block_1030() -{ - static const ushort key[] = { 0x410, 0x45f3 }; - int i, bpp, row, col, vbits=0; - unsigned long bitbuf=0; - - if ((get2(),get4()) != 0x80008 || !get4()) return; - bpp = get2(); - if (bpp != 10 && bpp != 12) return; - for (i=row=0; row < 8; row++) - for (col=0; col < 8; col++) { - if (vbits < bpp) { - bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); - vbits += 16; - } - white[row][col] = - bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); - vbits -= bpp; - } -} - -/* - Parse a CIFF file, better known as Canon CRW format. - */ -void CLASS parse_ciff (int offset, int length) -{ - int tboff, nrecs, c, type, len, save, wbi=-1; - ushort key[] = { 0x410, 0x45f3 }; - - fseek (ifp, offset+length-4, SEEK_SET); - tboff = get4() + offset; - fseek (ifp, tboff, SEEK_SET); - nrecs = get2(); - if (nrecs > 100) return; - while (nrecs--) { - type = get2(); - len = get4(); - save = ftell(ifp) + 4; - fseek (ifp, offset+get4(), SEEK_SET); - if ((((type >> 8) + 8) | 8) == 0x38) - parse_ciff (ftell(ifp), len); /* Parse a sub-table */ - - if (type == 0x0810) - fread (artist, 64, 1, ifp); - if (type == 0x080a) { - fread (make, 64, 1, ifp); - fseek (ifp, strlen(make) - 63, SEEK_CUR); - fread (model, 64, 1, ifp); - } - if (type == 0x1810) { - fseek (ifp, 12, SEEK_CUR); - flip = get4(); - } - if (type == 0x1835) /* Get the decoder table */ - tiff_compress = get4(); - if (type == 0x2007) { - thumb_offset = ftell(ifp); - thumb_length = len; - } - if (type == 0x1818) { - shutter = pow (2.0f, -int_to_float((get4(),get4()))); - aperture = pow (2.0f, int_to_float(get4())/2); - } - if (type == 0x102a) { - iso_speed = pow (2, (get4(),get2())/32.0 - 4) * 50; - aperture = pow (2, (get2(),(short)get2())/64.0); - shutter = pow (2,-((short)get2())/32.0); - wbi = (get2(),get2()); - if (wbi > 17) wbi = 0; - fseek (ifp, 32, SEEK_CUR); - if (shutter > 1e6) shutter = get2()/10.0; - } - if (type == 0x102c) { - if (get2() > 512) { /* Pro90, G1 */ - fseek (ifp, 118, SEEK_CUR); - FORC4 cam_mul[c ^ 2] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } else { /* G2, S30, S40 */ - fseek (ifp, 98, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - } - if (type == 0x0032) { - if (len == 768) { /* EOS D30 */ - fseek (ifp, 72, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - if (!wbi) cam_mul[0] = -1; /* use my auto white balance */ - } else if (!cam_mul[0]) { - if (get2() == key[0]) /* Pro1, G6, S60, S70 */ - c = (strstr(model,"Pro1") ? - "012346000000000000":"01345:000000006008")[wbi]-'0'+ 2; - else { /* G3, G5, S45, S50 */ - c = "023457000000006000"[wbi]-'0'; - key[0] = key[1] = 0; - } - fseek (ifp, 78 + c*8, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - if (!wbi) cam_mul[0] = -1; - } - } - if (type == 0x10a9) { /* D60, 10D, 300D, and clones */ - if (len > 66) wbi = "0134567028"[wbi]-'0'; - fseek (ifp, 2 + wbi*8, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1)] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - if (type == 0x1030 && (0x18040 >> wbi & 1)) - ciff_block_1030(); /* all that don't have 0x10a9 */ - if (type == 0x1031) { - raw_width = (get2(),get2()); - raw_height = get2(); - } - if (type == 0x5029) { - focal_len = len >> 16; - if ((len & 0xffff) == 2) focal_len /= 32; - } - if (type == 0x5813) flash_used = int_to_float(len); - if (type == 0x5814) canon_ev = int_to_float(len); - if (type == 0x5817) shot_order = len; - if (type == 0x5834) unique_id = len; - if (type == 0x580e) timestamp = len; - if (type == 0x180e) timestamp = get4(); -#ifdef LOCALTIME - if ((type | 0x4000) == 0x580e) - timestamp = mktime (gmtime (×tamp)); -#endif - fseek (ifp, save, SEEK_SET); - } -} - -void CLASS parse_rollei() -{ - char line[128], *val; - struct tm t; - - fseek (ifp, 0, SEEK_SET); - memset (&t, 0, sizeof t); - do { - fgets (line, 128, ifp); - if ((val = strchr(line,'='))) - *val++ = 0; - else - val = line + strlen(line); - if (!strcmp(line,"DAT")) - sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); - if (!strcmp(line,"TIM")) - sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); - if (!strcmp(line,"HDR")) - thumb_offset = atoi(val); - if (!strcmp(line,"X ")) - raw_width = atoi(val); - if (!strcmp(line,"Y ")) - raw_height = atoi(val); - if (!strcmp(line,"TX ")) - thumb_width = atoi(val); - if (!strcmp(line,"TY ")) - thumb_height = atoi(val); - } while (strncmp(line,"EOHD",4)); - data_offset = thumb_offset + thumb_width * thumb_height * 2; - t.tm_year -= 1900; - t.tm_mon -= 1; - if (mktime(&t) > 0) - timestamp = mktime(&t); - strcpy (make, "Rollei"); - strcpy (model,"d530flex"); - write_thumb = &CLASS rollei_thumb; -} - -void CLASS parse_sinar_ia() -{ - int entries, off; - char str[8], *cp; - - order = 0x4949; - fseek (ifp, 4, SEEK_SET); - entries = get4(); - fseek (ifp, get4(), SEEK_SET); - while (entries--) { - off = get4(); get4(); - fread (str, 8, 1, ifp); - if (!strcmp(str,"META")) meta_offset = off; - if (!strcmp(str,"THUMB")) thumb_offset = off; - if (!strcmp(str,"RAW0")) data_offset = off; - } - fseek (ifp, meta_offset+20, SEEK_SET); - fread (make, 64, 1, ifp); - make[63] = 0; - if ((cp = strchr(make,' '))) { - strcpy (model, cp+1); - *cp = 0; - } - raw_width = get2(); - raw_height = get2(); - load_raw = &CLASS unpacked_load_raw; - thumb_width = (get4(),get2()); - thumb_height = get2(); - write_thumb = &CLASS ppm_thumb; - maximum = 0x3fff; -} - -void CLASS parse_phase_one (int base) -{ - unsigned entries, tag, type, len, data, save, i, c; - float romm_cam[3][3]; - char *cp; - - memset (&ph1, 0, sizeof ph1); - fseek (ifp, base, SEEK_SET); - order = get4() & 0xffff; - if (get4() >> 8 != 0x526177) return; /* "Raw" */ - fseek (ifp, get4()+base, SEEK_SET); - entries = get4(); - get4(); - while (entries--) { - tag = get4(); - type = get4(); - len = get4(); - data = get4(); - save = ftell(ifp); - fseek (ifp, base+data, SEEK_SET); - switch (tag) { - case 0x100: flip = "0653"[data & 3]-'0'; break; - case 0x106: - for (i=0; i < 9; i++) - romm_cam[0][i] = getreal(11); - romm_coeff (romm_cam); - break; - case 0x107: - FORC3 cam_mul[c] = getreal(11); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - break; - case 0x108: raw_width = data; break; - case 0x109: raw_height = data; break; - case 0x10a: left_margin = data; break; - case 0x10b: top_margin = data; break; - case 0x10c: width = data; break; - case 0x10d: height = data; break; - case 0x10e: ph1.format = data; break; - case 0x10f: data_offset = data+base; break; - case 0x110: meta_offset = data+base; - meta_length = len; break; - case 0x112: ph1.key_off = save - 4; break; - case 0x210: ph1.tag_210 = int_to_float(data); break; - case 0x21a: ph1.tag_21a = data; break; - case 0x21c: strip_offset = data+base; break; - case 0x21d: ph1.t_black = data; break; - case 0x222: ph1.split_col = data - left_margin; break; - case 0x223: ph1.black_off = data+base; break; - case 0x301: - model[63] = 0; - fread (model, 1, 63, ifp); - if ((cp = strstr(model," camera"))) *cp = 0; - } - fseek (ifp, save, SEEK_SET); - } - load_raw = ph1.format < 3 ? - &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; - maximum = 0xffff; - strcpy (make, "Phase One"); - if (model[0]) return; - switch (raw_height) { - case 2060: strcpy (model,"LightPhase"); break; - case 2682: strcpy (model,"H 10"); break; - case 4128: strcpy (model,"H 20"); break; - case 5488: strcpy (model,"H 25"); break; - } -} - -void CLASS parse_fuji (int offset) -{ - unsigned entries, tag, len, save, c; - - fseek (ifp, offset, SEEK_SET); - entries = get4(); - if (entries > 255) return; - while (entries--) { - tag = get2(); - len = get2(); - save = ftell(ifp); - if (tag == 0x100) { - raw_height = get2(); - raw_width = get2(); - } else if (tag == 0x121) { - height = get2(); - if ((width = get2()) == 4284) width += 3; - } else if (tag == 0x130) - fuji_layout = fgetc(ifp) >> 7; - if (tag == 0x2ff0) - { - FORC4 cam_mul[c ^ 1] = get2(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } - fseek (ifp, save+len, SEEK_SET); - } - height <<= fuji_layout; - width >>= fuji_layout; -} - -int CLASS parse_jpeg (int offset) -{ - int len, save, hlen, mark; - - fseek (ifp, offset, SEEK_SET); - if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; - - while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) { - order = 0x4d4d; - len = get2() - 2; - save = ftell(ifp); - if (mark == 0xc0 || mark == 0xc3) { - fgetc(ifp); - raw_height = get2(); - raw_width = get2(); - } - order = get2(); - hlen = get4(); - if (get4() == 0x48454150) /* "HEAP" */ - parse_ciff (save+hlen, len-hlen); - parse_tiff (save+6); - fseek (ifp, save+len, SEEK_SET); - } - return 1; -} - -void CLASS parse_riff() -{ - unsigned i, size, end; - char tag[4], date[64], month[64]; - static const char mon[12][4] = - { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; - struct tm t; - - order = 0x4949; - fread (tag, 4, 1, ifp); - size = get4(); - end = ftell(ifp) + size; - if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { - get4(); - while (ftell(ifp)+7 < end) - parse_riff(); - } else if (!memcmp(tag,"nctg",4)) { - while (ftell(ifp)+7 < end) { - i = get2(); - size = get2(); - if ((i+1) >> 1 == 10 && size == 20) - get_timestamp(0); - else fseek (ifp, size, SEEK_CUR); - } - } else if (!memcmp(tag,"IDIT",4) && size < 64) { - fread (date, 64, 1, ifp); - date[size] = 0; - memset (&t, 0, sizeof t); - if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, - &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { - for (i=0; i < 12 && strcasecmp(mon[i],month); i++); - t.tm_mon = i; - t.tm_year -= 1900; - if (mktime(&t) > 0) - timestamp = mktime(&t); - } - } else - fseek (ifp, size, SEEK_CUR); -} - -void CLASS parse_smal (int offset, int fsize) -{ - int ver; - - fseek (ifp, offset+2, SEEK_SET); - order = 0x4949; - ver = fgetc(ifp); - if (ver == 6) - fseek (ifp, 5, SEEK_CUR); - if (get4() != fsize) return; - if (ver > 6) data_offset = get4(); - raw_height = height = get2(); - raw_width = width = get2(); - strcpy (make, "SMaL"); - sprintf (model, "v%d %dx%d", ver, width, height); - if (ver == 6) load_raw = &CLASS smal_v6_load_raw; - if (ver == 9) load_raw = &CLASS smal_v9_load_raw; -} - -void CLASS parse_cine() -{ - unsigned off_head, off_setup, off_image, i; - - order = 0x4949; - fseek (ifp, 4, SEEK_SET); - is_raw = get2() == 2; - fseek (ifp, 14, SEEK_CUR); - is_raw *= get4(); - off_head = get4(); - off_setup = get4(); - off_image = get4(); - timestamp = get4(); - if ((i = get4())) timestamp = i; - fseek (ifp, off_head+4, SEEK_SET); - raw_width = get4(); - raw_height = get4(); - switch (get2(),get2()) { - case 8: load_raw = &CLASS eight_bit_load_raw; break; - case 16: load_raw = &CLASS unpacked_load_raw; - } - fseek (ifp, off_setup+792, SEEK_SET); - strcpy (make, "CINE"); - sprintf (model, "%d", get4()); - fseek (ifp, 12, SEEK_CUR); - switch ((i=get4()) & 0xffffff) { - case 3: filters = 0x94949494; break; - case 4: filters = 0x49494949; break; - default: is_raw = 0; - } - fseek (ifp, 72, SEEK_CUR); - switch ((get4()+3600) % 360) { - case 270: flip = 4; break; - case 180: flip = 1; break; - case 90: flip = 7; break; - case 0: flip = 2; - } - cam_mul[0] = getreal(11); - cam_mul[2] = getreal(11); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - maximum = ~(-1 << get4()); - fseek (ifp, 668, SEEK_CUR); - shutter = get4()/1000000000.0; - fseek (ifp, off_image, SEEK_SET); - if (shot_select < is_raw) - fseek (ifp, shot_select*8, SEEK_CUR); - data_offset = (INT64) get4() + 8; - data_offset += (INT64) get4() << 32; -} -#ifdef LIBRAW_LIBRARY_BUILD -void CLASS adobe_coeff (const char *p_make, const char *p_model) -#else -void CLASS adobe_coeff (char *p_make, char *p_model) -#endif -{ - static const struct { - const char *prefix; - unsigned short t_black, t_maximum; - short trans[12]; - } table[] = { - { "Apple QuickTake", 0, 0, /* DJC */ - { 17576,-3191,-3318,5210,6733,-1942,9031,1280,-124 } }, - { "Canon EOS D2000", 0, 0, - { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, - { "Canon EOS D6000", 0, 0, - { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, - { "Canon EOS D30", 0, 0, - { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, - { "Canon EOS D60", 0, 0xfa0, - { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, - { "Canon EOS 5D Mark II", 0, 0x3cf0, - { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, - { "Canon EOS 5D", 0, 0xe6c, - { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, - { "Canon EOS 10D", 0, 0xfa0, - { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, - { "Canon EOS 20Da", 0, 0, - { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, - { "Canon EOS 20D", 0, 0xfff, - { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, - { "Canon EOS 30D", 0, 0, - { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, - { "Canon EOS 40D", 0, 0x3f60, - { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, - { "Canon EOS 50D", 0, 0x3d93, - { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, - { "Canon EOS 300D", 0, 0xfa0, - { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, - { "Canon EOS 350D", 0, 0xfff, - { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, - { "Canon EOS 400D", 0, 0xe8e, - { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, - { "Canon EOS 450D", 0, 0x390d, - { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, - { "Canon EOS 1000D", 0, 0xe43, - { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, - { "Canon EOS-1Ds Mark III", 0, 0x3bb0, - { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, - { "Canon EOS-1Ds Mark II", 0, 0xe80, - { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, - { "Canon EOS-1D Mark II N", 0, 0xe80, - { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, - { "Canon EOS-1D Mark III", 0, 0x3bb0, - { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, - { "Canon EOS-1D Mark II", 0, 0xe80, - { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, - { "Canon EOS-1DS", 0, 0xe20, - { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, - { "Canon EOS-1D", 0, 0xe20, - { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, - { "Canon EOS", 0, 0, - { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, - { "Canon PowerShot A50", 0, 0, - { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, - { "Canon PowerShot A5", 0, 0, - { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, - { "Canon PowerShot G10", 0, 0, - { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, - { "Canon PowerShot G1", 0, 0, - { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, - { "Canon PowerShot G2", 0, 0, - { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, - { "Canon PowerShot G3", 0, 0, - { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, - { "Canon PowerShot G5", 0, 0, - { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, - { "Canon PowerShot G6", 0, 0, - { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, - { "Canon PowerShot G9", 0, 0, - { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, - { "Canon PowerShot Pro1", 0, 0, - { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, - { "Canon PowerShot Pro70", 34, 0, - { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, - { "Canon PowerShot Pro90", 0, 0, - { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, - { "Canon PowerShot S30", 0, 0, - { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, - { "Canon PowerShot S40", 0, 0, - { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, - { "Canon PowerShot S45", 0, 0, - { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, - { "Canon PowerShot S50", 0, 0, - { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, - { "Canon PowerShot S60", 0, 0, - { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, - { "Canon PowerShot S70", 0, 0, - { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, - { "Canon PowerShot A610", 0, 0, /* DJC */ - { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, - { "Canon PowerShot A620", 0, 0, /* DJC */ - { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, - { "Canon PowerShot A630", 0, 0, /* DJC */ - { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, - { "Canon PowerShot A640", 0, 0, /* DJC */ - { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, - { "Canon PowerShot A650", 0, 0, /* DJC */ - { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, - { "Canon PowerShot A720", 0, 0, /* DJC */ - { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, - { "Canon PowerShot S3 IS", 0, 0, /* DJC */ - { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, - { "CINE 650", 0, 0, - { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, - { "CINE 660", 0, 0, - { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, - { "CINE", 0, 0, - { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, - { "Contax N Digital", 0, 0xf1e, - { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, - { "EPSON R-D1", 0, 0, - { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, - { "FUJIFILM FinePix E550", 0, 0, - { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, - { "FUJIFILM FinePix E900", 0, 0, - { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, - { "FUJIFILM FinePix F8", 0, 0, - { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, - { "FUJIFILM FinePix F7", 0, 0, - { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, - { "FUJIFILM FinePix S100FS", 514, 0, - { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, - { "FUJIFILM FinePix S20Pro", 0, 0, - { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, - { "FUJIFILM FinePix S2Pro", 128, 0, - { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, - { "FUJIFILM FinePix S3Pro", 0, 0, - { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, - { "FUJIFILM FinePix S5Pro", 0, 0, - { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, - { "FUJIFILM FinePix S5000", 0, 0, - { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, - { "FUJIFILM FinePix S5100", 0, 0x3e00, - { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, - { "FUJIFILM FinePix S5500", 0, 0x3e00, - { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, - { "FUJIFILM FinePix S5200", 0, 0, - { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, - { "FUJIFILM FinePix S5600", 0, 0, - { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, - { "FUJIFILM FinePix S6", 0, 0, - { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, - { "FUJIFILM FinePix S7000", 0, 0, - { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, - { "FUJIFILM FinePix S9000", 0, 0, - { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, - { "FUJIFILM FinePix S9500", 0, 0, - { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, - { "FUJIFILM FinePix S9100", 0, 0, - { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, - { "FUJIFILM FinePix S9600", 0, 0, - { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, - { "FUJIFILM IS-1", 0, 0, - { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, - { "FUJIFILM IS Pro", 0, 0, - { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, - { "Imacon Ixpress", 0, 0, /* DJC */ - { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, - { "KODAK NC2000", 0, 0, - { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, - { "Kodak DCS315C", 8, 0, - { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, - { "Kodak DCS330C", 8, 0, - { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, - { "KODAK DCS420", 0, 0, - { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, - { "KODAK DCS460", 0, 0, - { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, - { "KODAK EOSDCS1", 0, 0, - { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, - { "KODAK EOSDCS3B", 0, 0, - { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, - { "Kodak DCS520C", 180, 0, - { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, - { "Kodak DCS560C", 188, 0, - { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, - { "Kodak DCS620C", 180, 0, - { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, - { "Kodak DCS620X", 185, 0, - { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, - { "Kodak DCS660C", 214, 0, - { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, - { "Kodak DCS720X", 0, 0, - { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, - { "Kodak DCS760C", 0, 0, - { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, - { "Kodak DCS Pro SLR", 0, 0, - { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, - { "Kodak DCS Pro 14nx", 0, 0, - { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, - { "Kodak DCS Pro 14", 0, 0, - { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, - { "Kodak ProBack645", 0, 0, - { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, - { "Kodak ProBack", 0, 0, - { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, - { "KODAK P712", 0, 0, - { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, - { "KODAK P850", 0, 0xf7c, - { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, - { "KODAK P880", 0, 0xfff, - { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, - { "Leaf CMost", 0, 0, - { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, - { "Leaf Valeo 6", 0, 0, - { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, - { "Leaf Aptus 54S", 0, 0, - { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, - { "Leaf Aptus 65", 0, 0, - { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, - { "Leaf Aptus 75", 0, 0, - { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, - { "Leaf", 0, 0, - { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, - { "Mamiya ZD", 0, 0, - { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, - { "Micron 2010", 110, 0, /* DJC */ - { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, - { "Minolta DiMAGE 5", 0, 0xf7d, - { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, - { "Minolta DiMAGE 7Hi", 0, 0xf7d, - { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, - { "Minolta DiMAGE 7", 0, 0xf7d, - { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, - { "Minolta DiMAGE A1", 0, 0xf8b, - { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, - { "MINOLTA DiMAGE A200", 0, 0, - { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, - { "Minolta DiMAGE A2", 0, 0xf8f, - { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, - { "Minolta DiMAGE Z2", 0, 0, /* DJC */ - { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, - { "MINOLTA DYNAX 5", 0, 0xffb, - { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, - { "MINOLTA DYNAX 7", 0, 0xffb, - { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, - { "NIKON D100", 0, 0, - { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, - { "NIKON D1H", 0, 0, - { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, - { "NIKON D1X", 0, 0, - { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, - { "NIKON D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ - { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, - { "NIKON D2H", 0, 0, - { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, - { "NIKON D2X", 0, 0, - { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, - { "NIKON D40X", 0, 0, - { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, - { "NIKON D40", 0, 0, - { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, - { "NIKON D50", 0, 0, - { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, - { "NIKON D60", 0, 0, - { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, - { "NIKON D700", 0, 0, - { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, - { "NIKON D70", 0, 0, - { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, - { "NIKON D80", 0, 0, - { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, - { "NIKON D90", 0, 0xf00, - { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, - { "NIKON D200", 0, 0xfbc, - { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, - { "NIKON D300", 0, 0, - { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, - { "NIKON D3", 0, 0, - { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, - { "NIKON E950", 0, 0x3dd, /* DJC */ - { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, - { "NIKON E995", 0, 0, /* copied from E5000 */ - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E2100", 0, 0, /* copied from Z2, new white balance */ - { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} }, - { "NIKON E2500", 0, 0, - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ - { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, - { "NIKON E4500", 0, 0, - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E5000", 0, 0, - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E5400", 0, 0, - { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, - { "NIKON E5700", 0, 0, - { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, - { "NIKON E8400", 0, 0, - { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, - { "NIKON E8700", 0, 0, - { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, - { "NIKON E8800", 0, 0, - { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, - { "NIKON COOLPIX P6000", 0, 0, - { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, - { "OLYMPUS C5050", 0, 0, - { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, - { "OLYMPUS C5060", 0, 0, - { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, - { "OLYMPUS C7070", 0, 0, - { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, - { "OLYMPUS C70", 0, 0, - { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, - { "OLYMPUS C80", 0, 0, - { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, - { "OLYMPUS E-10", 0, 0xffc0, - { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, - { "OLYMPUS E-1", 0, 0xfff0, - { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, - { "OLYMPUS E-20", 0, 0xffc0, - { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, - { "OLYMPUS E-300", 0, 0, - { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, - { "OLYMPUS E-330", 0, 0, - { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, - { "OLYMPUS E-3", 0, 0xf99, - { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, - { "OLYMPUS E-400", 0, 0xfff0, - { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, - { "OLYMPUS E-410", 0, 0xf6a, - { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, - { "OLYMPUS E-420", 0, 0xfd7, - { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, - { "OLYMPUS E-500", 0, 0, - { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, - { "OLYMPUS E-510", 0, 0xf6a, - { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, - { "OLYMPUS E-520", 0, 0xfd2, - { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, - { "OLYMPUS SP350", 0, 0, - { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, - { "OLYMPUS SP3", 0, 0, - { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, - { "OLYMPUS SP500UZ", 0, 0xfff, - { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, - { "OLYMPUS SP510UZ", 0, 0xffe, - { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, - { "OLYMPUS SP550UZ", 0, 0xffe, - { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, - { "OLYMPUS SP560UZ", 0, 0xff9, - { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, - { "OLYMPUS SP570UZ", 0, 0, - { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, - { "PENTAX *ist DL2", 0, 0, - { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, - { "PENTAX *ist DL", 0, 0, - { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, - { "PENTAX *ist DS2", 0, 0, - { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, - { "PENTAX *ist DS", 0, 0, - { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, - { "PENTAX *ist D", 0, 0, - { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, - { "PENTAX K10D", 0, 0, - { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, - { "PENTAX K1", 0, 0, - { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, - { "PENTAX K20D", 0, 0, - { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, - { "PENTAX K200D", 0, 0, - { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, - { "PENTAX K2000", 0, 0, - { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, - { "PENTAX K-m", 0, 0, - { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, - { "Panasonic DMC-FZ8", 0, 0xf7f0, - { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, - { "Panasonic DMC-FZ18", 0, 0, - { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, - { "Panasonic DMC-FZ28", 15, 0xfff, - { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, - { "Panasonic DMC-FZ30", 0, 0xf94c, - { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, - { "Panasonic DMC-FZ50", 0, 0xfff0, /* aka "LEICA V-LUX1" */ - { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, - { "Panasonic DMC-L10", 15, 0xf96, - { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, - { "Panasonic DMC-L1", 0, 0xf7fc, /* aka "LEICA DIGILUX 3" */ - { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, - { "Panasonic DMC-LC1", 0, 0, /* aka "LEICA DIGILUX 2" */ - { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, - { "Panasonic DMC-LX1", 0, 0xf7f0, /* aka "LEICA D-LUX2" */ - { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, - { "Panasonic DMC-LX2", 0, 0, /* aka "LEICA D-LUX3" */ - { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, - { "Panasonic DMC-LX3", 15, 0xfff, /* aka "LEICA D-LUX4" */ - { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, - { "Panasonic DMC-FX150", 15, 0xfff, - { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, - { "Panasonic DMC-G1", 15, 0xfff, - { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, - { "Phase One H 20", 0, 0, /* DJC */ - { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, - { "Phase One P 2", 0, 0, - { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, - { "Phase One P 30", 0, 0, - { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, - { "Phase One P 45", 0, 0, - { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, - { "SAMSUNG GX-1", 0, 0, - { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, - { "Sinar", 0, 0, /* DJC */ - { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, - { "SONY DSC-F828", 491, 0, - { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, - { "SONY DSC-R1", 512, 0, - { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, - { "SONY DSC-V3", 0, 0, - { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, - { "SONY DSLR-A100", 0, 0xfeb, - { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, - { "SONY DSLR-A200", 0, 0, - { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, - { "SONY DSLR-A300", 0, 0, - { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, - { "SONY DSLR-A350", 0, 0xffc, - { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, - { "SONY DSLR-A700", 254, 0x1ffe, - { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, - { "SONY DSLR-A900", 254, 0x1ffe, - { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } } - }; - double cam_xyz[4][3]; - char name[130]; - int i, j; - - sprintf (name, "%s %s", p_make, p_model); - for (i=0; i < sizeof table / sizeof *table; i++) - if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { - if (table[i].t_black) black = (ushort) table[i].t_black; - if (table[i].t_maximum) maximum = (ushort) table[i].t_maximum; - for (j=0; j < 12; j++) -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.color.cam_xyz[0][j] = -#endif - cam_xyz[0][j] = table[i].trans[j] / 10000.0; - cam_xyz_coeff (cam_xyz); - break; - } -} - -void CLASS simple_coeff (int index) -{ - static const float table[][12] = { - /* index 0 -- all Foveon cameras */ - { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, - /* index 1 -- Kodak DC20 and DC25 */ - { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, - /* index 2 -- Logitech Fotoman Pixtura */ - { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, - /* index 3 -- Nikon E880, E900, and E990 */ - { -1.936280, 1.800443, -1.448486, 2.584324, - 1.405365, -0.524955, -0.289090, 0.408680, - -1.204965, 1.082304, 2.941367, -1.818705 } - }; - int i, c; - - for (raw_color = i=0; i < 3; i++) - FORCC rgb_cam[i][c] = table[index][i*colors+c]; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.rgb_cam_state = LIBRAW_COLORSTATE_CALCULATED; -#endif -} - -short CLASS guess_byte_order (int words) -{ - uchar test[4][2]; - int t=2, msb; - double diff, sum[2] = {0,0}; - - fread (test[0], 2, 2, ifp); - for (words-=2; words--; ) { - fread (test[t], 2, 1, ifp); - for (msb=0; msb < 2; msb++) { - diff = (test[t^2][msb] << 8 | test[t^2][!msb]) - - (test[t ][msb] << 8 | test[t ][!msb]); - sum[msb] += diff*diff; - } - t = (t+1) & 3; - } - return sum[0] < sum[1] ? 0x4d4d : 0x4949; -} - -/* - Identify which camera created this file, and set global variables - accordingly. - */ -void CLASS identify() -{ - char head[32], *cp; - unsigned hlen, fsize, i, c, is_canon; - struct jhead jh; - static const struct { - int fsize; - char t_make[12], t_model[19], withjpeg; - } table[] = { - { 62464, "Kodak", "DC20" ,0 }, - { 124928, "Kodak", "DC20" ,0 }, - { 1652736, "Kodak", "DCS200" ,0 }, - { 4159302, "Kodak", "C330" ,0 }, - { 4162462, "Kodak", "C330" ,0 }, - { 460800, "Kodak", "C603v" ,0 }, - { 614400, "Kodak", "C603v" ,0 }, - { 6163328, "Kodak", "C603" ,0 }, - { 6166488, "Kodak", "C603" ,0 }, - { 9116448, "Kodak", "C603y" ,0 }, - { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */ - { 614400, "Kodak", "KAI-0340" ,0 }, - { 787456, "Creative", "PC-CAM 600" ,0 }, - { 1138688, "Minolta", "RD175" ,0 }, - { 3840000, "Foculus", "531C" ,0 }, - { 786432, "AVT", "F-080C" ,0 }, - { 1447680, "AVT", "F-145C" ,0 }, - { 1920000, "AVT", "F-201C" ,0 }, - { 5067304, "AVT", "F-510C" ,0 }, - { 10134608, "AVT", "F-510C" ,0 }, - { 16157136, "AVT", "F-810C" ,0 }, - { 1409024, "Sony", "XCD-SX910CR" ,0 }, - { 2818048, "Sony", "XCD-SX910CR" ,0 }, - { 3884928, "Micron", "2010" ,0 }, - { 6624000, "Pixelink", "A782" ,0 }, - { 13248000, "Pixelink", "A782" ,0 }, - { 6291456, "RoverShot","3320AF" ,0 }, - { 6553440, "Canon", "PowerShot A460" ,0 }, - { 6653280, "Canon", "PowerShot A530" ,0 }, - { 6573120, "Canon", "PowerShot A610" ,0 }, - { 9219600, "Canon", "PowerShot A620" ,0 }, - { 10341600, "Canon", "PowerShot A720" ,0 }, - { 10383120, "Canon", "PowerShot A630" ,0 }, - { 12945240, "Canon", "PowerShot A640" ,0 }, - { 15636240, "Canon", "PowerShot A650" ,0 }, - { 5298000, "Canon", "PowerShot SD300" ,0 }, - { 7710960, "Canon", "PowerShot S3 IS" ,0 }, - { 5939200, "OLYMPUS", "C770UZ" ,0 }, - { 1581060, "NIKON", "E900" ,1 }, /* or E900s,E910 */ - { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */ - { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */ - { 4771840, "NIKON", "E990" ,1 }, /* or E995, Oly C3030Z */ - { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */ - { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */ - { 5865472, "NIKON", "E4500" ,1 }, - { 7438336, "NIKON", "E5000" ,1 }, /* or E5700 */ - { 8998912, "NIKON", "COOLPIX S6" ,1 }, - { 1976352, "CASIO", "QV-2000UX" ,1 }, - { 3217760, "CASIO", "QV-3*00EX" ,1 }, - { 6218368, "CASIO", "QV-5700" ,1 }, - { 6054400, "CASIO", "QV-R41" ,1 }, - { 7530816, "CASIO", "QV-R51" ,1 }, - { 7684000, "CASIO", "QV-4000" ,1 }, - { 4948608, "CASIO", "EX-S100" ,1 }, - { 7542528, "CASIO", "EX-Z50" ,1 }, - { 7753344, "CASIO", "EX-Z55" ,1 }, - { 7426656, "CASIO", "EX-P505" ,1 }, - { 9313536, "CASIO", "EX-P600" ,1 }, - { 10979200, "CASIO", "EX-P700" ,1 }, - { 3178560, "PENTAX", "Optio S" ,1 }, - { 4841984, "PENTAX", "Optio S" ,1 }, - { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i, CASIO EX-Z4 */ - { 10702848, "PENTAX", "Optio 750Z" ,1 }, - { 16098048, "SAMSUNG", "S85" ,1 }, - { 16215552, "SAMSUNG", "S85" ,1 }, - { 12582980, "Sinar", "" ,0 }, - { 33292868, "Sinar", "" ,0 }, - { 44390468, "Sinar", "" ,0 } }; - static const char *corp[] = - { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX", - "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar", "Phase One", - "SAMSUNG", "Mamiya" }; - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,0,2); -#endif - - tiff_flip = flip = filters = -1; /* 0 is valid, so -1 is unknown */ - raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; - maximum = height = width = top_margin = left_margin = 0; - cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; - iso_speed = shutter = aperture = focal_len = unique_id = 0; - memset (gpsdata, 0, sizeof gpsdata); - memset (white, 0, sizeof white); - thumb_offset = thumb_length = thumb_width = thumb_height = 0; - load_raw = thumb_load_raw = 0; - write_thumb = &CLASS jpeg_thumb; - data_offset = meta_length = tiff_bps = tiff_compress = 0; - kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; - timestamp = shot_order = tiff_samples = black = is_foveon = 0; - mix_green = profile_length = data_error = zero_is_bad = 0; - pixel_aspect = is_raw = raw_color = use_gamma = 1; - tile_width = tile_length = INT_MAX; - for (i=0; i < 4; i++) { - cam_mul[i] = i == 1; - pre_mul[i] = i < 3; - FORC3 cmatrix[c][i] = 0; - FORC3 rgb_cam[c][i] = c == i; - } -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cmatrix_state = LIBRAW_COLORSTATE_INIT; - color_flags.rgb_cam_state = LIBRAW_COLORSTATE_INIT; - color_flags.pre_mul_state = LIBRAW_COLORSTATE_INIT; - color_flags.cam_mul_state = LIBRAW_COLORSTATE_INIT; -#endif - colors = 3; - tiff_bps = 12; - for (i=0; i < 0x4000; i++) curve[i] = i; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.curve_state = LIBRAW_COLORSTATE_INIT; -#endif - - order = get2(); - hlen = get4(); - fseek (ifp, 0, SEEK_SET); - fread (head, 1, 32, ifp); - fseek (ifp, 0, SEEK_END); - fsize = ftell(ifp); - if ((cp = (char *) memmem (head, 32, "MMMM", 4)) || - (cp = (char *) memmem (head, 32, "IIII", 4))) { - parse_phase_one (cp-head); - if (cp-head) parse_tiff(0); - } else if (order == 0x4949 || order == 0x4d4d) { - if (!memcmp (head+6,"HEAPCCDR",8)) { - data_offset = hlen; - parse_ciff (hlen, fsize - hlen); - } else { - parse_tiff(0); - } - } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && - !memcmp (head+6,"Exif",4)) { - fseek (ifp, 4, SEEK_SET); - data_offset = 4 + get2(); - fseek (ifp, data_offset, SEEK_SET); - if (fgetc(ifp) != 0xff) - parse_tiff(12); - thumb_offset = 0; - } else if (!memcmp (head+25,"ARECOYK",7)) { - strcpy (make, "Contax"); - strcpy (model,"N Digital"); - fseek (ifp, 33, SEEK_SET); - get_timestamp(1); - fseek (ifp, 60, SEEK_SET); - FORC4 cam_mul[c ^ (c >> 1)] = get4(); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.cam_mul_state = LIBRAW_COLORSTATE_LOADED; -#endif - } else if (!strcmp (head, "PXN")) { - strcpy (make, "Logitech"); - strcpy (model,"Fotoman Pixtura"); - } else if (!strcmp (head, "qktk")) { - strcpy (make, "Apple"); - strcpy (model,"QuickTake 100"); - } else if (!strcmp (head, "qktn")) { - strcpy (make, "Apple"); - strcpy (model,"QuickTake 150"); - } else if (!memcmp (head,"FUJIFILM",8)) { - fseek (ifp, 84, SEEK_SET); - thumb_offset = get4(); - thumb_length = get4(); - fseek (ifp, 92, SEEK_SET); - parse_fuji (get4()); - if (thumb_offset > 120) { - fseek (ifp, 120, SEEK_SET); - is_raw += (i = get4()) && 1; - if (is_raw == 2 && shot_select) - parse_fuji (i); - } - fseek (ifp, 100, SEEK_SET); - data_offset = get4(); - parse_tiff (thumb_offset+12); - } else if (!memcmp (head,"RIFF",4)) { - fseek (ifp, 0, SEEK_SET); - parse_riff(); - } else if (!memcmp (head,"\0\001\0\001\0@",6)) { - fseek (ifp, 6, SEEK_SET); - fread (make, 1, 8, ifp); - fread (model, 1, 8, ifp); - fread (model2, 1, 16, ifp); - data_offset = get2(); - get2(); - raw_width = get2(); - raw_height = get2(); - load_raw = &CLASS nokia_load_raw; - filters = 0x61616161; - } else if (!memcmp (head,"DSC-Image",9)) - parse_rollei(); - else if (!memcmp (head,"PWAD",4)) - parse_sinar_ia(); - else if (!memcmp (head,"\0MRM",4)) - parse_minolta(0); - else if (!memcmp (head,"FOVb",4)) - parse_foveon(); - else if (!memcmp (head,"CI",2)) - parse_cine(); - else - for (i=0; i < sizeof table / sizeof *table; i++) - if (fsize == table[i].fsize) { - strcpy (make, table[i].t_make ); - strcpy (model, table[i].t_model); - if (table[i].withjpeg) - parse_external_jpeg(); - } - if (make[0] == 0) parse_smal (0, fsize); - if (make[0] == 0) parse_jpeg (is_raw = 0); - - for (i=0; i < sizeof corp / sizeof *corp; i++) - if (strstr (make, corp[i])) /* Simplify company names */ - strcpy (make, corp[i]); - if (!strncmp (make,"KODAK",5)) - make[16] = model[16] = 0; - cp = make + strlen(make); /* Remove trailing spaces */ - while (*--cp == ' ') *cp = 0; - cp = model + strlen(model); - while (*--cp == ' ') *cp = 0; - i = strlen(make); /* Remove make from model */ - if (!strncasecmp (model, make, i) && model[i++] == ' ') - memmove (model, model+i, 64-i); - if (!strncmp (model,"Digital Camera ",15)) - strcpy (model, model+15); - desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; - if (!is_raw) goto notraw; - - if (!maximum) maximum = (1 << tiff_bps) - 1; - if (!height) height = raw_height; - if (!width) width = raw_width; - if (fuji_width) { - width = height + fuji_width; - height = width - 1; - pixel_aspect = 1; - } - if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ - { height = 2616; width = 3896; } - if (height == 3136 && width == 4864) /* Pentax K20D */ - { height = 3124; width = 4688; } - if (height == 3014 && width == 4096) /* Ricoh GX200 */ - width = 4014; - if (dng_version) { - if (filters == UINT_MAX) filters = 0; - if (filters) is_raw = tiff_samples; - else colors = tiff_samples; - if (tiff_compress == 1) - load_raw = &CLASS adobe_dng_load_raw_nc; - if (tiff_compress == 7) - load_raw = &CLASS adobe_dng_load_raw_lj; - goto dng_skip; - } - if ((is_canon = !strcmp(make,"Canon"))) - load_raw = memcmp (head+6,"HEAPCCDR",8) ? - &CLASS lossless_jpeg_load_raw : &CLASS canon_compressed_load_raw; - if (!strcmp(make,"NIKON")) { - if (!load_raw) - load_raw = &CLASS packed_12_load_raw; - if (model[0] == 'E') - load_flags |= !data_offset << 2 | 2; - } - if (!strcmp(make,"CASIO")) { - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7f; - } - -/* Set parameters based on camera name (for non-DNG files). */ - - if (is_foveon) { - if (height*2 < width) pixel_aspect = 0.5; - if (height > width) pixel_aspect = 2; - filters = 0; - load_raw = &CLASS foveon_load_raw; - simple_coeff(0); - } else if (is_canon && tiff_bps == 15) { - switch (width) { - case 3344: width -= 66; - case 3872: width -= 6; - } - filters = 0; - load_raw = &CLASS canon_sraw_load_raw; - } else if (!strcmp(model,"PowerShot 600")) { - height = 613; - width = 854; - raw_width = 896; - pixel_aspect = 607/628.0; - colors = 4; - filters = 0xe1e4e1e4; - load_raw = &CLASS canon_600_load_raw; - } else if (!strcmp(model,"PowerShot A5") || - !strcmp(model,"PowerShot A5 Zoom")) { - height = 773; - width = 960; - raw_width = 992; - pixel_aspect = 256/235.0; - colors = 4; - filters = 0x1e4e1e4e; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A50")) { - height = 968; - width = 1290; - raw_width = 1320; - colors = 4; - filters = 0x1b4e4b1e; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot Pro70")) { - height = 1024; - width = 1552; - colors = 4; - filters = 0x1e4b4e1b; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot SD300")) { - height = 1752; - width = 2344; - raw_height = 1766; - raw_width = 2400; - top_margin = 12; - left_margin = 12; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A460")) { - height = 1960; - width = 2616; - raw_height = 1968; - raw_width = 2664; - top_margin = 4; - left_margin = 4; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A530")) { - height = 1984; - width = 2620; - raw_height = 1992; - raw_width = 2672; - top_margin = 6; - left_margin = 10; - load_raw = &CLASS canon_a5_load_raw; - raw_color = 0; - } else if (!strcmp(model,"PowerShot A610")) { - if (canon_s2is()) strcpy (model+10, "S2 IS"); - height = 1960; - width = 2616; - raw_height = 1968; - raw_width = 2672; - top_margin = 8; - left_margin = 12; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A620")) { - height = 2328; - width = 3112; - raw_height = 2340; - raw_width = 3152; - top_margin = 12; - left_margin = 36; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A720")) { - height = 2472; - width = 3298; - raw_height = 2480; - raw_width = 3336; - top_margin = 5; - left_margin = 6; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A630")) { - height = 2472; - width = 3288; - raw_height = 2484; - raw_width = 3344; - top_margin = 6; - left_margin = 12; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A640")) { - height = 2760; - width = 3672; - raw_height = 2772; - raw_width = 3736; - top_margin = 6; - left_margin = 12; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A650")) { - height = 3024; - width = 4032; - raw_height = 3048; - raw_width = 4104; - top_margin = 12; - left_margin = 48; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot S3 IS")) { - height = 2128; - width = 2840; - raw_height = 2136; - raw_width = 2888; - top_margin = 8; - left_margin = 44; - load_raw = &CLASS canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot Pro90 IS")) { - width = 1896; - colors = 4; - filters = 0xb4b4b4b4; - } else if (is_canon && raw_width == 2144) { - height = 1550; - width = 2088; - top_margin = 8; - left_margin = 4; - if (!strcmp(model,"PowerShot G1")) { - colors = 4; - filters = 0xb4b4b4b4; - } - } else if (is_canon && raw_width == 2224) { - height = 1448; - width = 2176; - top_margin = 6; - left_margin = 48; - } else if (is_canon && raw_width == 2376) { - height = 1720; - width = 2312; - top_margin = 6; - left_margin = 12; - } else if (is_canon && raw_width == 2672) { - height = 1960; - width = 2616; - top_margin = 6; - left_margin = 12; - } else if (is_canon && raw_width == 3152) { - height = 2056; - width = 3088; - top_margin = 12; - left_margin = 64; - if (unique_id == 0x80000170) - adobe_coeff ("Canon","EOS 300D"); - } else if (is_canon && raw_width == 3160) { - height = 2328; - width = 3112; - top_margin = 12; - left_margin = 44; - } else if (is_canon && raw_width == 3344) { - height = 2472; - width = 3288; - top_margin = 6; - left_margin = 4; - } else if (!strcmp(model,"EOS D2000C")) { - filters = 0x61616161; - black = curve[200]; - } else if (is_canon && raw_width == 3516) { - top_margin = 14; - left_margin = 42; - if (unique_id == 0x80000189) - adobe_coeff ("Canon","EOS 350D"); - goto canon_cr2; - } else if (is_canon && raw_width == 3596) { - top_margin = 12; - left_margin = 74; - goto canon_cr2; - } else if (is_canon && raw_width == 3944) { - height = 2602; - width = 3908; - top_margin = 18; - left_margin = 30; - } else if (is_canon && raw_width == 3948) { - top_margin = 18; - left_margin = 42; - height -= 2; - if (unique_id == 0x80000236) - adobe_coeff ("Canon","EOS 400D"); - if (unique_id == 0x80000254) - adobe_coeff ("Canon","EOS 1000D"); - goto canon_cr2; - } else if (is_canon && raw_width == 3984) { - top_margin = 20; - left_margin = 76; - height -= 2; - goto canon_cr2; - } else if (is_canon && raw_width == 4104) { - height = 3024; - width = 4032; - top_margin = 12; - left_margin = 48; - } else if (is_canon && raw_width == 4312) { - top_margin = 18; - left_margin = 22; - height -= 2; - if (unique_id == 0x80000176) - adobe_coeff ("Canon","EOS 450D"); - goto canon_cr2; - } else if (is_canon && raw_width == 4476) { - top_margin = 34; - left_margin = 90; - goto canon_cr2; - } else if (is_canon && raw_width == 4480) { - height = 3326; - width = 4432; - top_margin = 10; - left_margin = 12; - filters = 0x49494949; - } else if (is_canon && raw_width == 1208) { - top_margin = 51; - left_margin = 62; - raw_width = width *= 4; - goto canon_cr2; - } else if (is_canon && raw_width == 1448) { - top_margin = 51; - left_margin = 158; - raw_width = width *= 4; - goto canon_cr2; - } else if (is_canon && raw_width == 5108) { - top_margin = 13; - left_margin = 98; -canon_cr2: - height -= top_margin; - width -= left_margin; - } else if (is_canon && raw_width == 5712) { - height = 3752; - width = 5640; - top_margin = 20; - left_margin = 62; - } else if (!strcmp(model,"D1")) { - cam_mul[0] *= 256/527.0; - cam_mul[2] *= 256/317.0; - } else if (!strcmp(model,"D1X")) { - width -= 4; - pixel_aspect = 0.5; - } else if (!strcmp(model,"D40X") || - !strcmp(model,"D60") || - !strcmp(model,"D80")) { - height -= 3; - width -= 4; - } else if (!strcmp(model,"D3") || - !strcmp(model,"D700")) { - width -= 4; - left_margin = 2; - } else if (!strncmp(model,"D40",3) || - !strncmp(model,"D50",3) || - !strncmp(model,"D70",3)) { - width--; - } else if (!strcmp(model,"D90")) { - width -= 42; - } else if (!strcmp(model,"D100")) { - if (tiff_compress == 34713 && !nikon_is_compressed()) { - load_raw = &CLASS packed_12_load_raw; - load_flags |= 8; - raw_width = (width += 3) + 3; - } - } else if (!strcmp(model,"D200")) { - left_margin = 1; - width -= 4; - filters = 0x94949494; - } else if (!strncmp(model,"D2H",3)) { - left_margin = 6; - width -= 14; - } else if (!strncmp(model,"D2X",3)) { - if (width == 3264) width -= 32; - else width -= 8; - } else if (!strcmp(model,"D300")) { - width -= 32; - } else if (!strcmp(model,"COOLPIX P6000")) { - load_flags = 1; - filters = 0x94949494; - } else if (fsize == 1581060) { - height = 963; - width = 1287; - raw_width = 1632; - load_raw = &CLASS nikon_e900_load_raw; - maximum = 0x3f4; - colors = 4; - filters = 0x1e1e1e1e; - simple_coeff(3); - pre_mul[0] = 1.2085; - pre_mul[1] = 1.0943; - pre_mul[3] = 1.1103; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (fsize == 2465792) { - height = 1203; - width = 1616; - raw_width = 2048; - load_raw = &CLASS nikon_e900_load_raw; - colors = 4; - filters = 0x4b4b4b4b; - adobe_coeff ("NIKON","E950"); - } else if (fsize == 4771840) { - height = 1540; - width = 2064; - colors = 4; - filters = 0xe1e1e1e1; - load_raw = &CLASS packed_12_load_raw; - load_flags = 6; - if (!timestamp && nikon_e995()) - strcpy (model, "E995"); - if (strcmp(model,"E995")) { - filters = 0xb4b4b4b4; - simple_coeff(3); - pre_mul[0] = 1.196; - pre_mul[1] = 1.246; - pre_mul[2] = 1.018; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } - } else if (!strcmp(model,"E2100")) { - if (!timestamp && !nikon_e2100()) goto cp_e2500; - height = 1206; - width = 1616; - load_flags = 7; - } else if (!strcmp(model,"E2500")) { -cp_e2500: - strcpy (model, "E2500"); - height = 1204; - width = 1616; - colors = 4; - filters = 0x4b4b4b4b; - } else if (fsize == 4775936) { - height = 1542; - width = 2064; - load_raw = &CLASS packed_12_load_raw; - load_flags = 7; - pre_mul[0] = 1.818; - pre_mul[2] = 1.618; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - if (!timestamp) nikon_3700(); - if (model[0] == 'E' && atoi(model+1) < 3700) - filters = 0x49494949; - if (!strcmp(model,"Optio 33WR")) { - flip = 1; - filters = 0x16161616; - pre_mul[0] = 1.331; - pre_mul[2] = 1.820; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } - } else if (fsize == 5869568) { - height = 1710; - width = 2288; - filters = 0x16161616; - if (!timestamp && minolta_z2()) { - strcpy (make, "Minolta"); - strcpy (model,"DiMAGE Z2"); - } - load_raw = &CLASS packed_12_load_raw; - load_flags = 6 + (make[0] == 'M'); - } else if (!strcmp(model,"E4500")) { - height = 1708; - width = 2288; - colors = 4; - filters = 0xb4b4b4b4; - } else if (fsize == 7438336) { - height = 1924; - width = 2576; - colors = 4; - filters = 0xb4b4b4b4; - } else if (fsize == 8998912) { - height = 2118; - width = 2832; - maximum = 0xf83; - load_raw = &CLASS packed_12_load_raw; - load_flags = 7; - } else if (!strcmp(model,"FinePix S5100") || - !strcmp(model,"FinePix S5500")) { - load_raw = &CLASS unpacked_load_raw; - } else if (!strcmp(make,"FUJIFILM")) { - if (!strcmp(model+7,"S2Pro")) { - strcpy (model+7," S2Pro"); - height = 2144; - width = 2880; - flip = 6; - } else - maximum = 0x3e00; - if (is_raw == 2 && shot_select) - maximum = 0x2f00; - top_margin = (raw_height - height)/2; - left_margin = (raw_width - width )/2; - if (is_raw == 2) - data_offset += (shot_select > 0) * ( fuji_layout ? - (raw_width *= 2) : raw_height*raw_width*2 ); - fuji_width = width >> !fuji_layout; - width = (height >> fuji_layout) + fuji_width; - raw_height = height; - height = width - 1; - load_raw = &CLASS fuji_load_raw; - if (!(fuji_width & 1)) filters = 0x49494949; - } else if (!strcmp(model,"RD175")) { - height = 986; - width = 1534; - data_offset = 513; - filters = 0x61616161; - load_raw = &CLASS minolta_rd175_load_raw; - } else if (!strcmp(model,"KD-400Z")) { - height = 1712; - width = 2312; - raw_width = 2336; - goto konica_400z; - } else if (!strcmp(model,"KD-510Z")) { - goto konica_510z; - } else if (!strcasecmp(make,"MINOLTA")) { - load_raw = &CLASS unpacked_load_raw; - maximum = 0xfff; - if (!strncmp(model,"DiMAGE A",8)) { - if (!strcmp(model,"DiMAGE A200")) - filters = 0x49494949; - load_raw = &CLASS packed_12_load_raw; - } else if (!strncmp(model,"ALPHA",5) || - !strncmp(model,"DYNAX",5) || - !strncmp(model,"MAXXUM",6)) { - sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); - adobe_coeff (make, model+20); - load_raw = &CLASS packed_12_load_raw; - } else if (!strncmp(model,"DiMAGE G",8)) { - if (model[8] == '4') { - height = 1716; - width = 2304; - } else if (model[8] == '5') { -konica_510z: - height = 1956; - width = 2607; - raw_width = 2624; - } else if (model[8] == '6') { - height = 2136; - width = 2848; - } - data_offset += 14; - filters = 0x61616161; -konica_400z: - load_raw = &CLASS unpacked_load_raw; - maximum = 0x3df; - order = 0x4d4d; - } - } else if (!strcmp(model,"*ist DS")) { - height -= 2; - } else if (!strcmp(model,"K20D")) { - filters = 0x16161616; - } else if (!strcmp(model,"Optio S")) { - if (fsize == 3178560) { - height = 1540; - width = 2064; - load_raw = &CLASS eight_bit_load_raw; - cam_mul[0] *= 4; - cam_mul[2] *= 4; - pre_mul[0] = 1.391; - pre_mul[2] = 1.188; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else { - height = 1544; - width = 2068; - raw_width = 3136; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7c; - pre_mul[0] = 1.137; - pre_mul[2] = 1.453; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } - } else if (fsize == 6114240) { - height = 1737; - width = 2324; - raw_width = 3520; - load_raw = &CLASS packed_12_load_raw; - maximum = 0xf7a; - pre_mul[0] = 1.980; - pre_mul[2] = 1.570; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"Optio 750Z")) { - height = 2302; - width = 3072; - load_raw = &CLASS packed_12_load_raw; - load_flags = 7; - } else if (!strcmp(model,"S85")) { - height = 2448; - width = 3264; - raw_width = fsize/height/2; - order = 0x4d4d; - load_raw = &CLASS unpacked_load_raw; - maximum = 0xffff; - } else if (!strcmp(model,"STV680 VGA")) { - height = 484; - width = 644; - load_raw = &CLASS eight_bit_load_raw; - flip = 2; - filters = 0x16161616; - black = 16; - pre_mul[0] = 1.097; - pre_mul[2] = 1.128; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"KAI-0340")) { - height = 477; - width = 640; - order = 0x4949; - data_offset = 3840; - load_raw = &CLASS unpacked_load_raw; - pre_mul[0] = 1.561; - pre_mul[2] = 2.454; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"N95")) { - height = raw_height - (top_margin = 2); - } else if (!strcmp(model,"531C")) { - height = 1200; - width = 1600; - load_raw = &CLASS unpacked_load_raw; - filters = 0x49494949; - pre_mul[1] = 1.218; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"F-080C")) { - height = 768; - width = 1024; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"F-145C")) { - height = 1040; - width = 1392; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"F-201C")) { - height = 1200; - width = 1600; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"F-510C")) { - height = 1958; - width = 2588; - load_raw = fsize < 7500000 ? - &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; - maximum = 0xfff0; - } else if (!strcmp(model,"F-810C")) { - height = 2469; - width = 3272; - load_raw = &CLASS unpacked_load_raw; - maximum = 0xfff0; - } else if (!strcmp(model,"XCD-SX910CR")) { - height = 1024; - width = 1375; - raw_width = 1376; - filters = 0x49494949; - maximum = 0x3ff; - load_raw = fsize < 2000000 ? - &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; - } else if (!strcmp(model,"2010")) { - height = 1207; - width = 1608; - order = 0x4949; - filters = 0x16161616; - data_offset = 3212; - maximum = 0x3ff; - load_raw = &CLASS unpacked_load_raw; - } else if (!strcmp(model,"A782")) { - height = 3000; - width = 2208; - filters = 0x61616161; - load_raw = fsize < 10000000 ? - &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; - maximum = 0xffc0; - } else if (!strcmp(model,"3320AF")) { - height = 1536; - raw_width = width = 2048; - filters = 0x61616161; - load_raw = &CLASS unpacked_load_raw; - maximum = 0x3ff; - pre_mul[0] = 1.717; - pre_mul[2] = 1.138; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - fseek (ifp, 0x300000, SEEK_SET); - if ((order = guess_byte_order(0x10000)) == 0x4d4d) { - height -= (top_margin = 16); - width -= (left_margin = 28); - maximum = 0xf5c0; - strcpy (make, "ISG"); - model[0] = 0; - } - } else if (!strcmp(make,"Hasselblad")) { - if (load_raw == &CLASS lossless_jpeg_load_raw) - load_raw = &CLASS hasselblad_load_raw; - if (raw_width == 7262) { - height = 5444; - width = 7248; - top_margin = 4; - left_margin = 7; - filters = 0x61616161; - } else if (raw_width == 4090) { - strcpy (model, "V96C"); - height -= (top_margin = 6); - width -= (left_margin = 3) + 7; - filters = 0x61616161; - } - } else if (!strcmp(make,"Sinar")) { - if (!memcmp(head,"8BPS",4)) { - fseek (ifp, 14, SEEK_SET); - height = get4(); - width = get4(); - filters = 0x61616161; - data_offset = 68; - } - if (!load_raw) load_raw = &CLASS unpacked_load_raw; - maximum = 0x3fff; - } else if (!strcmp(make,"Leaf")) { - maximum = 0x3fff; - fseek (ifp, data_offset, SEEK_SET); - if (ljpeg_start (&jh, 1) && jh.bits == 15) - maximum = 0x1fff; - if (tiff_samples > 1) filters = 0; - if (tiff_samples > 1 || tile_length < raw_height) - load_raw = &CLASS leaf_hdr_load_raw; - if ((width | height) == 2048) { - if (tiff_samples == 1) { - filters = 1; - strcpy (cdesc, "RBTG"); - strcpy (model, "CatchLight"); - top_margin = 8; left_margin = 18; height = 2032; width = 2016; - } else { - strcpy (model, "DCB2"); - top_margin = 10; left_margin = 16; height = 2028; width = 2022; - } - } else if (width+height == 3144+2060) { - if (!model[0]) strcpy (model, "Cantare"); - if (width > height) { - top_margin = 6; left_margin = 32; height = 2048; width = 3072; - filters = 0x61616161; - } else { - left_margin = 6; top_margin = 32; width = 2048; height = 3072; - filters = 0x16161616; - } - if (!cam_mul[0] || model[0] == 'V') filters = 0; - else is_raw = tiff_samples; - } else if (width == 2116) { - strcpy (model, "Valeo 6"); - height -= 2 * (top_margin = 30); - width -= 2 * (left_margin = 55); - filters = 0x49494949; - } else if (width == 3171) { - strcpy (model, "Valeo 6"); - height -= 2 * (top_margin = 24); - width -= 2 * (left_margin = 24); - filters = 0x16161616; - } - } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) { - maximum = 0xfff0; - if ((fsize-data_offset) / (width*8/7) == height) - load_raw = &CLASS panasonic_load_raw; - if (!load_raw) load_raw = &CLASS unpacked_load_raw; - switch (width) { - case 2568: - adobe_coeff ("Panasonic","DMC-LC1"); break; - case 3130: - left_margin = -14; - case 3170: - left_margin += 18; - width = 3096; - if (height > 2326) { - height = 2326; - top_margin = 13; - filters = 0x49494949; - } - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-FZ8"); break; - case 3213: - width -= 27; - case 3177: - width -= 10; - filters = 0x49494949; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-L1"); break; - case 3304: - width -= 17; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-FZ30"); break; - case 3330: - width += 43; - left_margin = -6; - maximum = 0xf7f0; - case 3370: - width -= 82; - left_margin += 15; - if (height > 2480) - height = 2480 - (top_margin = 10); - filters = 0x49494949; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-FZ18"); break; - case 3690: - height -= 2; - left_margin = -14; - maximum = 0xf7f0; - case 3770: - width = 3672; - if (--height == 2798 && (height = 2760)) - top_margin = 15; - else filters = 0x49494949; - left_margin += 17; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-FZ50"); break; - case 3710: - width = 3682; - filters = 0x49494949; - adobe_coeff ("Panasonic","DMC-L10"); break; - case 3724: - width -= 14; - case 3836: - width -= 42; -lx3: filters = 0x16161616; - if (make[0] != 'P') - adobe_coeff ("Panasonic","DMC-LX3"); - break; - case 3880: - width -= 22; - left_margin = 6; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-LX1"); break; - case 4060: - width = 3982; - if (height == 2250) goto lx3; - width = 4018; - filters = 0x49494949; - zero_is_bad = 1; - adobe_coeff ("Panasonic","DMC-G1"); break; - case 4290: - height += 38; - left_margin = -14; - filters = 0x49494949; - case 4330: - width = 4248; - if ((height -= 39) == 2400) - top_margin = 15; - left_margin += 17; - adobe_coeff ("Panasonic","DMC-LX2"); break; - case 4508: - height -= 6; - width = 4429; - filters = 0x16161616; - adobe_coeff ("Panasonic","DMC-FX150"); break; - } - } else if (!strcmp(model,"C770UZ")) { - height = 1718; - width = 2304; - filters = 0x16161616; - load_raw = &CLASS packed_12_load_raw; - load_flags = 7; - } else if (!strcmp(make,"OLYMPUS")) { - height += height & 1; - filters = exif_cfa; - if (load_raw == &CLASS olympus_e410_load_raw) { - black >>= 4; - } else if (!strcmp(model,"E-10") || - !strncmp(model,"E-20",4)) { - black <<= 2; - } else if (!strcmp(model,"E-300") || - !strcmp(model,"E-500")) { - width -= 20; - if (load_raw == &CLASS unpacked_load_raw) { - maximum = 0xfc30; - black = 0; - } - } else if (!strcmp(model,"E-330")) { - width -= 30; - if (load_raw == &CLASS unpacked_load_raw) - maximum = 0xf790; - } else if (!strcmp(model,"SP550UZ")) { - thumb_length = fsize - (thumb_offset = 0xa39800); - thumb_height = 480; - thumb_width = 640; - } - } else if (!strcmp(model,"N Digital")) { - height = 2047; - width = 3072; - filters = 0x61616161; - data_offset = 0x1a00; - load_raw = &CLASS packed_12_load_raw; - } else if (!strcmp(model,"DSC-F828")) { - width = 3288; - left_margin = 5; - data_offset = 862144; - load_raw = &CLASS sony_load_raw; - filters = 0x9c9c9c9c; - colors = 4; - strcpy (cdesc, "RGBE"); - } else if (!strcmp(model,"DSC-V3")) { - width = 3109; - left_margin = 59; - data_offset = 787392; - load_raw = &CLASS sony_load_raw; - } else if (!strcmp(make,"SONY") && raw_width == 3984) { - adobe_coeff ("SONY","DSC-R1"); - width = 3925; - order = 0x4d4d; - } else if (!strcmp(model,"DSLR-A100")) { - height--; - } else if (!strcmp(model,"DSLR-A350")) { - height -= 4; - } else if (!strcmp(model,"C603v")) { - height = 480; - width = 640; - goto c603v; - } else if (!strcmp(model,"C603y")) { - height = 2134; - width = 2848; -c603v: - filters = 0; - load_raw = &CLASS kodak_yrgb_load_raw; - } else if (!strcmp(model,"C603")) { - raw_height = height = 2152; - raw_width = width = 2864; - goto c603; - } else if (!strcmp(model,"C330")) { - height = 1744; - width = 2336; - raw_height = 1779; - raw_width = 2338; - top_margin = 33; - left_margin = 1; -c603: - order = 0x4949; - if ((data_offset = fsize - raw_height*raw_width)) { - fseek (ifp, 168, SEEK_SET); - read_shorts (curve, 256); -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.curve_state = LIBRAW_COLORSTATE_LOADED; -#endif - } else use_gamma = 0; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcasecmp(make,"KODAK")) { - if (filters == UINT_MAX) filters = 0x61616161; - if (!strncmp(model,"NC2000",6)) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"EOSDCS3B")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"EOSDCS1")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS420")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS460")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS460A")) { - width -= 4; - left_margin = 2; - colors = 1; - filters = 0; - } else if (!strcmp(model,"DCS660M")) { - black = 214; - colors = 1; - filters = 0; - } else if (!strcmp(model,"DCS760M")) { - colors = 1; - filters = 0; - } - if (!strcmp(model+4,"20X")) - strcpy (cdesc, "MYCY"); - if (strstr(model,"DC25")) { - strcpy (model, "DC25"); - data_offset = 15424; - } - if (!strncmp(model,"DC2",3)) { - height = 242; - if (fsize < 100000) { - raw_width = 256; width = 249; - pixel_aspect = (4.0*height) / (3.0*width); - } else { - raw_width = 512; width = 501; - pixel_aspect = (493.0*height) / (373.0*width); - } - data_offset += raw_width + 1; - colors = 4; - filters = 0x8d8d8d8d; - simple_coeff(1); - pre_mul[1] = 1.179; - pre_mul[2] = 1.209; - pre_mul[3] = 1.036; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"40")) { - strcpy (model, "DC40"); - height = 512; - width = 768; - data_offset = 1152; - load_raw = &CLASS kodak_radc_load_raw; - } else if (strstr(model,"DC50")) { - strcpy (model, "DC50"); - height = 512; - width = 768; - data_offset = 19712; - load_raw = &CLASS kodak_radc_load_raw; - } else if (strstr(model,"DC120")) { - strcpy (model, "DC120"); - height = 976; - width = 848; - pixel_aspect = height/0.75/width; - load_raw = tiff_compress == 7 ? - &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw; - } else if (!strcmp(model,"DCS200")) { - thumb_height = 128; - thumb_width = 192; - thumb_offset = 6144; - thumb_misc = 360; - write_thumb = &CLASS layer_thumb; - height = 1024; - width = 1536; - data_offset = 79872; - load_raw = &CLASS eight_bit_load_raw; - black = 17; - } - } else if (!strcmp(model,"Fotoman Pixtura")) { - height = 512; - width = 768; - data_offset = 3632; - load_raw = &CLASS kodak_radc_load_raw; - filters = 0x61616161; - simple_coeff(2); - } else if (!strcmp(model,"QuickTake 100")) { - fseek (ifp, 544, SEEK_SET); - height = get2(); - width = get2(); - data_offset = (get4(),get2()) == 30 ? 738:736; - if (height > width) { - SWAP(height,width); - fseek (ifp, data_offset-6, SEEK_SET); - flip = ~get2() & 3 ? 5:6; - } - load_raw = &CLASS quicktake_100_load_raw; - filters = 0x61616161; - } else if (!strcmp(model,"QuickTake 150")) { - data_offset = 738 - head[5]; - if (head[5]) strcpy (model+10, "200"); - load_raw = &CLASS kodak_radc_load_raw; - height = 480; - width = 640; - filters = 0x61616161; - } else if (!strcmp(make,"Rollei") && !load_raw) { - switch (raw_width) { - case 1316: - height = 1030; - width = 1300; - top_margin = 1; - left_margin = 6; - break; - case 2568: - height = 1960; - width = 2560; - top_margin = 2; - left_margin = 8; - } - filters = 0x16161616; - load_raw = &CLASS rollei_load_raw; - pre_mul[0] = 1.8; - pre_mul[2] = 1.3; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"PC-CAM 600")) { - height = 768; - data_offset = width = 1024; - filters = 0x49494949; - load_raw = &CLASS eight_bit_load_raw; - pre_mul[0] = 1.14; - pre_mul[2] = 2.73; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"QV-2000UX")) { - height = 1208; - width = 1632; - data_offset = width * 2; - load_raw = &CLASS eight_bit_load_raw; - } else if (fsize == 3217760) { - height = 1546; - width = 2070; - raw_width = 2080; - load_raw = &CLASS eight_bit_load_raw; - } else if (!strcmp(model,"QV-4000")) { - height = 1700; - width = 2260; - load_raw = &CLASS unpacked_load_raw; - maximum = 0xffff; - } else if (!strcmp(model,"QV-5700")) { - height = 1924; - width = 2576; - load_raw = &CLASS casio_qv5700_load_raw; - } else if (!strcmp(model,"QV-R41")) { - height = 1720; - width = 2312; - raw_width = 3520; - left_margin = 2; - } else if (!strcmp(model,"QV-R51")) { - height = 1926; - width = 2580; - raw_width = 3904; - pre_mul[0] = 1.340; - pre_mul[2] = 1.672; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"EX-S100")) { - height = 1544; - width = 2058; - raw_width = 3136; - pre_mul[0] = 1.631; - pre_mul[2] = 1.106; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"EX-Z50")) { - height = 1931; - width = 2570; - raw_width = 3904; - pre_mul[0] = 2.529; - pre_mul[2] = 1.185; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"EX-Z55")) { - height = 1960; - width = 2570; - raw_width = 3904; - pre_mul[0] = 1.520; - pre_mul[2] = 1.316; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"EX-P505")) { - height = 1928; - width = 2568; - raw_width = 3852; - maximum = 0xfff; - pre_mul[0] = 2.07; - pre_mul[2] = 1.88; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (fsize == 9313536) { /* EX-P600 or QV-R61 */ - height = 2142; - width = 2844; - raw_width = 4288; - pre_mul[0] = 1.797; - pre_mul[2] = 1.219; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } else if (!strcmp(model,"EX-P700")) { - height = 2318; - width = 3082; - raw_width = 4672; - pre_mul[0] = 1.758; - pre_mul[2] = 1.504; -#ifdef LIBRAW_LIBRARY_BUILD - color_flags.pre_mul_state = LIBRAW_COLORSTATE_CONST; -#endif - } - if (!model[0]) - sprintf (model, "%dx%d", width, height); - if (filters == UINT_MAX) filters = 0x94949494; - if (raw_color) adobe_coeff (make, model); - if (thumb_offset && !thumb_height) { - fseek (ifp, thumb_offset, SEEK_SET); - if (ljpeg_start (&jh, 1)) { - thumb_width = jh.wide; - thumb_height = jh.high; - } - } -dng_skip: - if (!load_raw || height < 22) is_raw = 0; -#ifdef NO_JPEG - if (load_raw == &CLASS kodak_jpeg_load_raw) { -#ifdef DCRAW_VERBOSE - fprintf (stderr,_("%s: You must link dcraw with libjpeg!!\n"), ifname); -#endif - is_raw = 0; -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_NO_JPEGLIB; -#endif - } -#endif - if (!cdesc[0]) - strcpy (cdesc, colors == 3 ? "RGB":"GMCY"); - if (!raw_height) raw_height = height; - if (!raw_width ) raw_width = width; - if (filters && colors == 3) - for (i=0; i < 32; i+=4) { - if ((filters >> i & 15) == 9) - filters |= 2 << i; - if ((filters >> i & 15) == 6) - filters |= 8 << i; - } -notraw: - if (flip == -1) flip = tiff_flip; - if (flip == -1) flip = 0; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2); -#endif -} -void CLASS convert_to_rgb() -{ - int row, col, c, i, j, k; - ushort *img; - float out[3], out_cam[3][4]; - double num, inverse[3][3], bnd[2]={0,0}; - static const double xyzd50_srgb[3][3] = - { { 0.436083, 0.385083, 0.143055 }, - { 0.222507, 0.716888, 0.060608 }, - { 0.013930, 0.097097, 0.714022 } }; - static const double rgb_rgb[3][3] = - { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } }; - static const double adobe_rgb[3][3] = - { { 0.715146, 0.284856, 0.000000 }, - { 0.000000, 1.000000, 0.000000 }, - { 0.000000, 0.041166, 0.958839 } }; - static const double wide_rgb[3][3] = - { { 0.593087, 0.404710, 0.002206 }, - { 0.095413, 0.843149, 0.061439 }, - { 0.011621, 0.069091, 0.919288 } }; - static const double prophoto_rgb[3][3] = - { { 0.529317, 0.330092, 0.140588 }, - { 0.098368, 0.873465, 0.028169 }, - { 0.016879, 0.117663, 0.865457 } }; - static const double (*out_rgb[])[3] = - { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; - static const char *name[] = - { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; - static const unsigned phead[] = - { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, - 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; - unsigned pbody[] = - { 10, 0x63707274, 0, 36, /* cprt */ - 0x64657363, 0, 40, /* desc */ - 0x77747074, 0, 20, /* wtpt */ - 0x626b7074, 0, 20, /* bkpt */ - 0x72545243, 0, 14, /* rTRC */ - 0x67545243, 0, 14, /* gTRC */ - 0x62545243, 0, 14, /* bTRC */ - 0x7258595a, 0, 20, /* rXYZ */ - 0x6758595a, 0, 20, /* gXYZ */ - 0x6258595a, 0, 20 }; /* bXYZ */ - static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; - unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,0,2); -#endif - - bnd[gamm[1] >= 1] = 1; - if (gamm[1] && (gamm[1]-1)*(gamm[0]-1) <= 0) { - for (i=0; i < 36; i++) { - gamm[2] = (bnd[0] + bnd[1])/2; - bnd[(pow(gamm[2]/gamm[1],-gamm[0])-1)/gamm[0]-1/gamm[2] > -1] = gamm[2]; - } - gamm[3] = gamm[2]*(1/gamm[0]-1); - gamm[2] /= gamm[1]; - } - gamm[4] = 1 / (gamm[1]/2*SQR(gamm[2]) - gamm[3]*(1-gamm[2]) + - (1-pow(gamm[2],1+gamm[0]))*(1+gamm[3])/(1+gamm[0])) - 1; - - memcpy (out_cam, rgb_cam, sizeof out_cam); - raw_color |= colors == 1 || document_mode || - output_color < 1 || output_color > 5; - if (!raw_color) { - oprof = (unsigned *) calloc (phead[0], 1); - merror (oprof, "convert_to_rgb()"); - memcpy (oprof, phead, sizeof phead); - if (output_color == 5) oprof[4] = oprof[5]; - oprof[0] = 132 + 12*pbody[0]; - for (i=0; i < pbody[0]; i++) { - oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; - pbody[i*3+2] = oprof[0]; - oprof[0] += (pbody[i*3+3] + 3) & -4; - } - memcpy (oprof+32, pbody, sizeof pbody); - oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; - memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); - if (output_bps == 8 | gamma_16bit) - pcurve[3] = (short)(256/gamm[4]+0.5) << 16; - for (i=4; i < 7; i++) - memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve); - pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) { - for (num = k=0; k < 3; k++) - num += xyzd50_srgb[i][k] * inverse[j][k]; - oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5; - } - for (i=0; i < phead[0]/4; i++) - oprof[i] = htonl(oprof[i]); - strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw"); - strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]); - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (out_cam[i][j] = k=0; k < 3; k++) - out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; - } -#ifdef DCRAW_VERBOSE - if (verbose) - fprintf (stderr, raw_color ? _("Building histograms...\n") : - _("Converting to %s colorspace...\n"), name[output_color-1]); - -#endif -#ifdef LIBRAW_LIBRARY_BUILD - memset(histogram,0,sizeof(int)*LIBRAW_HISTOGRAM_SIZE*4); -#else - memset (histogram, 0, sizeof histogram); -#endif - for (img=image[0], row=0; row < height; row++) - for (col=0; col < width; col++, img+=4) { - if (!raw_color) { - out[0] = out[1] = out[2] = 0; - FORCC { - out[0] += out_cam[0][c] * img[c]; - out[1] += out_cam[1][c] * img[c]; - out[2] += out_cam[2][c] * img[c]; - } - FORC3 img[c] = CLIP((int) out[c]); - } - else if (document_mode) - img[0] = img[FC(row,col)]; - FORCC histogram[c][img[c] >> 3]++; - } - if (colors == 4 && output_color) colors = 3; - if (document_mode && filters) colors = 1; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,1,2); -#endif -} - -void CLASS fuji_rotate() -{ - int i, row, col; - double step; - float r, c, fr, fc; - unsigned ur, uc; - ushort wide, high, (*img)[4], (*pix)[4]; - - if (!fuji_width) return; -#ifdef DCRAW_VERBOSE - if (verbose) - fprintf (stderr,_("Rotating image 45 degrees...\n")); -#endif - fuji_width = (fuji_width - 1 + shrink) >> shrink; - step = sqrt(0.5); - wide = fuji_width / step; - high = (height - fuji_width) / step; - img = (ushort (*)[4]) calloc (wide*high, sizeof *img); - merror (img, "fuji_rotate()"); - -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,0,2); -#endif - - for (row=0; row < high; row++) - for (col=0; col < wide; col++) { - ur = r = fuji_width + (row-col)*step; - uc = c = (row+col)*step; - if (ur > height-2 || uc > width-2) continue; - fr = r - ur; - fc = c - uc; - pix = image + ur*width + uc; - for (i=0; i < colors; i++) - img[row*wide+col][i] = - (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + - (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; - } - free (image); - width = wide; - height = high; - image = img; - fuji_width = 0; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,1,2); -#endif -} - -void CLASS stretch() -{ - ushort newdim, (*img)[4], *pix0, *pix1; - int row, col, c; - double rc, frac; - - if (pixel_aspect == 1) return; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,0,2); -#endif -#ifdef DCRAW_VERBOSE - if (verbose) fprintf (stderr,_("Stretching the image...\n")); -#endif - if (pixel_aspect < 1) { - newdim = height / pixel_aspect + 0.5; - img = (ushort (*)[4]) calloc (width*newdim, sizeof *img); - merror (img, "stretch()"); - for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) { - frac = rc - (c = rc); - pix0 = pix1 = image[c*width]; - if (c+1 < height) pix1 += width*4; - for (col=0; col < width; col++, pix0+=4, pix1+=4) - FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; - } - height = newdim; - } else { - newdim = width * pixel_aspect + 0.5; - img = (ushort (*)[4]) calloc (height*newdim, sizeof *img); - merror (img, "stretch()"); - for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) { - frac = rc - (c = rc); - pix0 = pix1 = image[c]; - if (c+1 < width) pix1 += 4; - for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4) - FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; - } - width = newdim; - } - free (image); - image = img; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,1,2); -#endif -} - -int CLASS flip_index (int row, int col) -{ - if (flip & 4) SWAP(row,col); - if (flip & 2) row = iheight - 1 - row; - if (flip & 1) col = iwidth - 1 - col; - return row * iwidth + col; -} - -void CLASS gamma_lut (ushort lut[0x10000]) -{ - int perc, c, val, total, i; - float t_white=0, r; - -#ifdef LIBRAW_LIBRARY_BUILD - perc = width * height * imgdata.params.auto_bright_thr; -#else - perc = width * height * 0.01; /* 99th percentile white level */ -#endif - if (fuji_width) perc /= 2; - if ((highlight & ~2) || no_auto_bright) perc = -1; - FORCC { - for (val=0x2000, total=0; --val > 32; ) - if ((total += histogram[c][val]) > perc) break; - if (t_white < val) t_white = val; - } - t_white *= 8 / bright; - for (i=0; i < 0x10000; i++) { - r = i / t_white; - val = 65535 * ( !use_gamma ? r : - r <= gamm[2] ? r*gamm[1] : pow((double)r,gamm[0])*(1+gamm[3])-gamm[3]); - if (val > 65535) val = 65535; - lut[i] = val; - } -} - - -void CLASS tiff_set (ushort *ntag, - ushort tag, ushort type, int count, int val) -{ - struct tiff_tag *tt; - int c; - - tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; - tt->tag = tag; - tt->type = type; - tt->count = count; - if (type < 3 && count <= 4) - FORC(4) tt->val.c[c] = val >> (c << 3); - else if (type == 3 && count <= 2) - FORC(2) tt->val.s[c] = val >> (c << 4); - else tt->val.i = val; -} - -#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) - -void CLASS tiff_head (struct tiff_hdr *th, int full) -{ - int c, psize=0; - struct tm *t; - - memset (th, 0, sizeof *th); - th->t_order = htonl(0x4d4d4949) >> 16; - th->magic = 42; - th->ifd = 10; - if (full) { - tiff_set (&th->ntag, 254, 4, 1, 0); - tiff_set (&th->ntag, 256, 4, 1, width); - tiff_set (&th->ntag, 257, 4, 1, height); - tiff_set (&th->ntag, 258, 3, colors, output_bps); - if (colors > 2) - th->tag[th->ntag-1].val.i = TOFF(th->bps); - FORC4 th->bps[c] = output_bps; - tiff_set (&th->ntag, 259, 3, 1, 1); - tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1)); - } - tiff_set (&th->ntag, 270, 2, 512, TOFF(th->t_desc)); - tiff_set (&th->ntag, 271, 2, 64, TOFF(th->t_make)); - tiff_set (&th->ntag, 272, 2, 64, TOFF(th->t_model)); - if (full) { - if (oprof) psize = ntohl(oprof[0]); - tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize); - tiff_set (&th->ntag, 277, 3, 1, colors); - tiff_set (&th->ntag, 278, 4, 1, height); - tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8); - } else - tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0'); - tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0])); - tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2])); - tiff_set (&th->ntag, 284, 3, 1, 1); - tiff_set (&th->ntag, 296, 3, 1, 2); - tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft)); - tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date)); - tiff_set (&th->ntag, 315, 2, 64, TOFF(th->t_artist)); - tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif)); - if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th); - tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4])); - tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6])); - tiff_set (&th->nexif, 34855, 3, 1, iso_speed); - tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8])); - if (gpsdata[1]) { - tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps)); - tiff_set (&th->ngps, 0, 1, 4, 0x202); - tiff_set (&th->ngps, 1, 2, 2, gpsdata[29]); - tiff_set (&th->ngps, 2, 5, 3, TOFF(th->gps[0])); - tiff_set (&th->ngps, 3, 2, 2, gpsdata[30]); - tiff_set (&th->ngps, 4, 5, 3, TOFF(th->gps[6])); - tiff_set (&th->ngps, 5, 1, 1, gpsdata[31]); - tiff_set (&th->ngps, 6, 5, 1, TOFF(th->gps[18])); - tiff_set (&th->ngps, 7, 5, 3, TOFF(th->gps[12])); - tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20])); - tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23])); - memcpy (th->gps, gpsdata, sizeof th->gps); - } - th->rat[0] = th->rat[2] = 300; - th->rat[1] = th->rat[3] = 1; - FORC(6) th->rat[4+c] = 1000000; - th->rat[4] *= shutter; - th->rat[6] *= aperture; - th->rat[8] *= focal_len; - strncpy (th->t_desc, desc, 512); - strncpy (th->t_make, make, 64); - strncpy (th->t_model, model, 64); - strcpy (th->soft, "dcraw v" DCRAW_VERSION); - t = gmtime (×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->t_artist, artist, 64); -} - -void CLASS jpeg_thumb_writer (FILE *tfp,char *t_humb,int t_humb_length) -{ - ushort exif[5]; - struct tiff_hdr th; - fputc (0xff, tfp); - fputc (0xd8, tfp); - if (strcmp (t_humb+6, "Exif")) { - memcpy (exif, "\xff\xe1 Exif\0\0", 10); - exif[1] = htons (8 + sizeof th); - fwrite (exif, 1, sizeof exif, tfp); - tiff_head (&th, 0); - fwrite (&th, 1, sizeof th, tfp); - } - fwrite (t_humb+2, 1, t_humb_length-2, tfp); -} - - -void CLASS jpeg_thumb (FILE *tfp) -{ - char *thumb; - ushort exif[5]; - struct tiff_hdr th; - - thumb = (char *) malloc (thumb_length); - merror (thumb, "jpeg_thumb()"); - fread (thumb, 1, thumb_length, ifp); -#if 0 - fputc (0xff, tfp); - fputc (0xd8, tfp); - if (strcmp (thumb+6, "Exif")) { - memcpy (exif, "\xff\xe1 Exif\0\0", 10); - exif[1] = htons (8 + sizeof th); - fwrite (exif, 1, sizeof exif, tfp); - tiff_head (&th, 0); - fwrite (&th, 1, sizeof th, tfp); - } - fwrite (thumb+2, 1, thumb_length-2, tfp); -#else - jpeg_thumb_writer(tfp,thumb,thumb_length); -#endif - free (thumb); -} - -void CLASS write_ppm_tiff (FILE *ofp) -{ - struct tiff_hdr th; - uchar *ppm; - ushort *ppm2,lut16[0x10000]; - int c, row, col, soff, rstep, cstep; - - iheight = height; - iwidth = width; - if (flip & 4) SWAP(height,width); - ppm = (uchar *) calloc (width, colors*output_bps/8); - ppm2 = (ushort *) ppm; - merror (ppm, "write_ppm_tiff()"); - if (output_tiff) { - tiff_head (&th, 1); - fwrite (&th, sizeof th, 1, ofp); - if (oprof) - fwrite (oprof, ntohl(oprof[0]), 1, ofp); - } else if (colors > 3) - fprintf (ofp, - "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n", - width, height, colors, (1 << output_bps)-1, cdesc); - else - fprintf (ofp, "P%d\n%d %d\n%d\n", - colors/2+5, width, height, (1 << output_bps)-1); - if (output_bps == 8 || gamma_16bit ) gamma_lut (lut16); +#include "dcraw_defs.h" - soff = flip_index (0, 0); - cstep = flip_index (0, 1) - soff; - rstep = flip_index (1, 0) - flip_index (0, width); - for (row=0; row < height; row++, soff += rstep) { - for (col=0; col < width; col++, soff += cstep) - if (output_bps == 8) - FORCC ppm [col*colors+c] = lut16[image[soff][c]]/256; - else if(gamma_16bit) FORCC ppm2[col*colors+c] = lut16[image[soff][c]]; - else FORCC ppm2[col*colors+c] = image[soff][c]; - if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) - swab ((char*)ppm2, (char*)ppm2, width*colors*2); - fwrite (ppm, colors*output_bps/8, width, ofp); - } - free (ppm); -} +#include "../src/utils/read_utils.cpp" +#include "../src/utils/curves.cpp" +#include "../src/utils/utils_dcraw.cpp" + +#include "../src/tables/colordata.cpp" + +#include "../src/decoders/canon_600.cpp" +#include "../src/decoders/decoders_dcraw.cpp" +#include "../src/decoders/decoders_libraw_dcrdefs.cpp" +#include "../src/decoders/generic.cpp" +#include "../src/decoders/kodak_decoders.cpp" +#include "../src/decoders/dng.cpp" +#include "../src/decoders/smal.cpp" +#include "../src/decoders/load_mfbacks.cpp" + +#include "../src/metadata/sony.cpp" +#include "../src/metadata/nikon.cpp" +#include "../src/metadata/samsung.cpp" +#include "../src/metadata/cr3_parser.cpp" +#include "../src/metadata/canon.cpp" +#include "../src/metadata/epson.cpp" +#include "../src/metadata/olympus.cpp" +#include "../src/metadata/leica.cpp" +#include "../src/metadata/fuji.cpp" +#include "../src/metadata/adobepano.cpp" +#include "../src/metadata/pentax.cpp" +#include "../src/metadata/p1.cpp" +#include "../src/metadata/makernotes.cpp" +#include "../src/metadata/exif_gps.cpp" +#include "../src/metadata/kodak.cpp" +#include "../src/metadata/tiff.cpp" +#include "../src/metadata/ciff.cpp" +#include "../src/metadata/mediumformat.cpp" +#include "../src/metadata/minolta.cpp" +#include "../src/metadata/identify_tools.cpp" +#include "../src/metadata/normalize_model.cpp" +#include "../src/metadata/identify.cpp" +#include "../src/metadata/hasselblad_model.cpp" +#include "../src/metadata/misc_parsers.cpp" +#include "../src/tables/wblists.cpp" +#include "../src/postprocessing/postprocessing_aux.cpp" +#include "../src/postprocessing/postprocessing_utils_dcrdefs.cpp" +#include "../src/postprocessing/aspect_ratio.cpp" + +#include "../src/demosaic/misc_demosaic.cpp" +#include "../src/demosaic/xtrans_demosaic.cpp" +#include "../src/demosaic/ahd_demosaic.cpp" +#include "../src/write/file_write.cpp" diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_defs.h libkdcraw/libkdcraw/libraw/internal/dcraw_defs.h --- libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_defs.h 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/internal/dcraw_defs.h 2022-11-07 07:46:31.726795008 +0300 @@ -0,0 +1,62 @@ +/* -*- C++ -*- + * Copyright 2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#ifndef DCRAW_DEFS_H +#define DCRAW_DEFS_H + +#include <math.h> +#define LIBRAW_LIBRARY_BUILD +#define LIBRAW_IO_REDEFINED +#include "libraw/libraw.h" +#include "libraw/libraw_types.h" +#include "internal/defines.h" +#include "internal/var_defines.h" + +#define stmread(buf, maxlen, fp) stread(buf, MIN(maxlen, sizeof(buf)), fp) +#define strbuflen(buf) strnlen(buf, sizeof(buf) - 1) +#define makeIs(idx) (maker_index == idx) +#define strnXcat(buf, string) \ + strncat(buf, string, LIM(sizeof(buf) - strbuflen(buf) - 1, 0, sizeof(buf))) + +// DNG was written by: +#define nonDNG 0 +#define CameraDNG 1 +#define AdobeDNG 2 + +// Makernote tag type: +#define is_0x927c 0 /* most cameras */ +#define is_0xc634 2 /* Adobe DNG, Sony SR2, Pentax */ +#define ilm imgdata.lens.makernotes +#define icWBC imgdata.color.WB_Coeffs +#define icWBCCTC imgdata.color.WBCT_Coeffs +#define imCanon imgdata.makernotes.canon +#define imFuji imgdata.makernotes.fuji +#define imHassy imgdata.makernotes.hasselblad +#define imKodak imgdata.makernotes.kodak +#define imNikon imgdata.makernotes.nikon +#define imOly imgdata.makernotes.olympus +#define imPana imgdata.makernotes.panasonic +#define imPentax imgdata.makernotes.pentax +#define imSamsung imgdata.makernotes.samsung +#define imSony imgdata.makernotes.sony +#define imCommon imgdata.makernotes.common + + +#define ph1_bits(n) ph1_bithuff(n, 0) +#define ph1_huff(h) ph1_bithuff(*h, h + 1) +#define getbits(n) getbithuff(n, 0) +#define gethuff(h) getbithuff(*h, h + 1) + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_fileio.cpp libkdcraw/libkdcraw/libraw/internal/dcraw_fileio.cpp --- libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_fileio.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/internal/dcraw_fileio.cpp 2022-11-07 07:46:31.726795008 +0300 @@ -1,213 +1,28 @@ -/* - GENERATED FILE, DO NOT EDIT - Generated from dcraw/dcraw.c at Tue Apr 7 15:14:50 2009 - Look into original file (probably http://cybercom.net/~dcoffin/dcraw/dcraw.c) - for copyright information. +/* + Copyright 2008-2020 LibRaw LLC (info@libraw.org) + + * This file is provided for compatibility w/ old build scripts/tools: + * It includes multiple separate files that should be built separately + * if new build tools are used + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + This file is generated from Dave Coffin's dcraw.c + dcraw.c -- Dave Coffin's raw photo decoder + Copyright 1997-2010 by Dave Coffin, dcoffin a cybercom o net + + Look into dcraw homepage (probably http://cybercom.net/~dcoffin/dcraw/) + for more information */ -#define CLASS LibRaw:: -#include "libraw/libraw_types.h" -#define LIBRAW_LIBRARY_BUILD -#include "libraw/libraw.h" -#include "internal/defines.h" -#include "internal/var_defines.h" +#include "dcraw_fileio_defs.h" -/* - Seach from the current directory up to the root looking for - a ".badpixels" file, and fix those pixels now. - */ -void CLASS bad_pixels (char *fname) -{ - FILE *fp=0; - char *cp, line[128]; - int len, time, row, col, r, c, rad, tot, n, fixed=0; - - if (!filters) return; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,0,2); -#endif - if (fname) - fp = fopen (fname, "r"); - if (!fp) - { -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_NO_BADPIXELMAP; -#endif - return; - } - while (fgets (line, 128, fp)) { - cp = strchr (line, '#'); - if (cp) *cp = 0; - if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; - if ((unsigned) col >= width || (unsigned) row >= height) continue; - if (time > timestamp) continue; - for (tot=n=0, rad=1; rad < 3 && n==0; rad++) - for (r = row-rad; r <= row+rad; r++) - for (c = col-rad; c <= col+rad; c++) - if ((unsigned) r < height && (unsigned) c < width && - (r != row || c != col) && fc(r,c) == fc(row,col)) { - tot += BAYER2(r,c); - n++; - } - BAYER2(row,col) = tot/n; -#ifdef DCRAW_VERBOSE - if (verbose) { - if (!fixed++) - fprintf (stderr,_("Fixed dead pixels at:")); - fprintf (stderr, " %d,%d", col, row); - } -#endif - } -#ifdef DCRAW_VERBOSE - if (fixed) fputc ('\n', stderr); -#endif - fclose (fp); -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,1,2); -#endif -} - -void CLASS subtract (char *fname) -{ - FILE *fp; - int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; - ushort *pixel; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,0,2); -#endif - - if (!(fp = fopen (fname, "rb"))) { -#ifdef DCRAW_VERBOSE - perror (fname); -#endif -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_FILE; -#endif - return; - } - if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; - while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { - if (c == '#') comment = 1; - if (c == '\n') comment = 0; - if (comment) continue; - if (isdigit(c)) number = 1; - if (number) { - if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; - else if (isspace(c)) { - number = 0; nd++; - } else error = 1; - } - } - if (error || nd < 3) { - fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); - fclose (fp); return; - } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { -#ifdef DCRAW_VERBOSE - fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); -#endif -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_DIM; -#endif - fclose (fp); return; - } - pixel = (ushort *) calloc (width, sizeof *pixel); - merror (pixel, "subtract()"); - for (row=0; row < height; row++) { - fread (pixel, 2, width, fp); - for (col=0; col < width; col++) - BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); - } - free (pixel); - black = 0; -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,1,2); -#endif -} - -#ifndef NO_LCMS -void CLASS apply_profile (char *input, char *output) -{ - char *prof; - cmsHPROFILE hInProfile=0, hOutProfile=0; - cmsHTRANSFORM hTransform; - FILE *fp; - unsigned size; - -#if LCMS_VERSION < 2000 - cmsErrorAction (LCMS_ERROR_SHOW); -#endif - if (strcmp (input, "embed")) - hInProfile = cmsOpenProfileFromFile (input, "r"); - else if (profile_length) { -#ifndef LIBRAW_LIBRARY_BUILD - prof = (char *) malloc (profile_length); - merror (prof, "apply_profile()"); - fseek (ifp, profile_offset, SEEK_SET); - fread (prof, 1, profile_length, ifp); - hInProfile = cmsOpenProfileFromMem (prof, profile_length); - free (prof); -#else - hInProfile = cmsOpenProfileFromMem (imgdata.color.profile, profile_length); -#endif - } else - { -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_NO_EMBEDDED_PROFILE; -#endif -#ifdef DCRAW_VERBOSE - fprintf (stderr,_("%s has no embedded profile.\n"), ifname); -#endif - } - if (!hInProfile) - { -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_NO_INPUT_PROFILE; -#endif - return; - } - if (!output) - hOutProfile = cmsCreate_sRGBProfile(); - else if ((fp = fopen (output, "rb"))) { - fread (&size, 4, 1, fp); - fseek (fp, 0, SEEK_SET); - oprof = (unsigned *) malloc (size = ntohl(size)); - merror (oprof, "apply_profile()"); - fread (oprof, 1, size, fp); - fclose (fp); - if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { - free (oprof); - oprof = 0; - } -#ifdef DCRAW_VERBOSE - } else - fprintf (stderr,_("Cannot open file %s!\n"), output); -#else -} -#endif - if (!hOutProfile) - { -#ifdef LIBRAW_LIBRARY_BUILD - imgdata.process_warnings |= LIBRAW_WARN_BAD_OUTPUT_PROFILE; -#endif - goto quit; - } -#ifdef DCRAW_VERBOSE - if (verbose) - fprintf (stderr,_("Applying color profile...\n")); -#endif -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,0,2); -#endif - hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, - hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); - cmsDoTransform (hTransform, image, image, width*height); - raw_color = 1; /* Don't use rgb_cam with a profile */ - cmsDeleteTransform (hTransform); - cmsCloseProfile (hOutProfile); -quit: - cmsCloseProfile (hInProfile); -#ifdef LIBRAW_LIBRARY_BUILD - RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,1,2); -#endif -} -#endif +#include "../src/preprocessing/ext_preprocess.cpp" +#include "../src/write/apply_profile.cpp" diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_fileio_defs.h libkdcraw/libkdcraw/libraw/internal/dcraw_fileio_defs.h --- libkdcraw-wrk/libkdcraw/libraw/internal/dcraw_fileio_defs.h 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/internal/dcraw_fileio_defs.h 2022-11-07 07:46:31.726795008 +0300 @@ -0,0 +1,25 @@ +/* -*- C++ -*- + * Copyright 2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#ifndef DCRAW_FILEIO_DEFS_H +#define DCRAW_FILEIO_DEFS_H + +#include <math.h> +#define LIBRAW_LIBRARY_BUILD +#include "libraw/libraw.h" +#include "internal/defines.h" +#include "internal/var_defines.h" + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/defines.h libkdcraw/libkdcraw/libraw/internal/defines.h --- libkdcraw-wrk/libkdcraw/libraw/internal/defines.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/internal/defines.h 2022-11-07 07:46:31.726795008 +0300 @@ -1,17 +1,37 @@ -/* - 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. +/* + Copyright 2008-2020 LibRaw LLC (info@libraw.org) + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + This file is generated from Dave Coffin's dcraw.c + dcraw.c -- Dave Coffin's raw photo decoder + Copyright 1997-2010 by Dave Coffin, dcoffin a cybercom o net + + Look into dcraw homepage (probably http://cybercom.net/~dcoffin/dcraw/) + for more information */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#ifndef LIBRAW_INT_DEFINES_H +#define LIBRAW_INT_DEFINES_H +#ifndef USE_JPEG #define NO_JPEG -#define DCRAW_VERSION "8.93" -#define _USE_MATH_DEFINES +#endif +#ifndef USE_JASPER +#define NO_JASPER +#endif +#define DCRAW_VERSION "9.26" +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#define _USE_MATH_DEFINES #include <ctype.h> #include <errno.h> #include <fcntl.h> @@ -24,38 +44,18 @@ #include <string.h> #include <time.h> #include <sys/types.h> - -#ifdef _OPENMP -#include <omp.h> -#endif -/* - NO_JPEG disables decoding of compressed Kodak DC120 files. - NO_LCMS disables the "-p" option. - */ -#ifndef NO_JPEG -#include <jpeglib.h> -#endif -#ifndef NO_LCMS -#include LCMS_HEADER -#endif -#ifdef LOCALEDIR -#include <libintl.h> -#define _(String) gettext(String) -#else -#define _(String) (String) -#endif #ifdef __CYGWIN__ #include <io.h> #endif -#ifdef WIN32 +#if defined LIBRAW_WIN32_CALLS #include <sys/utime.h> +#ifndef LIBRAW_NO_WINSOCK2 #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") +#endif #define snprintf _snprintf -#define strcasecmp _stricmp +#define strcasecmp stricmp #define strncasecmp strnicmp -typedef __int64 INT64; -typedef unsigned __int64 UINT64; #else #include <unistd.h> #include <utime.h> @@ -64,27 +64,74 @@ typedef unsigned long long UINT64; #endif +#ifdef NODEPS +#define NO_JASPER +#define NO_JPEG +#define NO_LCMS +#endif +#ifndef NO_JASPER +#include <jasper/jasper.h> /* Decode Red camera movies */ +#endif +#ifndef NO_JPEG +#include <jpeglib.h> /* Decode compressed Kodak DC120 photos */ +#endif /* and Adobe Lossy DNGs */ +#ifndef NO_LCMS +#ifdef USE_LCMS +#include <lcms.h> /* Support color profiles */ +#else +#include <lcms2.h> /* Support color profiles */ +#endif +#endif +#ifdef LOCALEDIR +#include <libintl.h> +#define _(String) gettext(String) +#else +#define _(String) (String) +#endif + #ifdef LJPEG_DECODE #error Please compile dcraw.c by itself. #error Do not link it with ljpeg_decode. #endif #ifndef LONG_BIT -#define LONG_BIT (8 * sizeof (long)) +#define LONG_BIT (8 * sizeof(long)) #endif -#define FORC(cnt) for (c=0; c < cnt; c++) +#define FORC(cnt) for (c = 0; c < cnt; c++) #define FORC3 FORC(3) #define FORC4 FORC(4) -#define FORCC FORC(colors) +#define FORCC for (c = 0; c < colors && c < 4; c++) -#define SQR(x) ((x)*(x)) +#define SQR(x) ((x) * (x)) #define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define LIM(x,min,max) MAX(min,MIN(x,max)) -#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) -#define CLIP(x) LIM(x,0,65535) -#define SWAP(a,b) { a ^= b; a ^= (b ^= a); } +#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((int)(x), 0, 65535) +#define CLIP15(x) LIM((int)(x), 0, 32767) +#define SWAP(a, b) \ + { \ + a = a + b; \ + b = a - b; \ + a = a - b; \ + } + +#define my_swap(type, i, j) \ + { \ + type t = i; \ + i = j; \ + j = t; \ + } + +#ifdef __GNUC__ +inline +#elif defined(_MSC_VER) +__forceinline +#else +static +#endif +float fMAX(float a, float b) { return MAX(a, b); } /* In order to inline this calculation, I make the risky @@ -96,37 +143,50 @@ Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 - PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 - 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: + PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 + 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: - 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 - 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M - 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C - 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y - 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M - 4 C Y C Y C Y 4 Y C Y C Y C - PowerShot A5 5 G M G M G M 5 G M G M G M - 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y - 7 M G M G M G 7 M G M G M G - 0 1 2 3 4 5 - 0 C Y C Y C Y - 1 G M G M G M - 2 C Y C Y C Y - 3 M G M G M G + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M + 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C + 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y + 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M + 4 C Y C Y C Y 4 Y C Y C Y C + PowerShot A5 5 G M G M G M 5 G M G M G M + 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y + 7 M G M G M G 7 M G M G M G + 0 1 2 3 4 5 + 0 C Y C Y C Y + 1 G M G M G M + 2 C Y C Y C Y + 3 M G M G M G All RGB cameras use one of these Bayer grids: - 0x16161616: 0x61616161: 0x49494949: 0x94949494: + 0x16161616: 0x61616161: 0x49494949: 0x94949494: - 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 - 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G - 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B - 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G - 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G + 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B + 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G + 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B */ -#define BAYER(row,col) \ - image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] +// _RGBG means R, G1, B, G2 sequence +#define GRBG_2_RGBG(q) (q ^ (q >> 1) ^ 1) +#define RGGB_2_RGBG(q) (q ^ (q >> 1)) +#define BG2RG1_2_RGBG(q) (q ^ 2) +#define GRGB_2_RGBG(q) (q ^ 1) +#define RBGG_2_RGBG(q) ((q >> 1) | ((q & 1) << 1)) + +#define RAWINDEX(row, col) ((row)*raw_width + (col)) +#define RAW(row, col) raw_image[(row)*raw_width + (col)] +#define BAYER(row, col) \ + image[((row) >> shrink) * iwidth + ((col) >> shrink)][FC(row, col)] + +#define BAYER2(row, col) \ + image[((row) >> shrink) * iwidth + ((col) >> shrink)][fcol(row, col)] +#define BAYERC(row, col, c) \ + imgdata.image[((row) >> IO.shrink) * S.iwidth + ((col) >> IO.shrink)][c] -#define BAYER2(row,col) \ - image[((row) >> shrink)*iwidth + ((col) >> shrink)][fc(row,col)] +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/demosaic_packs.cpp libkdcraw/libkdcraw/libraw/internal/demosaic_packs.cpp --- libkdcraw-wrk/libkdcraw/libraw/internal/demosaic_packs.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/internal/demosaic_packs.cpp 2022-11-07 07:46:31.726795008 +0300 @@ -0,0 +1,35 @@ +/* + Copyright 2008-2013 LibRaw LLC (info@libraw.org) + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + + * This file is provided for compatibility w/ old build scripts/tools: + * It includes multiple separate files that should be built separately + * if new build tools are used + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + +*/ + +#include <math.h> + +#define LIBRAW_LIBRARY_BUILD +#define LIBRAW_IO_REDEFINED +#include "libraw/libraw.h" +#include "internal/defines.h" +#define SRC_USES_SHRINK +#define SRC_USES_BLACK +#define SRC_USES_CURVE + +/* DHT and AAHD are LGPL licensed, so include them */ +#include "../src/demosaic/dht_demosaic.cpp" +#include "../src/demosaic/aahd_demosaic.cpp" +#include "internal/var_defines.h" + +/* DCB is BSD licensed, so include it */ +#include "../src/demosaic/dcb_demosaic.cpp" diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/dmp_include.h libkdcraw/libkdcraw/libraw/internal/dmp_include.h --- libkdcraw-wrk/libkdcraw/libraw/internal/dmp_include.h 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/internal/dmp_include.h 2022-11-07 07:46:31.726795008 +0300 @@ -0,0 +1,27 @@ +/* -*- C++ -*- + * Copyright 2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#ifndef DMP_INCLUDE_H +#define DMP_INCLUDE_H + +#define LIBRAW_LIBRARY_BUILD +#define LIBRAW_IO_REDEFINED +#include "libraw/libraw.h" +#include "internal/defines.h" +#define SRC_USES_SHRINK +#define SRC_USES_BLACK +#define SRC_USES_CURVE + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/foveon.cpp libkdcraw/libkdcraw/libraw/internal/foveon.cpp --- libkdcraw-wrk/libkdcraw/libraw/internal/foveon.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/internal/foveon.cpp 1970-01-01 03:00:00.000000000 +0300 @@ -1,812 +0,0 @@ -/* - 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" : "ColorDTQCamRGB"); - 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; -} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/libraw_cameraids.h libkdcraw/libkdcraw/libraw/internal/libraw_cameraids.h --- libkdcraw-wrk/libkdcraw/libraw/internal/libraw_cameraids.h 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/internal/libraw_cameraids.h 2022-11-07 07:46:31.726795008 +0300 @@ -0,0 +1,300 @@ +/* -*- C++ -*- + * File: internal/libraw_cameraids.h + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Aug 17, 2020 + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#ifndef LIBRAW_CONST_H +#define LIBRAW_CONST_H + +#define CanonID_EOS_M50 0x00000412ULL +#define CanonID_EOS_M6_Mark_II 0x00000811ULL +#define CanonID_EOS_M200 0x00000812ULL +#define CanonID_EOS_D30 0x01140000ULL +#define CanonID_EOS_D60 0x01668000ULL +#define CanonID_EOS_M3 0x03740000ULL +#define CanonID_EOS_M10 0x03840000ULL +#define CanonID_EOS_M5 0x03940000ULL +#define CanonID_EOS_M100 0x03980000ULL +#define CanonID_EOS_M6 0x04070000ULL +#define CanonID_EOS_1D (0x80000000ULL + 0x001ULL) +#define CanonID_EOS_1DS (0x80000000ULL + 0x167ULL) +#define CanonID_EOS_10D (0x80000000ULL + 0x168ULL) +#define CanonID_EOS_1D_Mark_III (0x80000000ULL + 0x169ULL) +#define CanonID_EOS_300D (0x80000000ULL + 0x170ULL) +#define CanonID_EOS_1D_Mark_II (0x80000000ULL + 0x174ULL) +#define CanonID_EOS_20D (0x80000000ULL + 0x175ULL) +#define CanonID_EOS_450D (0x80000000ULL + 0x176ULL) +#define CanonID_EOS_1Ds_Mark_II (0x80000000ULL + 0x188ULL) +#define CanonID_EOS_350D (0x80000000ULL + 0x189ULL) +#define CanonID_EOS_40D (0x80000000ULL + 0x190ULL) +#define CanonID_EOS_5D (0x80000000ULL + 0x213ULL) +#define CanonID_EOS_1Ds_Mark_III (0x80000000ULL + 0x215ULL) +#define CanonID_EOS_5D_Mark_II (0x80000000ULL + 0x218ULL) +#define CanonID_EOS_1D_Mark_II_N (0x80000000ULL + 0x232ULL) +#define CanonID_EOS_30D (0x80000000ULL + 0x234ULL) +#define CanonID_EOS_400D (0x80000000ULL + 0x236ULL) +#define CanonID_EOS_7D (0x80000000ULL + 0x250ULL) +#define CanonID_EOS_500D (0x80000000ULL + 0x252ULL) +#define CanonID_EOS_1000D (0x80000000ULL + 0x254ULL) +#define CanonID_EOS_50D (0x80000000ULL + 0x261ULL) +#define CanonID_EOS_1D_X (0x80000000ULL + 0x269ULL) +#define CanonID_EOS_550D (0x80000000ULL + 0x270ULL) +#define CanonID_EOS_1D_Mark_IV (0x80000000ULL + 0x281ULL) +#define CanonID_EOS_5D_Mark_III (0x80000000ULL + 0x285ULL) +#define CanonID_EOS_600D (0x80000000ULL + 0x286ULL) +#define CanonID_EOS_60D (0x80000000ULL + 0x287ULL) +#define CanonID_EOS_1100D (0x80000000ULL + 0x288ULL) +#define CanonID_EOS_7D_Mark_II (0x80000000ULL + 0x289ULL) +#define CanonID_EOS_650D (0x80000000ULL + 0x301ULL) +#define CanonID_EOS_6D (0x80000000ULL + 0x302ULL) +#define CanonID_EOS_1D_C (0x80000000ULL + 0x324ULL) +#define CanonID_EOS_70D (0x80000000ULL + 0x325ULL) +#define CanonID_EOS_700D (0x80000000ULL + 0x326ULL) +#define CanonID_EOS_1200D (0x80000000ULL + 0x327ULL) +#define CanonID_EOS_1D_X_Mark_II (0x80000000ULL + 0x328ULL) +#define CanonID_EOS_M (0x80000000ULL + 0x331ULL) +#define CanonID_EOS_100D (0x80000000ULL + 0x346ULL) +#define CanonID_EOS_760D (0x80000000ULL + 0x347ULL) +#define CanonID_EOS_5D_Mark_IV (0x80000000ULL + 0x349ULL) +#define CanonID_EOS_80D (0x80000000ULL + 0x350ULL) +#define CanonID_EOS_M2 (0x80000000ULL + 0x355ULL) +#define CanonID_EOS_5DS (0x80000000ULL + 0x382ULL) +#define CanonID_EOS_750D (0x80000000ULL + 0x393ULL) +#define CanonID_EOS_5DS_R (0x80000000ULL + 0x401ULL) +#define CanonID_EOS_1300D (0x80000000ULL + 0x404ULL) +#define CanonID_EOS_800D (0x80000000ULL + 0x405ULL) +#define CanonID_EOS_6D_Mark_II (0x80000000ULL + 0x406ULL) +#define CanonID_EOS_77D (0x80000000ULL + 0x408ULL) +#define CanonID_EOS_200D (0x80000000ULL + 0x417ULL) +#define CanonID_EOS_3000D (0x80000000ULL + 0x422ULL) +#define CanonID_EOS_R (0x80000000ULL + 0x424ULL) +#define CanonID_EOS_1D_X_Mark_III (0x80000000ULL + 0x428ULL) +#define CanonID_EOS_1500D (0x80000000ULL + 0x432ULL) +#define CanonID_EOS_RP (0x80000000ULL + 0x433ULL) +#define CanonID_EOS_250D (0x80000000ULL + 0x436ULL) +#define CanonID_EOS_90D (0x80000000ULL + 0x437ULL) + +// CanonID_EOS_D2000C after Canon's TIFF2CR2 convertor: +#define CanonID_EOS_D2000C (0x80000000ULL + 0x520ULL) +// CanonID_EOS_D6000C id after Canon's TIFF2CR2 convertor: +#define CanonID_EOS_D6000C (0x80000000ULL + 0x560ULL) + +#define OlyID_str2hex(str) ((unsigned long long)str[0]<<32 | str[1]<<24 | str[2]<<16 | str[3]<<8 | str[4]) +#define OlyID_E_20 OlyID_str2hex("D4029") +#define OlyID_E_1 OlyID_str2hex("D4040") +#define OlyID_E_300 OlyID_str2hex("D4041") +#define OlyID_SP_550UZ OlyID_str2hex("D4321") +#define OlyID_SP_510UZ OlyID_str2hex("D4322") +#define OlyID_SP_560UZ OlyID_str2hex("D4355") +#define OlyID_SP_570UZ OlyID_str2hex("D4364") +#define OlyID_SP_565UZ OlyID_str2hex("D4374") +#define OlyID_XZ_1 OlyID_str2hex("D4401") +#define OlyID_XZ_2 OlyID_str2hex("D4531") +#define OlyID_XZ_10 OlyID_str2hex("D4546") +#define OlyID_STYLUS_1 OlyID_str2hex("D4572") +#define OlyID_SH_2 OlyID_str2hex("D4585") +#define OlyID_TG_4 OlyID_str2hex("D4586") +#define OlyID_TG_5 OlyID_str2hex("D4593") +#define OlyID_TG_6 OlyID_str2hex("D4603") +#define OlyID_E_10 OlyID_str2hex("D4842") +#define OlyID_AIR_A01 OlyID_str2hex("K0055") +#define OlyID_NORMA OlyID_str2hex("NORMA") +#define OlyID_E_330 OlyID_str2hex("S0003") +#define OlyID_E_500 OlyID_str2hex("S0004") +#define OlyID_E_400 OlyID_str2hex("S0009") +#define OlyID_E_510 OlyID_str2hex("S0010") +#define OlyID_E_3 OlyID_str2hex("S0011") +#define OlyID_E_410 OlyID_str2hex("S0013") +#define OlyID_E_420 OlyID_str2hex("S0016") +#define OlyID_E_30 OlyID_str2hex("S0017") +#define OlyID_E_520 OlyID_str2hex("S0018") +#define OlyID_E_P1 OlyID_str2hex("S0019") +#define OlyID_E_620 OlyID_str2hex("S0023") +#define OlyID_E_P2 OlyID_str2hex("S0026") +#define OlyID_E_PL1 OlyID_str2hex("S0027") +#define OlyID_E_450 OlyID_str2hex("S0029") +#define OlyID_E_600 OlyID_str2hex("S0030") +#define OlyID_E_P3 OlyID_str2hex("S0032") +#define OlyID_E_5 OlyID_str2hex("S0033") +#define OlyID_E_PL2 OlyID_str2hex("S0034") +#define OlyID_E_M5 OlyID_str2hex("S0036") +#define OlyID_E_PL3 OlyID_str2hex("S0038") +#define OlyID_E_PM1 OlyID_str2hex("S0039") +#define OlyID_E_PL1s OlyID_str2hex("S0040") +#define OlyID_E_PL5 OlyID_str2hex("S0042") +#define OlyID_E_PM2 OlyID_str2hex("S0043") +#define OlyID_E_P5 OlyID_str2hex("S0044") +#define OlyID_E_PL6 OlyID_str2hex("S0045") +#define OlyID_E_PL7 OlyID_str2hex("S0046") +#define OlyID_E_M1 OlyID_str2hex("S0047") +#define OlyID_E_M10 OlyID_str2hex("S0051") +#define OlyID_E_M5_Mark_II OlyID_str2hex("S0052") +#define OlyID_E_M10_Mark_II OlyID_str2hex("S0059") +#define OlyID_PEN_F OlyID_str2hex("S0061") +#define OlyID_E_PL8 OlyID_str2hex("S0065") +#define OlyID_E_M1_Mark_II OlyID_str2hex("S0067") +#define OlyID_E_M10_Mark_III OlyID_str2hex("S0068") +#define OlyID_E_PL9 OlyID_str2hex("S0076") +#define OlyID_E_M1X OlyID_str2hex("S0080") +#define OlyID_E_PL10 OlyID_str2hex("S0085") +#define OlyID_E_M5_Mark_III OlyID_str2hex("S0089") +#define OlyID_E_M1_Mark_III OlyID_str2hex("S0092") +#define OlyID_C_3030Z OlyID_str2hex("SX351") +#define OlyID_C_5050Z OlyID_str2hex("SX558") +#define OlyID_C_350Z OlyID_str2hex("SX751") +#define OlyID_C_740UZ OlyID_str2hex("SX754") +#define OlyID_C_5060WZ OlyID_str2hex("SX756") +#define OlyID_C_8080WZ OlyID_str2hex("SX757") +#define OlyID_C_770UZ OlyID_str2hex("SX772") +#define OlyID_C_7070WZ OlyID_str2hex("SX851") +#define OlyID_C_7000Z OlyID_str2hex("SX852") +#define OlyID_SP_500UZ OlyID_str2hex("SX853") +#define OlyID_SP_310 OlyID_str2hex("SX854") +#define OlyID_SP_350 OlyID_str2hex("SX855") +#define OlyID_SP_320 OlyID_str2hex("SX873") + +#define PentaxID_Optio_S 0x1296cULL +#define PentaxID_Optio_S_V101 0x12971ULL +#define PentaxID_staristD 0x12994ULL +#define PentaxID_Optio_33WR 0x129c6ULL +#define PentaxID_Optio_S4 0x129d5ULL +#define PentaxID_Optio_750Z 0x12a66ULL +#define PentaxID_staristDS 0x12aa2ULL +#define PentaxID_staristDL 0x12b1aULL +#define PentaxID_staristDS2 0x12b60ULL +#define PentaxID_GX_1S 0x12b62ULL +#define PentaxID_staristDL2 0x12b7eULL +#define PentaxID_GX_1L 0x12b80ULL +#define PentaxID_K100D 0x12b9cULL +#define PentaxID_K110D 0x12b9dULL +#define PentaxID_K100D_Super 0x12ba2ULL +#define PentaxID_K10D 0x12c1eULL +#define PentaxID_GX10 0x12c20ULL +#define PentaxID_K20D 0x12cd2ULL +#define PentaxID_GX20 0x12cd4ULL +#define PentaxID_K200D 0x12cfaULL +#define PentaxID_K2000 0x12d72ULL +#define PentaxID_K_m 0x12d73ULL +#define PentaxID_K_7 0x12db8ULL +#define PentaxID_K_x 0x12dfeULL +#define PentaxID_645D 0x12e08ULL +#define PentaxID_K_r 0x12e6cULL +#define PentaxID_K_5 0x12e76ULL +#define PentaxID_Q 0x12ee4ULL +#define PentaxID_K_01 0x12ef8ULL +#define PentaxID_K_30 0x12f52ULL +#define PentaxID_Q10 0x12f66ULL +#define PentaxID_K_5_II 0x12f70ULL +#define PentaxID_K_5_II_s 0x12f71ULL +#define PentaxID_Q7 0x12f7aULL +#define PentaxID_MX_1 0x12f84ULL +#define PentaxID_K_50 0x12fb6ULL +#define PentaxID_K_3 0x12fc0ULL +#define PentaxID_K_500 0x12fcaULL +#define PentaxID_645Z 0x13010ULL +#define PentaxID_K_S1 0x1301aULL +#define PentaxID_K_S2 0x13024ULL +#define PentaxID_Q_S1 0x1302eULL +#define PentaxID_K_1 0x13092ULL +#define PentaxID_K_3_II 0x1309cULL +#define PentaxID_GR_III 0x1320eULL +#define PentaxID_K_70 0x13222ULL +#define PentaxID_KP 0x1322cULL +#define PentaxID_K_1_Mark_II 0x13240ULL + +#define SonyID_DSC_R1 0x002ULL +#define SonyID_DSLR_A100 0x100ULL +#define SonyID_DSLR_A900 0x101ULL +#define SonyID_DSLR_A700 0x102ULL +#define SonyID_DSLR_A200 0x103ULL +#define SonyID_DSLR_A350 0x104ULL +#define SonyID_DSLR_A300 0x105ULL +#define SonyID_DSLR_A900_APSC 0x106ULL +#define SonyID_DSLR_A380 0x107ULL +#define SonyID_DSLR_A330 0x108ULL +#define SonyID_DSLR_A230 0x109ULL +#define SonyID_DSLR_A290 0x10aULL +#define SonyID_DSLR_A850 0x10dULL +#define SonyID_DSLR_A850_APSC 0x10eULL +#define SonyID_DSLR_A550 0x111ULL +#define SonyID_DSLR_A500 0x112ULL +#define SonyID_DSLR_A450 0x113ULL +#define SonyID_NEX_5 0x116ULL +#define SonyID_NEX_3 0x117ULL +#define SonyID_SLT_A33 0x118ULL +#define SonyID_SLT_A55 0x119ULL +#define SonyID_DSLR_A560 0x11aULL +#define SonyID_DSLR_A580 0x11bULL +#define SonyID_NEX_C3 0x11cULL +#define SonyID_SLT_A35 0x11dULL +#define SonyID_SLT_A65 0x11eULL +#define SonyID_SLT_A77 0x11fULL +#define SonyID_NEX_5N 0x120ULL +#define SonyID_NEX_7 0x121ULL +#define SonyID_NEX_VG20 0x122ULL +#define SonyID_SLT_A37 0x123ULL +#define SonyID_SLT_A57 0x124ULL +#define SonyID_NEX_F3 0x125ULL +#define SonyID_SLT_A99 0x126ULL +#define SonyID_NEX_6 0x127ULL +#define SonyID_NEX_5R 0x128ULL +#define SonyID_DSC_RX100 0x129ULL +#define SonyID_DSC_RX1 0x12aULL +#define SonyID_NEX_VG900 0x12bULL +#define SonyID_NEX_VG30 0x12cULL +#define SonyID_ILCE_3000 0x12eULL +#define SonyID_SLT_A58 0x12fULL +#define SonyID_NEX_3N 0x131ULL +#define SonyID_ILCE_7 0x132ULL +#define SonyID_NEX_5T 0x133ULL +#define SonyID_DSC_RX100M2 0x134ULL +#define SonyID_DSC_RX10 0x135ULL +#define SonyID_DSC_RX1R 0x136ULL +#define SonyID_ILCE_7R 0x137ULL +#define SonyID_ILCE_6000 0x138ULL +#define SonyID_ILCE_5000 0x139ULL +#define SonyID_DSC_RX100M3 0x13dULL +#define SonyID_ILCE_7S 0x13eULL +#define SonyID_ILCA_77M2 0x13fULL +#define SonyID_ILCE_5100 0x153ULL +#define SonyID_ILCE_7M2 0x154ULL +#define SonyID_DSC_RX100M4 0x155ULL +#define SonyID_DSC_RX10M2 0x156ULL +#define SonyID_DSC_RX1RM2 0x158ULL +#define SonyID_ILCE_QX1 0x15aULL +#define SonyID_ILCE_7RM2 0x15bULL +#define SonyID_ILCE_7SM2 0x15eULL +#define SonyID_ILCA_68 0x161ULL +#define SonyID_ILCA_99M2 0x162ULL +#define SonyID_DSC_RX10M3 0x163ULL +#define SonyID_DSC_RX100M5 0x164ULL +#define SonyID_ILCE_6300 0x165ULL +#define SonyID_ILCE_9 0x166ULL +#define SonyID_ILCE_6500 0x168ULL +#define SonyID_ILCE_7RM3 0x16aULL +#define SonyID_ILCE_7M3 0x16bULL +#define SonyID_DSC_RX0 0x16cULL +#define SonyID_DSC_RX10M4 0x16dULL +#define SonyID_DSC_RX100M6 0x16eULL +#define SonyID_DSC_HX99 0x16fULL +#define SonyID_DSC_RX100M5A 0x171ULL +#define SonyID_ILCE_6400 0x173ULL +#define SonyID_DSC_RX0M2 0x174ULL +#define SonyID_DSC_RX100M7 0x176ULL +#define SonyID_ILCE_7RM4 0x177ULL +#define SonyID_ILCE_9M2 0x178ULL +#define SonyID_ILCE_6600 0x17aULL +#define SonyID_ILCE_6100 0x17bULL + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/libraw_cxx_defs.h libkdcraw/libkdcraw/libraw/internal/libraw_cxx_defs.h --- libkdcraw-wrk/libkdcraw/libraw/internal/libraw_cxx_defs.h 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/internal/libraw_cxx_defs.h 2022-11-07 07:46:31.726795008 +0300 @@ -0,0 +1,130 @@ +/* -*- C++ -*- + * File: internal/libraw_cxx_defs.h + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Aug 17, 2020 + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#ifndef _LIBRAW_CXX_DEFS_H +#define _LIBRAW_CXX_DEFS_H + +#include <math.h> +#include <errno.h> +#include <float.h> +#include <new> +#include <exception> +#include <sys/types.h> +#include <sys/stat.h> +#define LIBRAW_LIBRARY_BUILD +#include "libraw/libraw.h" +#include "internal/defines.h" +#ifdef USE_ZLIB +#include <zlib.h> +#endif + +#ifndef LIBRAW_WIN32_CALLS +#include <netinet/in.h> +#else +#ifndef LIBRAW_NO_WINSOCK2 +#include <winsock2.h> +#endif +#include <io.h> +#endif + +#ifdef USE_RAWSPEED +#include <RawSpeed/StdAfx.h> +#include <RawSpeed/FileMap.h> +#include <RawSpeed/RawParser.h> +#include <RawSpeed/RawDecoder.h> +#include <RawSpeed/CameraMetaData.h> +#include <RawSpeed/ColorFilterArray.h> +extern const char *_rawspeed_data_xml[]; +extern const int RAWSPEED_DATA_COUNT; +class CameraMetaDataLR : public RawSpeed::CameraMetaData +{ +public: + CameraMetaDataLR() : CameraMetaData() {} + CameraMetaDataLR(char *filename) : RawSpeed::CameraMetaData(filename) {} + CameraMetaDataLR(char *data, int sz); +}; + +CameraMetaDataLR *make_camera_metadata(); + +#endif + +#ifdef USE_DNGSDK +#include "dng_host.h" +#include "dng_negative.h" +#include "dng_simple_image.h" +#include "dng_info.h" +#endif + +#define P1 imgdata.idata +#define S imgdata.sizes +#define O imgdata.params +#define C imgdata.color +#define T imgdata.thumbnail +#define MN imgdata.makernotes +#define IO libraw_internal_data.internal_output_params +#define ID libraw_internal_data.internal_data + +#define makeIs(idx) (imgdata.idata.maker_index == idx) +#define mnCamID imgdata.lens.makernotes.CamID + +#define EXCEPTION_HANDLER(e) \ + do \ + { \ + switch (e) \ + { \ + case LIBRAW_EXCEPTION_MEMPOOL: \ + recycle(); \ + return LIBRAW_MEMPOOL_OVERFLOW; \ + case LIBRAW_EXCEPTION_ALLOC: \ + recycle(); \ + return LIBRAW_UNSUFFICIENT_MEMORY; \ + case LIBRAW_EXCEPTION_TOOBIG: \ + recycle(); \ + return LIBRAW_TOO_BIG; \ + case LIBRAW_EXCEPTION_DECODE_RAW: \ + case LIBRAW_EXCEPTION_DECODE_JPEG: \ + recycle(); \ + return LIBRAW_DATA_ERROR; \ + case LIBRAW_EXCEPTION_DECODE_JPEG2000: \ + recycle(); \ + return LIBRAW_DATA_ERROR; \ + case LIBRAW_EXCEPTION_IO_EOF: \ + case LIBRAW_EXCEPTION_IO_CORRUPT: \ + recycle(); \ + return LIBRAW_IO_ERROR; \ + case LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK: \ + recycle(); \ + return LIBRAW_CANCELLED_BY_CALLBACK; \ + case LIBRAW_EXCEPTION_BAD_CROP: \ + recycle(); \ + return LIBRAW_BAD_CROP; \ + default: \ + return LIBRAW_UNSPECIFIED_ERROR; \ + } \ + } while (0) + +// copy-n-paste from image pipe +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define LIM(x, min, max) MAX(min, MIN(x, max)) +#ifndef CLIP +#define CLIP(x) LIM(x, 0, 65535) +#endif +#define THUMB_READ_BEYOND 16384 + +#define ZERO(a) memset(&a, 0, sizeof(a)) + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/libraw_internal_funcs.h libkdcraw/libkdcraw/libraw/internal/libraw_internal_funcs.h --- libkdcraw-wrk/libkdcraw/libraw/internal/libraw_internal_funcs.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/internal/libraw_internal_funcs.h 2022-11-07 07:46:31.726795008 +0300 @@ -1,24 +1,17 @@ -/* +/* -*- C++ -*- * File: libraw_internal_funcs.h - * Copyright 2008 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 14, 2008 - * - * LibRaw internal data structures (not visible outside) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #ifndef _LIBRAW_INTERNAL_FUNCS_H @@ -27,76 +20,193 @@ #ifndef LIBRAW_LIBRARY_BUILD #error "This file should be used only for libraw library build" #else -// inline functions - ushort sget2 (uchar *s); + +/* inline functions */ + static int stread(char *buf, size_t len, LibRaw_abstract_datastream *fp); + static int getwords(char *line, char *words[], int maxwords, int maxlen); + static void remove_trailing_spaces(char *string, size_t len); + static void remove_caseSubstr(char *string, char *remove); + static void removeExcessiveSpaces(char *string); + static void trimSpaces(char *s); +/* static tables/variables */ + static libraw_static_table_t tagtype_dataunit_bytes; + static libraw_static_table_t Canon_wbi2std; + static libraw_static_table_t Canon_KeyIsZero_Len2048_linenums_2_StdWBi; + static libraw_static_table_t Canon_KeyIs0x0410_Len3072_linenums_2_StdWBi; + static libraw_static_table_t Canon_KeyIs0x0410_Len2048_linenums_2_StdWBi; + static libraw_static_table_t Canon_D30_linenums_2_StdWBi; + static libraw_static_table_t Canon_G9_linenums_2_StdWBi; + + static libraw_static_table_t Fuji_wb_list1; + static libraw_static_table_t FujiCCT_K; + static libraw_static_table_t Fuji_wb_list2; + + static libraw_static_table_t Pentax_wb_list1; + static libraw_static_table_t Pentax_wb_list2; + + static libraw_static_table_t Oly_wb_list1; + static libraw_static_table_t Oly_wb_list2; + + static libraw_static_table_t Sony_SRF_wb_list; + static libraw_static_table_t Sony_SR2_wb_list; + static libraw_static_table_t Sony_SR2_wb_list1; +/* */ + int find_ifd_by_offset(int ); + ushort sget2 (uchar *s); + ushort sget2Rev(uchar *s); + int parseCR3(unsigned long long oAtomList, unsigned long long szAtomList, short &nesting, char *AtomNameStack, short& nTrack, short &TrackType); + void selectCRXTrack(short maxTrack); + void setCanonBodyFeatures (unsigned long long id); + void processCanonCameraInfo (unsigned long long id, uchar *CameraInfo, unsigned maxlen, unsigned type, unsigned dng_writer); + static float _CanonConvertAperture(ushort in); + void Canon_CameraSettings(unsigned len); + void Canon_WBpresets (int skip1, int skip2); + void Canon_WBCTpresets (short WBCTversion); + void parseCanonMakernotes (unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void processNikonLensData (uchar *LensData, unsigned len); + void Nikon_NRW_WBtag (int wb, int skip); + void parseNikonMakernote (int base, int uptag, unsigned dng_writer); + void parseEpsonMakernote (int base, int uptag, unsigned dng_writer); + void parseSigmaMakernote (int base, int uptag, unsigned dng_writer); + void setOlympusBodyFeatures (unsigned long long id); + void getOlympus_CameraType2 (); + void getOlympus_SensorTemperature (unsigned len); + void parseOlympus_Equipment (unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void parseOlympus_CameraSettings (int base, unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void parseOlympus_ImageProcessing (unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void parseOlympus_RawInfo (unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void setPhaseOneFeatures (unsigned long long id); + void setPentaxBodyFeatures (unsigned long long id); + void PentaxISO (ushort c); + void PentaxLensInfo (unsigned long long id, unsigned len); + void parsePentaxMakernotes(int base, unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void parseRicohMakernotes(int base, unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void parseSamsungMakernotes(int base, unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + void setSonyBodyFeatures (unsigned long long id); + void fixupArri(); + void parseSonyLensType2 (uchar a, uchar b); + void parseSonyLensFeatures (uchar a, uchar b); + void process_Sony_0x0116 (uchar * buf, ushort, unsigned long long id); + void process_Sony_0x2010 (uchar * buf, ushort); + void process_Sony_0x9050 (uchar * buf, ushort, unsigned long long id); + void process_Sony_0x9400 (uchar * buf, ushort, unsigned long long id); + void process_Sony_0x9402 (uchar * buf, ushort); + void process_Sony_0x9403 (uchar * buf, ushort); + void process_Sony_0x9406 (uchar * buf, ushort); + void process_Sony_0x940c (uchar * buf, ushort); + void process_Sony_0x940e (uchar * buf, ushort, unsigned long long id); + void parseSonyMakernotes (int base, unsigned tag, unsigned type, unsigned len, unsigned dng_writer, + uchar *&table_buf_0x0116, ushort &table_buf_0x0116_len, + uchar *&table_buf_0x2010, ushort &table_buf_0x2010_len, + uchar *&table_buf_0x9050, ushort &table_buf_0x9050_len, + uchar *&table_buf_0x9400, ushort &table_buf_0x9400_len, + uchar *&table_buf_0x9402, ushort &table_buf_0x9402_len, + uchar *&table_buf_0x9403, ushort &table_buf_0x9403_len, + uchar *&table_buf_0x9406, ushort &table_buf_0x9406_len, + uchar *&table_buf_0x940c, ushort &table_buf_0x940c_len, + uchar *&table_buf_0x940e, ushort &table_buf_0x940e_len); + void parseSonySR2 (uchar *cbuf_SR2, unsigned SR2SubIFDOffset, unsigned SR2SubIFDLength, unsigned dng_writer); + void parseSonySRF (unsigned len); + void parseFujiMakernotes (unsigned tag, unsigned type, unsigned len, unsigned dng_writer); + const char* HassyRawFormat_idx2HR(unsigned idx); + void process_Hassy_Lens (int LensMount); + void parseHassyModel (); + + void setLeicaBodyFeatures(int LeicaMakernoteSignature); + void parseLeicaLensID(); + int parseLeicaLensName(unsigned len); + int parseLeicaInternalBodySerial(unsigned len); + void parseLeicaMakernote(int base, int uptag, unsigned MakernoteTagType); + void parseAdobePanoMakernote (); + void parseAdobeRAFMakernote (); + void GetNormalizedModel (); + void SetStandardIlluminants (unsigned, const char* ); + ushort get2(); unsigned sget4 (uchar *s); unsigned getint (int type); float int_to_float (int i); double getreal (int type); - void read_shorts (ushort *pixel, int count); + double sgetreal(int type, uchar *s); + void read_shorts (ushort *pixel, unsigned count); -// Canon P&S cameras +/* Canon P&S cameras */ void canon_600_fixed_wb (int temp); int canon_600_color (int ratio[2], int mar); void canon_600_auto_wb(); void canon_600_coeff(); void canon_600_load_raw(); + void canon_600_correct(); int canon_s2is(); - void canon_a5_load_raw(); - void parse_ciff (int offset, int length); + void parse_ciff (int offset, int length, int); void ciff_block_1030(); + // LJPEG decoder - unsigned getbits (int nbits); - void init_decoder(); - uchar * make_decoder (const uchar *source, int level); + unsigned getbithuff (int nbits, ushort *huff); + ushort* make_decoder_ref (const uchar **source); + ushort* make_decoder (const uchar *source); int ljpeg_start (struct jhead *jh, int info_only); - int ljpeg_diff (struct decode *dindex); + void ljpeg_end(struct jhead *jh); + int ljpeg_diff (ushort *huff); ushort * ljpeg_row (int jrow, struct jhead *jh); + ushort * ljpeg_row_unrolled (int jrow, struct jhead *jh); + void ljpeg_idct (struct jhead *jh); + unsigned ph1_bithuff (int nbits, ushort *huff); // Canon DSLRs - void crw_init_tables (unsigned table); + void crw_init_tables (unsigned table, ushort *huff[2]); int canon_has_lowbits(); - void canon_compressed_load_raw(); + void canon_load_raw(); void lossless_jpeg_load_raw(); void canon_sraw_load_raw(); - void canon_black(double *); // Adobe DNG - void adobe_copy_pixel (int row, int col, ushort **rp); - void adobe_dng_load_raw_lj(); - void adobe_dng_load_raw_nc(); + void adobe_copy_pixel (unsigned int row, unsigned int col, ushort **rp); + void lossless_dng_load_raw(); + void deflate_dng_load_raw(); + void packed_dng_load_raw(); + void lossy_dng_load_raw(); +//void adobe_dng_load_raw_nc(); // Pentax - void pentax_k10_load_raw(); + void pentax_load_raw(); + void pentax_4shot_load_raw(); + void pentax_tree(); // Nikon (and Minolta Z2) - void nikon_compressed_load_raw(); void nikon_load_raw(); - int nikon_is_compressed(); + void nikon_read_curve(); + void nikon_load_striped_packed_raw(); + void nikon_load_padded_packed_raw(); + void nikon_load_sraw(); + void nikon_yuv_load_raw(); + void nikon_coolscan_load_raw(); int nikon_e995(); int nikon_e2100(); void nikon_3700(); int minolta_z2(); - void nikon_e900_load_raw(); - void nikon_e2100_load_raw(); +// void nikon_e2100_load_raw(); // Fuji - void fuji_load_raw(); +//void fuji_load_raw(); void parse_fuji (int offset); - - +// RedCine + void parse_redcine(); + void redcine_load_raw(); // Rollei void rollei_load_raw(); void parse_rollei(); +// Contax + void parse_kyocera (); + // MF backs - int bayer (unsigned row, unsigned col); +//int bayer (unsigned row, unsigned col); + int p1raw(unsigned,unsigned); void phase_one_flat_field (int is_float, int nc); - void phase_one_correct(); void phase_one_load_raw(); unsigned ph1_bits (int nbits); void phase_one_load_raw_c(); @@ -104,20 +214,29 @@ void leaf_hdr_load_raw(); void sinar_4shot_load_raw(); void imacon_full_load_raw(); - void packed_12_load_raw(); + void hasselblad_full_load_raw(); + void packed_load_raw(); + float find_green(int,int,int,int); void unpacked_load_raw(); + void unpacked_load_raw_FujiDBP(); + void unpacked_load_raw_reversed(); + void unpacked_load_raw_fuji_f700s20(); void parse_sinar_ia(); void parse_phase_one (int base); // Misc P&S cameras + void parse_broadcom(); + void broadcom_load_raw(); void nokia_load_raw(); - unsigned pana_bits (int nbits); + void android_loose_load_raw(); + void android_tight_load_raw(); + void canon_rmf_load_raw(); + unsigned pana_data (int nb, unsigned *bytes); void panasonic_load_raw(); - void olympus_e300_load_raw(); - void olympus_e410_load_raw(); - void olympus_cseries_load_raw(); +// void panasonic_16x10_load_raw(); + void olympus_load_raw(); +// void olympus_cseries_load_raw(); void minolta_rd175_load_raw(); - void casio_qv5700_load_raw(); void quicktake_100_load_raw(); const int* make_decoder_int (const int *source, int level); int radc_token (int tree); @@ -140,62 +259,130 @@ int kodak_65000_decode (short *out, int bsize); void kodak_65000_load_raw(); void kodak_rgb_load_raw(); - void kodak_yrgb_load_raw(); - + void kodak_ycbcr_load_raw(); +// void kodak_yrgb_load_raw(); + void kodak_c330_load_raw(); + void kodak_c603_load_raw(); + void kodak_rgb_load_thumb(); + void kodak_ycbcr_load_thumb(); + void float_dng_load_raw_placeholder(); + void vc5_dng_load_raw_placeholder(); // It's a Sony (and K&M) void sony_decrypt (unsigned *data, int len, int start, int key); void sony_load_raw(); void sony_arw_load_raw(); void sony_arw2_load_raw(); + void sony_arq_load_raw(); + void samsung_load_raw(); + void samsung2_load_raw(); + void samsung3_load_raw(); void parse_minolta (int base); -#ifndef NO_FOVEON +#ifdef USE_X3FTOOLS // Foveon/Sigma - void foveon_load_camf(); - void foveon_load_raw(); - const char* foveon_camf_param (const char *block, const char *param); - void * foveon_camf_matrix (unsigned dim[3], const char *name); - int foveon_fixed (void *ptr, int size, const char *name); - float foveon_avg (short *pix, int range[2], float cfilt); - short * foveon_make_curve (double max, double mul, double filt); - void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt); - int foveon_apply_curve (short *curve, int i); - void foveon_interpolate(); - char * foveon_gets (int offset, char *str, int len); - void parse_foveon(); +// We always have x3f code compiled in! + void parse_x3f(); + void x3f_load_raw(); + void x3f_dpq_interpolate_rg(); + void x3f_dpq_interpolate_af(int xstep, int ystep, int scale); // 1x1 af pixels + void x3f_dpq_interpolate_af_sd(int xstart,int ystart, int xend, int yend, int xstep, int ystep, int scale); // sd Quattro interpolation +#else + void parse_x3f() {} + void x3f_load_raw(){} +#endif +#ifdef USE_6BY9RPI + void rpi_load_raw8(); + void rpi_load_raw12(); + void rpi_load_raw14(); + void rpi_load_raw16(); + void parse_raspberrypi(); #endif - // CAM/RGB void pseudoinverse (double (*in)[3], double (*out)[3], int size); - void cam_xyz_coeff (double cam_xyz[4][3]); - void adobe_coeff (const char *, const char *); void simple_coeff (int index); // Tiff/Exif parsers void tiff_get (unsigned base,unsigned *tag, unsigned *type, unsigned *len, unsigned *save); + short tiff_sget(unsigned save, uchar *buf, unsigned buf_len, INT64 *tag_offset, + unsigned *tag_id, unsigned *tag_type, INT64 *tag_dataoffset, + unsigned *tag_datalen, int *tag_dataunit_len); void parse_thumb_note (int base, unsigned toff, unsigned tlen); void parse_makernote (int base, int uptag); + void parse_makernote_0xc634(int base, int uptag, unsigned dng_writer); void parse_exif (int base); - void linear_table (unsigned len); + void parse_exif_interop(int base); + void linear_table(unsigned len); + void Kodak_DCR_WBtags(int wb, unsigned type, int wbi); + void Kodak_KDC_WBtags(int wb, int wbi); + short KodakIllumMatrix (unsigned type, float *romm_camIllum); void parse_kodak_ifd (int base); int parse_tiff_ifd (int base); - void parse_tiff (int base); + int parse_tiff (int base); + void apply_tiff(void); void parse_gps (int base); - void romm_coeff (float romm_cam[3][3]); + void parse_gps_libraw(int base); + void aRGB_coeff(double aRGB_cam[3][3]); + void romm_coeff(float romm_cam[3][3]); void parse_mos (int offset); + void parse_qt (int end); void get_timestamp (int reversed); -// External JPEGs, what cameras uses it ? - void parse_external_jpeg(); - // The identify short guess_byte_order (int words); - + void identify_process_dng_fields(); + void identify_finetune_pentax(); + void identify_finetune_by_filesize(int); + void identify_finetune_dcr(char head[64],int,int); // Tiff writer - void tiff_set (ushort *ntag, ushort tag, ushort type, int count, int val); + void tiff_set(struct tiff_hdr *th, ushort *ntag,ushort tag, ushort type, int count, int val); void tiff_head (struct tiff_hdr *th, int full); + +// split AHD code + void ahd_interpolate_green_h_and_v(int top, int left, ushort (*out_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3]); + void ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][3], short (*out_lab)[LIBRAW_AHD_TILE][3]); + void ahd_interpolate_r_and_b_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], short (*out_lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3]); + void ahd_interpolate_build_homogeneity_map(int top, int left, short (*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], char (*out_homogeneity_map)[LIBRAW_AHD_TILE][2]); + void ahd_interpolate_combine_homogeneous_pixels(int top, int left, ushort (*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], char (*homogeneity_map)[LIBRAW_AHD_TILE][2]); + + void init_fuji_compr(struct fuji_compressed_params* info); + void init_fuji_block(struct fuji_compressed_block* info, const struct fuji_compressed_params *params, INT64 raw_offset, unsigned dsize); + void copy_line_to_xtrans(struct fuji_compressed_block* info, int cur_line, int cur_block, int cur_block_width); + void copy_line_to_bayer(struct fuji_compressed_block* info, int cur_line, int cur_block, int cur_block_width); + void xtrans_decode_block(struct fuji_compressed_block* info, const struct fuji_compressed_params *params, int cur_line); + void fuji_bayer_decode_block(struct fuji_compressed_block* info, const struct fuji_compressed_params *params, int cur_line); + void fuji_compressed_load_raw(); + void fuji_14bit_load_raw(); + void parse_fuji_compressed_header(); + void crxLoadRaw(); + int crxParseImageHeader(uchar *cmp1TagData, int nTrack); + void panasonicC6_load_raw(); + void panasonicC7_load_raw(); + + void nikon_14bit_load_raw(); + +// DCB + void dcb_pp(); + void dcb_copy_to_buffer(float (*image2)[3]); + void dcb_restore_from_buffer(float (*image2)[3]); + void dcb_color(); + void dcb_color_full(); + void dcb_map(); + void dcb_correction(); + void dcb_correction2(); + void dcb_refinement(); + void rgb_to_lch(double (*image3)[3]); + void lch_to_rgb(double (*image3)[3]); + void fbdd_correction(); + void fbdd_correction2(double (*image3)[3]); + void fbdd_green(); + void dcb_ver(float (*image3)[3]); + void dcb_hor(float (*image2)[3]); + void dcb_color2(float (*image2)[3]); + void dcb_color3(float (*image3)[3]); + void dcb_decide(float (*image2)[3], float (*image3)[3]); + void dcb_nyquist(); #endif #endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/var_defines.h libkdcraw/libkdcraw/libraw/internal/var_defines.h --- libkdcraw-wrk/libkdcraw/libraw/internal/var_defines.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/internal/var_defines.h 2022-11-07 07:46:31.726795008 +0300 @@ -1,45 +1,51 @@ -/* +/* -*- C++ -*- * File: var_defines.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8, 2008 * * LibRaw redefinitions of dcraw internal variables - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #ifndef VAR_DEFINES_H #define VAR_DEFINES_H -// imgdata.idata -#define make (imgdata.idata.make) -#define model (imgdata.idata.model) -#define is_raw (imgdata.idata.raw_count) -#define dng_version (imgdata.idata.dng_version) -#define is_foveon (imgdata.idata.is_foveon) -#define colors (imgdata.idata.colors) -#define cdesc (imgdata.idata.cdesc) -#define filters (imgdata.idata.filters) +// imgdata.idata +#define make (imgdata.idata.make) +#define model (imgdata.idata.model) +#define software (imgdata.idata.software) +#define is_raw (imgdata.idata.raw_count) +#define dng_version (imgdata.idata.dng_version) +#define is_foveon (imgdata.idata.is_foveon) +#define colors (imgdata.idata.colors) +#define cdesc (imgdata.idata.cdesc) +#define filters (imgdata.idata.filters) +#define xtrans (imgdata.idata.xtrans) +#define xtrans_abs (imgdata.idata.xtrans_abs) +#define xmpdata (imgdata.idata.xmpdata) +#define xmplen (imgdata.idata.xmplen) //imgdata image -#define image (imgdata.image) +#define image (imgdata.image) +#define raw_image (imgdata.rawdata.raw_image) +#define color_image (imgdata.rawdata.color_image) +#define normalized_make (imgdata.idata.normalized_make) +#define normalized_model (imgdata.idata.normalized_model) +#define maker_index (imgdata.idata.maker_index) // imgdata.sizes #define raw_height (imgdata.sizes.raw_height) #define raw_width (imgdata.sizes.raw_width) +#define raw_pitch (imgdata.sizes.raw_pitch) #define height (imgdata.sizes.height) #define width (imgdata.sizes.width) #define top_margin (imgdata.sizes.top_margin) @@ -50,6 +56,8 @@ #define iwidth (imgdata.sizes.iwidth) #define pixel_aspect (imgdata.sizes.pixel_aspect) #define flip (imgdata.sizes.flip) +#define mask (imgdata.sizes.mask) +#define raw_stride (libraw_internal_data.unpacker_data.raw_stride) //imgdata.color #define white (imgdata.color.white) @@ -62,8 +70,10 @@ #endif #ifndef SRC_USES_BLACK #define black (imgdata.color.black) +#define cblack (imgdata.color.cblack) #endif #define maximum (imgdata.color.maximum) +#define channel_maximum (imgdata.color.channel_maximum) #define profile_length (imgdata.color.profile_length) #define color_flags (imgdata.color.color_flags) #define ph1 (imgdata.color.phase_one_data) @@ -72,25 +82,27 @@ #define model2 (imgdata.color.model2) //imgdata.thumbnail - #define thumb_width (imgdata.thumbnail.twidth) #define thumb_height (imgdata.thumbnail.theight) #define thumb_length (imgdata.thumbnail.tlength) //imgdata.others -#define iso_speed (imgdata.other.iso_speed) -#define shutter (imgdata.other.shutter) -#define aperture (imgdata.other.aperture) -#define focal_len (imgdata.other.focal_len) -#define timestamp (imgdata.other.timestamp) -#define shot_order (imgdata.other.shot_order) -#define gpsdata (imgdata.other.gpsdata) -#define desc (imgdata.other.desc) -#define artist (imgdata.other.artist) +#define iso_speed (imgdata.other.iso_speed) +#define shutter (imgdata.other.shutter) +#define aperture (imgdata.other.aperture) +#define focal_len (imgdata.other.focal_len) +#define timestamp (imgdata.other.timestamp) +#define shot_order (imgdata.other.shot_order) +#define gpsdata (imgdata.other.gpsdata) +#define desc (imgdata.other.desc) +#define artist (imgdata.other.artist) + +#define FujiCropMode (imgdata.makernotes.fuji.CropMode) //imgdata.output #define greybox (imgdata.params.greybox) +#define cropbox (imgdata.params.cropbox) #define aber (imgdata.params.aber) #define gamm (imgdata.params.gamm) #define user_mul (imgdata.params.user_mul) @@ -99,9 +111,7 @@ #define threshold (imgdata.params.threshold) #define half_size (imgdata.params.half_size) #define four_color_rgb (imgdata.params.four_color_rgb) -#define document_mode (imgdata.params.document_mode) #define highlight (imgdata.params.highlight) -//#define verbose (imgdata.params.verbose) #define use_auto_wb (imgdata.params.use_auto_wb) #define use_camera_wb (imgdata.params.use_camera_wb) #define use_camera_matrix (imgdata.params.use_camera_matrix) @@ -111,19 +121,23 @@ #define output_tiff (imgdata.params.output_tiff) #define med_passes (imgdata.params.med_passes) #define no_auto_bright (imgdata.params.no_auto_bright) +#define auto_bright_thr (imgdata.params.auto_bright_thr) #define use_fuji_rotate (imgdata.params.use_fuji_rotate) #define filtering_mode (imgdata.params.filtering_mode) -//rgb_constants -#define xyz_rgb (rgb_constants.xyz_rgb) -#define d65_white (rgb_constants.d65_white) +// DCB +#define dcb_iterations (imgdata.params.iterations) +#define dcb_enhance_fl (imgdata.params.dcb_enhance) +#define fbdd_noiserd (imgdata.params.fbdd_noiserd) //libraw_internal_data.internal_data #define meta_data (libraw_internal_data.internal_data.meta_data) #define ifp libraw_internal_data.internal_data.input #define ifname ((char*)libraw_internal_data.internal_data.input->fname()) +#define ofp libraw_internal_data.internal_data.output #define profile_offset (libraw_internal_data.internal_data.profile_offset) #define thumb_offset (libraw_internal_data.internal_data.toffset) +#define pana_black (libraw_internal_data.internal_data.pana_black) //libraw_internal_data.internal_output_params #define mix_green (libraw_internal_data.internal_output_params.mix_green) @@ -143,8 +157,10 @@ //libraw_internal_data.identify_data #define exif_cfa (libraw_internal_data.identify_data.olympus_exif_cfa) #define unique_id (libraw_internal_data.identify_data.unique_id) +#define OlyID (libraw_internal_data.identify_data.OlyID) #define tiff_nifds (libraw_internal_data.identify_data.tiff_nifds) #define tiff_flip (libraw_internal_data.identify_data.tiff_flip) +#define metadata_blocks (libraw_internal_data.identify_data.metadata_blocks) //libraw_internal_data.unpacker_data #define order (libraw_internal_data.unpacker_data.order) @@ -154,6 +170,7 @@ #define kodak_cbpp (libraw_internal_data.unpacker_data.kodak_cbpp) #define strip_offset (libraw_internal_data.unpacker_data.strip_offset) #define data_offset (libraw_internal_data.unpacker_data.data_offset) +#define data_size (libraw_internal_data.unpacker_data.data_size) #define meta_offset (libraw_internal_data.unpacker_data.meta_offset) #define meta_length (libraw_internal_data.unpacker_data.meta_length) #define thumb_misc (libraw_internal_data.unpacker_data.thumb_misc) @@ -161,10 +178,21 @@ #define tiff_samples (libraw_internal_data.unpacker_data.tiff_samples) #define tiff_bps (libraw_internal_data.unpacker_data.tiff_bps) #define tiff_compress (libraw_internal_data.unpacker_data.tiff_compress) +#define tiff_sampleformat (libraw_internal_data.unpacker_data.tiff_sampleformat) #define zero_after_ff (libraw_internal_data.unpacker_data.zero_after_ff) #define tile_width (libraw_internal_data.unpacker_data.tile_width) #define tile_length (libraw_internal_data.unpacker_data.tile_length) #define load_flags (libraw_internal_data.unpacker_data.load_flags) +#define pana_encoding (libraw_internal_data.unpacker_data.pana_encoding) +#define pana_bpp (libraw_internal_data.unpacker_data.pana_bpp) +#define CM_found (libraw_internal_data.unpacker_data.CM_found) + +#define is_NikonTransfer (libraw_internal_data.unpacker_data.is_NikonTransfer) +#define is_Sony (libraw_internal_data.unpacker_data.is_Sony) +#define is_4K_RAFdata (libraw_internal_data.unpacker_data.is_4K_RAFdata) +#define is_PentaxRicohMakernotes (libraw_internal_data.unpacker_data.is_PentaxRicohMakernotes) +#define is_pana_raw (libraw_internal_data.unpacker_data.is_pana_raw) + #ifdef LIBRAW_IO_REDEFINED #define fread(ptr,size,n,stream) stream->read(ptr,size,n) @@ -172,8 +200,13 @@ #define fseeko(stream,o,w) stream->seek(o,w) #define ftell(stream) stream->tell() #define ftello(stream) stream->tell() +#define feof(stream) stream->eof() +#ifdef getc +#undef getc +#endif #define getc(stream) stream->get_char() #define fgetc(stream) stream->get_char() +#define fgetcb(stream) stream->get_char_buf() #define fgets(str,n,stream) stream->gets(str,n) #define fscanf(stream,fmt,ptr) stream->scanf_one(fmt,ptr) #endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/internal/x3f_tools.h libkdcraw/libkdcraw/libraw/internal/x3f_tools.h --- libkdcraw-wrk/libkdcraw/libraw/internal/x3f_tools.h 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/internal/x3f_tools.h 2022-11-07 07:46:31.726795008 +0300 @@ -0,0 +1,539 @@ +/* -*- C++ -*- + * Copyright 2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ + +/* Library for accessing X3F Files +---------------------------------------------------------------- +BSD-style License +---------------------------------------------------------------- + +* Copyright (c) 2010, Roland Karlsson (roland@proxel.se) +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the organization nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ROLAND KARLSSON ''AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL ROLAND KARLSSON BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef X3F_TOOLS_H +#define X3F_TOOLS_H + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <stdio.h> +#include "../libraw/libraw_datastream.h" + +/* From X3F_IO.H */ + +#define SIZE_UNIQUE_IDENTIFIER 16 +#define SIZE_WHITE_BALANCE 32 +#define SIZE_COLOR_MODE 32 +#define NUM_EXT_DATA_2_1 32 +#define NUM_EXT_DATA_3_0 64 +#define NUM_EXT_DATA NUM_EXT_DATA_3_0 + +#define X3F_VERSION(MAJ, MIN) (uint32_t)(((MAJ) << 16) + MIN) +#define X3F_VERSION_2_0 X3F_VERSION(2, 0) +#define X3F_VERSION_2_1 X3F_VERSION(2, 1) +#define X3F_VERSION_2_2 X3F_VERSION(2, 2) +#define X3F_VERSION_2_3 X3F_VERSION(2, 3) +#define X3F_VERSION_3_0 X3F_VERSION(3, 0) +#define X3F_VERSION_4_0 X3F_VERSION(4, 0) + +/* Main file identifier */ +#define X3F_FOVb (uint32_t)(0x62564f46) +/* Directory identifier */ +#define X3F_SECd (uint32_t)(0x64434553) +/* Property section identifiers */ +#define X3F_PROP (uint32_t)(0x504f5250) +#define X3F_SECp (uint32_t)(0x70434553) +/* Image section identifiers */ +#define X3F_IMAG (uint32_t)(0x46414d49) +#define X3F_IMA2 (uint32_t)(0x32414d49) +#define X3F_SECi (uint32_t)(0x69434553) +/* CAMF section identifiers */ +#define X3F_CAMF (uint32_t)(0x464d4143) +#define X3F_SECc (uint32_t)(0x63434553) +/* CAMF entry identifiers */ +#define X3F_CMbP (uint32_t)(0x50624d43) +#define X3F_CMbT (uint32_t)(0x54624d43) +#define X3F_CMbM (uint32_t)(0x4d624d43) +#define X3F_CMb (uint32_t)(0x00624d43) +/* SDQ section identifiers ? - TODO */ +#define X3F_SPPA (uint32_t)(0x41505053) +#define X3F_SECs (uint32_t)(0x73434553) + +#define X3F_IMAGE_THUMB_PLAIN (uint32_t)(0x00020003) +#define X3F_IMAGE_THUMB_HUFFMAN (uint32_t)(0x0002000b) +#define X3F_IMAGE_THUMB_JPEG (uint32_t)(0x00020012) +#define X3F_IMAGE_THUMB_SDQ (uint32_t)(0x00020019) /* SDQ ? - TODO */ + +#define X3F_IMAGE_RAW_HUFFMAN_X530 (uint32_t)(0x00030005) +#define X3F_IMAGE_RAW_HUFFMAN_10BIT (uint32_t)(0x00030006) +#define X3F_IMAGE_RAW_TRUE (uint32_t)(0x0003001e) +#define X3F_IMAGE_RAW_MERRILL (uint32_t)(0x0001001e) +#define X3F_IMAGE_RAW_QUATTRO (uint32_t)(0x00010023) +#define X3F_IMAGE_RAW_SDQ (uint32_t)(0x00010025) +#define X3F_IMAGE_RAW_SDQH (uint32_t)(0x00010027) +#define X3F_IMAGE_RAW_SDQH2 (uint32_t)(0x00010029) + +#define X3F_IMAGE_HEADER_SIZE 28 +#define X3F_CAMF_HEADER_SIZE 28 +#define X3F_PROPERTY_LIST_HEADER_SIZE 24 + +typedef uint16_t utf16_t; + +typedef int bool_t; + +typedef enum x3f_extended_types_e +{ + X3F_EXT_TYPE_NONE = 0, + X3F_EXT_TYPE_EXPOSURE_ADJUST = 1, + X3F_EXT_TYPE_CONTRAST_ADJUST = 2, + X3F_EXT_TYPE_SHADOW_ADJUST = 3, + X3F_EXT_TYPE_HIGHLIGHT_ADJUST = 4, + X3F_EXT_TYPE_SATURATION_ADJUST = 5, + X3F_EXT_TYPE_SHARPNESS_ADJUST = 6, + X3F_EXT_TYPE_RED_ADJUST = 7, + X3F_EXT_TYPE_GREEN_ADJUST = 8, + X3F_EXT_TYPE_BLUE_ADJUST = 9, + X3F_EXT_TYPE_FILL_LIGHT_ADJUST = 10 +} x3f_extended_types_t; + +typedef struct x3f_property_s +{ + /* Read from file */ + uint32_t name_offset; + uint32_t value_offset; + + /* Computed */ + utf16_t *name; /* 0x0000 terminated UTF 16 */ + utf16_t *value; /* 0x0000 terminated UTF 16 */ +} x3f_property_t; + +typedef struct x3f_property_table_s +{ + uint32_t size; + x3f_property_t *element; +} x3f_property_table_t; + +typedef struct x3f_property_list_s +{ + /* 2.0 Fields */ + uint32_t num_properties; + uint32_t character_format; + uint32_t reserved; + uint32_t total_length; + + x3f_property_table_t property_table; + + void *data; + + uint32_t data_size; + +} x3f_property_list_t; + +typedef struct x3f_table8_s +{ + uint32_t size; + uint8_t *element; +} x3f_table8_t; + +typedef struct x3f_table16_s +{ + uint32_t size; + uint16_t *element; +} x3f_table16_t; + +typedef struct x3f_table32_s +{ + uint32_t size; + uint32_t *element; +} x3f_table32_t; + +typedef struct +{ + uint8_t *data; /* Pointer to actual image data */ + void *buf; /* Pointer to allocated buffer for free() */ + uint32_t rows; + uint32_t columns; + uint32_t channels; + uint32_t row_stride; +} x3f_area8_t; + +typedef struct +{ + uint16_t *data; /* Pointer to actual image data */ + void *buf; /* Pointer to allocated buffer for free() */ + uint32_t rows; + uint32_t columns; + uint32_t channels; + uint32_t row_stride; +} x3f_area16_t; + +#define UNDEFINED_LEAF 0xffffffff + +typedef struct x3f_huffnode_s +{ + struct x3f_huffnode_s *branch[2]; + uint32_t leaf; +} x3f_huffnode_t; + +typedef struct x3f_hufftree_s +{ + uint32_t free_node_index; /* Free node index in huffman tree array */ + uint32_t total_node_index; + x3f_huffnode_t *nodes; /* Coding tree */ +} x3f_hufftree_t; + +typedef struct x3f_true_huffman_element_s +{ + uint8_t code_size; + uint8_t code; +} x3f_true_huffman_element_t; + +typedef struct x3f_true_huffman_s +{ + uint32_t size; + x3f_true_huffman_element_t *element; +} x3f_true_huffman_t; + +/* 0=bottom, 1=middle, 2=top */ +#define TRUE_PLANES 3 + +typedef struct x3f_true_s +{ + uint16_t seed[TRUE_PLANES]; /* Always 512,512,512 */ + uint16_t unknown; /* Always 0 */ + x3f_true_huffman_t table; /* Huffman table - zero + terminated. size is the number of + leaves plus 1.*/ + + x3f_table32_t plane_size; /* Size of the 3 planes */ + uint8_t *plane_address[TRUE_PLANES]; /* computed offset to the planes */ + x3f_hufftree_t tree; /* Coding tree */ + x3f_area16_t x3rgb16; /* 3x16 bit X3-RGB data */ +} x3f_true_t; + +typedef struct x3f_quattro_s +{ + struct + { + uint16_t columns; + uint16_t rows; + } plane[TRUE_PLANES]; + uint32_t unknown; + + bool_t quattro_layout; + x3f_area16_t top16; /* Container for the bigger top layer */ +} x3f_quattro_t; + +typedef struct x3f_huffman_s +{ + x3f_table16_t mapping; /* Value Mapping = X3F lossy compression */ + x3f_table32_t table; /* Coding Table */ + x3f_hufftree_t tree; /* Coding tree */ + x3f_table32_t row_offsets; /* Row offsets */ + x3f_area8_t rgb8; /* 3x8 bit RGB data */ + x3f_area16_t x3rgb16; /* 3x16 bit X3-RGB data */ +} x3f_huffman_t; + +typedef struct x3f_image_data_s +{ + /* 2.0 Fields */ + /* ------------------------------------------------------------------ */ + /* Known combinations of type and format are: + 1-6, 2-3, 2-11, 2-18, 3-6 */ + uint32_t type; /* 1 = RAW X3 (SD1) + 2 = thumbnail or maybe just RGB + 3 = RAW X3 */ + uint32_t format; /* 3 = 3x8 bit pixmap + 6 = 3x10 bit huffman with map table + 11 = 3x8 bit huffman + 18 = JPEG */ + uint32_t type_format; /* type<<16 + format */ + /* ------------------------------------------------------------------ */ + + uint32_t columns; /* width / row size in pixels */ + uint32_t rows; /* height */ + uint32_t row_stride; /* row size in bytes */ + + /* NULL if not used */ + x3f_huffman_t *huffman; /* Huffman help data */ + x3f_true_t *tru; /* TRUE help data */ + x3f_quattro_t *quattro; /* Quattro help data */ + + void *data; /* Take from file if NULL. Otherwise, + this is the actual data bytes in + the file. */ + uint32_t data_size; + +} x3f_image_data_t; + +typedef struct camf_dim_entry_s +{ + uint32_t size; + uint32_t name_offset; + uint32_t n; /* 0,1,2,3... */ + char *name; +} camf_dim_entry_t; + +typedef enum +{ + M_FLOAT, + M_INT, + M_UINT +} matrix_type_t; + +typedef struct camf_entry_s +{ + /* pointer into decoded data */ + void *entry; + + /* entry header */ + uint32_t id; + uint32_t version; + uint32_t entry_size; + uint32_t name_offset; + uint32_t value_offset; + + /* computed values */ + char *name_address; + void *value_address; + uint32_t name_size; + uint32_t value_size; + + /* extracted values for explicit CAMF entry types*/ + uint32_t text_size; + char *text; + + uint32_t property_num; + char **property_name; + uint8_t **property_value; + + uint32_t matrix_dim; + camf_dim_entry_t *matrix_dim_entry; + + /* Offset, pointer and size and type of raw data */ + uint32_t matrix_type; + uint32_t matrix_data_off; + void *matrix_data; + uint32_t matrix_element_size; + + /* Pointer and type of copied data */ + matrix_type_t matrix_decoded_type; + void *matrix_decoded; + + /* Help data to try to estimate element size */ + uint32_t matrix_elements; + uint32_t matrix_used_space; + double matrix_estimated_element_size; + +} camf_entry_t; + +typedef struct camf_entry_table_s +{ + uint32_t size; + camf_entry_t *element; +} camf_entry_table_t; + +typedef struct x3f_camf_typeN_s +{ + uint32_t val0; + uint32_t val1; + uint32_t val2; + uint32_t val3; +} x3f_camf_typeN_t; + +typedef struct x3f_camf_type2_s +{ + uint32_t reserved; + uint32_t infotype; + uint32_t infotype_version; + uint32_t crypt_key; +} x3f_camf_type2_t; + +typedef struct x3f_camf_type4_s +{ + uint32_t decoded_data_size; + uint32_t decode_bias; + uint32_t block_size; + uint32_t block_count; +} x3f_camf_type4_t; + +typedef struct x3f_camf_type5_s +{ + uint32_t decoded_data_size; + uint32_t decode_bias; + uint32_t unknown2; + uint32_t unknown3; +} x3f_camf_type5_t; + +typedef struct x3f_camf_s +{ + + /* Header info */ + uint32_t type; + union { + x3f_camf_typeN_t tN; + x3f_camf_type2_t t2; + x3f_camf_type4_t t4; + x3f_camf_type5_t t5; + }; + + /* The encrypted raw data */ + void *data; + uint32_t data_size; + + /* Help data for type 4 Huffman compression */ + x3f_true_huffman_t table; + x3f_hufftree_t tree; + uint8_t *decoding_start; + uint32_t decoding_size; + + /* The decrypted data */ + void *decoded_data; + uint32_t decoded_data_size; + + /* Pointers into the decrypted data */ + camf_entry_table_t entry_table; +} x3f_camf_t; + +typedef struct x3f_directory_entry_header_s +{ + uint32_t identifier; /* Should be ´SECp´, "SECi", ... */ + uint32_t version; /* 0x00020001 is version 2.1 */ + union { + x3f_property_list_t property_list; + x3f_image_data_t image_data; + x3f_camf_t camf; + } data_subsection; +} x3f_directory_entry_header_t; + +typedef struct x3f_directory_entry_s +{ + struct + { + uint32_t offset; + uint32_t size; + } input, output; + + uint32_t type; + + x3f_directory_entry_header_t header; +} x3f_directory_entry_t; + +typedef struct x3f_directory_section_s +{ + uint32_t identifier; /* Should be ´SECd´ */ + uint32_t version; /* 0x00020001 is version 2.1 */ + + /* 2.0 Fields */ + uint32_t num_directory_entries; + x3f_directory_entry_t *directory_entry; +} x3f_directory_section_t; + +typedef struct x3f_header_s +{ + /* 2.0 Fields */ + uint32_t identifier; /* Should be ´FOVb´ */ + uint32_t version; /* 0x00020001 means 2.1 */ + uint8_t unique_identifier[SIZE_UNIQUE_IDENTIFIER]; + uint32_t mark_bits; + uint32_t columns; /* Columns and rows ... */ + uint32_t rows; /* ... before rotation */ + uint32_t rotation; /* 0, 90, 180, 270 */ + + char white_balance[SIZE_WHITE_BALANCE]; /* Introduced in 2.1 */ + char color_mode[SIZE_COLOR_MODE]; /* Introduced in 2.3 */ + + /* Introduced in 2.1 and extended from 32 to 64 in 3.0 */ + uint8_t extended_types[NUM_EXT_DATA]; /* x3f_extended_types_t */ + float extended_data[NUM_EXT_DATA]; /* 32 bits, but do type differ? */ +} x3f_header_t; + +typedef struct x3f_info_s +{ + char *error; + struct + { + LibRaw_abstract_datastream *file; /* Use if more data is needed */ + } input, output; +} x3f_info_t; + +typedef struct x3f_s +{ + x3f_info_t info; + x3f_header_t header; + x3f_directory_section_t directory_section; +} x3f_t; + +typedef enum x3f_return_e +{ + X3F_OK = 0, + X3F_ARGUMENT_ERROR = 1, + X3F_INFILE_ERROR = 2, + X3F_OUTFILE_ERROR = 3, + X3F_INTERNAL_ERROR = 4 +} x3f_return_t; + +x3f_return_t x3f_delete(x3f_t *x3f); + +/* Hacky external flags */ +/* --------------------------------------------------------------------- */ + +extern int legacy_offset; +extern bool_t auto_legacy_offset; + +/* --------------------------------------------------------------------- */ +/* Huffman Decode Macros */ +/* --------------------------------------------------------------------- */ + +#define HUF_TREE_MAX_LENGTH 27 +#define HUF_TREE_MAX_NODES(_leaves) ((HUF_TREE_MAX_LENGTH + 1) * (_leaves)) +#define HUF_TREE_GET_LENGTH(_v) (((_v) >> 27) & 0x1f) +#define HUF_TREE_GET_CODE(_v) ((_v)&0x07ffffff) + +x3f_t *x3f_new_from_file(LibRaw_abstract_datastream *infile); +x3f_return_t x3f_delete(x3f_t *x3f); +x3f_directory_entry_t *x3f_get_raw(x3f_t *x3f); +x3f_directory_entry_t *x3f_get_thumb_plain(x3f_t *x3f); +x3f_return_t x3f_load_data(x3f_t *x3f, x3f_directory_entry_t *DE); +x3f_directory_entry_t *x3f_get_thumb_huffman(x3f_t *x3f); +x3f_directory_entry_t *x3f_get_thumb_jpeg(x3f_t *x3f); +x3f_directory_entry_t *x3f_get_camf(x3f_t *x3f); +x3f_directory_entry_t *x3f_get_prop(x3f_t *x3f); +/* extern */ int64_t x3f_load_data_size(x3f_t *x3f, x3f_directory_entry_t *DE); + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/libraw/libraw.h libkdcraw/libkdcraw/libraw/libraw/libraw.h --- libkdcraw-wrk/libkdcraw/libraw/libraw/libraw.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/libraw/libraw.h 2022-11-07 07:46:31.726795008 +0300 @@ -1,38 +1,68 @@ -/* +/* -*- C++ -*- * File: libraw.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> - * Created: Sat Mar 8, 2008 + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Mar 8, 2008 * * LibRaw C++ interface * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + +*/ #ifndef _LIBRAW_CLASS_H #define _LIBRAW_CLASS_H -#ifdef HAVE_CONFIG_H -#include "config.h" +#ifdef __linux__ +#define _FILE_OFFSET_BITS 64 #endif +/* maximum file size to use LibRaw_file_datastream (fully buffered) I/O */ +#define LIBRAW_USE_STREAMS_DATASTREAM_MAXSIZE (250 * 1024L * 1024L) + #include <limits.h> #include <memory.h> #include <stdio.h> #include <stdlib.h> +#include <math.h> + +/* better WIN32 defines */ +/* better WIN32 defines */ + +#if defined(WIN32) || defined(_WIN32) + +/* Win32 API */ +# ifndef LIBRAW_WIN32_CALLS +# define LIBRAW_WIN32_CALLS +# endif + +/* DLLs: Microsoft or Intel compiler */ +# if defined(_MSC_VER) || defined(__INTEL_COMPILER) +# ifndef LIBRAW_WIN32_DLLDEFS +# define LIBRAW_WIN32_DLLDEFS +# endif +#endif + +/* wchar_t* API for std::filebuf */ +# if (defined(_MSC_VER) && (_MSC_VER > 1310)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 910)) +# ifndef LIBRAW_WIN32_UNICODEPATHS +# define LIBRAW_WIN32_UNICODEPATHS +# endif +# elif _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T +# ifndef LIBRAW_WIN32_UNICODEPATHS +# define LIBRAW_WIN32_UNICODEPATHS +# endif +# endif + +#endif #include "libraw_datastream.h" #include "libraw_types.h" @@ -40,194 +70,416 @@ #include "libraw_internal.h" #include "libraw_alloc.h" -//#define DCRAW_VERBOSE - #ifdef __cplusplus -extern "C" +extern "C" { #endif -DllDef const char *libraw_strerror(int errorcode); -DllDef const char *libraw_strprogress(enum LibRaw_progress); - // LibRaw C API -DllDef libraw_data_t *libraw_init(unsigned int flags); -DllDef int libraw_open_file(libraw_data_t*, const char *); -DllDef int libraw_open_buffer(libraw_data_t*, void * buffer, size_t size); -DllDef int libraw_unpack(libraw_data_t*); -DllDef int libraw_unpack_thumb(libraw_data_t*); -DllDef void libraw_recycle(libraw_data_t*); -DllDef void libraw_close(libraw_data_t*); - // version helpers -DllDef const char* libraw_version(); -DllDef int libraw_versionNumber(); - // Camera list -DllDef const char** libraw_cameraList(); -DllDef int libraw_cameraCount(); - -DllDef void libraw_set_memerror_handler(libraw_data_t*, memory_callback cb, void *datap); -DllDef void libraw_set_dataerror_handler(libraw_data_t*,data_callback func,void *datap); -DllDef void libraw_set_progress_handler(libraw_data_t*,progress_callback cb,void *datap); -DllDef int libraw_add_masked_borders_to_bitmap(libraw_data_t* lr); -DllDef const char * libraw_unpack_function_name(libraw_data_t* lr); -DllDef int libraw_rotate_fuji_raw(libraw_data_t* lr); - - // DCRAW compatibility -DllDef int libraw_adjust_sizes_info_only(libraw_data_t*); -DllDef int libraw_dcraw_document_mode_processing(libraw_data_t*); -DllDef int libraw_dcraw_ppm_tiff_writer(libraw_data_t* lr,const char *filename); -DllDef int libraw_dcraw_thumb_writer(libraw_data_t* lr,const char *fname); -DllDef int libraw_dcraw_process(libraw_data_t* lr); -DllDef libraw_processed_image_t* dcraw_make_mem_image(libraw_data_t* lr, int *errc); -DllDef libraw_processed_image_t* dcraw_make_mem_thumb(libraw_data_t* lr, int *errc); + DllDef const char *libraw_strerror(int errorcode); + DllDef const char *libraw_strprogress(enum LibRaw_progress); + /* LibRaw C API */ + DllDef libraw_data_t *libraw_init(unsigned int flags); + DllDef int libraw_open_file(libraw_data_t *, const char *); + DllDef int libraw_open_file_ex(libraw_data_t *, const char *, + INT64 max_buff_sz); +#if defined(_WIN32) || defined(WIN32) + DllDef int libraw_open_wfile(libraw_data_t *, const wchar_t *); + DllDef int libraw_open_wfile_ex(libraw_data_t *, const wchar_t *, + INT64 max_buff_sz); +#endif + DllDef int libraw_open_buffer(libraw_data_t *, void *buffer, size_t size); + DllDef int libraw_unpack(libraw_data_t *); + DllDef int libraw_unpack_thumb(libraw_data_t *); + DllDef void libraw_recycle_datastream(libraw_data_t *); + DllDef void libraw_recycle(libraw_data_t *); + DllDef void libraw_close(libraw_data_t *); + DllDef void libraw_subtract_black(libraw_data_t *); + DllDef int libraw_raw2image(libraw_data_t *); + DllDef void libraw_free_image(libraw_data_t *); + /* version helpers */ + DllDef const char *libraw_version(); + DllDef int libraw_versionNumber(); + /* Camera list */ + DllDef const char **libraw_cameraList(); + DllDef int libraw_cameraCount(); + + /* helpers */ + DllDef void libraw_set_memerror_handler(libraw_data_t *, memory_callback cb, + void *datap); + DllDef void libraw_set_exifparser_handler(libraw_data_t *, + exif_parser_callback cb, + void *datap); + DllDef void libraw_set_dataerror_handler(libraw_data_t *, data_callback func, + void *datap); + DllDef void libraw_set_progress_handler(libraw_data_t *, progress_callback cb, + void *datap); + DllDef const char *libraw_unpack_function_name(libraw_data_t *lr); + DllDef int libraw_get_decoder_info(libraw_data_t *lr, + libraw_decoder_info_t *d); + DllDef int libraw_COLOR(libraw_data_t *, int row, int col); + DllDef unsigned libraw_capabilities(); + + /* DCRAW compatibility */ + DllDef int libraw_adjust_sizes_info_only(libraw_data_t *); + DllDef int libraw_dcraw_ppm_tiff_writer(libraw_data_t *lr, + const char *filename); + DllDef int libraw_dcraw_thumb_writer(libraw_data_t *lr, const char *fname); + DllDef int libraw_dcraw_process(libraw_data_t *lr); + DllDef libraw_processed_image_t * + libraw_dcraw_make_mem_image(libraw_data_t *lr, int *errc); + DllDef libraw_processed_image_t * + libraw_dcraw_make_mem_thumb(libraw_data_t *lr, int *errc); + DllDef void libraw_dcraw_clear_mem(libraw_processed_image_t *); + /* getters/setters used by 3DLut Creator */ + DllDef void libraw_set_demosaic(libraw_data_t *lr, int value); + DllDef void libraw_set_output_color(libraw_data_t *lr, int value); + DllDef void libraw_set_user_mul(libraw_data_t *lr, int index, float val); + DllDef void libraw_set_output_bps(libraw_data_t *lr, int value); + DllDef void libraw_set_gamma(libraw_data_t *lr, int index, float value); + DllDef void libraw_set_no_auto_bright(libraw_data_t *lr, int value); + DllDef void libraw_set_bright(libraw_data_t *lr, float value); + DllDef void libraw_set_highlight(libraw_data_t *lr, int value); + DllDef void libraw_set_fbdd_noiserd(libraw_data_t *lr, int value); + DllDef int libraw_get_raw_height(libraw_data_t *lr); + DllDef int libraw_get_raw_width(libraw_data_t *lr); + DllDef int libraw_get_iheight(libraw_data_t *lr); + DllDef int libraw_get_iwidth(libraw_data_t *lr); + DllDef float libraw_get_cam_mul(libraw_data_t *lr, int index); + DllDef float libraw_get_pre_mul(libraw_data_t *lr, int index); + DllDef float libraw_get_rgb_cam(libraw_data_t *lr, int index1, int index2); + DllDef int libraw_get_color_maximum(libraw_data_t *lr); + DllDef void libraw_set_output_tif(libraw_data_t *lr, int value); + DllDef libraw_iparams_t *libraw_get_iparams(libraw_data_t *lr); + DllDef libraw_lensinfo_t *libraw_get_lensinfo(libraw_data_t *lr); + DllDef libraw_imgother_t *libraw_get_imgother(libraw_data_t *lr); #ifdef __cplusplus } #endif - #ifdef __cplusplus class DllDef LibRaw { - public: - libraw_data_t imgdata; - int verbose; - - LibRaw(unsigned int flags = LIBRAW_OPTIONS_NONE); - - libraw_output_params_t* output_params_ptr() { return &imgdata.params;} - int open_file(const char *fname); - int open_buffer(void *buffer, size_t size); - int open_datastream(LibRaw_abstract_datastream *); - int unpack(void); - int unpack_thumb(void); - - int adjust_sizes_info_only(void); - void set_memerror_handler( memory_callback cb,void *data) {callbacks.memcb_data = data; callbacks.mem_cb = cb; } - void set_dataerror_handler(data_callback func, void *data) { callbacks.datacb_data = data; callbacks.data_cb = func;} - void set_progress_handler(progress_callback pcb, void *data) { callbacks.progresscb_data = data; callbacks.progress_cb = pcb;} - - // helpers - static const char* version() { return LIBRAW_VERSION_STR;} - static int versionNumber() { return LIBRAW_VERSION; } - static const char** cameraList(); - static int cameraCount(); - static const char* strprogress(enum LibRaw_progress); - static const char* strerror(int p) { return libraw_strerror(p);} - // dcraw emulation - int dcraw_document_mode_processing(); - int dcraw_ppm_tiff_writer(const char *filename); - int dcraw_thumb_writer(const char *fname); - int dcraw_process(void); - // memory writers - libraw_processed_image_t* dcraw_make_mem_image(int *errcode=NULL); - libraw_processed_image_t* dcraw_make_mem_thumb(int *errcode=NULL); - - // free all internal data structures - void recycle(); - ~LibRaw(void) { recycle(); delete tls; } - - int FC(int row,int col) { return (imgdata.idata.filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3);} - int fc (int row, int col); - int add_masked_borders_to_bitmap(); - - const char *unpack_function_name(); - int rotate_fuji_raw(); - - private: - void* malloc(size_t t); - void* calloc(size_t n,size_t t); - void free(void *p); - void merror (void *ptr, const char *where); - void derror(); - -// data - - LibRaw_TLS *tls; - libraw_internal_data_t libraw_internal_data; - decode first_decode[2048], *second_decode, *free_decode; - tiff_ifd_t tiff_ifd[10]; - libraw_memmgr memmgr; - libraw_callbacks_t callbacks; - - LibRaw_constants rgb_constants; - void (LibRaw:: *write_thumb)(FILE *), - (LibRaw:: *write_fun)(FILE *); - void (LibRaw:: *load_raw)(), - (LibRaw:: *thumb_load_raw)(); - - void kodak_thumb_loader(); - void write_thumb_ppm_tiff(FILE *); // kodak - void foveon_thumb_loader (void); //Sigma - - - // moved from implementation level to private: visibility - void init_masked_ptrs(); - ushort *get_masked_pointer(int row, int col); - - int own_filtering_supported(){ return 0;} - void identify(); - void write_ppm_tiff (FILE *ofp); - void convert_to_rgb(); - void kodak_ycbcr_load_raw(); - void remove_zeroes(); -#ifndef NO_LCMS - void apply_profile(char*,char*); -#endif -// Iterpolators - void pre_interpolate(); - void border_interpolate (int border); - void lin_interpolate(); - void vng_interpolate(); - void ppg_interpolate(); - void ahd_interpolate(); - -// Image filters - void bad_pixels(char*); - void subtract(char*); - void hat_transform (float *temp, float *base, int st, int size, int sc); - void wavelet_denoise(); - void scale_colors(); - void median_filter (); - void blend_highlights(); - void recover_highlights(); - - void fuji_rotate(); - void stretch(); - -// Thmbnail functions - void foveon_thumb (FILE *tfp); - void jpeg_thumb_writer (FILE *tfp,char *thumb,int thumb_length); - void jpeg_thumb (FILE *tfp); - void ppm_thumb (FILE *tfp); - void layer_thumb (FILE *tfp); - void rollei_thumb (FILE *tfp); - void kodak_thumb_load_raw(); - - // utility for cut'n'pasted code - void foveon_decoder (unsigned size, unsigned code); - unsigned get4(); +public: + libraw_data_t imgdata; - int flip_index (int row, int col); - void gamma_lut(ushort lut[0x10000]); + LibRaw(unsigned int flags = LIBRAW_OPTIONS_NONE); + libraw_output_params_t *output_params_ptr() { return &imgdata.params; } + int open_file(const char *fname, + INT64 max_buffered_sz = LIBRAW_USE_STREAMS_DATASTREAM_MAXSIZE); +#if defined(_WIN32) || defined(WIN32) + int open_file(const wchar_t *fname, + INT64 max_buffered_sz = LIBRAW_USE_STREAMS_DATASTREAM_MAXSIZE); +#endif + int open_buffer(void *buffer, size_t size); + virtual int open_datastream(LibRaw_abstract_datastream *); + virtual int open_bayer(unsigned char *data, unsigned datalen, + ushort _raw_width, ushort _raw_height, + ushort _left_margin, ushort _top_margin, + ushort _right_margin, ushort _bottom_margin, + unsigned char procflags, unsigned char bayer_pattern, + unsigned unused_bits, unsigned otherflags, + unsigned black_level); + int error_count() { return libraw_internal_data.unpacker_data.data_error; } + void recycle_datastream(); + int unpack(void); + int unpack_thumb(void); + int thumbOK(INT64 maxsz = -1); + int adjust_sizes_info_only(void); + int subtract_black(); + int subtract_black_internal(); + int raw2image(); + int raw2image_ex(int do_subtract_black); + void raw2image_start(); + void free_image(); + int adjust_maximum(); + void set_exifparser_handler(exif_parser_callback cb, void *data) + { + callbacks.exifparser_data = data; + callbacks.exif_cb = cb; + } + void set_memerror_handler(memory_callback cb, void *data) + { + callbacks.memcb_data = data; + callbacks.mem_cb = cb; + } + void set_dataerror_handler(data_callback func, void *data) + { + callbacks.datacb_data = data; + callbacks.data_cb = func; + } + void set_progress_handler(progress_callback pcb, void *data) + { + callbacks.progresscb_data = data; + callbacks.progress_cb = pcb; + } + + static const char* cameramakeridx2maker(unsigned maker); + int setMakeFromIndex(unsigned index); + + void convertFloatToInt(float dmin = 4096.f, float dmax = 32767.f, + float dtarget = 16383.f); + /* helpers */ + static unsigned capabilities(); + static const char *version(); + static int versionNumber(); + static const char **cameraList(); + static int cameraCount(); + static const char *strprogress(enum LibRaw_progress); + static const char *strerror(int p); + /* dcraw emulation */ + int dcraw_ppm_tiff_writer(const char *filename); + int dcraw_thumb_writer(const char *fname); + int dcraw_process(void); + /* information calls */ + int is_fuji_rotated() + { + return libraw_internal_data.internal_output_params.fuji_width; + } + int is_sraw(); + int sraw_midpoint(); + int is_nikon_sraw(); + int is_coolscan_nef(); + int is_jpeg_thumb(); + int is_floating_point(); + int have_fpdata(); + /* memory writers */ + virtual libraw_processed_image_t *dcraw_make_mem_image(int *errcode = NULL); + virtual libraw_processed_image_t *dcraw_make_mem_thumb(int *errcode = NULL); + static void dcraw_clear_mem(libraw_processed_image_t *); + + /* Additional calls for make_mem_image */ + void get_mem_image_format(int *width, int *height, int *colors, + int *bps) const; + int copy_mem_image(void *scan0, int stride, int bgr); + + /* free all internal data structures */ + void recycle(); + virtual ~LibRaw(void); + + int COLOR(int row, int col) + { + if (!imgdata.idata.filters) + return 6; /* Special value 0+1+2+3 */ + if (imgdata.idata.filters < 1000) + return fcol(row, col); + return libraw_internal_data.internal_output_params.fuji_width + ? FCF(row, col) + : FC(row, col); + } + + int FC(int row, int col) + { + return (imgdata.idata.filters >> (((row << 1 & 14) | (col & 1)) << 1) & 3); + } + int fcol(int row, int col); + + const char *unpack_function_name(); + virtual int get_decoder_info(libraw_decoder_info_t *d_info); + libraw_internal_data_t *get_internal_data_pointer() + { + return &libraw_internal_data; + } + + static float powf_lim(float a, float b, float limup) + { + return (b > limup || b < -limup) ? 0.f : powf(a, b); + } + static float libraw_powf64l(float a, float b) { return powf_lim(a, b, 64.f); } + + static unsigned sgetn(int n, uchar *s) + { + unsigned result = 0; + while (n-- > 0) + result = (result << 8) | (*s++); + return result; + } + + /* Phase one correction/subtractBL calls */ + /* Returns libraw error code */ + + int phase_one_subtract_black(ushort *src, ushort *dest); + int phase_one_correct(); + + int set_rawspeed_camerafile(char *filename); + virtual void setCancelFlag(); + virtual void clearCancelFlag(); + virtual int adobe_coeff(unsigned, const char *, int internal_only = 0); + + void set_dng_host(void *); + +protected: + static void *memmem(char *haystack, size_t haystacklen, char *needle, + size_t needlelen); + static char *strcasestr(char *h, const char *n); + static size_t strnlen(const char *s, size_t n); + int is_curve_linear(); + void checkCancel(); + void cam_xyz_coeff(float _rgb_cam[3][4], double cam_xyz[4][3]); + void phase_one_allocate_tempbuffer(); + void phase_one_free_tempbuffer(); + virtual int is_phaseone_compressed(); + virtual int is_canon_600(); + /* Hotspots */ + virtual void copy_fuji_uncropped(unsigned short cblack[4], + unsigned short *dmaxp); + virtual void copy_bayer(unsigned short cblack[4], unsigned short *dmaxp); + virtual void fuji_rotate(); + virtual void convert_to_rgb_loop(float out_cam[3][4]); + virtual void lin_interpolate_loop(int *code, int size); + virtual void scale_colors_loop(float scale_mul[4]); + + /* Fujifilm compressed decoder public interface (to make parallel decoder) */ + virtual void + fuji_decode_loop(const struct fuji_compressed_params *common_info, int count, + INT64 *offsets, unsigned *sizes); + void fuji_decode_strip(const struct fuji_compressed_params *info_common, + int cur_block, INT64 raw_offset, unsigned size); + /* CR3 decoder public interface to make parallel decoder */ + virtual void crxLoadDecodeLoop(void *, int); + int crxDecodePlane(void *, uint32_t planeNumber); + virtual void crxLoadFinalizeLoopE3(void *, int); + void crxConvertPlaneLineDf(void *, int); + + int FCF(int row, int col) + { + int rr, cc; + if (libraw_internal_data.unpacker_data.fuji_layout) + { + rr = libraw_internal_data.internal_output_params.fuji_width - 1 - col + + (row >> 1); + cc = col + ((row + 1) >> 1); + } + else + { + rr = libraw_internal_data.internal_output_params.fuji_width - 1 + row - + (col >> 1); + cc = row + ((col + 1) >> 1); + } + return FC(rr, cc); + } + void adjust_bl(); + void *malloc(size_t t); + void *calloc(size_t n, size_t t); + void *realloc(void *p, size_t s); + void free(void *p); + void merror(void *ptr, const char *where); + void derror(); + + LibRaw_TLS *tls; + libraw_internal_data_t libraw_internal_data; + decode first_decode[2048], *second_decode, *free_decode; + tiff_ifd_t tiff_ifd[LIBRAW_IFD_MAXCOUNT]; + libraw_memmgr memmgr; + libraw_callbacks_t callbacks; + + void (LibRaw::*write_thumb)(); + void (LibRaw::*write_fun)(); + void (LibRaw::*load_raw)(); + void (LibRaw::*thumb_load_raw)(); + void (LibRaw::*pentax_component_load_raw)(); + + void kodak_thumb_loader(); + void write_thumb_ppm_tiff(FILE *); +#ifdef USE_X3FTOOLS + void x3f_thumb_loader(); + INT64 x3f_thumb_size(); +#endif -// == internal functions + int own_filtering_supported() { return 0; } + void identify(); + void initdata(); + unsigned parse_custom_cameras(unsigned limit, libraw_custom_camera_t table[], + char **list); + void write_ppm_tiff(); + void convert_to_rgb(); + void remove_zeroes(); + void crop_masked_pixels(); +#ifndef NO_LCMS + void apply_profile(const char *, const char *); +#endif + void pre_interpolate(); + void border_interpolate(int border); + void lin_interpolate(); + void vng_interpolate(); + void ppg_interpolate(); + void cielab(ushort rgb[3], short lab[3]); + void xtrans_interpolate(int); + void ahd_interpolate(); + void dht_interpolate(); + void aahd_interpolate(); + + void dcb(int iterations, int dcb_enhance); + void fbdd(int noiserd); + void exp_bef(float expos, float preser); + + void bad_pixels(const char *); + void subtract(const char *); + void hat_transform(float *temp, float *base, int st, int size, int sc); + void wavelet_denoise(); + void scale_colors(); + void median_filter(); + void blend_highlights(); + void recover_highlights(); + void green_matching(); + + void stretch(); + + void jpeg_thumb_writer(FILE *tfp, char *thumb, int thumb_length); + void jpeg_thumb(); + void ppm_thumb(); + void ppm16_thumb(); + void layer_thumb(); + void rollei_thumb(); + void kodak_thumb_load_raw(); + + unsigned get4(); + + int flip_index(int row, int col); + void gamma_curve(double pwr, double ts, int mode, int imax); + void cubic_spline(const int *x_, const int *y_, const int len); + + /* RawSpeed data */ + void *_rawspeed_camerameta; + void *_rawspeed_decoder; + void fix_after_rawspeed(int bl); + int try_rawspeed(); /* returns LIBRAW_SUCCESS on success */ + /* Fast cancel flag */ + long _exitflag; + + /* DNG SDK data */ + void *dnghost; + void *dngnegative; + void *dngimage; + int valid_for_dngsdk(); + int try_dngsdk(); + /* X3F data */ + void *_x3f_data; /* keep it even if USE_X3FTOOLS is not defined to do not change sizeof(LibRaw)*/ + + int raw_was_read() + { + return imgdata.rawdata.raw_image || imgdata.rawdata.color4_image || + imgdata.rawdata.color3_image || imgdata.rawdata.float_image || + imgdata.rawdata.float3_image || imgdata.rawdata.float4_image; + } -#ifdef LIBRAW_LIBRARY_BUILD +#ifdef LIBRAW_LIBRARY_BUILD #include "internal/libraw_internal_funcs.h" #endif - }; -#ifdef LIBRAW_LIBRARY_BUILD -#define RUN_CALLBACK(stage,iter,expect) if(callbacks.progress_cb) { \ - int rr = (*callbacks.progress_cb)(callbacks.progresscb_data,stage,iter,expect); \ - if(rr!=0) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; \ - } +#ifdef LIBRAW_LIBRARY_BUILD +#define RUN_CALLBACK(stage, iter, expect) \ + if (callbacks.progress_cb) \ + { \ + int rr = (*callbacks.progress_cb)(callbacks.progresscb_data, stage, iter, \ + expect); \ + if (rr != 0) \ + throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; \ + } #endif +#endif /* __cplusplus */ -#endif // __cplusplus - - -#endif // _LIBRAW_CLASS_H +#endif /* _LIBRAW_CLASS_H */ diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_alloc.h libkdcraw/libkdcraw/libraw/libraw/libraw_alloc.h --- libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_alloc.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/libraw/libraw_alloc.h 2022-11-07 07:46:31.726795008 +0300 @@ -1,24 +1,19 @@ -/* +/* -*- C++ -*- * File: libraw_alloc.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> - * Created: Sat Mar 22, 2008 + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Mar 22, 2008 * * LibRaw C++ interface * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #ifndef __LIBRAW_ALLOC_H @@ -26,73 +21,97 @@ #include <stdlib.h> #include <string.h> -#ifdef WIN32 -#define bzero(p,sz) memset(p,0,sz) -#endif +#include "libraw_const.h" #ifdef __cplusplus -#define MSIZE 32 +#define LIBRAW_MSIZE 512 -class libraw_memmgr +class DllDef libraw_memmgr { - public: - libraw_memmgr() - { - bzero(mems,sizeof(mems)); - calloc_cnt=0; - } - void *malloc(size_t sz) +public: + libraw_memmgr(unsigned ee) : extra_bytes(ee) + { + size_t alloc_sz = LIBRAW_MSIZE * sizeof(void *); + mems = (void **)::malloc(alloc_sz); + memset(mems, 0, alloc_sz); + } + ~libraw_memmgr() + { + cleanup(); + ::free(mems); + } + void *malloc(size_t sz) + { +#ifdef LIBRAW_USE_CALLOC_INSTEAD_OF_MALLOC + void *ptr = ::calloc(sz + extra_bytes, 1); +#else + void *ptr = ::malloc(sz + extra_bytes); +#endif + mem_ptr(ptr); + return ptr; + } + void *calloc(size_t n, size_t sz) + { + void *ptr = ::calloc(n + (extra_bytes + sz - 1) / (sz ? sz : 1), sz); + mem_ptr(ptr); + return ptr; + } + void *realloc(void *ptr, size_t newsz) + { + void *ret = ::realloc(ptr, newsz + extra_bytes); + forget_ptr(ptr); + mem_ptr(ret); + return ret; + } + void free(void *ptr) + { + forget_ptr(ptr); + ::free(ptr); + } + void cleanup(void) + { + for (int i = 0; i < LIBRAW_MSIZE; i++) + if (mems[i]) + { + ::free(mems[i]); + mems[i] = NULL; + } + } + +private: + void **mems; + unsigned extra_bytes; + void mem_ptr(void *ptr) + { + if (ptr) + { + for (int i = 0; i < LIBRAW_MSIZE - 1; i++) + if (!mems[i]) { - void *ptr = ::malloc(sz); - mem_ptr(ptr); - return ptr; + mems[i] = ptr; + return; } - void *calloc(size_t n, size_t sz) +#ifdef LIBRAW_MEMPOOL_CHECK + /* remember ptr in last mems item to be free'ed at cleanup */ + if (!mems[LIBRAW_MSIZE - 1]) + mems[LIBRAW_MSIZE - 1] = ptr; + throw LIBRAW_EXCEPTION_MEMPOOL; +#endif + } + } + void forget_ptr(void *ptr) + { + if (ptr) + for (int i = 0; i < LIBRAW_MSIZE; i++) + if (mems[i] == ptr) { - void *ptr = ::calloc(n,sz); - mem_ptr(ptr); - return ptr; + mems[i] = NULL; + break; } - void free(void *ptr) - { - ::free(ptr); - forget_ptr(ptr); - } - void cleanup(void) - { - for(int i = 0; i< MSIZE; i++) - if(mems[i]) - { -// fprintf(stderr,"Found lost fragment at 0x%x\n",mems[i]); - free(mems[i]); - mems[i] = NULL; - } - } - - private: - void *mems[MSIZE]; - int calloc_cnt; - void mem_ptr(void *ptr) - { - if(ptr) - for(int i=0;i < MSIZE; i++) - if(!mems[i]) - { - mems[i] = ptr; - break; - } - } - void forget_ptr(void *ptr) - { - if(ptr) - for(int i=0;i < MSIZE; i++) - if(mems[i] == ptr) - mems[i] = NULL; - } - + } }; -#endif //C++ +#endif /* C++ */ #endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_const.h libkdcraw/libkdcraw/libraw/libraw/libraw_const.h --- libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_const.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/libraw/libraw_const.h 2022-11-07 07:46:31.726795008 +0300 @@ -1,159 +1,667 @@ -/* +/* -*- C++ -*- * File: libraw_const.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 - * * LibRaw error codes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #ifndef _LIBRAW_ERRORS_H #define _LIBRAW_ERRORS_H -enum LibRaw_constructor_flags +#define LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD 0.75 +#define LIBRAW_DEFAULT_AUTO_BRIGHTNESS_THRESHOLD 0.01 +/* limit allocation size, default is 2Gb */ +#ifndef LIBRAW_MAX_ALLOC_MB_DEFAULT +#define LIBRAW_MAX_ALLOC_MB_DEFAULT 2048L +#endif + +/* limit thumbnail size, default is 512Mb*/ +#ifndef LIBRAW_MAX_THUMBNAIL_MB +#define LIBRAW_MAX_THUMBNAIL_MB 512L +#endif + +/* Check if enough file space exists before tag read */ +#ifndef LIBRAW_NO_IOSPACE_CHECK +#define LIBRAW_IOSPACE_CHECK +#endif +#ifndef LIBRAW_NO_CR3_MEMPOOL +#define LIBRAW_CR3_MEMPOOL +#endif + + +/* LibRaw uses own memory pool management, with LIBRAW_MSIZE (512) +entries. It is enough for parsing/decoding non-damaged files, but +may overflow on specially crafted files (eg. with many string values +like XMP blocks. +LIBRAW_MEMPOOL_CHECK define will result in error on pool overflow */ +#ifndef LIBRAW_NO_MEMPOOL_CHECK +#define LIBRAW_MEMPOOL_CHECK +#endif + +#define LIBRAW_MAX_METADATA_BLOCKS 1024 +#define LIBRAW_CBLACK_SIZE 4104 +#define LIBRAW_IFD_MAXCOUNT 10 +#define LIBRAW_CRXTRACKS_MAXCOUNT 16 + +#define LIBRAW_AHD_TILE 512 + +enum LibRaw_open_flags { - LIBRAW_OPTIONS_NONE =0, - LIBRAW_OPIONS_NO_MEMERR_CALLBACK=1, - LIBRAW_OPIONS_NO_DATAERR_CALLBACK=1<<1 + LIBRAW_OPEN_BIGFILE=1, + LIBRAW_OPEN_FILE= 1<<1 }; -enum LibRaw_warnings +enum LibRaw_openbayer_patterns { - LIBRAW_WARN_NONE =0, - LIBRAW_WARN_FOVEON_NOMATRIX =1, - LIBRAW_WARN_FOVEON_INVALIDWB =1<<1, - LIBRAW_WARN_BAD_CAMERA_WB =1<<2, - LIBRAW_WARN_NO_METADATA =1<<3, - LIBRAW_WARN_NO_JPEGLIB = 1<<4, - LIBRAW_WARN_NO_EMBEDDED_PROFILE = 1<<5, - LIBRAW_WARN_NO_INPUT_PROFILE = 1<<6, - LIBRAW_WARN_BAD_OUTPUT_PROFILE= 1<<7, - LIBRAW_WARN_NO_BADPIXELMAP=1<<8, - LIBRAW_WARN_BAD_DARKFRAME_FILE=1<<9, - LIBRAW_WARN_BAD_DARKFRAME_DIM=1<<10 + LIBRAW_OPENBAYER_RGGB = 0x94, + LIBRAW_OPENBAYER_BGGR = 0x16, + LIBRAW_OPENBAYER_GRBG = 0x61, + LIBRAW_OPENBAYER_GBRG = 0x49 }; -enum LibRaw_exceptions +enum LibRaw_dngfields_marks +{ + LIBRAW_DNGFM_FORWARDMATRIX = 1, + LIBRAW_DNGFM_ILLUMINANT = 1 << 1, + LIBRAW_DNGFM_COLORMATRIX = 1 << 2, + LIBRAW_DNGFM_CALIBRATION = 1 << 3, + LIBRAW_DNGFM_ANALOGBALANCE = 1 << 4, + LIBRAW_DNGFM_BLACK = 1 << 5, + LIBRAW_DNGFM_WHITE = 1 << 6, + LIBRAW_DNGFM_OPCODE2 = 1 << 7, + LIBRAW_DNGFM_LINTABLE = 1 << 8, + LIBRAW_DNGFM_CROPORIGIN = 1 << 9, + LIBRAW_DNGFM_CROPSIZE = 1 << 10, + LIBRAW_DNGFM_PREVIEWCS = 1 << 11, + LIBRAW_DNGFM_ASSHOTNEUTRAL = 1 << 12, + LIBRAW_DNGFM_BASELINEEXPOSURE = 1 << 13, + LIBRAW_DNGFM_LINEARRESPONSELIMIT = 1 << 14 +}; + +enum LibRaw_As_Shot_WB_Applied_codes +{ + LIBRAW_ASWB_APPLIED = 1, + LIBRAW_ASWB_CANON = 2, + LIBRAW_ASWB_NIKON = 4, + LIBRAW_ASWB_NIKON_SRAW = 8, + LIBRAW_ASWB_PENTAX = 16 +}; + +#define tagtypeIs(typex) (type == typex) +enum LibRaw_ExifTagTypes { + LIBRAW_EXIFTAG_TYPE_UNKNOWN = 0, + LIBRAW_EXIFTAG_TYPE_BYTE = 1, + LIBRAW_EXIFTAG_TYPE_ASCII = 2, + LIBRAW_EXIFTAG_TYPE_SHORT = 3, + LIBRAW_EXIFTAG_TYPE_LONG = 4, + LIBRAW_EXIFTAG_TYPE_RATIONAL = 5, + LIBRAW_EXIFTAG_TYPE_SBYTE = 6, + LIBRAW_EXIFTAG_TYPE_UNDEFINED = 7, + LIBRAW_EXIFTAG_TYPE_SSHORT = 8, + LIBRAW_EXIFTAG_TYPE_SLONG = 9, + LIBRAW_EXIFTAG_TYPE_SRATIONAL = 10, + LIBRAW_EXIFTAG_TYPE_FLOAT = 11, + LIBRAW_EXIFTAG_TYPE_DOUBLE = 12, + LIBRAW_EXIFTAG_TYPE_IFD = 13, + LIBRAW_EXIFTAG_TYPE_UNICODE = 14, + LIBRAW_EXIFTAG_TYPE_COMPLEX = 15, + LIBRAW_EXIFTAG_TYPE_LONG8 = 16, + LIBRAW_EXIFTAG_TYPE_SLONG8 = 17, + LIBRAW_EXIFTAG_TYPE_IFD8 = 18 +}; + +#define LIBRAW_EXIFTOOLTAGTYPE_int8u LIBRAW_EXIFTAG_TYPE_BYTE +#define LIBRAW_EXIFTOOLTAGTYPE_string LIBRAW_EXIFTAG_TYPE_ASCII +#define LIBRAW_EXIFTOOLTAGTYPE_int16u LIBRAW_EXIFTAG_TYPE_SHORT +#define LIBRAW_EXIFTOOLTAGTYPE_int32u LIBRAW_EXIFTAG_TYPE_LONG +#define LIBRAW_EXIFTOOLTAGTYPE_rational64u LIBRAW_EXIFTAG_TYPE_RATIONAL +#define LIBRAW_EXIFTOOLTAGTYPE_int8s LIBRAW_EXIFTAG_TYPE_SBYTE +#define LIBRAW_EXIFTOOLTAGTYPE_undef LIBRAW_EXIFTAG_TYPE_UNDEFINED +#define LIBRAW_EXIFTOOLTAGTYPE_binary LIBRAW_EXIFTAG_TYPE_UNDEFINED +#define LIBRAW_EXIFTOOLTAGTYPE_int16s LIBRAW_EXIFTAG_TYPE_SSHORT +#define LIBRAW_EXIFTOOLTAGTYPE_int32s LIBRAW_EXIFTAG_TYPE_SLONG +#define LIBRAW_EXIFTOOLTAGTYPE_rational64s LIBRAW_EXIFTAG_TYPE_SRATIONAL +#define LIBRAW_EXIFTOOLTAGTYPE_float LIBRAW_EXIFTAG_TYPE_FLOAT +#define LIBRAW_EXIFTOOLTAGTYPE_double LIBRAW_EXIFTAG_TYPE_DOUBLE +#define LIBRAW_EXIFTOOLTAGTYPE_ifd LIBRAW_EXIFTAG_TYPE_IFD +#define LIBRAW_EXIFTOOLTAGTYPE_unicode LIBRAW_EXIFTAG_TYPE_UNICODE +#define LIBRAW_EXIFTOOLTAGTYPE_complex LIBRAW_EXIFTAG_TYPE_COMPLEX +#define LIBRAW_EXIFTOOLTAGTYPE_int64u LIBRAW_EXIFTAG_TYPE_LONG8 +#define LIBRAW_EXIFTOOLTAGTYPE_int64s LIBRAW_EXIFTAG_TYPE_SLONG8 +#define LIBRAW_EXIFTOOLTAGTYPE_ifd64 LIBRAW_EXIFTAG_TYPE_IFD8 + +#define LIBRAW_LENS_NOT_SET 0xffffffffffffffffULL + +enum LibRaw_whitebalance_code +{ +// clang-format off + /* + EXIF light sources + 12 = FL-D; Daylight fluorescent (D 5700K – 7100K) (F1,F5) + 13 = FL-N; Day white fluorescent (N 4600K – 5400K) (F7,F8) + 14 = FL-W; Cool white fluorescent (W 3900K – 4500K) (F2,F6, office, store, warehouse) + 15 = FL-WW; White fluorescent (WW 3200K – 3700K) (F3, residential) + 16 = FL-L; Soft/Warm white fluorescent (L 2600K - 3250K) (F4, kitchen, bath) + */ +//clang-format on + LIBRAW_WBI_Unknown = 0, + LIBRAW_WBI_Daylight = 1, + LIBRAW_WBI_Fluorescent = 2, + LIBRAW_WBI_Tungsten = 3, + LIBRAW_WBI_Flash = 4, + LIBRAW_WBI_FineWeather = 9, + LIBRAW_WBI_Cloudy = 10, + LIBRAW_WBI_Shade = 11, + LIBRAW_WBI_FL_D = 12, + LIBRAW_WBI_FL_N = 13, + LIBRAW_WBI_FL_W = 14, + LIBRAW_WBI_FL_WW = 15, + LIBRAW_WBI_FL_L = 16, + LIBRAW_WBI_Ill_A = 17, + LIBRAW_WBI_Ill_B = 18, + LIBRAW_WBI_Ill_C = 19, + LIBRAW_WBI_D55 = 20, + LIBRAW_WBI_D65 = 21, + LIBRAW_WBI_D75 = 22, + LIBRAW_WBI_D50 = 23, + LIBRAW_WBI_StudioTungsten = 24, + LIBRAW_WBI_Sunset = 64, + LIBRAW_WBI_Underwater = 65, + LIBRAW_WBI_FluorescentHigh = 66, + LIBRAW_WBI_HT_Mercury = 67, + LIBRAW_WBI_AsShot = 81, + LIBRAW_WBI_Auto = 82, + LIBRAW_WBI_Custom = 83, + LIBRAW_WBI_Auto1 = 85, + LIBRAW_WBI_Auto2 = 86, + LIBRAW_WBI_Auto3 = 87, + LIBRAW_WBI_Auto4 = 88, + LIBRAW_WBI_Custom1 = 90, + LIBRAW_WBI_Custom2 = 91, + LIBRAW_WBI_Custom3 = 92, + LIBRAW_WBI_Custom4 = 93, + LIBRAW_WBI_Custom5 = 94, + LIBRAW_WBI_Custom6 = 95, + LIBRAW_WBI_PC_Set1 = 96, + LIBRAW_WBI_PC_Set2 = 97, + LIBRAW_WBI_PC_Set3 = 98, + LIBRAW_WBI_PC_Set4 = 99, + LIBRAW_WBI_PC_Set5 = 100, + LIBRAW_WBI_Measured = 110, + LIBRAW_WBI_BW = 120, + LIBRAW_WBI_Kelvin = 254, + LIBRAW_WBI_Other = 255, + LIBRAW_WBI_None = 0xffff +}; + +enum LibRaw_MultiExposure_related +{ + LIBRAW_ME_NONE = 0, + LIBRAW_ME_SIMPLE = 1, + LIBRAW_ME_OVERLAY = 2, + LIBRAW_ME_HDR = 3 +}; + +enum LibRaw_dng_processing +{ + LIBRAW_DNG_NONE = 0, + LIBRAW_DNG_FLOAT = 1, + LIBRAW_DNG_LINEAR = 2, + LIBRAW_DNG_DEFLATE = 4, + LIBRAW_DNG_XTRANS = 8, + LIBRAW_DNG_OTHER = 16, + LIBRAW_DNG_8BIT = 32, + /*LIBRAW_DNG_LARGERANGE=64,*/ /* more than 16 bit integer */ + LIBRAW_DNG_ALL = + LIBRAW_DNG_FLOAT | LIBRAW_DNG_LINEAR | LIBRAW_DNG_XTRANS | + LIBRAW_DNG_8BIT | LIBRAW_DNG_OTHER /* |LIBRAW_DNG_LARGERANGE */, + LIBRAW_DNG_DEFAULT = LIBRAW_DNG_FLOAT | LIBRAW_DNG_LINEAR | + LIBRAW_DNG_DEFLATE | LIBRAW_DNG_8BIT +}; + +enum LibRaw_runtime_capabilities { - LIBRAW_EXCEPTION_NONE =0, - LIBRAW_EXCEPTION_ALLOC =1, - LIBRAW_EXCEPTION_DECODE_RAW =2, - LIBRAW_EXCEPTION_DECODE_JPEG=3, - LIBRAW_EXCEPTION_IO_EOF =4, - LIBRAW_EXCEPTION_IO_CORRUPT =5, - LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK=6 + LIBRAW_CAPS_RAWSPEED = 1, + LIBRAW_CAPS_DNGSDK = 2, + LIBRAW_CAPS_GPRSDK = 4, + LIBRAW_CAPS_UNICODEPATHS = 8, + LIBRAW_CAPS_X3FTOOLS = 16, + LIBRAW_CAPS_RPI6BY9 = 32 }; +enum LibRaw_colorspace { + LIBRAW_COLORSPACE_NotFound = 0, + LIBRAW_COLORSPACE_sRGB, + LIBRAW_COLORSPACE_AdobeRGB, + LIBRAW_COLORSPACE_WideGamutRGB, + LIBRAW_COLORSPACE_ProPhotoRGB, + LIBRAW_COLORSPACE_ICC, + LIBRAW_COLORSPACE_Uncalibrated, // Tag 0x0001 InteropIndex containing "R03" + LIBRAW_COLORSPACE_Uncalibrated = Adobe RGB + LIBRAW_COLORSPACE_CameraLinearUniWB, + LIBRAW_COLORSPACE_CameraLinear, + LIBRAW_COLORSPACE_CameraGammaUniWB, + LIBRAW_COLORSPACE_CameraGamma, + LIBRAW_COLORSPACE_MonochromeLinear, + LIBRAW_COLORSPACE_MonochromeGamma, + LIBRAW_COLORSPACE_Unknown = 255 +}; -enum LibRaw_colorstate -{ - LIBRAW_COLORSTATE_UNKNOWN =0, - LIBRAW_COLORSTATE_INIT =1, - LIBRAW_COLORSTATE_CONST =2, - LIBRAW_COLORSTATE_LOADED =3, - LIBRAW_COLORSTATE_CALCULATED=4, - LIBRAW_COLORSTATE_RESERVED1 =5, - LIBRAW_COLORSTATE_RESERVED2 =6, - LIBRAW_COLORSTATE_RESERVED3 =7 -}; - -enum LibRaw_filtering -{ - LIBRAW_FILTERING_DEFAULT =0, - LIBRAW_FILTERING_NOZEROES =1, // no remove zeroes - LIBRAW_FILTERING_NOBLACKS =2, // no black subtraction - LIBRAW_FILTERING_NORAWCURVE =4, // no raw data postprocessing (e.g. PhaseOne corrections etc) - LIBRAW_FILTERING_NONE =7, // (_NOZEROES | _NOBLACKS | _NORAWCURVE) - LIBRAW_FILTERING_LIBRAWOWN =(8 | LIBRAW_FILTERING_NONE), // NONE + 8 - LIBRAW_FILTERING_AUTOMATIC_BIT =16, // - restore automatic mode after processing - LIBRAW_FILTERING_AUTOMATIC = (LIBRAW_FILTERING_LIBRAWOWN | LIBRAW_FILTERING_AUTOMATIC_BIT) +enum LibRaw_cameramaker_index +{ + LIBRAW_CAMERAMAKER_Unknown = 0, + LIBRAW_CAMERAMAKER_Agfa, + LIBRAW_CAMERAMAKER_Alcatel, + LIBRAW_CAMERAMAKER_Apple, + LIBRAW_CAMERAMAKER_Aptina, + LIBRAW_CAMERAMAKER_AVT, + LIBRAW_CAMERAMAKER_Baumer, + LIBRAW_CAMERAMAKER_Broadcom, + LIBRAW_CAMERAMAKER_Canon, + LIBRAW_CAMERAMAKER_Casio, + LIBRAW_CAMERAMAKER_CINE, + LIBRAW_CAMERAMAKER_Clauss, + LIBRAW_CAMERAMAKER_Contax, + LIBRAW_CAMERAMAKER_Creative, + LIBRAW_CAMERAMAKER_DJI, + LIBRAW_CAMERAMAKER_DXO, + LIBRAW_CAMERAMAKER_Epson, + LIBRAW_CAMERAMAKER_Foculus, + LIBRAW_CAMERAMAKER_Fujifilm, + LIBRAW_CAMERAMAKER_Generic, + LIBRAW_CAMERAMAKER_Gione, + LIBRAW_CAMERAMAKER_GITUP, + LIBRAW_CAMERAMAKER_Google, + LIBRAW_CAMERAMAKER_GoPro, + LIBRAW_CAMERAMAKER_Hasselblad, + LIBRAW_CAMERAMAKER_HTC, + LIBRAW_CAMERAMAKER_I_Mobile, + LIBRAW_CAMERAMAKER_Imacon, + LIBRAW_CAMERAMAKER_JK_Imaging, + LIBRAW_CAMERAMAKER_Kodak, + LIBRAW_CAMERAMAKER_Konica, + LIBRAW_CAMERAMAKER_Leaf, + LIBRAW_CAMERAMAKER_Leica, + LIBRAW_CAMERAMAKER_Lenovo, + LIBRAW_CAMERAMAKER_LG, + LIBRAW_CAMERAMAKER_Logitech, + LIBRAW_CAMERAMAKER_Mamiya, + LIBRAW_CAMERAMAKER_Matrix, + LIBRAW_CAMERAMAKER_Meizu, + LIBRAW_CAMERAMAKER_Micron, + LIBRAW_CAMERAMAKER_Minolta, + LIBRAW_CAMERAMAKER_Motorola, + LIBRAW_CAMERAMAKER_NGM, + LIBRAW_CAMERAMAKER_Nikon, + LIBRAW_CAMERAMAKER_Nokia, + LIBRAW_CAMERAMAKER_Olympus, + LIBRAW_CAMERAMAKER_OmniVison, + LIBRAW_CAMERAMAKER_Panasonic, + LIBRAW_CAMERAMAKER_Parrot, + LIBRAW_CAMERAMAKER_Pentax, + LIBRAW_CAMERAMAKER_PhaseOne, + LIBRAW_CAMERAMAKER_PhotoControl, + LIBRAW_CAMERAMAKER_Photron, + LIBRAW_CAMERAMAKER_Pixelink, + LIBRAW_CAMERAMAKER_Polaroid, + LIBRAW_CAMERAMAKER_RED, + LIBRAW_CAMERAMAKER_Ricoh, + LIBRAW_CAMERAMAKER_Rollei, + LIBRAW_CAMERAMAKER_RoverShot, + LIBRAW_CAMERAMAKER_Samsung, + LIBRAW_CAMERAMAKER_Sigma, + LIBRAW_CAMERAMAKER_Sinar, + LIBRAW_CAMERAMAKER_SMaL, + LIBRAW_CAMERAMAKER_Sony, + LIBRAW_CAMERAMAKER_ST_Micro, + LIBRAW_CAMERAMAKER_THL, + LIBRAW_CAMERAMAKER_VLUU, + LIBRAW_CAMERAMAKER_Xiaomi, + LIBRAW_CAMERAMAKER_XIAOYI, + LIBRAW_CAMERAMAKER_YI, + LIBRAW_CAMERAMAKER_Yuneec, + LIBRAW_CAMERAMAKER_Zeiss, + // Insert additional indexes here + LIBRAW_CAMERAMAKER_TheLastOne }; +enum LibRaw_camera_mounts +{ + LIBRAW_MOUNT_Unknown = 0, + LIBRAW_MOUNT_Alpa, + LIBRAW_MOUNT_C, /* C-mount */ + LIBRAW_MOUNT_Canon_EF_M, + LIBRAW_MOUNT_Canon_EF_S, + LIBRAW_MOUNT_Canon_EF, + LIBRAW_MOUNT_Canon_RF, + LIBRAW_MOUNT_Contax_N, + LIBRAW_MOUNT_Contax645, + LIBRAW_MOUNT_FT, /* original 4/3 */ + LIBRAW_MOUNT_mFT, /* micro 4/3 */ + LIBRAW_MOUNT_Fuji_GF, /* Fujifilm GFX cameras, G mount */ + LIBRAW_MOUNT_Fuji_GX, /* Fujifilm GX680 */ + LIBRAW_MOUNT_Fuji_X, + LIBRAW_MOUNT_Hasselblad_H, /* Hasselblad Hn cameras, HC & HCD lenses */ + LIBRAW_MOUNT_Hasselblad_V, + LIBRAW_MOUNT_Hasselblad_XCD, /* Hasselblad Xn cameras, XCD lenses */ + LIBRAW_MOUNT_Leica_M, /* Leica rangefinder bayonet */ + LIBRAW_MOUNT_Leica_R, /* Leica SLRs, 'R' for reflex */ + LIBRAW_MOUNT_Leica_S, /* LIBRAW_FORMAT_LeicaS 'MF' */ + LIBRAW_MOUNT_Leica_SL, /* lens, mounts on 'L' throat, FF */ + LIBRAW_MOUNT_Leica_TL, /* lens, mounts on 'L' throat, APS-C */ + LIBRAW_MOUNT_LPS_L, /* Leica/Panasonic/Sigma camera mount, takes L, SL and TL lenses */ + LIBRAW_MOUNT_Mamiya67, /* Mamiya RB67, RZ67 */ + LIBRAW_MOUNT_Mamiya645, + LIBRAW_MOUNT_Minolta_A, + LIBRAW_MOUNT_Nikon_CX, /* used in 'Nikon 1' series */ + LIBRAW_MOUNT_Nikon_F, + LIBRAW_MOUNT_Nikon_Z, + LIBRAW_MOUNT_Pentax_645, + LIBRAW_MOUNT_Pentax_K, + LIBRAW_MOUNT_Pentax_Q, + LIBRAW_MOUNT_RicohModule, + LIBRAW_MOUNT_Rollei_bayonet, /* Rollei Hy-6: Leaf AFi, Sinar Hy6- models */ + LIBRAW_MOUNT_Samsung_NX_M, + LIBRAW_MOUNT_Samsung_NX, + LIBRAW_MOUNT_Sigma_X3F, + LIBRAW_MOUNT_Sony_E, + LIBRAW_MOUNT_LF, + LIBRAW_MOUNT_DigitalBack, + LIBRAW_MOUNT_FixedLens, + LIBRAW_MOUNT_IL_UM, /* Interchangeable lens, mount unknown */ + LIBRAW_MOUNT_TheLastOne +}; + +enum LibRaw_camera_formats +{ + LIBRAW_FORMAT_Unknown = 0, + LIBRAW_FORMAT_APSC, + LIBRAW_FORMAT_FF, + LIBRAW_FORMAT_MF, + LIBRAW_FORMAT_APSH, + LIBRAW_FORMAT_1INCH, + LIBRAW_FORMAT_1div2p3INCH, /* 1/2.3" */ + LIBRAW_FORMAT_1div1p7INCH, /* 1/1.7" */ + LIBRAW_FORMAT_FT, /* sensor size in FT & mFT cameras */ + LIBRAW_FORMAT_CROP645, /* 44x33mm */ + LIBRAW_FORMAT_LeicaS, /* 'MF' Leicas */ + LIBRAW_FORMAT_645, + LIBRAW_FORMAT_66, + LIBRAW_FORMAT_69, + LIBRAW_FORMAT_LF, + LIBRAW_FORMAT_Leica_DMR, + LIBRAW_FORMAT_67, + LIBRAW_FORMAT_SigmaAPSC, /* DP1, DP2, SD15, SD14, SD10, SD9 */ + LIBRAW_FORMAT_SigmaMerrill, /* SD1, 'SD1 Merrill', 'DP1 Merrill', 'DP2 Merrill' */ + LIBRAW_FORMAT_SigmaAPSH, /* 'sd Quattro H' */ + LIBRAW_FORMAT_3648, /* DALSA FTF4052C (Mamiya ZD) */ + LIBRAW_FORMAT_68, /* Fujifilm GX680 */ + LIBRAW_FORMAT_TheLastOne +}; + +enum LibRawImageAspects +{ + LIBRAW_IMAGE_ASPECT_UNKNOWN = 0, + LIBRAW_IMAGE_ASPECT_3to2 = 1, + LIBRAW_IMAGE_ASPECT_1to1 = 2, + LIBRAW_IMAGE_ASPECT_4to3 = 3, + LIBRAW_IMAGE_ASPECT_16to9 = 4, + LIBRAW_IMAGE_ASPECT_5to4 = 5, + LIBRAW_IMAGE_ASPECT_OTHER = 6 +}; + +enum LibRaw_lens_focal_types +{ + LIBRAW_FT_UNDEFINED = 0, + LIBRAW_FT_PRIME_LENS = 1, + LIBRAW_FT_ZOOM_LENS = 2, + LIBRAW_FT_ZOOM_LENS_CONSTANT_APERTURE = 3, + LIBRAW_FT_ZOOM_LENS_VARIABLE_APERTURE = 4 +}; + +enum LibRaw_Canon_RecordModes { + LIBRAW_Canon_RecordMode_UNDEFINED = 0, + LIBRAW_Canon_RecordMode_JPEG, + LIBRAW_Canon_RecordMode_CRW_THM, + LIBRAW_Canon_RecordMode_AVI_THM, + LIBRAW_Canon_RecordMode_TIF, + LIBRAW_Canon_RecordMode_TIF_JPEG, + LIBRAW_Canon_RecordMode_CR2, + LIBRAW_Canon_RecordMode_CR2_JPEG, + LIBRAW_Canon_RecordMode_UNKNOWN, + LIBRAW_Canon_RecordMode_MOV, + LIBRAW_Canon_RecordMode_MP4, + LIBRAW_Canon_RecordMode_CRM, + LIBRAW_Canon_RecordMode_CR3, + LIBRAW_Canon_RecordMode_CR3_JPEG, + LIBRAW_Canon_RecordMode_HEIF, + LIBRAW_Canon_RecordMode_CR3_HEIF, + LIBRAW_Canon_RecordMode_TheLastOne +}; + +enum LibRaw_sony_cameratypes +{ + LIBRAW_SONY_DSC = 1, + LIBRAW_SONY_DSLR = 2, + LIBRAW_SONY_NEX = 3, + LIBRAW_SONY_SLT = 4, + LIBRAW_SONY_ILCE = 5, + LIBRAW_SONY_ILCA = 6 +}; + +enum LibRaw_KodakSensors +{ + LIBRAW_Kodak_UnknownSensor = 0, + LIBRAW_Kodak_M1 = 1, + LIBRAW_Kodak_M15 = 2, + LIBRAW_Kodak_M16 = 3, + LIBRAW_Kodak_M17 = 4, + LIBRAW_Kodak_M2 = 5, + LIBRAW_Kodak_M23 = 6, + LIBRAW_Kodak_M24 = 7, + LIBRAW_Kodak_M3 = 8, + LIBRAW_Kodak_M5 = 9, + LIBRAW_Kodak_M6 = 10, + LIBRAW_Kodak_C14 = 11, + LIBRAW_Kodak_X14 = 12, + LIBRAW_Kodak_M11 = 13 +}; + +enum LibRaw_HasselbladFormatCodes { + LIBRAW_HF_Unknown = 0, + LIBRAW_HF_3FR, + LIBRAW_HF_FFF, + LIBRAW_HF_Imacon, + LIBRAW_HF_HasselbladDNG, + LIBRAW_HF_AdobeDNG, + LIBRAW_HF_AdobeDNG_fromPhocusDNG +}; + +enum LibRaw_processing_options +{ + LIBRAW_PROCESSING_SONYARW2_NONE = 0, + LIBRAW_PROCESSING_SONYARW2_BASEONLY = 1, + LIBRAW_PROCESSING_SONYARW2_DELTAONLY = 1 << 1, + LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE = 1 << 2, + LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE = 1 << 3, + LIBRAW_PROCESSING_SONYARW2_ALLFLAGS = + LIBRAW_PROCESSING_SONYARW2_BASEONLY + + LIBRAW_PROCESSING_SONYARW2_DELTAONLY + + LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE + + LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE, + LIBRAW_PROCESSING_DP2Q_INTERPOLATERG = 1 << 4, + LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF = 1 << 5, + LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES = 1 << 6, + LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT = 1 << 7, + LIBRAW_PROCESSING_SRAW_NO_RGB = 1 << 8, + LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE = 1 << 9, + LIBRAW_PROCESSING_ARQ_SKIP_CHANNEL_SWAP = 1 << 10, + LIBRAW_PROCESSING_NO_ROTATE_FOR_KODAK_THUMBNAILS = 1 << 11, + LIBRAW_PROCESSING_USE_DNG_DEFAULT_CROP = 1 << 12, + LIBRAW_PROCESSING_USE_PPM16_THUMBS = 1 << 13, + LIBRAW_PROCESSING_SKIP_MAKERNOTES = 1 << 14, + LIBRAW_PROCESSING_DONT_CHECK_DNG_ILLUMINANT = 1 << 15, + LIBRAW_PROCESSING_DNGSDK_ZEROCOPY = 1 << 16, + LIBRAW_PROCESSING_ZEROFILTERS_FOR_MONOCHROMETIFFS = 1 << 17, + LIBRAW_PROCESSING_DNG_ADD_ENHANCED = 1 << 18, + LIBRAW_PROCESSING_DNG_ADD_PREVIEWS = 1 << 19, + LIBRAW_PROCESSING_DNG_PREFER_LARGEST_IMAGE = 1 << 20, + LIBRAW_PROCESSING_DNG_STAGE2 = 1 << 21, + LIBRAW_PROCESSING_DNG_STAGE3 = 1 << 22, + LIBRAW_PROCESSING_DNG_ALLOWSIZECHANGE = 1 << 23, + LIBRAW_PROCESSING_DNG_DISABLEWBADJUST = 1 << 24, + LIBRAW_PROCESSING_PROVIDE_NONSTANDARD_WB = 1 << 25, + LIBRAW_PROCESSING_CAMERAWB_FALLBACK_TO_DAYLIGHT = 1 << 26 +}; + +enum LibRaw_decoder_flags +{ + LIBRAW_DECODER_HASCURVE = 1 << 4, + LIBRAW_DECODER_SONYARW2 = 1 << 5, + LIBRAW_DECODER_TRYRAWSPEED = 1 << 6, + LIBRAW_DECODER_OWNALLOC = 1 << 7, + LIBRAW_DECODER_FIXEDMAXC = 1 << 8, + LIBRAW_DECODER_ADOBECOPYPIXEL = 1 << 9, + LIBRAW_DECODER_LEGACY_WITH_MARGINS = 1 << 10, + LIBRAW_DECODER_3CHANNEL = 1 << 11, + LIBRAW_DECODER_SINAR4SHOT = 1 << 11, + LIBRAW_DECODER_FLATDATA = 1 << 12, + LIBRAW_DECODER_FLAT_BG2_SWAPPED = 1<<13, + LIBRAW_DECODER_NOTSET = 1 << 15 +}; + +#define LIBRAW_XTRANS 9 + +enum LibRaw_constructor_flags +{ + LIBRAW_OPTIONS_NONE = 0, + LIBRAW_OPIONS_NO_MEMERR_CALLBACK = 1, + LIBRAW_OPIONS_NO_DATAERR_CALLBACK = 1 << 1 +}; + +enum LibRaw_warnings +{ + LIBRAW_WARN_NONE = 0, + LIBRAW_WARN_BAD_CAMERA_WB = 1 << 2, + LIBRAW_WARN_NO_METADATA = 1 << 3, + LIBRAW_WARN_NO_JPEGLIB = 1 << 4, + LIBRAW_WARN_NO_EMBEDDED_PROFILE = 1 << 5, + LIBRAW_WARN_NO_INPUT_PROFILE = 1 << 6, + LIBRAW_WARN_BAD_OUTPUT_PROFILE = 1 << 7, + LIBRAW_WARN_NO_BADPIXELMAP = 1 << 8, + LIBRAW_WARN_BAD_DARKFRAME_FILE = 1 << 9, + LIBRAW_WARN_BAD_DARKFRAME_DIM = 1 << 10, + LIBRAW_WARN_NO_JASPER = 1 << 11, + LIBRAW_WARN_RAWSPEED_PROBLEM = 1 << 12, + LIBRAW_WARN_RAWSPEED_UNSUPPORTED = 1 << 13, + LIBRAW_WARN_RAWSPEED_PROCESSED = 1 << 14, + LIBRAW_WARN_FALLBACK_TO_AHD = 1 << 15, + LIBRAW_WARN_PARSEFUJI_PROCESSED = 1 << 16, + LIBRAW_WARN_DNGSDK_PROCESSED = 1 << 17, + LIBRAW_WARN_DNG_IMAGES_REORDERED = 1 << 18, + LIBRAW_WARN_DNG_STAGE2_APPLIED = 1 << 19, + LIBRAW_WARN_DNG_STAGE3_APPLIED = 1 << 20, +}; + +enum LibRaw_exceptions +{ + LIBRAW_EXCEPTION_NONE = 0, + LIBRAW_EXCEPTION_ALLOC = 1, + LIBRAW_EXCEPTION_DECODE_RAW = 2, + LIBRAW_EXCEPTION_DECODE_JPEG = 3, + LIBRAW_EXCEPTION_IO_EOF = 4, + LIBRAW_EXCEPTION_IO_CORRUPT = 5, + LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK = 6, + LIBRAW_EXCEPTION_BAD_CROP = 7, + LIBRAW_EXCEPTION_IO_BADFILE = 8, + LIBRAW_EXCEPTION_DECODE_JPEG2000 = 9, + LIBRAW_EXCEPTION_TOOBIG = 10, + LIBRAW_EXCEPTION_MEMPOOL = 11 +}; enum LibRaw_progress { - LIBRAW_PROGRESS_START = 0, - LIBRAW_PROGRESS_OPEN = 1, - LIBRAW_PROGRESS_IDENTIFY = 1<<1, - LIBRAW_PROGRESS_SIZE_ADJUST = 1<<2, - LIBRAW_PROGRESS_LOAD_RAW = 1<<3, - LIBRAW_PROGRESS_REMOVE_ZEROES = 1<<4, - LIBRAW_PROGRESS_BAD_PIXELS = 1<<5, - LIBRAW_PROGRESS_DARK_FRAME = 1<<6, - LIBRAW_PROGRESS_FOVEON_INTERPOLATE = 1<<7, - LIBRAW_PROGRESS_SCALE_COLORS = 1<<8, - LIBRAW_PROGRESS_PRE_INTERPOLATE = 1<<9, - LIBRAW_PROGRESS_INTERPOLATE = 1<<10, - LIBRAW_PROGRESS_MIX_GREEN = 1<<11, - LIBRAW_PROGRESS_MEDIAN_FILTER = 1<<12, - LIBRAW_PROGRESS_HIGHLIGHTS = 1<<13, - LIBRAW_PROGRESS_FUJI_ROTATE = 1<<14, - LIBRAW_PROGRESS_FLIP = 1<<15, - LIBRAW_PROGRESS_APPLY_PROFILE = 1<<16, - LIBRAW_PROGRESS_CONVERT_RGB = 1<<17, - LIBRAW_PROGRESS_STRETCH = 1<<18, -// reserved - LIBRAW_PROGRESS_STAGE19 = 1<<19, - LIBRAW_PROGRESS_STAGE20 = 1<<20, - LIBRAW_PROGRESS_STAGE21 = 1<<21, - LIBRAW_PROGRESS_STAGE22 = 1<<22, - LIBRAW_PROGRESS_STAGE23 = 1<<23, - LIBRAW_PROGRESS_STAGE24 = 1<<24, - LIBRAW_PROGRESS_STAGE25 = 1<<25, - LIBRAW_PROGRESS_STAGE26 = 1<<26, - LIBRAW_PROGRESS_STAGE27 = 1<<27, - - LIBRAW_PROGRESS_THUMB_LOAD = 1<<28, - LIBRAW_PROGRESS_TRESERVED1 = 1<<29, - LIBRAW_PROGRESS_TRESERVED2 = 1<<30 + LIBRAW_PROGRESS_START = 0, + LIBRAW_PROGRESS_OPEN = 1, + LIBRAW_PROGRESS_IDENTIFY = 1 << 1, + LIBRAW_PROGRESS_SIZE_ADJUST = 1 << 2, + LIBRAW_PROGRESS_LOAD_RAW = 1 << 3, + LIBRAW_PROGRESS_RAW2_IMAGE = 1 << 4, + LIBRAW_PROGRESS_REMOVE_ZEROES = 1 << 5, + LIBRAW_PROGRESS_BAD_PIXELS = 1 << 6, + LIBRAW_PROGRESS_DARK_FRAME = 1 << 7, + LIBRAW_PROGRESS_FOVEON_INTERPOLATE = 1 << 8, + LIBRAW_PROGRESS_SCALE_COLORS = 1 << 9, + LIBRAW_PROGRESS_PRE_INTERPOLATE = 1 << 10, + LIBRAW_PROGRESS_INTERPOLATE = 1 << 11, + LIBRAW_PROGRESS_MIX_GREEN = 1 << 12, + LIBRAW_PROGRESS_MEDIAN_FILTER = 1 << 13, + LIBRAW_PROGRESS_HIGHLIGHTS = 1 << 14, + LIBRAW_PROGRESS_FUJI_ROTATE = 1 << 15, + LIBRAW_PROGRESS_FLIP = 1 << 16, + LIBRAW_PROGRESS_APPLY_PROFILE = 1 << 17, + LIBRAW_PROGRESS_CONVERT_RGB = 1 << 18, + LIBRAW_PROGRESS_STRETCH = 1 << 19, + /* reserved */ + LIBRAW_PROGRESS_STAGE20 = 1 << 20, + LIBRAW_PROGRESS_STAGE21 = 1 << 21, + LIBRAW_PROGRESS_STAGE22 = 1 << 22, + LIBRAW_PROGRESS_STAGE23 = 1 << 23, + LIBRAW_PROGRESS_STAGE24 = 1 << 24, + LIBRAW_PROGRESS_STAGE25 = 1 << 25, + LIBRAW_PROGRESS_STAGE26 = 1 << 26, + LIBRAW_PROGRESS_STAGE27 = 1 << 27, + + LIBRAW_PROGRESS_THUMB_LOAD = 1 << 28, + LIBRAW_PROGRESS_TRESERVED1 = 1 << 29, + LIBRAW_PROGRESS_TRESERVED2 = 1 << 30 }; #define LIBRAW_PROGRESS_THUMB_MASK 0x0fffffff enum LibRaw_errors { - LIBRAW_SUCCESS = 0, - LIBRAW_UNSPECIFIED_ERROR=-1, - LIBRAW_FILE_UNSUPPORTED = -2, - LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE=-3, - LIBRAW_OUT_OF_ORDER_CALL=-4, - LIBRAW_NO_THUMBNAIL=-5, - LIBRAW_UNSUPPORTED_THUMBNAIL=-6, - LIBRAW_CANNOT_ADDMASK=-7, - LIBRAW_UNSUFFICIENT_MEMORY=-100007, - LIBRAW_DATA_ERROR=-100008, - LIBRAW_IO_ERROR=-100009, - LIBRAW_CANCELLED_BY_CALLBACK=-100010 + LIBRAW_SUCCESS = 0, + LIBRAW_UNSPECIFIED_ERROR = -1, + LIBRAW_FILE_UNSUPPORTED = -2, + LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE = -3, + LIBRAW_OUT_OF_ORDER_CALL = -4, + LIBRAW_NO_THUMBNAIL = -5, + LIBRAW_UNSUPPORTED_THUMBNAIL = -6, + LIBRAW_INPUT_CLOSED = -7, + LIBRAW_NOT_IMPLEMENTED = -8, + LIBRAW_UNSUFFICIENT_MEMORY = -100007, + LIBRAW_DATA_ERROR = -100008, + LIBRAW_IO_ERROR = -100009, + LIBRAW_CANCELLED_BY_CALLBACK = -100010, + LIBRAW_BAD_CROP = -100011, + LIBRAW_TOO_BIG = -100012, + LIBRAW_MEMPOOL_OVERFLOW = -100013 }; -#define LIBRAW_FATAL_ERROR(ec) ((ec)<-100000) +#define LIBRAW_FATAL_ERROR(ec) ((ec) < -100000) enum LibRaw_thumbnail_formats { - LIBRAW_THUMBNAIL_UNKNOWN=0, - LIBRAW_THUMBNAIL_JPEG=1, - LIBRAW_THUMBNAIL_BITMAP=2, - LIBRAW_THUMBNAIL_LAYER=4, - LIBRAW_THUMBNAIL_ROLLEI=5 + LIBRAW_THUMBNAIL_UNKNOWN = 0, + LIBRAW_THUMBNAIL_JPEG = 1, + LIBRAW_THUMBNAIL_BITMAP = 2, + LIBRAW_THUMBNAIL_BITMAP16 = 3, + LIBRAW_THUMBNAIL_LAYER = 4, + LIBRAW_THUMBNAIL_ROLLEI = 5 }; enum LibRaw_image_formats { - LIBRAW_IMAGE_BITMAP=1, - LIBRAW_IMAGE_JPEG=2 + LIBRAW_IMAGE_JPEG = 1, + LIBRAW_IMAGE_BITMAP = 2 }; #endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_datastream.h libkdcraw/libkdcraw/libraw/libraw/libraw_datastream.h --- libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_datastream.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/libraw/libraw_datastream.h 2022-11-07 07:46:31.726795008 +0300 @@ -1,24 +1,19 @@ /* -*- C -*- * File: libraw_datastream.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sun Jan 18 13:07:35 2009 * * LibRaw Data stream interface - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #ifndef __LIBRAW_DATASTREAM_H @@ -31,273 +26,274 @@ #ifndef __cplusplus -struct LibRaw_abstract_datastream; - -#else // __cplusplus +#else /* __cplusplus */ +#if defined _WIN32 +#ifndef LIBRAW_NO_WINSOCK2 +#include <winsock2.h> +#endif +#endif +/* No unique_ptr on Apple ?? */ +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) || \ + (defined(_MSC_VER) && _MSVC_LANG >= 201103L) +/* OK - use unique_ptr unless LIBRAW_USE_AUTOPTR defined externally*/ +#else +/* Force to use auto_ptr */ +#ifndef LIBRAW_USE_AUTOPTR +#define LIBRAW_USE_AUTOPTR +#endif +#endif #include "libraw_const.h" +#include "libraw_types.h" +#include <fstream> +#include <memory> +#include <vector> -class LibRaw_buffer_datastream; +#if defined(_WIN32) && (_MSC_VER) >= 1500 +#define WIN32SECURECALLS +#endif -class LibRaw_abstract_datastream -{ - public: - LibRaw_abstract_datastream(){substream=0;}; - virtual ~LibRaw_abstract_datastream(void){if(substream) delete substream;} - virtual int valid(){return 0;} - // file input emulation - virtual int read(void *,size_t, size_t ){ return -1;} - virtual int seek(off_t o, int whence){return -1;} - virtual int tell(){return -1;} - virtual int get_char(){return -1;} - virtual char* gets(char *, int){ return NULL;} - virtual int scanf_one(const char *, void *){return -1;} - virtual int eof(){return -1;} - - virtual const char* fname(){ return NULL;}; - virtual int subfile_open(const char*){ return EINVAL;} - virtual void subfile_close(){} - virtual int tempbuffer_open(void*, size_t); - virtual void tempbuffer_close() - { - if(substream) delete substream; - substream = NULL; - } +#ifdef USE_DNGSDK - protected: - LibRaw_abstract_datastream *substream; -}; +#if defined LIBRAW_WIN32_CALLS +#define qWinOS 1 +#define qMacOS 0 +#elif defined(__APPLE__) +#define qWinOS 0 +#define qMacOS 1 +#else +/* define OS types for DNG here */ +#endif +#define qDNGXMPDocOps 0 +#define qDNGUseLibJPEG 1 +#define qDNGXMPFiles 0 +#define qDNGExperimental 1 +#define qDNGThreadSafe 1 +#include "dng_stream.h" +#endif /* DNGSDK */ + +#define IOERROR() \ + do \ + { \ + throw LIBRAW_EXCEPTION_IO_EOF; \ + } while (0) +class LibRaw_buffer_datastream; +class LibRaw_bit_buffer; -class LibRaw_file_datastream : public LibRaw_abstract_datastream +class DllDef LibRaw_abstract_datastream { - public: - LibRaw_file_datastream(const char *fname) - { - if(fname) - {filename = fname; f = fopen(fname,"rb");} - else - {filename=0;f=0;} - sav=0; - } - - virtual ~LibRaw_file_datastream() {if(f)fclose(f); if(sav)fclose(sav);} - - virtual int valid() { return f?1:0;} - -#define CHK() do {if(!f) throw LIBRAW_EXCEPTION_IO_EOF;}while(0) - virtual int read(void * ptr,size_t size, size_t nmemb) - { - CHK(); - return substream?substream->read(ptr,size,nmemb):int(fread(ptr,size,nmemb,f)); - } - virtual int eof() - { - CHK(); - return substream?substream->eof():feof(f); - } - virtual int seek(off_t o, int whence) - { - CHK(); - return substream?substream->seek(o,whence):fseek(f,o,whence); - } - virtual int tell() - { - CHK(); - return substream?substream->tell():ftell(f); - } - virtual int get_char() - { - CHK(); - return substream?substream->get_char():fgetc(f); - } - virtual char* gets(char *str, int sz) - { - CHK(); - return substream?substream->gets(str,sz):fgets(str,sz,f); - } - virtual int scanf_one(const char *fmt, void*val) - { - CHK(); - return substream?substream->scanf_one(fmt,val):fscanf(f,fmt,val); - } +public: + LibRaw_abstract_datastream() { }; + virtual ~LibRaw_abstract_datastream(void) { } + virtual int valid() = 0; + virtual int read(void *, size_t, size_t) = 0; + virtual int seek(INT64, int) = 0; + virtual INT64 tell() = 0; + virtual INT64 size() = 0; + virtual int get_char() = 0; + virtual char *gets(char *, int) = 0; + virtual int scanf_one(const char *, void *) = 0; + virtual int eof() = 0; + virtual void *make_jas_stream() = 0; + virtual int jpeg_src(void *); + virtual void buffering_off() {} + /* reimplement in subclass to use parallel access in xtrans_load_raw() if + * OpenMP is not used */ + virtual int lock() { return 1; } /* success */ + virtual void unlock() {} + virtual const char *fname() { return NULL; }; +#ifdef LIBRAW_WIN32_UNICODEPATHS + virtual const wchar_t *wfname() { return NULL; }; +#endif +}; - virtual const char *fname() { return filename; } +#ifdef LIBRAW_WIN32_DLLDEFS +#ifdef LIBRAW_USE_AUTOPTR +template class DllDef std::auto_ptr<std::streambuf>; +#else +template class DllDef std::unique_ptr<std::streambuf>; +#endif +#endif - // secondary - virtual int subfile_open(const char *fn) - { - if(sav) return EBUSY; - sav = f; - f = fopen(fn,"rb"); - if(!f) - { - f = sav; - sav = NULL; - return ENOENT; - } - else - return 0; - } - virtual void subfile_close() - { - if(!sav) return; - fclose(f); - f = sav; - sav = 0; - } +class DllDef LibRaw_file_datastream : public LibRaw_abstract_datastream +{ +protected: +#ifdef LIBRAW_USE_AUTOPTR + std::auto_ptr<std::streambuf> f; /* will close() automatically through dtor */ +#else + std::unique_ptr<std::streambuf> f; +#endif + std::string filename; + INT64 _fsize; +#ifdef LIBRAW_WIN32_UNICODEPATHS + std::wstring wfilename; +#endif + FILE *jas_file; - private: - FILE *f,*sav; - const char *filename; +public: + virtual ~LibRaw_file_datastream(); + LibRaw_file_datastream(const char *fname); +#ifdef LIBRAW_WIN32_UNICODEPATHS + LibRaw_file_datastream(const wchar_t *fname); +#endif + virtual void *make_jas_stream(); + virtual int valid(); + virtual int read(void *ptr, size_t size, size_t nmemb); + virtual int eof(); + virtual int seek(INT64 o, int whence); + virtual INT64 tell(); + virtual INT64 size() { return _fsize; } + virtual int get_char() {return f->sbumpc();} + virtual char *gets(char *str, int sz); + virtual int scanf_one(const char *fmt, void *val); + virtual const char *fname(); +#ifdef LIBRAW_WIN32_UNICODEPATHS + virtual const wchar_t *wfname(); +#endif }; -#undef CHK -class LibRaw_buffer_datastream : public LibRaw_abstract_datastream +class DllDef LibRaw_buffer_datastream : public LibRaw_abstract_datastream { - public: - LibRaw_buffer_datastream(void *buffer, size_t bsize) - { - buf = (unsigned char*)buffer; streampos = 0; streamsize = bsize; - } - virtual ~LibRaw_buffer_datastream(){} - virtual int valid() { return buf?1:0;} - virtual int read(void * ptr,size_t sz, size_t nmemb) - { - if(substream) return substream->read(ptr,sz,nmemb); - size_t to_read = sz*nmemb; - if(to_read > streamsize - streampos) - to_read = streamsize-streampos; - if(to_read<1) - return 0; - memmove(ptr,buf+streampos,to_read); - streampos+=to_read; - return int((to_read+sz-1)/sz); - } +public: + LibRaw_buffer_datastream(void *buffer, size_t bsize); + virtual ~LibRaw_buffer_datastream(); + virtual int valid(); + virtual void *make_jas_stream(); + virtual int jpeg_src(void *jpegdata); + virtual int read(void *ptr, size_t sz, size_t nmemb); + virtual int eof(); + virtual int seek(INT64 o, int whence); + virtual INT64 tell(); + virtual INT64 size() { return streamsize; } + virtual char *gets(char *s, int sz); + virtual int scanf_one(const char *fmt, void *val); + virtual int get_char() + { + if (streampos >= streamsize) return -1; + return buf[streampos++]; + } + +private: + unsigned char *buf; + size_t streampos, streamsize; +}; - virtual int eof() - { - if(substream) return substream->eof(); - return streampos >= streamsize; - } +class DllDef LibRaw_bigfile_datastream : public LibRaw_abstract_datastream +{ +public: + LibRaw_bigfile_datastream(const char *fname); +#ifdef LIBRAW_WIN32_UNICODEPATHS + LibRaw_bigfile_datastream(const wchar_t *fname); +#endif + virtual ~LibRaw_bigfile_datastream(); + virtual int valid(); + virtual void *make_jas_stream(); + + virtual int read(void *ptr, size_t size, size_t nmemb); + virtual int eof(); + virtual int seek(INT64 o, int whence); + virtual INT64 tell(); + virtual INT64 size() { return _fsize; } + virtual char *gets(char *str, int sz); + virtual int scanf_one(const char *fmt, void *val); + virtual const char *fname(); +#ifdef LIBRAW_WIN32_UNICODEPATHS + virtual const wchar_t *wfname(); +#endif + virtual int get_char() + { +#ifndef LIBRAW_WIN32_CALLS + return getc_unlocked(f); +#else + return fgetc(f); +#endif + } - virtual int seek(off_t o, int whence) - { - if(substream) return substream->seek(o,whence); - switch(whence) - { - case SEEK_SET: - if(o<0) - streampos = 0; - else if (size_t(o) > streamsize) - streampos = streamsize; - else - streampos = size_t(o); - return 0; - case SEEK_CUR: - if(o<0) - { - if(size_t(-o) >= streampos) - streampos = 0; - else - streampos += o; - } - else if (o>0) - { - if(o+streampos> streamsize) - streampos = streamsize; - else - streampos += o; - } - return 0; - case SEEK_END: - if(o>0) - streampos = streamsize; - else if ( size_t(-o) > streamsize) - streampos = 0; - else - streampos = streamsize+o; - return 0; - default: - return 0; - } - } - - virtual int tell() - { - if(substream) return substream->tell(); - return int(streampos); - } +protected: + FILE *f; + std::string filename; + INT64 _fsize; +#ifdef LIBRAW_WIN32_UNICODEPATHS + std::wstring wfilename; +#endif +}; - virtual int get_char() - { - if(substream) return substream->get_char(); - if(streampos>=streamsize) - return -1; - return buf[streampos++]; - } - virtual char* gets(char *s, int sz) - { - if (substream) return substream->gets(s,sz); - unsigned char *psrc,*pdest,*str; - str = (unsigned char *)s; - psrc = buf+streampos; - pdest = str; - while ( (size_t(psrc - buf) < streamsize) - && - ((pdest-str)<sz) - ) - { - *pdest = *psrc; - if(*psrc == '\n') - break; - psrc++; - pdest++; - } - if(size_t(psrc-buf) < streamsize) - psrc++; - if((pdest-str)<sz) - *(++pdest)=0; - streampos = psrc - buf; - return s; - } - virtual int scanf_one(const char *fmt, void* val) - { - if(substream) return substream->scanf_one(fmt,val); - int scanf_res; - if(streampos>streamsize) return 0; - scanf_res = sscanf((char*)(buf+streampos),fmt,val); - if(scanf_res>0) - { - int xcnt=0; - while(streampos<streamsize) - { - streampos++; - xcnt++; - if(buf[streampos] == 0 - || buf[streampos]==' ' - || buf[streampos]=='\t' - || buf[streampos]=='\n' - || xcnt>24) - break; - } - } - return scanf_res; - } - private: - unsigned char *buf; - size_t streampos,streamsize; +#ifdef LIBRAW_WIN32_CALLS +class DllDef LibRaw_windows_datastream : public LibRaw_buffer_datastream +{ +public: + /* ctor: high level constructor opens a file by name */ + LibRaw_windows_datastream(const TCHAR *sFile); + /* ctor: construct with a file handle - caller is responsible for closing the + * file handle */ + LibRaw_windows_datastream(HANDLE hFile); + /* dtor: unmap and close the mapping handle */ + virtual ~LibRaw_windows_datastream(); + virtual INT64 size() { return cbView_; } + +protected: + void Open(HANDLE hFile); + inline void reconstruct_base() + { + /* this subterfuge is to overcome the private-ness of + * LibRaw_buffer_datastream */ + (LibRaw_buffer_datastream &)*this = + LibRaw_buffer_datastream(pView_, (size_t)cbView_); + } + + HANDLE hMap_; /* handle of the file mapping */ + void *pView_; /* pointer to the mapped memory */ + __int64 cbView_; /* size of the mapping in bytes */ }; -inline int LibRaw_abstract_datastream::tempbuffer_open(void *buf, size_t size) +#endif + +#ifdef USE_DNGSDK + +class libraw_dng_stream : public dng_stream { - if(substream) return EBUSY; - substream = new LibRaw_buffer_datastream(buf,size); - return substream?0:EINVAL; -} +public: + libraw_dng_stream(LibRaw_abstract_datastream *p) + : dng_stream((dng_abort_sniffer *)NULL, kBigBufferSize, 0), + parent_stream(p) + { + if (parent_stream) + { + parent_stream->buffering_off(); + off = parent_stream->tell(); + parent_stream->seek(0UL, SEEK_SET); /* seek to start */ + } + } + ~libraw_dng_stream() + { + if (parent_stream) + parent_stream->seek(off, SEEK_SET); + } + virtual uint64 DoGetLength() + { + if (parent_stream) + return parent_stream->size(); + return 0; + } + virtual void DoRead(void *data, uint32 count, uint64 offset) + { + if (parent_stream) + { + parent_stream->seek(offset, SEEK_SET); + parent_stream->read(data, 1, count); + } + } +private: + libraw_dng_stream(const libraw_dng_stream &stream); + libraw_dng_stream &operator=(const libraw_dng_stream &stream); + LibRaw_abstract_datastream *parent_stream; + INT64 off; +}; #endif -#endif +#endif /* cplusplus */ +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_internal.h libkdcraw/libkdcraw/libraw/libraw/libraw_internal.h --- libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_internal.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/libraw/libraw_internal.h 2022-11-07 07:46:31.730795008 +0300 @@ -1,240 +1,319 @@ -/* +/* -*- C++ -*- * File: libraw_internal.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * * LibRaw internal data structures (not visible outside) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -#ifndef _LIBRAW_INTERNAL_TYPES_H -#define _LIBRAW_INTERNAL_TYPES_H +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: -#include <stdio.h> -#ifdef __cplusplus +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). -#ifndef CLASS -#define CLASS LibRaw:: -#endif + */ -#else -// C build -#ifndef CLASS -#define CLASS -#endif -#endif +#ifndef _LIBRAW_INTERNAL_TYPES_H +#define _LIBRAW_INTERNAL_TYPES_H +#include <stdio.h> #ifdef __cplusplus #include "libraw_datastream.h" +#include "libraw_types.h" class LibRaw_TLS { public: - struct - { - unsigned bitbuf; - int vbits, reset; - }getbits; - struct - { - UINT64 bitbuf; - int vbits; - - }ph1_bits; - int make_decoder_leaf; - struct - { - struct decode *dstart[18], *dindex; - const int *s; - }radc_token; - struct - { - unsigned pad[128], p; - }sony_decrypt; - unsigned foveon_decoder_huff[1024]; - uchar jpeg_buffer[4096]; - struct - { - uchar buf[0x4000]; - int vbits, padding; - }pana_bits; - - // init - should use in constructor/recycle - void init() - { - getbits.bitbuf = 0; getbits.vbits = getbits.reset = 0; - ph1_bits.bitbuf = 0; ph1_bits.vbits = 0; - pana_bits.vbits = 0; - } + struct + { + unsigned bitbuf; + int vbits, reset; + } getbits; + struct + { + UINT64 bitbuf; + int vbits; + + } ph1_bits; + struct + { + unsigned pad[128], p; + } sony_decrypt; + struct + { + uchar buf[0x4002]; + int vpos, padding; + } pana_data; + uchar jpeg_buffer[4096]; + struct + { + float cbrt[0x10000], xyz_cam[3][4]; + } ahd_data; + void init() + { + getbits.bitbuf = 0; + getbits.vbits = getbits.reset = 0; + ph1_bits.bitbuf = 0; + ph1_bits.vbits = 0; + pana_data.vpos = 0; + ahd_data.cbrt[0] = -2.0f; + } }; - class LibRaw_constants { - public: - static const float d65_white[3]; - static const double xyz_rgb[3][3]; +public: + static const float d65_white[3]; + static const double xyz_rgb[3][3]; + static const double xyzd50_srgb[3][3]; + static const double rgb_rgb[3][3]; + static const double adobe_rgb[3][3]; + static const double wide_rgb[3][3]; + static const double prophoto_rgb[3][3]; + static const double aces_rgb[3][3]; }; -#endif // __cplusplus - -#ifdef WIN32 -typedef long off_t; -#endif +#endif /* __cplusplus */ typedef struct { #ifndef __cplusplus - struct + struct #endif - LibRaw_abstract_datastream *input; - int input_internal; -// char *ifname; - char *meta_data; - off_t profile_offset; - off_t toffset; + LibRaw_abstract_datastream *input; + FILE *output; + int input_internal; + char *meta_data; + INT64 profile_offset; + INT64 toffset; + unsigned pana_black[4]; } internal_data_t; -typedef struct -{ - unsigned mix_green; - unsigned raw_color; - unsigned use_gamma; - unsigned zero_is_bad; - ushort shrink; - ushort fuji_width; - ushort fwidth,fheight; -} internal_output_params_t; - #define LIBRAW_HISTOGRAM_SIZE 0x2000 typedef struct { - int (*histogram)[LIBRAW_HISTOGRAM_SIZE]; - unsigned *oprof; + int (*histogram)[LIBRAW_HISTOGRAM_SIZE]; + unsigned *oprof; } output_data_t; typedef struct { - unsigned olympus_exif_cfa; - unsigned unique_id; - unsigned tiff_nifds; - int tiff_flip; -}identify_data_t; + unsigned olympus_exif_cfa; + unsigned long long unique_id; + unsigned long long OlyID; + unsigned tiff_nifds; + int tiff_flip; + int metadata_blocks; +} identify_data_t; +// contents of tag CMP1 for relevant track in CR3 file typedef struct { - short order; // II* / MM* - file word byte order - ushort sraw_mul[4],cr2_slice[3]; - unsigned kodak_cbpp; - off_t strip_offset, data_offset; - off_t meta_offset; - unsigned meta_length; - unsigned thumb_misc; - unsigned fuji_layout; - unsigned tiff_samples; - unsigned tiff_bps; - unsigned tiff_compress; - unsigned zero_after_ff; - unsigned tile_width, tile_length,load_flags; - unsigned data_error; -}unpacker_data_t; - + int32_t version; + int32_t f_width; + int32_t f_height; + int32_t tileWidth; + int32_t tileHeight; + int32_t nBits; + int32_t nPlanes; + int32_t cfaLayout; + int32_t encType; + int32_t imageLevels; + int32_t hasTileCols; + int32_t hasTileRows; + int32_t mdatHdrSize; + // Not from header, but from datastream + uint32_t MediaSize; + INT64 MediaOffset; + uint32_t MediaType; /* 1 -> /C/RAW, 2-> JPEG */ +} crx_data_header_t; +typedef struct +{ + short order; + ushort sraw_mul[4], cr2_slice[3]; + unsigned kodak_cbpp; + INT64 strip_offset, data_offset; + INT64 meta_offset; + unsigned data_size; + unsigned meta_length; + unsigned thumb_misc; + unsigned fuji_layout; + unsigned tiff_samples; + unsigned tiff_bps; + unsigned tiff_compress; + unsigned tiff_sampleformat; + unsigned zero_after_ff; + unsigned tile_width, tile_length, load_flags; + unsigned data_error; + int hasselblad_parser_flag; + long long posRAFData; + unsigned lenRAFData; + int fuji_total_lines, fuji_total_blocks, fuji_block_width, fuji_bits, + fuji_raw_type; + int pana_encoding, pana_bpp; + crx_data_header_t crx_header[LIBRAW_CRXTRACKS_MAXCOUNT]; + int crx_track_selected; + short CR3_CTMDtag; + short CR3_Version; + int CM_found; + unsigned is_NikonTransfer; + unsigned is_Sony; + unsigned is_pana_raw; + unsigned + is_4K_RAFdata; /* =1 for Fuji X-A3, X-A5, X-A7, X-A10, X-A20, X-T100, XF10 */ + unsigned is_PentaxRicohMakernotes; /* =1 for Ricoh software by Pentax, Camera DNG */ + + unsigned dng_frames[LIBRAW_IFD_MAXCOUNT*2]; /* bits: 0-7: shot_select, 8-15: IFD#, 16-31: low 16 bit of newsubfile type */ + unsigned short raw_stride; +} unpacker_data_t; typedef struct { - internal_data_t internal_data; - internal_output_params_t internal_output_params; - output_data_t output_data; - identify_data_t identify_data; - unpacker_data_t unpacker_data; -// callbacks_t callbacks; + internal_data_t internal_data; + libraw_internal_output_params_t internal_output_params; + output_data_t output_data; + identify_data_t identify_data; + unpacker_data_t unpacker_data; } libraw_internal_data_t; - -struct decode +struct decode { - struct decode *branch[2]; - int leaf; + struct decode *branch[2]; + int leaf; }; -struct tiff_ifd_t +struct tiff_ifd_t { - int t_width, t_height, bps, comp, phint, offset, t_flip, samples, bytes; + int t_width, t_height, bps, comp, phint, offset, t_flip, samples, bytes, extrasamples; + int t_tile_width, t_tile_length, sample_format, predictor; + int rows_per_strip; + int *strip_offsets, strip_offsets_count; + int *strip_byte_counts, strip_byte_counts_count; + unsigned t_filters; + int t_vwidth, t_vheight, t_lm,t_tm; + int t_fuji_width; + float t_shutter; + /* Per-IFD DNG fields */ + INT64 opcode2_offset; + INT64 lineartable_offset; + int lineartable_len; + libraw_dng_color_t dng_color[2]; + libraw_dng_levels_t dng_levels; + int newsubfiletype; }; - -struct jhead { - int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; - struct decode *huff[6]; - ushort *row; +struct jhead +{ + int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort quant[64], idct[64], *huff[20], *free[20], *row; }; -struct tiff_tag { + +struct libraw_tiff_tag +{ ushort tag, type; int count; - union { char c[4]; short s[2]; int i; } val; + union { + char c[4]; + short s[2]; + int i; + } val; }; -struct tiff_hdr { +struct tiff_hdr +{ ushort t_order, magic; int ifd; ushort pad, ntag; - struct tiff_tag tag[23]; + struct libraw_tiff_tag tag[23]; int nextifd; ushort pad2, nexif; - struct tiff_tag exif[4]; + struct libraw_tiff_tag exif[4]; ushort pad3, ngps; - struct tiff_tag gpst[10]; + struct libraw_tiff_tag gpst[10]; short bps[4]; int rat[10]; unsigned gps[26]; char t_desc[512], t_make[64], t_model[64], soft[32], date[20], t_artist[64]; }; - - #ifdef DEBUG_STAGE_CHECKS -#define CHECK_ORDER_HIGH(expected_stage) \ - do { if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) >= expected_stage) {fprintf(stderr,"CHECK_HIGH: check %d >= %d\n",imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK,expected_stage);return LIBRAW_OUT_OF_ORDER_CALL;} } while(0) - -#define CHECK_ORDER_LOW(expected_stage) \ - do { printf("Checking LOW %d/%d : %d\n",imgdata.progress_flags,expected_stage,imgdata.progress_flags<expected_stage); if( (imgdata.progress_flags&LIBRAW_PROGRESS_THUMB_MASK) < expected_stage ) { printf("failed!\n"); return LIBRAW_OUT_OF_ORDER_CALL;} } while(0) -#define CHECK_ORDER_BIT(expected_stage) \ - do { if(imgdata.progress_flags & expected_stage) return LIBRAW_OUT_OF_ORDER_CALL; } while(0) - -#define SET_PROC_FLAG(stage) do {imgdata.progress_flags |= stage; fprintf(stderr,"SET_FLAG: %d\n",stage); } while (0) +#define CHECK_ORDER_HIGH(expected_stage) \ + do \ + { \ + if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) >= \ + expected_stage) \ + { \ + fprintf(stderr, "CHECK_HIGH: check %d >= %d\n", \ + imgdata.progress_flags &LIBRAW_PROGRESS_THUMB_MASK, \ + expected_stage); \ + return LIBRAW_OUT_OF_ORDER_CALL; \ + } \ + } while (0) + +#define CHECK_ORDER_LOW(expected_stage) \ + do \ + { \ + printf("Checking LOW %d/%d : %d\n", imgdata.progress_flags, \ + expected_stage, imgdata.progress_flags < expected_stage); \ + if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) < \ + expected_stage) \ + { \ + printf("failed!\n"); \ + return LIBRAW_OUT_OF_ORDER_CALL; \ + } \ + } while (0) +#define CHECK_ORDER_BIT(expected_stage) \ + do \ + { \ + if (imgdata.progress_flags & expected_stage) \ + return LIBRAW_OUT_OF_ORDER_CALL; \ + } while (0) + +#define SET_PROC_FLAG(stage) \ + do \ + { \ + imgdata.progress_flags |= stage; \ + fprintf(stderr, "SET_FLAG: %d\n", stage); \ + } while (0) #else -#define CHECK_ORDER_HIGH(expected_stage) \ - do { if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) >= expected_stage) \ - {return LIBRAW_OUT_OF_ORDER_CALL;} } while(0) - -#define CHECK_ORDER_LOW(expected_stage) \ - do { if((imgdata.progress_flags&LIBRAW_PROGRESS_THUMB_MASK) < expected_stage) \ - return LIBRAW_OUT_OF_ORDER_CALL; } while(0) - -#define CHECK_ORDER_BIT(expected_stage) \ - do { if(imgdata.progress_flags & expected_stage) return LIBRAW_OUT_OF_ORDER_CALL; } while(0) - -#define SET_PROC_FLAG(stage) do {imgdata.progress_flags |= stage;} while (0) +#define CHECK_ORDER_HIGH(expected_stage) \ + do \ + { \ + if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) >= \ + expected_stage) \ + { \ + return LIBRAW_OUT_OF_ORDER_CALL; \ + } \ + } while (0) + +#define CHECK_ORDER_LOW(expected_stage) \ + do \ + { \ + if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) < \ + expected_stage) \ + return LIBRAW_OUT_OF_ORDER_CALL; \ + } while (0) + +#define CHECK_ORDER_BIT(expected_stage) \ + do \ + { \ + if (imgdata.progress_flags & expected_stage) \ + return LIBRAW_OUT_OF_ORDER_CALL; \ + } while (0) + +#define SET_PROC_FLAG(stage) \ + do \ + { \ + imgdata.progress_flags |= stage; \ + } while (0) #endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_types.h libkdcraw/libkdcraw/libraw/libraw/libraw_types.h --- libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_types.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/libraw/libraw_types.h 2022-11-07 07:46:31.730795008 +0300 @@ -1,285 +1,1032 @@ -/* +/* -*- C++ -*- * File: libraw_types.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * * LibRaw C data structures * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #ifndef _LIBRAW_TYPES_H #define _LIBRAW_TYPES_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifndef WIN32 +#include <sys/types.h> +#ifndef _WIN32 #include <sys/time.h> #endif + #include <stdio.h> -#ifdef _OPENMP -#include <omp.h> + +#if defined(_WIN32) +#if defined(_MSC_VER) && (_MSC_VER <= 1500) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else /* WIN32, but not old MSVC */ +#include <stdint.h> +#endif /* _WIN32 */ +#include <sys/types.h> +#else +#include <inttypes.h> #endif +#if defined(_OPENMP) + +#if defined(_WIN32) +#if defined(_MSC_VER) && \ + (_MSC_VER >= 1600 || (_MSC_VER == 1500 && _MSC_FULL_VER >= 150030729)) +/* VS2010+ : OpenMP works OK, VS2008: have tested by cgilles */ +#define LIBRAW_USE_OPENMP +#elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 910) +/* Have not tested on 9.x and 10.x, but Intel documentation claims OpenMP 2.5 + * support in 9.1 */ +#define LIBRAW_USE_OPENMP +#else +#undef LIBRAW_USE_OPENMP +#endif +/* Not Win32 */ +#elif (defined(__APPLE__) || defined(__MACOSX__)) && defined(_REENTRANT) +/* Latest XCode works with OpenMP, need to recheck here */ +#undef LIBRAW_USE_OPENMP +#else +#define LIBRAW_USE_OPENMP +#endif +#endif + +#ifdef LIBRAW_USE_OPENMP +#include <omp.h> +#endif #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -#ifndef USE_LCMS +#if defined(USE_LCMS) +#include <lcms.h> +#elif defined(USE_LCMS2) +#include <lcms2.h> +#else #define NO_LCMS #endif #include "libraw_const.h" #include "libraw_version.h" +#ifdef _WIN32 + typedef __int64 INT64; + typedef unsigned __int64 UINT64; +#else typedef long long INT64; typedef unsigned long long UINT64; -//#define ushort UshORt -typedef unsigned char uchar; -typedef unsigned short ushort; +#endif + + typedef unsigned char uchar; + typedef unsigned short ushort; -#ifdef WIN32 +#ifdef LIBRAW_WIN32_DLLDEFS #ifdef LIBRAW_NODLL -# define DllDef +#define DllDef #else -# ifdef LIBRAW_BUILDLIB -# define DllDef __declspec( dllexport ) -# else -# define DllDef __declspec( dllimport ) -# endif +#ifdef LIBRAW_BUILDLIB +#define DllDef __declspec(dllexport) +#else +#define DllDef __declspec(dllimport) +#endif #endif -// NO Win32 #else -# define DllDef +#define DllDef #endif + typedef struct + { + const char *decoder_name; + unsigned decoder_flags; + } libraw_decoder_info_t; + + typedef struct + { + unsigned mix_green; + unsigned raw_color; + unsigned zero_is_bad; + ushort shrink; + ushort fuji_width; + } libraw_internal_output_params_t; + + typedef void (*memory_callback)(void *data, const char *file, + const char *where); + typedef void (*exif_parser_callback)(void *context, int tag, int type, + int len, unsigned int ord, void *ifp, + INT64 base); + + DllDef void default_memory_callback(void *data, const char *file, + const char *where); + + typedef void (*data_callback)(void *data, const char *file, const int offset); + + DllDef void default_data_callback(void *data, const char *file, + const int offset); + + typedef int (*progress_callback)(void *data, enum LibRaw_progress stage, + int iteration, int expected); + typedef int (*pre_identify_callback)(void *ctx); + typedef void (*post_identify_callback)(void *ctx); + typedef void (*process_step_callback)(void *ctx); -//class LibRaw; - -typedef void (* memory_callback)(void * data, const char *file, const char *where); - -DllDef void default_memory_callback(void *data,const char *file, const char *where); - -typedef void (*data_callback)(void *data,const char *file, const int offset); - -DllDef void default_data_callback(void *data,const char *file, const int offset); - -typedef int (* progress_callback) (void *data,enum LibRaw_progress stage, int iteration,int expected); - -typedef struct -{ + typedef struct + { memory_callback mem_cb; - void* memcb_data; + void *memcb_data; data_callback data_cb; - void* datacb_data; + void *datacb_data; progress_callback progress_cb; void *progresscb_data; -} libraw_callbacks_t; - -// Output bitmap type - -typedef struct -{ - enum LibRaw_image_formats type; - ushort height, - width, - colors, - bits, - gamma_corrected; - unsigned int data_size; // ðàçìåð ïîëÿ äàííûõ â áàéòàõ - unsigned char data[1]; // we'll allocate more! -}libraw_processed_image_t; - -//Decoded from exif and used in calculations -typedef struct -{ - char make[64]; - char model[64]; - - unsigned raw_count; - unsigned dng_version; - unsigned is_foveon; - int colors; - - unsigned filters; // camera CFA pattern mask - char cdesc[5]; + exif_parser_callback exif_cb; + void *exifparser_data; + pre_identify_callback pre_identify_cb; + post_identify_callback post_identify_cb; + process_step_callback pre_subtractblack_cb, pre_scalecolors_cb, + pre_preinterpolate_cb, pre_interpolate_cb, interpolate_bayer_cb, + interpolate_xtrans_cb, post_interpolate_cb, pre_converttorgb_cb, + post_converttorgb_cb; + } libraw_callbacks_t; + + typedef struct + { + enum LibRaw_image_formats type; + ushort height, width, colors, bits; + unsigned int data_size; + unsigned char data[1]; + } libraw_processed_image_t; + + typedef struct + { + char guard[4]; + char make[64]; + char model[64]; + char software[64]; + char normalized_make[64]; + char normalized_model[64]; + unsigned maker_index; + unsigned raw_count; + unsigned dng_version; + unsigned is_foveon; + int colors; + unsigned filters; + char xtrans[6][6]; + char xtrans_abs[6][6]; + char cdesc[5]; + unsigned xmplen; + char *xmpdata; + + } libraw_iparams_t; + + typedef struct + { + ushort cleft, ctop, cwidth, cheight, aspect; + } libraw_raw_inset_crop_t; + + typedef struct + { + ushort raw_height, raw_width, height, width, top_margin, left_margin; + ushort iheight, iwidth; + unsigned raw_pitch; + double pixel_aspect; + int flip; + int mask[8][4]; + libraw_raw_inset_crop_t raw_inset_crop; + } libraw_image_sizes_t; + + struct ph1_t + { + int format, key_off, tag_21a; + int t_black, split_col, black_col, split_row, black_row; + float tag_210; + }; -}libraw_iparams_t; + typedef struct + { + unsigned parsedfields; + ushort illuminant; + float calibration[4][4]; + float colormatrix[4][3]; + float forwardmatrix[3][4]; + } libraw_dng_color_t; + + typedef struct + { + unsigned parsedfields; + unsigned dng_cblack[LIBRAW_CBLACK_SIZE]; + unsigned dng_black; + float dng_fcblack[LIBRAW_CBLACK_SIZE]; + float dng_fblack; + unsigned dng_whitelevel[4]; + unsigned default_crop[4]; /* Origin and size */ + unsigned preview_colorspace; + float analogbalance[4]; + float asshotneutral[4]; + float baseline_exposure; + float LinearResponseLimit; + } libraw_dng_levels_t; + + typedef struct + { + float romm_cam[9]; + } libraw_P1_color_t; + + typedef struct + { + int ColorDataVer; + int ColorDataSubVer; + int SpecularWhiteLevel; + int NormalWhiteLevel; + int ChannelBlackLevel[4]; + int AverageBlackLevel; + /* multishot */ + unsigned int multishot[4]; + /* metering */ + short MeteringMode; + short SpotMeteringMode; + uchar FlashMeteringMode; + short FlashExposureLock; + short ExposureMode; + short AESetting; + uchar HighlightTonePriority; + /* stabilization */ + short ImageStabilization; + /* focus */ + short FocusMode; + short AFPoint; + short FocusContinuous; + short AFPointsInFocus30D; + uchar AFPointsInFocus1D[8]; + ushort AFPointsInFocus5D; /* bytes in reverse*/ + /* AFInfo */ + ushort AFAreaMode; + ushort NumAFPoints; + ushort ValidAFPoints; + ushort AFImageWidth; + ushort AFImageHeight; + short AFAreaWidths[61]; /* cycle to NumAFPoints */ + short AFAreaHeights[61]; /* --''-- */ + short AFAreaXPositions[61]; /* --''-- */ + short AFAreaYPositions[61]; /* --''-- */ + short AFPointsInFocus[4]; /* cycle to floor((NumAFPoints+15)/16) */ + short AFPointsSelected[4]; /* --''-- */ + ushort PrimaryAFPoint; + /* flash */ + short FlashMode; + short FlashActivity; + short FlashBits; + short ManualFlashOutput; + short FlashOutput; + short FlashGuideNumber; + /* drive */ + short ContinuousDrive; + /* sensor */ + short SensorWidth; + short SensorHeight; + short SensorLeftBorder; + short SensorTopBorder; + short SensorRightBorder; + short SensorBottomBorder; + short BlackMaskLeftBorder; + short BlackMaskTopBorder; + short BlackMaskRightBorder; + short BlackMaskBottomBorder; + int AFMicroAdjMode; + float AFMicroAdjValue; + short MakernotesFlip; + short RecordMode; + short SRAWQuality; + unsigned wbi; + float firmware; + short RF_lensID; + } libraw_canon_makernotes_t; + + typedef struct + { + int BaseISO; + double Gain; + char Sensor[8]; + char SensorUnit[64]; // SU + char HostBody[64]; // HB + int SensorCode; + int SensorSubCode; + int CoatingCode; + int uncropped; + +/* CaptureSequenceInitiator is based on the content of the 'model' tag + - values like 'Pinhole', 'Flash Sync', '500 Mech.' etc in .3FR 'model' tag + come from MAIN MENU > SETTINGS > Camera; + - otherwise 'model' contains: + 1. if CF/CFV/CFH, SU enclosure, can be with SU type if '-' is present + 2. else if '-' is present, HB + SU type; + 3. HB; +*/ + char CaptureSequenceInitiator[32]; + +/* SensorUnitConnector, makernotes 0x0015 tag: + - in .3FR - SU side + - in .FFF - HB side +*/ + char SensorUnitConnector[64]; + + int format; // 3FR, FFF, Imacon (H3D-39 and maybe others), Hasselblad/Phocus DNG, Adobe DNG + int nIFD_CM[2]; // number of IFD containing CM + int RecommendedCrop[2]; + +/* mnColorMatrix is in makernotes tag 0x002a; + not present in .3FR files and Imacon/H3D-39 .FFF files; + when present in .FFF and Phocus .DNG files, it is a copy of CM1 from .3FR; + available samples contain all '1's in the first 3 elements +*/ + double mnColorMatrix[4][3]; + + } libraw_hasselblad_makernotes_t; + + typedef struct + { + float ExpoMidPointShift; + ushort DynamicRange; + ushort FilmMode; + ushort DynamicRangeSetting; + ushort DevelopmentDynamicRange; + ushort AutoDynamicRange; + ushort DRangePriority; + ushort DRangePriorityAuto; + ushort DRangePriorityFixed; + + /* + tag 0x9200, converted to BrightnessCompensation + F700, S3Pro, S5Pro, S20Pro, S200EXR + E550, E900, F810, S5600, S6500fd, S9000, S9500, S100FS + */ + float BrightnessCompensation; /* in EV, if =4, raw data * 2^4 */ + + ushort FocusMode; + ushort AFMode; + ushort FocusPixel[2]; + ushort ImageStabilization[3]; + ushort FlashMode; + ushort WB_Preset; + + /* ShutterType: + 0 - mechanical + 1 = electronic + 2 = electronic, long shutter speed + 3 = electronic, front curtain + */ + ushort ShutterType; + ushort ExrMode; + ushort Macro; + unsigned Rating; + + /* CropMode: + 1 - FF on GFX, + 2 - sports finder (mechanical shutter), + 4 - 1.25x crop (electronic shutter, continuous high) + */ + ushort CropMode; + ushort FrameRate; + ushort FrameWidth; + ushort FrameHeight; + char SerialSignature[0x0c + 1]; + char RAFVersion[4 + 1]; + ushort RAFDataVersion; + int isTSNERDTS; + + /* DriveMode: + 0 - single frame + 1 - continuous low + 2 - continuous high + */ + short DriveMode; + } libraw_fuji_info_t; + + typedef struct + { + ushort cleft, ctop, cwidth, cheight; + } libraw_sensor_highspeed_crop_t; + + typedef struct + { + double ExposureBracketValue; + ushort ActiveDLighting; + ushort ShootingMode; + /* stabilization */ + uchar ImageStabilization[7]; + uchar VibrationReduction; + uchar VRMode; + /* focus */ + char FocusMode[7]; + uchar AFPoint; + ushort AFPointsInFocus; + uchar ContrastDetectAF; + uchar AFAreaMode; + uchar PhaseDetectAF; + uchar PrimaryAFPoint; + uchar AFPointsUsed[29]; + ushort AFImageWidth; + ushort AFImageHeight; + ushort AFAreaXPposition; + ushort AFAreaYPosition; + ushort AFAreaWidth; + ushort AFAreaHeight; + uchar ContrastDetectAFInFocus; + /* flash */ + char FlashSetting[13]; + char FlashType[20]; + uchar FlashExposureCompensation[4]; + uchar ExternalFlashExposureComp[4]; + uchar FlashExposureBracketValue[4]; + uchar FlashMode; + signed char FlashExposureCompensation2; + signed char FlashExposureCompensation3; + signed char FlashExposureCompensation4; + uchar FlashSource; + uchar FlashFirmware[2]; + uchar ExternalFlashFlags; + uchar FlashControlCommanderMode; + uchar FlashOutputAndCompensation; + uchar FlashFocalLength; + uchar FlashGNDistance; + uchar FlashGroupControlMode[4]; + uchar FlashGroupOutputAndCompensation[4]; + uchar FlashColorFilter; + ushort NEFCompression; + int ExposureMode; + int ExposureProgram; + int nMEshots; + int MEgainOn; + double ME_WB[4]; + uchar AFFineTune; + uchar AFFineTuneIndex; + int8_t AFFineTuneAdj; + unsigned LensDataVersion; + unsigned FlashInfoVersion; + unsigned ColorBalanceVersion; + uchar key; + ushort NEFBitDepth[4]; + ushort HighSpeedCropFormat; /* 1 -> 1.3x; 2 -> DX; 3 -> 5:4; 4 -> 3:2; 6 -> + 16:9; 11 -> FX uncropped; 12 -> DX uncropped; + 17 -> 1:1 */ + libraw_sensor_highspeed_crop_t SensorHighSpeedCrop; + ushort SensorWidth; + ushort SensorHeight; + } libraw_nikon_makernotes_t; + + typedef struct + { + int SensorCalibration[2]; + ushort FocusMode[2]; + ushort AutoFocus; + ushort AFPoint; + unsigned AFAreas[64]; + double AFPointSelected[5]; + ushort AFResult; + ushort DriveMode[5]; + ushort ColorSpace; + uchar AFFineTune; + short AFFineTuneAdj[3]; + char CameraType2[6]; + } libraw_olympus_makernotes_t; + + typedef struct + { + /* Compression: + 34826 (Panasonic RAW 2): LEICA DIGILUX 2; + 34828 (Panasonic RAW 3): LEICA D-LUX 3; LEICA V-LUX 1; Panasonic DMC-LX1; + Panasonic DMC-LX2; Panasonic DMC-FZ30; Panasonic DMC-FZ50; 34830 (not in + exiftool): LEICA DIGILUX 3; Panasonic DMC-L1; 34316 (Panasonic RAW 1): + others (LEICA, Panasonic, YUNEEC); + */ + ushort Compression; + ushort BlackLevelDim; + float BlackLevel[8]; + unsigned Multishot; /* 0 is Off, 65536 is Pixel Shift */ + float gamma; + int HighISOMultiplier[3]; /* 0->R, 1->G, 2->B */ + } libraw_panasonic_makernotes_t; + + typedef struct + { + ushort FocusMode; + ushort AFPointSelected; + unsigned AFPointsInFocus; + ushort FocusPosition; + uchar DriveMode[4]; + short AFAdjustment; + uchar MultiExposure; /* last bit is not "1" if ME is not used */ + ushort Quality; /* 4 is raw, 7 is raw w/ pixel shift, 8 is raw w/ dynamic + pixel shift */ + /* uchar AFPointMode; */ + /* uchar SRResult; */ + /* uchar ShakeReduction; */ + } libraw_pentax_makernotes_t; + + typedef struct + { + unsigned ImageSizeFull[4]; + unsigned ImageSizeCrop[4]; + int ColorSpace[2]; + unsigned key[11]; + double DigitalGain; /* PostAEGain, digital stretch */ + int DeviceType; + char LensFirmware[32]; + } libraw_samsung_makernotes_t; + + typedef struct + { + ushort BlackLevelTop; + ushort BlackLevelBottom; + short offset_left, offset_top; /* KDC files, negative values or zeros */ + ushort clipBlack, clipWhite; /* valid for P712, P850, P880 */ + float romm_camDaylight[3][3]; + float romm_camTungsten[3][3]; + float romm_camFluorescent[3][3]; + float romm_camFlash[3][3]; + float romm_camCustom[3][3]; + float romm_camAuto[3][3]; + ushort val018percent, val100percent, val170percent; + short MakerNoteKodak8a; + float ISOCalibrationGain; + float AnalogISO; + } libraw_kodak_makernotes_t; + + typedef struct { + char Software[64]; // tag 0x0203 + char SystemType[64]; // tag 0x0204 + char FirmwareString[256]; // tag 0x0301 + char SystemModel[64]; + } libraw_p1_makernotes_t; + + typedef struct + { + ushort CameraType; + uchar Sony0x9400_version; /* 0 if not found/deciphered, 0xa, 0xb, 0xc + following exiftool convention */ + uchar Sony0x9400_ReleaseMode2; + unsigned Sony0x9400_SequenceImageNumber; + uchar Sony0x9400_SequenceLength1; + unsigned Sony0x9400_SequenceFileNumber; + uchar Sony0x9400_SequenceLength2; + uint8_t AFAreaModeSetting; + ushort FlexibleSpotPosition[2]; + uint8_t AFPointSelected; + uint8_t AFPointsUsed[10]; + uint8_t AFTracking; + uint8_t AFType; + ushort FocusLocation[4]; + int8_t AFMicroAdjValue; + int8_t AFMicroAdjOn; + uchar AFMicroAdjRegisteredLenses; + ushort VariableLowPassFilter; + unsigned LongExposureNoiseReduction; + ushort HighISONoiseReduction; + ushort HDR[2]; + ushort group2010; + ushort real_iso_offset; + ushort MeteringMode_offset; + ushort ExposureProgram_offset; + ushort ReleaseMode2_offset; + unsigned MinoltaCamID; + float firmware; + ushort ImageCount3_offset; + unsigned ImageCount3; + unsigned ElectronicFrontCurtainShutter; + ushort MeteringMode2; + char SonyDateTime[20]; + unsigned ShotNumberSincePowerUp; + ushort PixelShiftGroupPrefix; + unsigned PixelShiftGroupID; + char nShotsInPixelShiftGroup; + char numInPixelShiftGroup; /* '0' if ARQ, first shot in the group has '1' + here */ + ushort prd_ImageHeight, prd_ImageWidth; + ushort prd_RawBitDepth; + ushort prd_StorageMethod; /* 82 -> Padded; 89 -> Linear */ + ushort prd_BayerPattern; /* 0 -> not valid; 1 -> RGGB; 4 -> GBRG */ + + ushort SonyRawFileType; /* takes precedence over RAWFileType and Quality: + 0 for uncompressed 14-bit raw + 1 for uncompressed 12-bit raw + 2 for compressed raw + 3 for lossless compressed raw + */ + ushort RAWFileType; /* takes precedence over Quality + 0 for compressed raw, 1 for uncompressed; + */ + unsigned Quality; /* 0 or 6 for raw, 7 or 8 for compressed raw */ + ushort FileFormat; /* 1000 SR2 + 2000 ARW 1.0 + 3000 ARW 2.0 + 3100 ARW 2.1 + 3200 ARW 2.2 + 3300 ARW 2.3 + 3310 ARW 2.3.1 + 3320 ARW 2.3.2 + 3330 ARW 2.3.3 + 3350 ARW 2.3.5 + */ + } libraw_sony_info_t; + + typedef struct + { + ushort curve[0x10000]; + unsigned cblack[LIBRAW_CBLACK_SIZE]; + unsigned black; + unsigned data_maximum; + unsigned maximum; + long linear_max[4]; + float fmaximum; + float fnorm; + ushort white[8][8]; + float cam_mul[4]; + float pre_mul[4]; + float cmatrix[3][4]; + float ccm[3][4]; + float rgb_cam[3][4]; + float cam_xyz[4][3]; + struct ph1_t phase_one_data; + float flash_used; + float canon_ev; + char model2[64]; + char UniqueCameraModel[64]; + char LocalizedCameraModel[64]; + char ImageUniqueID[64]; + char RawDataUniqueID[17]; + char OriginalRawFileName[64]; + void *profile; + unsigned profile_length; + unsigned black_stat[8]; + libraw_dng_color_t dng_color[2]; + libraw_dng_levels_t dng_levels; + int WB_Coeffs[256][4]; /* R, G1, B, G2 coeffs */ + float WBCT_Coeffs[64][5]; /* CCT, than R, G1, B, G2 coeffs */ + int as_shot_wb_applied; + libraw_P1_color_t P1_color[2]; + unsigned raw_bps; /* for Phase One, raw format */ + /* Phase One raw format values, makernotes tag 0x010e: + 0 Name unknown + 1 "RAW 1" + 2 "RAW 2" + 3 "IIQ L" + 4 Never seen + 5 "IIQ S" + 6 "IIQ S v.2" + 7 Never seen + 8 Name unknown + */ + int ExifColorSpace; + } libraw_colordata_t; -typedef struct -{ - ushort raw_height, - raw_width, - height, - width, - top_margin, - left_margin; - ushort iheight, - iwidth; - double pixel_aspect; - int flip; + typedef struct + { + enum LibRaw_thumbnail_formats tformat; + ushort twidth, theight; + unsigned tlength; + int tcolors; + char *thumb; + } libraw_thumbnail_t; + + typedef struct + { + float latitude[3]; /* Deg,min,sec */ + float longitude[3]; /* Deg,min,sec */ + float gpstimestamp[3]; /* Deg,min,sec */ + float altitude; + char altref, latref, longref, gpsstatus; + char gpsparsed; + } libraw_gps_info_t; + + typedef struct + { + float iso_speed; + float shutter; + float aperture; + float focal_len; + time_t timestamp; + unsigned shot_order; + unsigned gpsdata[32]; + libraw_gps_info_t parsed_gps; + char desc[512], artist[64]; + float analogbalance[4]; + } libraw_imgother_t; + + typedef struct { + float FlashEC; + float FlashGN; + float CameraTemperature; + float SensorTemperature; + float SensorTemperature2; + float LensTemperature; + float AmbientTemperature; + float BatteryTemperature; + float exifAmbientTemperature; + float exifHumidity; + float exifPressure; + float exifWaterDepth; + float exifAcceleration; + float exifCameraElevationAngle; + float real_ISO; + float exifExposureIndex; + ushort ColorSpace; + char firmware[128]; + } libraw_metadata_common_t; + + typedef struct + { + unsigned greybox[4]; /* -A x1 y1 x2 y2 */ + unsigned cropbox[4]; /* -B x1 y1 x2 y2 */ + double aber[4]; /* -C */ + double gamm[6]; /* -g */ + float user_mul[4]; /* -r mul0 mul1 mul2 mul3 */ + unsigned shot_select; /* -s */ + float bright; /* -b */ + float threshold; /* -n */ + int half_size; /* -h */ + int four_color_rgb; /* -f */ + int highlight; /* -H */ + int use_auto_wb; /* -a */ + int use_camera_wb; /* -w */ + int use_camera_matrix; /* +M/-M */ + int output_color; /* -o */ + char *output_profile; /* -o */ + char *camera_profile; /* -p */ + char *bad_pixels; /* -P */ + char *dark_frame; /* -K */ + int output_bps; /* -4 */ + int output_tiff; /* -T */ + int user_flip; /* -t */ + int user_qual; /* -q */ + int user_black; /* -k */ + int user_cblack[4]; + int user_sat; /* -S */ + int med_passes; /* -m */ + float auto_bright_thr; + float adjust_maximum_thr; + int no_auto_bright; /* -W */ + int use_fuji_rotate; /* -j */ + int green_matching; + /* DCB parameters */ + int dcb_iterations; + int dcb_enhance_fl; + int fbdd_noiserd; + int exp_correc; + float exp_shift; + float exp_preser; + /* Raw speed */ + int use_rawspeed; + /* DNG SDK */ + int use_dngsdk; + /* Disable Auto-scale */ + int no_auto_scale; + /* Disable intepolation */ + int no_interpolation; + /* int x3f_flags; */ + /* Sony ARW2 digging mode */ + /* int sony_arw2_options; */ + unsigned raw_processing_options; + unsigned max_raw_memory_mb; + int sony_arw2_posterization_thr; + /* Nikon Coolscan */ + float coolscan_nef_gamma; + char p4shot_order[5]; + /* Custom camera list */ + char **custom_camera_strings; + } libraw_output_params_t; + + typedef struct + { + /* really allocated bitmap */ + void *raw_alloc; + /* alias to single_channel variant */ + ushort *raw_image; + /* alias to 4-channel variant */ + ushort (*color4_image)[4]; + /* alias to 3-color variand decoded by RawSpeed */ + ushort (*color3_image)[3]; + /* float bayer */ + float *float_image; + /* float 3-component */ + float (*float3_image)[3]; + /* float 4-component */ + float (*float4_image)[4]; + + /* Phase One black level data; */ + short (*ph1_cblack)[2]; + short (*ph1_rblack)[2]; + /* save color and sizes here, too.... */ + libraw_iparams_t iparams; + libraw_image_sizes_t sizes; + libraw_internal_output_params_t ioparams; + libraw_colordata_t color; + } libraw_rawdata_t; + + typedef struct + { + unsigned long long LensID; + char Lens[128]; + ushort LensFormat; /* to characterize the image circle the lens covers */ + ushort LensMount; /* 'male', lens itself */ + unsigned long long CamID; + ushort CameraFormat; /* some of the sensor formats */ + ushort CameraMount; /* 'female', body throat */ + char body[64]; + short FocalType; /* -1/0 is unknown; 1 is fixed focal; 2 is zoom */ + char LensFeatures_pre[16], LensFeatures_suf[16]; + float MinFocal, MaxFocal; + float MaxAp4MinFocal, MaxAp4MaxFocal, MinAp4MinFocal, MinAp4MaxFocal; + float MaxAp, MinAp; + float CurFocal, CurAp; + float MaxAp4CurFocal, MinAp4CurFocal; + float MinFocusDistance; + float FocusRangeIndex; + float LensFStops; + unsigned long long TeleconverterID; + char Teleconverter[128]; + unsigned long long AdapterID; + char Adapter[128]; + unsigned long long AttachmentID; + char Attachment[128]; + ushort FocalUnits; + float FocalLengthIn35mmFormat; + } libraw_makernotes_lens_t; + + typedef struct + { + float EffectiveMaxAp; + uchar LensIDNumber, LensFStops, MCUVersion, LensType; + } libraw_nikonlens_t; + + typedef struct + { + float MinFocal, MaxFocal, MaxAp4MinFocal, MaxAp4MaxFocal; + } libraw_dnglens_t; + + typedef struct + { + float MinFocal, MaxFocal, MaxAp4MinFocal, MaxAp4MaxFocal, EXIF_MaxAp; + char LensMake[128], Lens[128], LensSerial[128], InternalLensSerial[128]; + ushort FocalLengthIn35mmFormat; + libraw_nikonlens_t nikon; + libraw_dnglens_t dng; + libraw_makernotes_lens_t makernotes; + } libraw_lensinfo_t; + + typedef struct + { + libraw_canon_makernotes_t canon; + libraw_nikon_makernotes_t nikon; + libraw_hasselblad_makernotes_t hasselblad; + libraw_fuji_info_t fuji; + libraw_olympus_makernotes_t olympus; + libraw_sony_info_t sony; + libraw_kodak_makernotes_t kodak; + libraw_panasonic_makernotes_t panasonic; + libraw_pentax_makernotes_t pentax; + libraw_p1_makernotes_t phaseone; + libraw_samsung_makernotes_t samsung; + libraw_metadata_common_t common; + } libraw_makernotes_t; + + typedef struct + { + short DriveMode; + short FocusMode; + short MeteringMode; + short AFPoint; + short ExposureMode; + short ExposureProgram; + short ImageStabilization; + char BodySerial[64]; + char InternalBodySerial[64]; /* this may be PCB or sensor serial, depends on + make/model */ + } libraw_shootinginfo_t; + + typedef struct + { + unsigned fsize; + ushort rw, rh; + uchar lm, tm, rm, bm; + ushort lf; + uchar cf, max, flags; + char t_make[10], t_model[20]; + ushort offset; + } libraw_custom_camera_t; + + typedef struct + { + ushort (*image)[4]; + libraw_image_sizes_t sizes; + libraw_iparams_t idata; + libraw_lensinfo_t lens; + libraw_makernotes_t makernotes; + libraw_shootinginfo_t shootinginfo; + libraw_output_params_t params; + unsigned int progress_flags; + unsigned int process_warnings; + libraw_colordata_t color; + libraw_imgother_t other; + libraw_thumbnail_t thumbnail; + libraw_rawdata_t rawdata; + void *parent_class; + } libraw_data_t; + + struct fuji_compressed_params + { + int8_t *q_table; /* quantization table */ + int q_point[5]; /* quantization points */ + int max_bits; + int min_value; + int raw_bits; + int total_values; + int maxDiff; + ushort line_width; + }; - // masked border sizes - ushort right_margin,bottom_margin; // right masked width and bottom height, inited after idendify() +#ifdef __cplusplus +} +#endif -} libraw_image_sizes_t; +#if defined (LIBRAW_LIBRARY_BUILD) && defined(__cplusplus) -//Phase One data -struct ph1_t +class libraw_static_table_t { - int format, key_off, t_black, black_off, split_col, tag_21a; - float tag_210; +public: + libraw_static_table_t(const int *a, const unsigned s): data(a),_size(s) {} + libraw_static_table_t(): data(0),_size(0){} + libraw_static_table_t(const libraw_static_table_t& s) : data(s.data), _size(s._size) {} + unsigned size() const { return _size; } + libraw_static_table_t& operator = (const libraw_static_table_t& s) + { + _size = s._size; + data = s.data; + return *this; + } + int operator [] (unsigned idx) const + { + if (idx < _size) return data[idx]; + if(_size>0 && data) return data[0]; + return 0; + } +private: + const int *data; + unsigned _size; }; +#endif -typedef struct -{ - // 32 bits total - unsigned curve_state : 3; - unsigned rgb_cam_state : 3; - unsigned cmatrix_state : 3; - unsigned pre_mul_state : 3; - unsigned cam_mul_state : 3; - unsigned filler : 17; -} color_data_state_t; -typedef struct -{ - color_data_state_t color_flags; - ushort white[8][8]; // white block extracted from ciff/CRW - float cam_mul[4]; // camera white balance (from RAW) - float pre_mul[4]; // either set in identify() or calculated. Used on output - float cmatrix[3][4]; // camera color matrix - float rgb_cam[3][4]; // another way to set color matrix - float cam_xyz[4][3]; // Camera to XYZ matrix (DNG coeffs) - ushort curve[0x4001]; // camera tone curve/ljpeg curve - unsigned black; - unsigned maximum; - struct ph1_t phase_one_data; - float flash_used; // canon/CRW only - float canon_ev; // canon/CRW only - char model2[64]; - // profile - void *profile; - unsigned profile_length; -}libraw_colordata_t; +/* Byte order */ +#if defined(__POWERPC__) +#define LibRawBigEndian 1 -typedef struct -{ - enum LibRaw_thumbnail_formats tformat; - ushort twidth, - theight; - unsigned tlength; - int tcolors; - - // thumbnail buffer - char *thumb; -}libraw_thumbnail_t; +#elif defined(__INTEL__) +#define LibRawBigEndian 0 -// Decoded from exif/raw, but not used in real calculations -typedef struct -{ - float iso_speed; - float shutter; - float aperture; - float focal_len; - time_t timestamp; - unsigned shot_order; - unsigned gpsdata[32]; - // string variables - char desc[512], - artist[64]; -} libraw_imgother_t; +#elif defined(_M_IX86) || defined(__i386__) +#define LibRawBigEndian 0 -typedef struct -{ - unsigned greybox[4]; /* -A x1 y1 x2 y2 */ - double aber[4]; /* -C */ - double gamm[5]; /* -g */ - float user_mul[4]; /* -r mul0 mul1 mul2 mul3 */ - unsigned shot_select; /* -s */ - float bright; /* -b */ - float threshold; /* -n */ - int half_size; /* -h */ - int four_color_rgb; /* -f */ - int document_mode; /* -d/-D */ - int highlight; /* -H */ -// int verbose; /* -v */ - int use_auto_wb; /* -a */ - int use_camera_wb; /* -w */ - int use_camera_matrix; /* +M/-M */ - int output_color; /* -o */ - char *output_profile; /* -o */ - char *camera_profile; /* -p */ - char *bad_pixels; /* -P */ - char *dark_frame; /* -K */ - int output_bps; /* -4 */ - int gamma_16bit; /* -1 */ - int output_tiff; /* -T */ - int user_flip; /* -t */ - int user_qual; /* -q */ - int user_black; /* -k */ - int user_sat; /* -S */ - - int med_passes; /* -m */ - float auto_bright_thr; - int no_auto_bright; /* -W */ - int use_fuji_rotate;/* -j */ - enum LibRaw_filtering filtering_mode; -}libraw_output_params_t; +#elif defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) +#define LibRawBigEndian 0 -typedef struct -{ - ushort *buffer; // actual pixel buffer size=(raw_width*raw_height - width*height) - ushort *tl; // top left size=(top_margin*left_margin) - ushort *top; // top size=(top_margin*width) - ushort *tr; // top right size=((raw_width-width-left_margin)*top_margin) - ushort *left; // left size=(left_margin*height) - ushort *right; // right size=(raw_width-width-left_margin)*height; - ushort *bl; // bottom left size=(raw_height-height-top_margin)*left_margin - ushort *bottom; // bottom size=(raw_height-height-top_margin)*width - ushort *br; // bottom right size=(raw_height-height-top_margin)* - ushort (*ph1_black)[2]; // Phase One black -}libraw_masked_t; +#elif defined(__LITTLE_ENDIAN__) +#define LibRawBigEndian 0 -typedef struct -{ - unsigned int progress_flags; - unsigned int process_warnings; - libraw_iparams_t idata; - libraw_image_sizes_t sizes; - libraw_colordata_t color; - libraw_imgother_t other; - libraw_thumbnail_t thumbnail; - libraw_masked_t masked_pixels; - ushort (*image)[4] ; - libraw_output_params_t params; - // pointer to LibRaw class for use in C calls - void *parent_class; -} libraw_data_t; +#elif defined(__BIG_ENDIAN__) +#define LibRawBigEndian 1 +#elif defined(_ARM_) +#define LibRawBigEndian 0 +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define LibRawBigEndian 0 -#ifdef __cplusplus -} +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define LibRawBigEndian 1 +#else +#ifndef qXCodeRez +#error Unable to figure out byte order. +#endif #endif #endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_version.h libkdcraw/libkdcraw/libraw/libraw/libraw_version.h --- libkdcraw-wrk/libkdcraw/libraw/libraw/libraw_version.h 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/libraw/libraw_version.h 2022-11-07 07:46:31.730795008 +0300 @@ -1,47 +1,63 @@ -/* +/* -*- C++ -*- * File: libraw_version.h - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> - * Created: Mon Sept 8, 2008 + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Mon Sept 8, 2008 * * LibRaw C++ interface * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 +(See the file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 +(See the file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #ifndef __VERSION_H #define __VERSION_H -#define LIBRAW_MAJOR_VERSION 0 -#define LIBRAW_MINOR_VERSION 7 -#define LIBRAW_PATCH_VERSION 2 -#define LIBRAW_VERSION_TAIL Release +#define LIBRAW_MAJOR_VERSION 0 +#define LIBRAW_MINOR_VERSION 20 +#define LIBRAW_PATCH_VERSION 2 +#define LIBRAW_VERSION_TAIL Release + +#define LIBRAW_SHLIB_CURRENT 20 +#define LIBRAW_SHLIB_REVISION 0 +#define LIBRAW_SHLIB_AGE 0 + +#define _LIBRAW_VERSION_MAKE(a, b, c, d) #a "." #b "." #c "-" #d +#define LIBRAW_VERSION_MAKE(a, b, c, d) _LIBRAW_VERSION_MAKE(a, b, c, d) + +#define LIBRAW_VERSION_STR \ + LIBRAW_VERSION_MAKE(LIBRAW_MAJOR_VERSION, LIBRAW_MINOR_VERSION, \ + LIBRAW_PATCH_VERSION, LIBRAW_VERSION_TAIL) + +#define LIBRAW_MAKE_VERSION(major, minor, patch) \ + (((major) << 16) | ((minor) << 8) | (patch)) -#define _LIBRAW_VERSION_MAKE(a,b,c,d) #a"."#b"."#c"-"#d -#define LIBRAW_VERSION_MAKE(a,b,c,d) _LIBRAW_VERSION_MAKE(a,b,c,d) +#define LIBRAW_VERSION \ + LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION, LIBRAW_MINOR_VERSION, \ + LIBRAW_PATCH_VERSION) -#define LIBRAW_VERSION_STR LIBRAW_VERSION_MAKE(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,LIBRAW_PATCH_VERSION,LIBRAW_VERSION_TAIL) +#define LIBRAW_CHECK_VERSION(major, minor, patch) \ + (LibRaw::versionNumber() >= LIBRAW_MAKE_VERSION(major, minor, patch)) -#define LIBRAW_MAKE_VERSION(major,minor,patch) \ - (((major) << 16) | ((minor) << 8) | (patch)) +#define LIBRAW_RUNTIME_CHECK_VERSION_EXACT() \ + ((LibRaw::versionNumber() & 0xffff00) == \ + LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION, LIBRAW_MINOR_VERSION, 0)) -#define LIBRAW_VERSION \ - LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,LIBRAW_PATCH_VERSION) +#define LIBRAW_RUNTIME_CHECK_VERSION_NOTLESS() \ + ((LibRaw::versionNumber() & 0xffff00) >= \ + LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION, LIBRAW_MINOR_VERSION, 0)) -#define LIBRAW_CHECK_VERSION(major,minor,patch) \ - ( LibRaw::versionNumber() >= LIBRAW_MAKE_VERSION(major,minor,patch) ) +#define LIBRAW_COMPILE_CHECK_VERSION(major, minor) \ + (LIBRAW_MAKE_VERSION(major, minor, 0) == (LIBRAW_VERSION & 0xffff00)) +#define LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(major, minor) \ + (LIBRAW_MAKE_VERSION(major, minor, 0) <= (LIBRAW_VERSION & 0xffff00)) #endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/4channels.cpp libkdcraw/libkdcraw/libraw/samples/4channels.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/4channels.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/4channels.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -1,65 +1,59 @@ -/* +/* -*- C++ -*- * File: 4channels.cpp - * Copyright 2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Mon Feb 09, 2009 * * LibRaw sample * Generates 4 TIFF file from RAW data, one file per channel * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ #include <stdio.h> #include <string.h> #include <math.h> -#ifndef WIN32 +#include "libraw/libraw.h" + +#ifndef LIBRAW_WIN32_CALLS #include <netinet/in.h> #else #include <winsock2.h> #endif -#include "libraw/libraw.h" - -#ifdef WIN32 +#ifdef LIBRAW_WIN32_CALLS #define snprintf _snprintf #endif int main(int ac, char *av[]) { - int i, ret; - int autoscale=0,filtering_mode=LIBRAW_FILTERING_DEFAULT,black_subtraction=1; - char outfn[1024],thumbfn[1024]; - - LibRaw RawProcessor; - if(ac<2) - { - usage: - printf( - "4channeld - LibRaw %s sample. %d cameras supported\n" - "Usage: %s [-s N] [-g] [-A] [-B] [-N] raw-files....\n" - "\t-s N - select Nth image in file (default=0)\n" - "\t-g - use gamma correction with gamma 2.2 (not precise,use for visual inspection only)\n" - "\t-A - autoscaling (by integer factor)\n" - "\t-B - no black subtraction\n" - "\t-N - no raw curve\n" - ,LibRaw::version(), - LibRaw::cameraCount(), - av[0]); - return 0; - } - + int i, ret; + int autoscale = 0, black_subtraction = 1, use_gamma = 0; + char outfn[1024]; + + LibRaw RawProcessor; + if (ac < 2) + { + usage: + printf("4channels - LibRaw %s sample. %d cameras supported\n" + "Usage: %s [-s N] [-g] [-A] [-B] [-N] raw-files....\n" + "\t-s N - select Nth image in file (default=0)\n" + "\t-g - use gamma correction with gamma 2.2 (not precise,use for " + "visual inspection only)\n" + "\t-A - autoscaling (by integer factor)\n" + "\t-B - no black subtraction\n", + LibRaw::version(), LibRaw::cameraCount(), av[0]); + return 0; + } + #define P1 RawProcessor.imgdata.idata #define S RawProcessor.imgdata.sizes #define C RawProcessor.imgdata.color @@ -67,121 +61,113 @@ #define P2 RawProcessor.imgdata.other #define OUT RawProcessor.imgdata.params - OUT.document_mode=2; - OUT.output_bps=16; - OUT.output_tiff=1; - OUT.user_flip=0; - OUT.no_auto_bright = 1; - OUT.half_size=1; - OUT.filtering_mode= LIBRAW_FILTERING_AUTOMATIC; - - for (i=1;i<ac;i++) - { - if(av[i][0]=='-') - { - if(av[i][1]=='s' && av[i][2]==0) - { - i++; - OUT.shot_select=atoi(av[i]); - } - else if(av[i][1]=='g' && av[i][2]==0) - OUT.gamma_16bit=1; - else if(av[i][1]=='A' && av[i][2]==0) - autoscale=1; - else if(av[i][1]=='B' && av[i][2]==0) - { - filtering_mode |= (LIBRAW_FILTERING_NOZEROES | LIBRAW_FILTERING_NOBLACKS); - black_subtraction=0; - } - else if(av[i][1]=='N' && av[i][2]==0) - filtering_mode |= LIBRAW_FILTERING_NORAWCURVE; - else - goto usage; - continue; - } - if(filtering_mode) - OUT.filtering_mode = (LibRaw_filtering) filtering_mode; - int r,c; - printf("Processing file %s\n",av[i]); - if( (ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot open %s: %s\n",av[i],libraw_strerror(ret)); - continue; // no recycle b/c open file will recycle itself - } - if(P1.is_foveon) - { - printf("Cannot process foveon image %s\n",av[i]); - continue ; - } - if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret)); - continue; - } - if(black_subtraction && C.black>0) - { - for(int j=0; j<S.iheight*S.iwidth; j++) - for(int c = 0; c< 4; c++) - if(RawProcessor.imgdata.image[j][c]>C.black) - RawProcessor.imgdata.image[j][c]-=C.black; - else - RawProcessor.imgdata.image[j][c]=0; - } - - if(autoscale) - { - unsigned max=0,scale; - for(int j=0; j<S.iheight*S.iwidth; j++) - for(int c = 0; c< 4; c++) - if(max < RawProcessor.imgdata.image[j][c]) - max = RawProcessor.imgdata.image[j][c]; - if (max >0 && max< 1<<15) - { - scale = (1<<16)/max; - printf("Scaling with multiplier=%d (max=%d)\n",scale,max); - for(int j=0; j<S.iheight*S.iwidth; j++) - for(c=0;c<4;c++) - RawProcessor.imgdata.image[j][c] *= scale; - } - printf("Black level (scaled)=%d\n",C.black*scale); - } - else - printf("Black level (unscaled)=%d\n",C.black); - - - // hack to make dcraw tiff writer happy - int isrgb=(P1.colors==4?0:1); - P1.colors = 1; - S.width = S.iwidth; - S.height = S.iheight; - - for (int layer=0;layer<4;layer++) - { - if(layer>0) - { - for (int rc = 0; rc < S.iheight*S.iwidth; rc++) - RawProcessor.imgdata.image[rc][0] = RawProcessor.imgdata.image[rc][layer]; - } - char lname[8]; - if(isrgb) - { - snprintf(lname,7,"%c",(char*)("RGBG")[layer]); - if(layer==3) - strcat(lname,"2"); - } - else - snprintf(lname,7,"%c",(char*)("GCMY")[layer]); - - if(OUT.shot_select) - snprintf(outfn,sizeof(outfn),"%s-%d.%s.tiff",av[i],OUT.shot_select,lname); - else - snprintf(outfn,sizeof(outfn),"%s.%s.tiff",av[i],lname); - - printf("Writing file %s\n",outfn); - if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) - fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); - } - - } - return 0; + OUT.output_bps = 16; + OUT.output_tiff = 1; + OUT.user_flip = 0; + OUT.no_auto_bright = 1; + OUT.half_size = 1; + + for (i = 1; i < ac; i++) + { + if (av[i][0] == '-') + { + if (av[i][1] == 's' && av[i][2] == 0) + { + i++; + OUT.shot_select = av[i] ? atoi(av[i]) : 0; + } + else if (av[i][1] == 'g' && av[i][2] == 0) + use_gamma = 1; + else if (av[i][1] == 'A' && av[i][2] == 0) + autoscale = 1; + else if (av[i][1] == 'B' && av[i][2] == 0) + { + black_subtraction = 0; + } + else + goto usage; + continue; + } + if (!use_gamma) + OUT.gamm[0] = OUT.gamm[1] = 1; + + int c; + printf("Processing file %s\n", av[i]); + if ((ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot open %s: %s\n", av[i], libraw_strerror(ret)); + continue; // no recycle b/c open file will recycle itself + } + if (P1.is_foveon) + { + printf("Cannot process Foveon image %s\n", av[i]); + continue; + } + if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret)); + continue; + } + RawProcessor.raw2image(); + if (black_subtraction) + { + RawProcessor.subtract_black(); + } + + if (autoscale) + { + unsigned max = 0, scale = 1; + for (int j = 0; j < S.iheight * S.iwidth; j++) + for (int c = 0; c < 4; c++) + if (max < RawProcessor.imgdata.image[j][c]) + max = RawProcessor.imgdata.image[j][c]; + if (max > 0 && max < 1 << 15) + { + scale = (1 << 16) / max; + printf("Scaling with multiplier=%d (max=%d)\n", scale, max); + for (int j = 0; j < S.iheight * S.iwidth; j++) + for (c = 0; c < 4; c++) + RawProcessor.imgdata.image[j][c] *= scale; + } + printf("Black level (scaled)=%d\n", C.black * scale); + } + else + printf("Black level (unscaled)=%d\n", C.black); + + // hack to make dcraw tiff writer happy + int isrgb = (P1.colors == 4 ? 0 : 1); + P1.colors = 1; + S.width = S.iwidth; + S.height = S.iheight; + + for (int layer = 0; layer < 4; layer++) + { + if (layer > 0) + { + for (int rc = 0; rc < S.iheight * S.iwidth; rc++) + RawProcessor.imgdata.image[rc][0] = + RawProcessor.imgdata.image[rc][layer]; + } + char lname[8]; + if (isrgb) + { + snprintf(lname, 7, "%c", ((char *)("RGBG"))[layer]); + if (layer == 3) + strcat(lname, "2"); + } + else + snprintf(lname, 7, "%c", ((char *)("GCMY"))[layer]); + + if (OUT.shot_select) + snprintf(outfn, sizeof(outfn), "%s-%d.%s.tiff", av[i], OUT.shot_select, + lname); + else + snprintf(outfn, sizeof(outfn), "%s.%s.tiff", av[i], lname); + + printf("Writing file %s\n", outfn); + if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) + fprintf(stderr, "Cannot write %s: %s\n", outfn, libraw_strerror(ret)); + } + } + return 0; } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/Makefile libkdcraw/libkdcraw/libraw/samples/Makefile --- libkdcraw-wrk/libkdcraw/libraw/samples/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/samples/Makefile 2022-11-07 07:46:31.642795007 +0300 @@ -0,0 +1,2 @@ +all: + (cd ..; make all_samples) diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/README-samples.rus libkdcraw/libkdcraw/libraw/samples/README-samples.rus --- libkdcraw-wrk/libkdcraw/libraw/samples/README-samples.rus 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/samples/README-samples.rus 2022-11-07 07:46:31.642795007 +0300 @@ -0,0 +1,2 @@ + +See ../doc/Samples-LibRaw-rus.html and ../doc/Samples-LibRaw-eng.html diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/dcraw_emu.cpp libkdcraw/libkdcraw/libraw/samples/dcraw_emu.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/dcraw_emu.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/dcraw_emu.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -1,27 +1,25 @@ -/* +/* -*- C++ -*- * File: dcraw_emu.cpp - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sun Mar 23, 2008 * - * LibRaw simple C++ API (almost complete dcraw emulator) + * LibRaw simple C++ API sample: almost complete dcraw emulator * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ -#ifdef HAVE_CONFIG_H -#include "config.h" +#ifdef _MSC_VER +// suppress sprintf-related warning. sprintf() is permitted in sample code +#define _CRT_SECURE_NO_WARNINGS #endif #include <stdio.h> @@ -29,260 +27,627 @@ #include <stdlib.h> #include <math.h> #include <ctype.h> -#ifndef WIN32 -#include <fcntl.h> -#include <unistd.h> -#include <sys/stat.h> + +#include "libraw/libraw.h" + +#ifndef LIBRAW_WIN32_CALLS #include <sys/mman.h> +#include <sys/time.h> +#include <unistd.h> +#else +#include <io.h> #endif +#include <fcntl.h> +#include <sys/stat.h> -#include "libraw/libraw.h" -#ifdef WIN32 +#ifdef LIBRAW_WIN32_CALLS #define snprintf _snprintf +#include <windows.h> +#else +#define O_BINARY 0 #endif -#ifdef _OPENMP -#include <omp.h> +#ifdef USE_DNGSDK +#include "dng_host.h" +#include "dng_negative.h" +#include "dng_simple_image.h" +#include "dng_info.h" #endif void usage(const char *prog) { - printf("dcraw_emu: almost complete dcraw emulator\n"); - printf("Usage: %s [OPTION]... [FILE]...\n", prog); - printf( -"-v Verbose: print progress messages (repeated -v will add verbosity)\n" -"-w Use camera white balance, if possible\n" -"-a Average the whole image for white balance\n" -"-A <x y w h> Average a grey box for white balance\n" -"-r <r g b g> Set custom white balance\n" -"+M/-M Use/don't use an embedded color matrix\n" -"-C <r b> Correct chromatic aberration\n" -"-P <file> Fix the dead pixels listed in this file\n" -"-K <file> Subtract dark frame (16-bit raw PGM)\n" -"-k <num> Set the darkness level\n" -"-S <num> Set the saturation level\n" -"-n <num> Set threshold for wavelet denoising\n" -"-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)\n" -"-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)\n" -"-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)\n" + printf("dcraw_emu: almost complete dcraw emulator\n"); + printf("Usage: %s [OPTION]... [FILE]...\n", prog); + printf("-c float-num Set adjust maximum threshold (default 0.75)\n" + "-v Verbose: print progress messages (repeated -v will add " + "verbosity)\n" + "-w Use camera white balance, if possible\n" + "-a Average the whole image for white balance\n" + "-A <x y w h> Average a grey box for white balance\n" + "-r <r g b g> Set custom white balance\n" + "+M/-M Use/don't use an embedded color matrix\n" + "-C <r b> Correct chromatic aberration\n" + "-P <file> Fix the dead pixels listed in this file\n" + "-K <file> Subtract dark frame (16-bit raw PGM)\n" + "-k <num> Set the darkness level\n" + "-S <num> Set the saturation level\n" + "-R <num> Set raw processing options to num\n" + "-n <num> Set threshold for wavelet denoising\n" + "-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)\n" + "-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)\n" + "-o [0-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)\n" #ifndef NO_LCMS -"-o file Output ICC profile\n" -"-p file Camera input profile (use \'embed\' for embedded profile)\n" + "-o file Output ICC profile\n" + "-p file Camera input profile (use \'embed\' for embedded profile)\n" #endif -"-j Don't stretch or rotate raw pixels\n" -"-W Don't automatically brighten the image\n" -"-b <num> Adjust brightness (default = 1.0)\n" -"-q [0-3] Set the interpolation quality\n" -"-h Half-size color image (twice as fast as \"-q 0\")\n" -"-f Interpolate RGGB as four colors\n" -"-m <num> Apply a 3x3 median filter to R-G and B-G\n" -"-s [0..N-1] Select one raw image from input file\n" -"-4 Write 16-bit linear instead of 8-bit with gamma\n" -"-g pow ts Set gamma curve to gamma pow and toe slope ts (default = 2.222 4.5)\n" -"-T Write TIFF instead of PPM\n" -#ifndef WIN32 -"-B Use mmap()-ed buffer instead of plain FILE I/O\n" + "-j Don't stretch or rotate raw pixels\n" + "-W Don't automatically brighten the image\n" + "-b <num> Adjust brightness (default = 1.0)\n" + "-q N Set the interpolation quality:\n" + " 0 - linear, 1 - VNG, 2 - PPG, 3 - AHD, 4 - DCB\n" + " 11 - DHT, 12 - AAHD\n" + "-h Half-size color image (twice as fast as \"-q 0\")\n" + "-f Interpolate RGGB as four colors\n" + "-m <num> Apply a 3x3 median filter to R-G and B-G\n" + "-s [0..N-1] Select one raw image from input file\n" + "-4 Linear 16-bit, same as \"-6 -W -g 1 1\n" + "-6 Write 16-bit output\n" + "-g pow ts Set gamma curve to gamma pow and toe slope ts (default = " + "2.222 4.5)\n" + "-T Write TIFF instead of PPM\n" + "-G Use green_matching() filter\n" + "-B <x y w h> use cropbox\n" + "-F Use FILE I/O instead of streambuf API\n" + "-Z <suf> Output filename generation rules\n" + " .suf => append .suf to input name, keeping existing suffix " + "too\n" + " suf => replace input filename last extension\n" + " - => output to stdout\n" + " filename.suf => output to filename.suf\n" + "-timing Detailed timing report\n" + "-fbdd N 0 - disable FBDD noise reduction (default), 1 - light " + "FBDD, 2 - full\n" + "-dcbi N Number of extra DCD iterations (default - 0)\n" + "-dcbe DCB color enhance\n" + "-aexpo <e p> exposure correction\n" + "-apentax4shot enables merge of 4-shot pentax files\n" + "-apentax4shotorder 3102 sets pentax 4-shot alignment order\n" + "-mmap Use memory mmaped buffer instead of plain FILE I/O\n" + "-mem Use memory buffer instead of FILE I/O\n" + "-disars Do not use RawSpeed library\n" + "-disinterp Do not run interpolation step\n" + "-dsrawrgb1 Disable YCbCr to RGB conversion for sRAW (Cb/Cr " + "interpolation enabled)\n" + "-dsrawrgb2 Disable YCbCr to RGB conversion for sRAW (Cb/Cr " + "interpolation disabled)\n" +#ifdef USE_DNGSDK + "-dngsdk Use Adobe DNG SDK for DNG decode\n" + "-dngflags N set DNG decoding options to value N\n" #endif - ); - exit(1); + ); + exit(1); } -static int verbosity=0; +static int verbosity = 0; +int cnt = 0; +int my_progress_callback(void *d, enum LibRaw_progress p, int iteration, + int expected) +{ + char *passed = (char *)(d ? d : "default string"); // data passed to callback + // at set_callback stage + + if (verbosity > 2) // verbosity set by repeat -v switches + { + printf("CB: %s pass %d of %d (data passed=%s)\n", libraw_strprogress(p), + iteration, expected, passed); + } + else if (iteration == 0) // 1st iteration of each step + printf("Starting %s (expecting %d iterations)\n", libraw_strprogress(p), + expected); + else if (iteration == expected - 1) + printf("%s finished\n", libraw_strprogress(p)); -int cnt=0; -int my_progress_callback(void *d,enum LibRaw_progress p,int iteration, int expected) + /// if(++cnt>10) return 1; // emulate user termination on 10-th callback + /// call + + return 0; // always return 0 to continue processing +} + +// timer +#ifndef LIBRAW_WIN32_CALLS +static struct timeval start, end; +void timerstart(void) { gettimeofday(&start, NULL); } +void timerprint(const char *msg, const char *filename) +{ + gettimeofday(&end, NULL); + float msec = (end.tv_sec - start.tv_sec) * 1000.0f + + (end.tv_usec - start.tv_usec) / 1000.0f; + printf("Timing: %s/%s: %6.3f msec\n", filename, msg, msec); +} +#else +LARGE_INTEGER start; +void timerstart(void) { QueryPerformanceCounter(&start); } +void timerprint(const char *msg, const char *filename) { - char *passed = (char*)(d?d:"default string"); // data passed to callback at set_callback stage + LARGE_INTEGER unit, end; + QueryPerformanceCounter(&end); + QueryPerformanceFrequency(&unit); + float msec = (float)(end.QuadPart - start.QuadPart); + msec /= (float)unit.QuadPart / 1000.0f; + printf("Timing: %s/%s: %6.3f msec\n", filename, msg, msec); +} - if(verbosity>2) // verbosity set by repeat -v switches - { - printf("CB: %s pass %d of %d (data passed=%s)\n",libraw_strprogress(p),iteration,expected,passed); - } - else if (iteration == 0) // 1st iteration of each step - printf("Starting %s (expecting %d iterations)\n", libraw_strprogress(p),expected); - else if (iteration == expected-1) - printf("%s finished\n",libraw_strprogress(p)); +#endif + +struct file_mapping +{ + void *map; + INT64 fsize; +#ifdef LIBRAW_WIN32_CALLS + HANDLE fd, fd_map; + file_mapping() : map(0), fsize(0), fd(INVALID_HANDLE_VALUE), fd_map(INVALID_HANDLE_VALUE){} +#else + int fd; + file_mapping() : map(0), fsize(0), fd(-1){} +#endif +}; -/// if(++cnt>10) return 1; // emulate user termination on 10-th callback call +void create_mapping(struct file_mapping& data, const std::string& fn) +{ +#ifdef LIBRAW_WIN32_CALLS + std::wstring fpath(fn.begin(), fn.end()); + if ((data.fd = CreateFileW(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) return; + LARGE_INTEGER fs; + if (!GetFileSizeEx(data.fd, &fs)) return; + data.fsize = fs.QuadPart; + if ((data.fd_map = ::CreateFileMapping(data.fd, 0, PAGE_READONLY, fs.HighPart, fs.LowPart, 0)) == INVALID_HANDLE_VALUE) return; + data.map = MapViewOfFile(data.fd_map, FILE_MAP_READ, 0, 0, data.fsize); +#else + struct stat stt; + if ((data.fd = open(fn.c_str(), O_RDONLY)) < 0) return; + if (fstat(data.fd, &stt) != 0) return; + data.fsize = stt.st_size; + data.map = mmap(0, data.fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, data.fd, 0); + return; +#endif +} - return 0; // always return 0 to continue processing +void close_mapping(struct file_mapping& data) +{ +#ifdef LIBRAW_WIN32_CALLS + if (data.map) UnmapViewOfFile(data.map); + if (data.fd_map != INVALID_HANDLE_VALUE) CloseHandle(data.fd_map); + if (data.fd != INVALID_HANDLE_VALUE) CloseHandle(data.fd); + data.map = 0; + data.fsize = 0; + data.fd = data.fd_map = INVALID_HANDLE_VALUE; +#else + if (data.map) + munmap(data.map, data.fsize); + if (data.fd >= 0) + close(data.fd); + data.map = 0; + data.fsize = 0; + data.fd = -1; +#endif } int main(int argc, char *argv[]) { - if(argc==1) usage(argv[0]); - - LibRaw RawProcessor; - int i,arg,c,ret; - char opm,opt,*cp,*sp; - int use_mmap=0, msize; - void *iobuffer; + if (argc == 1) + usage(argv[0]); + LibRaw RawProcessor; + int i, arg, c, ret; + char opm, opt, *cp, *sp; + int use_bigfile = 0, use_timing = 0, use_mem = 0, use_mmap = 0; + char *outext = NULL; +#ifdef USE_DNGSDK + dng_host *dnghost = NULL; +#endif + struct file_mapping mapping; + void *iobuffer = 0; +#ifdef OUT +#undef OUT +#endif #define OUT RawProcessor.imgdata.params - - argv[argc] = ""; - for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) - { - opt = argv[arg++][1]; - if ((cp = strchr (sp="nbrkStqmHACgU", opt))) - for (i=0; i < "11411111142"[cp-sp]-'0'; i++) - if (!isdigit(argv[arg+i][0])) - { - fprintf (stderr,"Non-numeric argument to \"-%c\"\n", opt); - return 1; - } - switch (opt) - { - case 'v': verbosity++; break; - - case 'U': OUT.auto_bright_thr = atof(argv[arg++]); break; - case 'n': OUT.threshold = atof(argv[arg++]); break; - case 'b': OUT.bright = atof(argv[arg++]); break; - case 'P': OUT.bad_pixels = argv[arg++]; break; - case 'K': OUT.dark_frame = argv[arg++]; break; - case 'r': - for(c=0;c<4;c++) - OUT.user_mul[c] = atof(argv[arg++]); - break; - case 'C': - OUT.aber[0] = 1 / atof(argv[arg++]); - OUT.aber[2] = 1 / atof(argv[arg++]); - break; - case 'g': - OUT.gamm[0] = 1 / atof(argv[arg++]); - OUT.gamm[1] = atof(argv[arg++]); - break; - case 'k': OUT.user_black = atoi(argv[arg++]); break; - case 'S': OUT.user_sat = atoi(argv[arg++]); break; - case 't': OUT.user_flip = atoi(argv[arg++]); break; - case 'q': OUT.user_qual = atoi(argv[arg++]); break; - case 'm': OUT.med_passes = atoi(argv[arg++]); break; - case 'H': OUT.highlight = atoi(argv[arg++]); break; - case 's': OUT.shot_select = abs(atoi(argv[arg++])); break; - case 'o': - if(isdigit(argv[arg+1][0]) && !isdigit(argv[arg+1][1])) - OUT.output_color = atoi(argv[arg++]); + + argv[argc] = (char *)""; + for (arg = 1; (((opm = argv[arg][0]) - 2) | 2) == '+';) + { + char *optstr = argv[arg]; + opt = argv[arg++][1]; + if ((cp = strchr(sp = (char *)"cnbrkStqmHABCgU", opt)) != 0) + for (i = 0; i < "111411111144221"[cp - sp] - '0'; i++) + if (!isdigit(argv[arg + i][0]) && !optstr[2]) + { + fprintf(stderr, "Non-numeric argument to \"-%c\"\n", opt); + return 1; + } + if (!strchr("ftdeam", opt) && argv[arg - 1][2]) + fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]); + switch (opt) + { + case 'v': + verbosity++; + break; + case 'G': + OUT.green_matching = 1; + break; + case 'c': + OUT.adjust_maximum_thr = (float)atof(argv[arg++]); + break; + case 'U': + OUT.auto_bright_thr = (float)atof(argv[arg++]); + break; + case 'n': + OUT.threshold = (float)atof(argv[arg++]); + break; + case 'b': + OUT.bright = (float)atof(argv[arg++]); + break; + case 'P': + OUT.bad_pixels = argv[arg++]; + break; + case 'K': + OUT.dark_frame = argv[arg++]; + break; + case 'r': + for (c = 0; c < 4; c++) + OUT.user_mul[c] = (float)atof(argv[arg++]); + break; + case 'C': + OUT.aber[0] = 1 / atof(argv[arg++]); + OUT.aber[2] = 1 / atof(argv[arg++]); + break; + case 'g': + OUT.gamm[0] = 1 / atof(argv[arg++]); + OUT.gamm[1] = atof(argv[arg++]); + break; + case 'k': + OUT.user_black = atoi(argv[arg++]); + break; + case 'S': + OUT.user_sat = atoi(argv[arg++]); + break; + case 'R': + OUT.raw_processing_options = atoi(argv[arg++]); + break; + case 't': + if (!strcmp(optstr, "-timing")) + use_timing = 1; + else if (!argv[arg - 1][2]) + OUT.user_flip = atoi(argv[arg++]); + else + fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]); + break; + case 'q': + OUT.user_qual = atoi(argv[arg++]); + break; + case 'm': + if (!strcmp(optstr, "-mmap")) + use_mmap = 1; + else + if (!strcmp(optstr, "-mem")) + use_mem = 1; + else + { + if (!argv[arg - 1][2]) + OUT.med_passes = atoi(argv[arg++]); + else + fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]); + } + break; + case 'H': + OUT.highlight = atoi(argv[arg++]); + break; + case 's': + OUT.shot_select = abs(atoi(argv[arg++])); + break; + case 'o': + if (isdigit(argv[arg][0]) && !isdigit(argv[arg][1])) + OUT.output_color = atoi(argv[arg++]); #ifndef NO_LCMS - else - OUT.output_profile = argv[arg++]; - break; - case 'p': OUT.camera_profile = argv[arg++]; -#endif - break; - case 'h': OUT.half_size = 1; - // no break: "-h" implies "-f" - case 'f': - OUT.four_color_rgb = 1; - break; - case 'A': for(c=0; c<4;c++) OUT.greybox[c] = atoi(argv[arg++]); - case 'a': OUT.use_auto_wb = 1; break; - case 'w': OUT.use_camera_wb = 1; break; - case 'M': OUT.use_camera_matrix = (opm == '+'); break; - case 'j': OUT.use_fuji_rotate = 0; break; - case 'W': OUT.no_auto_bright = 1; break; - case 'T': OUT.output_tiff = 1; break; - case '4': OUT.output_bps = 16; break; - case '1': OUT.gamma_16bit = 1; break; -#ifndef WIN32 - case 'B': use_mmap = 1; break; -#endif - default: - fprintf (stderr,"Unknown option \"-%c\".\n", opt); - return 1; - } + else + OUT.output_profile = argv[arg++]; + break; + case 'p': + OUT.camera_profile = argv[arg++]; +#endif + break; + case 'h': + OUT.half_size = 1; + break; + case 'f': + if (!strcmp(optstr, "-fbdd")) + OUT.fbdd_noiserd = atoi(argv[arg++]); + else + { + if (!argv[arg - 1][2]) + OUT.four_color_rgb = 1; + else + fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]); + } + break; + case 'A': + for (c = 0; c < 4; c++) + OUT.greybox[c] = atoi(argv[arg++]); + break; + case 'B': + for (c = 0; c < 4; c++) + OUT.cropbox[c] = atoi(argv[arg++]); + break; + case 'a': + if (!strcmp(optstr, "-aexpo")) + { + OUT.exp_correc = 1; + OUT.exp_shift = (float)atof(argv[arg++]); + OUT.exp_preser = (float)atof(argv[arg++]); + } + else if (!strcmp(optstr, "-apentax4shot")) + { + OUT.raw_processing_options |= LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES; + } + else if (!strcmp(optstr, "-apentax4shotorder")) + { + strncpy(OUT.p4shot_order, argv[arg++], 5); + } + else if (!argv[arg - 1][2]) + OUT.use_auto_wb = 1; + else + fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]); + break; + case 'w': + OUT.use_camera_wb = 1; + break; + case 'M': + OUT.use_camera_matrix = (opm == '+')?3:0; + break; + case 'j': + OUT.use_fuji_rotate = 0; + break; + case 'W': + OUT.no_auto_bright = 1; + break; + case 'T': + OUT.output_tiff = 1; + break; + case '4': + OUT.gamm[0] = OUT.gamm[1] = OUT.no_auto_bright = 1; /* no break here! */ + case '6': + OUT.output_bps = 16; + break; + case 'F': + use_bigfile = 1; + break; + case 'Z': + outext = strdup(argv[arg++]); + break; + case 'd': + if (!strcmp(optstr, "-dcbi")) + OUT.dcb_iterations = atoi(argv[arg++]); + else if (!strcmp(optstr, "-disars")) + OUT.use_rawspeed = 0; + else if (!strcmp(optstr, "-disinterp")) + OUT.no_interpolation = 1; + else if (!strcmp(optstr, "-dcbe")) + OUT.dcb_enhance_fl = 1; + else if (!strcmp(optstr, "-dsrawrgb1")) + { + OUT.raw_processing_options |= LIBRAW_PROCESSING_SRAW_NO_RGB; + OUT.raw_processing_options &= ~LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE; } - putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field - OUT.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; + else if (!strcmp(optstr, "-dsrawrgb2")) + { + OUT.raw_processing_options &= ~LIBRAW_PROCESSING_SRAW_NO_RGB; + OUT.raw_processing_options |= LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE; + } +#ifdef USE_DNGSDK + else if (!strcmp(optstr, "-dngsdk")) + { + dnghost = new dng_host; + RawProcessor.set_dng_host(dnghost); + } + else if (!strcmp(optstr, "-dngflags")) + { + OUT.use_dngsdk = atoi(argv[arg++]); + } +#endif + else + fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]); + break; + default: + fprintf(stderr, "Unknown option \"-%c\".\n", opt); + return 1; + } + } +#ifndef LIBRAW_WIN32_CALLS + putenv((char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field +#else + _putenv( + (char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field +#endif #define P1 RawProcessor.imgdata.idata #define S RawProcessor.imgdata.sizes #define C RawProcessor.imgdata.color #define T RawProcessor.imgdata.thumbnail #define P2 RawProcessor.imgdata.other - if(verbosity>1) - RawProcessor.set_progress_handler(my_progress_callback,(void*)"Sample data passed"); -#ifdef _OPENMP - if(verbosity) - printf ("Using %d threads\n", omp_get_max_threads()); -#endif + if (outext && !strcmp(outext, "-")) + use_timing = verbosity = 0; - for ( ; arg < argc; arg++) + if (verbosity > 1) + RawProcessor.set_progress_handler(my_progress_callback, + (void *)"Sample data passed"); +#ifdef LIBRAW_USE_OPENMP + if (verbosity) + printf("Using %d threads\n", omp_get_max_threads()); +#endif + + for (; arg < argc; arg++) + { + char outfn[1024]; + + if (verbosity) + printf("Processing file %s\n", argv[arg]); + + timerstart(); + + if (use_mmap) + { + create_mapping(mapping, argv[arg]); + if (!mapping.map) + { + fprintf(stderr, "Cannot map %s\n", argv[arg]); + close_mapping(mapping); + continue; + } + if ((ret = RawProcessor.open_buffer(mapping.map,mapping.fsize) != + LIBRAW_SUCCESS)) + { + fprintf(stderr, "Cannot open_buffer %s: %s\n", argv[arg], libraw_strerror(ret)); + close_mapping(mapping); + continue; // no recycle b/c open file will recycle itself + } + } + else if (use_mem) + { + int file = open(argv[arg], O_RDONLY | O_BINARY); + struct stat st; + if (file < 0) + { + fprintf(stderr, "Cannot open %s: %s\n", argv[arg], strerror(errno)); + continue; + } + if (fstat(file, &st)) + { + fprintf(stderr, "Cannot stat %s: %s\n", argv[arg], strerror(errno)); + close(file); + continue; + } + if (!(iobuffer = malloc(st.st_size))) + { + fprintf(stderr, "Cannot allocate %d kbytes for memory buffer\n", + (int)(st.st_size / 1024)); + close(file); + continue; + } + int rd; + if (st.st_size != (rd = read(file, iobuffer, st.st_size))) + { + fprintf(stderr, + "Cannot read %d bytes instead of %d to memory buffer\n", + (int)rd, (int)st.st_size); + close(file); + free(iobuffer); + continue; + } + close(file); + if ((ret = RawProcessor.open_buffer(iobuffer, st.st_size)) != + LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot open_buffer %s: %s\n", argv[arg], + libraw_strerror(ret)); + free(iobuffer); + continue; // no recycle b/c open file will recycle itself + } + } + else + { + if (use_bigfile) + // force open_file switch to bigfile processing + ret = RawProcessor.open_file(argv[arg], 1); + else + ret = RawProcessor.open_file(argv[arg]); + + if (ret != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot open %s: %s\n", argv[arg], + libraw_strerror(ret)); + continue; // no recycle b/c open_file will recycle itself + } + } + + if (use_timing) + timerprint("LibRaw::open_file()", argv[arg]); + + timerstart(); + if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot unpack %s: %s\n", argv[arg], + libraw_strerror(ret)); + continue; + } + + if (use_timing) + timerprint("LibRaw::unpack()", argv[arg]); + + timerstart(); + if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_process())) + { + fprintf(stderr, "Cannot do postpocessing on %s: %s\n", argv[arg], + libraw_strerror(ret)); + if (LIBRAW_FATAL_ERROR(ret)) + continue; + } + if (use_timing) + timerprint("LibRaw::dcraw_process()", argv[arg]); + + if (!outext) + snprintf(outfn, sizeof(outfn), "%s.%s", argv[arg], + OUT.output_tiff ? "tiff" : (P1.colors > 1 ? "ppm" : "pgm")); + else if (!strcmp(outext, "-")) + snprintf(outfn, sizeof(outfn), "-"); + else + { + if (*outext == '.') // append + snprintf(outfn, sizeof(outfn), "%s%s", argv[arg], outext); + else if (strchr(outext, '.') && *outext != '.') // dot is not 1st char + strncpy(outfn, outext, sizeof(outfn)); + else + { + strncpy(outfn, argv[arg], sizeof(outfn)); + if (strlen(outfn) > 0) { - char outfn[1024]; + char *lastchar = outfn + strlen(outfn); // points to term 0 + while (--lastchar > outfn) + { + if (*lastchar == '/' || *lastchar == '\\') + break; + if (*lastchar == '.') + { + *lastchar = 0; + break; + }; + } + } + strncat(outfn, ".", sizeof(outfn) - strlen(outfn) - 1); + strncat(outfn, outext, sizeof(outfn) - strlen(outfn) - 1); + } + } - if(verbosity) printf("Processing file %s\n",argv[arg]); -#ifndef WIN32 - if(use_mmap) - { - int file = open(argv[arg],O_RDONLY); - struct stat st; - if(file<0) - { - fprintf(stderr,"Cannot open %s: %s\n",argv[arg],strerror(errno)); - continue; - } - if(fstat(file,&st)) - { - fprintf(stderr,"Cannot stat %s: %s\n",argv[arg],strerror(errno)); - close(file); - continue; - } - int pgsz = getpagesize(); - msize = ((st.st_size+pgsz-1)/pgsz)*pgsz; - iobuffer = mmap(NULL,msize,PROT_READ,MAP_PRIVATE,file,0); - if(!iobuffer) - { - fprintf(stderr,"Cannot mmap %s: %s\n",argv[arg],strerror(errno)); - close(file); - continue; - } - close(file); - if( (ret = RawProcessor.open_buffer(iobuffer,st.st_size) != LIBRAW_SUCCESS)) - { - fprintf(stderr,"Cannot open_buffer %s: %s\n",argv[arg],libraw_strerror(ret)); - continue; // no recycle b/c open file will recycle itself - } - - } - else -#endif - { - if( (ret = RawProcessor.open_file(argv[arg])) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot open %s: %s\n",argv[arg],libraw_strerror(ret)); - continue; // no recycle b/c open_file will recycle itself - } - } - if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot unpack %s: %s\n",argv[arg],libraw_strerror(ret)); - continue; - } - if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_process())) - { - fprintf(stderr,"Cannot do postpocessing on %s: %s\n",argv[arg],libraw_strerror(ret)); - if(LIBRAW_FATAL_ERROR(ret)) - continue; - } - snprintf(outfn,sizeof(outfn), - "%s.%s", - argv[arg], OUT.output_tiff ? "tiff" : (P1.colors>1?"ppm":"pgm")); - - if(verbosity) printf("Writing file %s\n",outfn); - - if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) - fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); - -#ifndef WIN32 - if(use_mmap && iobuffer) - { - munmap(iobuffer,msize); - iobuffer=0; - } + if (verbosity) + { + printf("Writing file %s\n", outfn); + } + + if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) + fprintf(stderr, "Cannot write %s: %s\n", outfn, libraw_strerror(ret)); + + RawProcessor.recycle(); // just for show this call + + if (use_mmap && mapping.map) + close_mapping(mapping); + else if (use_mem && iobuffer) + { + free(iobuffer); + iobuffer = 0; + } + } +#ifdef USE_DNGSDK + if (dnghost) + delete dnghost; #endif - - RawProcessor.recycle(); // just for show this call - } - return 0; + return 0; } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/dcraw_half.c libkdcraw/libkdcraw/libraw/samples/dcraw_half.c --- libkdcraw-wrk/libkdcraw/libraw/samples/dcraw_half.c 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/dcraw_half.c 2022-11-07 07:46:31.730795008 +0300 @@ -1,24 +1,20 @@ -/* +/* -*- C++ -*- * File: dcraw_half.c - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * - * LibRaw C API sample (emulates call to "dcraw -h") + * LibRaw C API sample: emulates "dcraw -h" * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ #include <stdio.h> #include <string.h> @@ -27,57 +23,56 @@ #include "libraw/libraw.h" - -#define HANDLE_FATAL_ERROR(ret)\ - if(ret)\ - {\ - fprintf(stderr,"%s: libraw %s\n",av[i],libraw_strerror(ret));\ - if(LIBRAW_FATAL_ERROR(ret))\ - exit(1); \ - }\ - -#define HANDLE_ALL_ERRORS(ret)\ - if(ret)\ - {\ - fprintf(stderr,"%s: libraw %s\n",av[i],libraw_strerror(ret));\ - continue; \ - }\ - +#define HANDLE_FATAL_ERROR(ret) \ + if (ret) \ + { \ + fprintf(stderr, "%s: libraw %s\n", av[i], libraw_strerror(ret)); \ + if (LIBRAW_FATAL_ERROR(ret)) \ + exit(1); \ + } + +#define HANDLE_ALL_ERRORS(ret) \ + if (ret) \ + { \ + fprintf(stderr, "%s: libraw %s\n", av[i], libraw_strerror(ret)); \ + continue; \ + } int main(int ac, char *av[]) { - int i; - libraw_data_t *iprc = libraw_init(0); - - if(!iprc) - { - fprintf(stderr,"Cannot create libraw handle\n"); - exit(1); - } - - iprc->params.half_size = 1; /* dcraw -h */ - - for (i=1;i<ac;i++) - { - char outfn[1024]; - int ret = libraw_open_file(iprc,av[i]); - HANDLE_ALL_ERRORS(ret); - - printf("Processing %s (%s %s)\n",av[i],iprc->idata.make,iprc->idata.model); - - ret = libraw_unpack(iprc); - HANDLE_ALL_ERRORS(ret); - - ret = libraw_dcraw_process(iprc); - HANDLE_ALL_ERRORS(ret); - - strcpy(outfn,av[i]); - strcat(outfn,".ppm"); - printf("Writing to %s\n",outfn); - - ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn); - HANDLE_FATAL_ERROR(ret); - } - libraw_close(iprc); - return 0; + int i; + libraw_data_t *iprc = libraw_init(0); + + if (!iprc) + { + fprintf(stderr, "Cannot create libraw handle\n"); + exit(1); + } + + iprc->params.half_size = 1; /* dcraw -h */ + + for (i = 1; i < ac; i++) + { + char outfn[1024]; + int ret = libraw_open_file(iprc, av[i]); + HANDLE_ALL_ERRORS(ret); + + printf("Processing %s (%s %s)\n", av[i], iprc->idata.make, + iprc->idata.model); + + ret = libraw_unpack(iprc); + HANDLE_ALL_ERRORS(ret); + + ret = libraw_dcraw_process(iprc); + HANDLE_ALL_ERRORS(ret); + + strcpy(outfn, av[i]); + strcat(outfn, ".ppm"); + printf("Writing to %s\n", outfn); + + ret = libraw_dcraw_ppm_tiff_writer(iprc, outfn); + HANDLE_FATAL_ERROR(ret); + } + libraw_close(iprc); + return 0; } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/half_mt.c libkdcraw/libkdcraw/libraw/samples/half_mt.c --- libkdcraw-wrk/libkdcraw/libraw/samples/half_mt.c 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/half_mt.c 2022-11-07 07:46:31.730795008 +0300 @@ -1,24 +1,22 @@ -/* +/* -*- C++ -*- * File: halt_mt.c - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> - * Created: Sat Mar 8 , 2008 + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Mar 8, 2008 * - * LibRaw C API mutithreaded sample (emulates call to "dcraw -h [-w] [-a] [-v]") + * LibRaw C API mutithreaded sample: emulates call to "dcraw -h [-w] [-a] +[-v]" * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ #include <stdio.h> #include <string.h> @@ -28,151 +26,153 @@ #include "libraw/libraw.h" -#define HANDLE_ERRORS(ret) do { \ - if(ret) \ - { \ - fprintf(stderr,"%s: %s\n",fn,libraw_strerror(ret)); \ - if(LIBRAW_FATAL_ERROR(ret)) \ - { \ - libraw_close(iprc); \ - return -1; \ - } \ - } \ - }while(0) - +#define HANDLE_ERRORS(ret) \ + do \ + { \ + if (ret) \ + { \ + fprintf(stderr, "%s: %s\n", fn, libraw_strerror(ret)); \ + if (LIBRAW_FATAL_ERROR(ret)) \ + { \ + libraw_close(iprc); \ + return NULL; \ + } \ + } \ + } while (0) -// global settings -int verbose=0,use_camera_wb=0,use_auto_wb=0,tiff_mode=0; +int verbose = 0, use_camera_wb = 0, use_auto_wb = 0, tiff_mode = 0; -// global file queue pthread_mutex_t qm; -char **queue=NULL; -size_t qsize=0,qptr=0; +char **queue = NULL; +size_t qsize = 0, qptr = 0; char *get_next_file() { - char *ret; - if(!queue) return NULL; - if(qptr>=qsize) return NULL; - pthread_mutex_lock(&qm); - ret = queue[qptr++]; - pthread_mutex_unlock(&qm); - return ret; + char *ret; + if (!queue) + return NULL; + if (qptr >= qsize) + return NULL; + pthread_mutex_lock(&qm); + ret = queue[qptr++]; + pthread_mutex_unlock(&qm); + return ret; } - -// thread routine -int process_files(void *q) +void *process_files(void *q) { - int ret; - int count=0; - char outfn[1024], *fn; - libraw_data_t *iprc = libraw_init(0); - - if(!iprc) - { - fprintf(stderr,"Cannot create libraw handle\n"); - return -1; - } - - while((fn = get_next_file())) - { - - iprc->params.half_size = 1; /* dcraw -h */ - iprc->params.use_camera_wb = use_camera_wb; - iprc->params.use_auto_wb = use_auto_wb; - iprc->params.output_tiff = tiff_mode; - - ret = libraw_open_file(iprc,fn); - if(verbose) fprintf(stderr,"%s: %s/%s\n",fn,iprc->idata.make,iprc->idata.model); - HANDLE_ERRORS(ret); - - ret = libraw_unpack(iprc); - HANDLE_ERRORS(ret); - - ret = libraw_dcraw_process(iprc); - HANDLE_ERRORS(ret); - - snprintf(outfn,1023,"%s.ppm",fn); - - if(verbose) fprintf(stderr,"Writing file %s\n",outfn); - ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn); - HANDLE_ERRORS(ret); - count++; - } - libraw_close(iprc); - return count; + int ret; + int count = 0; + char outfn[1024], *fn; + libraw_data_t *iprc = libraw_init(0); + + if (!iprc) + { + fprintf(stderr, "Cannot create libraw handle\n"); + return NULL; + } + + while ((fn = get_next_file())) + { + + iprc->params.half_size = 1; /* dcraw -h */ + iprc->params.use_camera_wb = use_camera_wb; + iprc->params.use_auto_wb = use_auto_wb; + iprc->params.output_tiff = tiff_mode; + + ret = libraw_open_file(iprc, fn); + if (verbose) + fprintf(stderr, "%s: %s/%s\n", fn, iprc->idata.make, iprc->idata.model); + HANDLE_ERRORS(ret); + + ret = libraw_unpack(iprc); + HANDLE_ERRORS(ret); + + ret = libraw_dcraw_process(iprc); + HANDLE_ERRORS(ret); + + snprintf(outfn, 1023, "%s.%s", fn, tiff_mode ? "tiff" : "ppm"); + + if (verbose) + fprintf(stderr, "Writing file %s\n", outfn); + ret = libraw_dcraw_ppm_tiff_writer(iprc, outfn); + HANDLE_ERRORS(ret); + count++; + } + libraw_close(iprc); + return NULL; } -void usage(const char*p) +void usage(const char *p) { - printf("%s: Multi-threaded LibRaw sample app. Emulates dcraw -h [-w] [-a]\n",p); - printf( - "Options:\n" - "-J n - set parrallel job coun (default 2)\n" - "-v - verbose\n" - "-w - use camera white balance\n" - "-a - average image for white balance\n"); - exit(1); + printf("%s: Multi-threaded LibRaw sample app. Emulates dcraw -h [-w] [-a]\n", + p); + printf("Options:\n" + "-J n - set parallel job count (default 2)\n" + "-v - verbose\n" + "-w - use camera white balance\n" + "-a - average image for white balance\n"); + exit(1); } int show_files(void *q) { - char *p; - int cnt = 0; - while(p = get_next_file()) - { - printf("%s\n",p); - cnt++; - } - return cnt; - + char *p; + int cnt = 0; + while ((p = get_next_file())) + { + printf("%s\n", p); + cnt++; + } + return cnt; } int main(int ac, char *av[]) { - int i, thread_count,max_threads = 2; - pthread_t *threads; - if(ac<2) - usage(av[0]); - - queue = calloc(ac-1,sizeof(queue[0])); - - for (i=1;i<ac;i++) + int i, max_threads = 2; + pthread_t *threads; + if (ac < 2) + usage(av[0]); + + queue = calloc(ac - 1, sizeof(queue[0])); + + for (i = 1; i < ac; i++) + { + if (av[i][0] == '-') + { + if (av[i][1] == 'w') + use_camera_wb = 1; + if (av[i][1] == 'a') + use_auto_wb = 1; + if (av[i][1] == 'v') + verbose = 1; + if (av[i][1] == 'T') + tiff_mode = 1; + if (av[i][1] == 'J') + { + max_threads = atoi(av[++i]); + if (max_threads < 1) { - if(av[i][0]=='-') - { - if(av[i][1]=='w') use_camera_wb = 1; - if(av[i][1]=='a') use_auto_wb = 1; - if(av[i][1]=='v') verbose = 1; - if(av[i][1]=='T') tiff_mode = 1; - if(av[i][1]=='J') - { - max_threads=atoi(av[++i]); - if(max_threads<1) - { - fprintf(stderr,"Job count should be at least 1\n"); - exit(1); - } - } - } - else - queue[qsize++] = av[i]; + fprintf(stderr, "Job count should be at least 1\n"); + exit(1); } - pthread_mutex_init(&qm,NULL); - threads = calloc(max_threads,sizeof(threads[0])); - for(i=0;i<max_threads;i++) - pthread_create(&threads[i],NULL,process_files,NULL); - for(i=0;i<max_threads;i++) - { - int *iptr; - if(threads[i]) - { - pthread_join(threads[i],&iptr); - if(iptr) - printf("Thread %d : %d files\n",i,(int)iptr); - } - } - - return 0; + } + } + else + queue[qsize++] = av[i]; + } + pthread_mutex_init(&qm, NULL); + threads = calloc(max_threads, sizeof(threads[0])); + for (i = 0; i < max_threads; i++) + pthread_create(&threads[i], NULL, process_files, NULL); + for (i = 0; i < max_threads; i++) + { + int *iptr; + if (threads[i]) + { + pthread_join(threads[i], (void *)&iptr); + } + } + + return 0; } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/half_mt_win32.c libkdcraw/libkdcraw/libraw/samples/half_mt_win32.c --- libkdcraw-wrk/libkdcraw/libraw/samples/half_mt_win32.c 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/half_mt_win32.c 2022-11-07 07:46:31.730795008 +0300 @@ -1,25 +1,22 @@ -/* +/* -*- C++ -*- * File: halt_mt_win32.c - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> - * Created: Sat Mar 8 , 2008 + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Mar 8, 2008 * - * LibRaw C API mutithreaded sample (emulates call to "dcraw -h [-w] [-a] [-v]") + * LibRaw C API mutithreaded sample: emulates call to "dcraw -h [-w] [-a] +[-v]" * Win32 version - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ #include <stdio.h> #include <string.h> @@ -28,185 +25,188 @@ #include <windows.h> #include "libraw/libraw.h" -#ifdef WIN32 +#ifdef LIBRAW_WIN32_CALLS #define snprintf _snprintf #endif - -#define HANDLE_ERRORS(ret) do { \ - if(ret) \ - { \ - fprintf(stderr,"%s: %s\n",fn,libraw_strerror(ret)); \ - if(LIBRAW_FATAL_ERROR(ret)) \ - { \ - libraw_close(iprc); \ - return -1; \ - } \ - } \ - }while(0) - +#define HANDLE_ERRORS(ret) \ + do \ + { \ + if (ret) \ + { \ + fprintf(stderr, "%s: %s\n", fn, libraw_strerror(ret)); \ + if (LIBRAW_FATAL_ERROR(ret)) \ + { \ + libraw_close(iprc); \ + return -1; \ + } \ + } \ + } while (0) // global settings -int verbose=0,use_camera_wb=0,use_auto_wb=0,tiff_mode=0; +int verbose = 0, use_camera_wb = 0, use_auto_wb = 0, tiff_mode = 0; // global file queue HANDLE qmutex; -char **queue=NULL; -size_t qsize=0,qptr=0; +char **queue = NULL; +size_t qsize = 0, qptr = 0; char *get_next_file() { - char *ret; - DWORD dwWaitResult; - if(!queue) return NULL; - if(qptr>=qsize) return NULL; - - dwWaitResult = WaitForSingleObject( - qmutex, // handle to mutex - INFINITE); // no time-out interval - switch (dwWaitResult) - { - // The thread got ownership of the mutex - case WAIT_OBJECT_0: - ret = queue[qptr++]; - ReleaseMutex(qmutex); - break; - case WAIT_ABANDONED: - return NULL; // cannot obtain the lock - }; - return ret; + char *ret; + DWORD dwWaitResult; + if (!queue) + return NULL; + if (qptr >= qsize) + return NULL; + + dwWaitResult = WaitForSingleObject(qmutex, // handle to mutex + INFINITE); // no time-out interval + switch (dwWaitResult) + { + // The thread got ownership of the mutex + case WAIT_OBJECT_0: + ret = queue[qptr++]; + ReleaseMutex(qmutex); + break; + case WAIT_ABANDONED: + return NULL; // cannot obtain the lock + }; + return ret; } - // thread routine int process_files(void *q) { - int ret; - int count=0; - char outfn[1024], *fn; - libraw_data_t *iprc = libraw_init(0); - - if(!iprc) - { - fprintf(stderr,"Cannot create libraw handle\n"); - return -1; - } - - while((fn = get_next_file())) - { - - iprc->params.half_size = 1; /* dcraw -h */ - iprc->params.use_camera_wb = use_camera_wb; - iprc->params.use_auto_wb = use_auto_wb; - iprc->params.output_tiff = tiff_mode; - - ret = libraw_open_file(iprc,fn); - if(verbose) fprintf(stderr,"%s: %s/%s\n",fn,iprc->idata.make,iprc->idata.model); - HANDLE_ERRORS(ret); - - ret = libraw_unpack(iprc); - HANDLE_ERRORS(ret); - - ret = libraw_dcraw_process(iprc); - HANDLE_ERRORS(ret); - - snprintf(outfn,1023,"%s.%s",fn,tiff_mode?"tif":"ppm"); - - if(verbose) fprintf(stderr,"Writing file %s\n",outfn); - ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn); - HANDLE_ERRORS(ret); - count++; - } - libraw_close(iprc); - printf("Processed %d files\n",count); - return 0; + int ret; + int count = 0; + char outfn[1024], *fn; + libraw_data_t *iprc = libraw_init(0); + + if (!iprc) + { + fprintf(stderr, "Cannot create libraw handle\n"); + return -1; + } + + while ((fn = get_next_file())) + { + + iprc->params.half_size = 1; /* dcraw -h */ + iprc->params.use_camera_wb = use_camera_wb; + iprc->params.use_auto_wb = use_auto_wb; + iprc->params.output_tiff = tiff_mode; + + ret = libraw_open_file(iprc, fn); + if (verbose) + fprintf(stderr, "%s: %s/%s\n", fn, iprc->idata.make, iprc->idata.model); + HANDLE_ERRORS(ret); + + ret = libraw_unpack(iprc); + HANDLE_ERRORS(ret); + + ret = libraw_dcraw_process(iprc); + HANDLE_ERRORS(ret); + + snprintf(outfn, 1023, "%s.%s", fn, tiff_mode ? "tif" : "ppm"); + + if (verbose) + fprintf(stderr, "Writing file %s\n", outfn); + ret = libraw_dcraw_ppm_tiff_writer(iprc, outfn); + HANDLE_ERRORS(ret); + count++; + } + libraw_close(iprc); + printf("Processed %d files\n", count); + return 0; } -void usage(const char*p) +void usage(const char *p) { - printf( - "Options:\n" - "-J n - set parrallel job coun (default 2)\n" - "-v - verbose\n" - "-w - use camera white balance\n" - "-T - output TIFF instead of PPM\n" - "-a - average image for white balance\n"); - exit(1); + printf("Options:\n" + "-J n - set parallel job count (default 2)\n" + "-v - verbose\n" + "-w - use camera white balance\n" + "-T - output TIFF instead of PPM\n" + "-a - average image for white balance\n"); + exit(1); } int show_files(void *q) { - char *p; - int cnt = 0; - while(p = get_next_file()) - { - printf("%s\n",p); - cnt++; - } - return cnt; - + char *p; + int cnt = 0; + while (p = get_next_file()) + { + printf("%s\n", p); + cnt++; + } + return cnt; } int main(int ac, char *av[]) { - int i,max_threads = 2; - HANDLE *threads; - DWORD ThreadID; + int i, max_threads = 2; + HANDLE *threads; + DWORD ThreadID; + + if (ac < 2) + usage(av[0]); + + queue = calloc(ac - 1, sizeof(queue[0])); + + for (i = 1; i < ac; i++) + { + if (av[i][0] == '-') + { + if (av[i][1] == 'w') + use_camera_wb = 1; + if (av[i][1] == 'a') + use_auto_wb = 1; + if (av[i][1] == 'v') + verbose = 1; + if (av[i][1] == 'T') + tiff_mode = 1; + if (av[i][1] == 'J') + { + max_threads = atoi(av[++i]); + if (max_threads < 1) + { + fprintf(stderr, "Job count should be at least 1\n"); + exit(1); + } + } + } + else + queue[qsize++] = av[i]; + } + qmutex = CreateMutex(NULL, FALSE, NULL); + threads = calloc(max_threads, sizeof(threads[0])); + for (i = 0; i < max_threads; i++) + { + + if (NULL == + (threads[i] = CreateThread(NULL, // default security attributes + 0, // default stack size + (LPTHREAD_START_ROUTINE)process_files, + NULL, // no thread function arguments + 0, // default creation flags + &ThreadID) // receive thread identifier + )) + { + printf("CreateThread error: %d\n", GetLastError()); + return 1; + } + } + + WaitForMultipleObjects(max_threads, threads, TRUE, INFINITE); - if(ac<2) - usage(av[0]); + // Close thread and mutex handles - queue = calloc(ac-1,sizeof(queue[0])); + for (i = 0; i < max_threads; i++) + CloseHandle(threads[i]); - for (i=1;i<ac;i++) - { - if(av[i][0]=='-') - { - if(av[i][1]=='w') use_camera_wb = 1; - if(av[i][1]=='a') use_auto_wb = 1; - if(av[i][1]=='v') verbose = 1; - if(av[i][1]=='T') tiff_mode = 1; - if(av[i][1]=='J') - { - max_threads=atoi(av[++i]); - if(max_threads<1) - { - fprintf(stderr,"Job count should be at least 1\n"); - exit(1); - } - } - } - else - queue[qsize++] = av[i]; - } - qmutex = CreateMutex(NULL,FALSE,NULL); - threads = calloc(max_threads,sizeof(threads[0])); - for(i=0;i<max_threads;i++) - { - - if (NULL == (threads[i] = CreateThread( - NULL, // default security attributes - 0, // default stack size - (LPTHREAD_START_ROUTINE) process_files, - NULL, // no thread function arguments - 0, // default creation flags - &ThreadID) // receive thread identifier - ) - ) - { - printf("CreateThread error: %d\n", GetLastError()); - return 1; - } - } - - WaitForMultipleObjects(max_threads, threads, TRUE, INFINITE); - - // Close thread and mutex handles - - for( i=0; i < max_threads; i++ ) - CloseHandle(threads[i]); - - CloseHandle(qmutex); - - return 0; + CloseHandle(qmutex); + + return 0; } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/identify.cpp libkdcraw/libkdcraw/libraw/samples/identify.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/identify.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/identify.cpp 1970-01-01 03:00:00.000000000 +0300 @@ -1,147 +0,0 @@ -/* - * File: identify.cpp - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> - * Created: Sat Mar 8 , 2008 - * - * LibRaw C++ demo (emulates dcraw -i [-v]) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include <stdio.h> -#include <string.h> -#include <math.h> -#include <time.h> - -#include "libraw/libraw.h" - -#ifdef WIN32 -#define snprintf _snprintf -#endif - - -int main(int ac, char *av[]) -{ - int verbose = 0, ret,print_unpack=0,print_frame=0; - LibRaw MyCoolRawProcessor; - - for (int i=1;i<ac;i++) { - if(av[i][0]=='-') - { - if(av[i][1]=='v' && av[i][2]==0) verbose++; - if(av[i][1]=='u' && av[i][2]==0) print_unpack++; - if(av[i][1]=='f' && av[i][2]==0) print_frame++; - continue; - } - if( (ret = MyCoolRawProcessor.open_file(av[i])) != LIBRAW_SUCCESS) - { - printf("Cannot decode %s: %s\n",av[i],libraw_strerror(ret)); - continue; // no recycle, open_file will recycle - } - if(verbose) { - -#define P1 MyCoolRawProcessor.imgdata.idata -#define P2 MyCoolRawProcessor.imgdata.other - -#define S MyCoolRawProcessor.imgdata.sizes -#define O MyCoolRawProcessor.imgdata.params -#define C MyCoolRawProcessor.imgdata.color -#define T MyCoolRawProcessor.imgdata.thumbnail - - - if( (ret = MyCoolRawProcessor.adjust_sizes_info_only())) - { - printf("Cannot decode %s: %s\n",av[i],libraw_strerror(ret)); - continue; // no recycle, open_file will recycle - } - - printf ("\nFilename: %s\n", av[i]); - printf ("Timestamp: %s", ctime(&(P2.timestamp))); - printf ("Camera: %s %s\n", P1.make, P1.model); - if (P2.artist[0]) - printf ("Owner: %s\n", P2.artist); - if (P1.dng_version) { - printf ("DNG Version: "); - for (int i=24; i >= 0; i -= 8) - printf ("%d%c", P1.dng_version >> i & 255, i ? '.':'\n'); - } - printf ("ISO speed: %d\n", (int) P2.iso_speed); - printf ("Shutter: "); - if (P2.shutter > 0 && P2.shutter < 1) - P2.shutter = (printf ("1/"), 1 / P2.shutter); - printf ("%0.1f sec\n", P2.shutter); - printf ("Aperture: f/%0.1f\n", P2.aperture); - printf ("Focal length: %0.1f mm\n", P2.focal_len); - if(C.profile) - printf ("Embedded ICC profile: yes, %d bytes\n", C.profile_length); - else - printf ("Embedded ICC profile: no\n", C.profile_length); - - printf ("Number of raw images: %d\n", P1.raw_count); - if (S.pixel_aspect != 1) - printf ("Pixel Aspect Ratio: %0.6f\n", S.pixel_aspect); - if (T.tlength) - printf ("Thumb size: %4d x %d\n", T.twidth, T.theight); - printf ("Full size: %4d x %d\n", S.raw_width, S.raw_height); - - printf ("Image size: %4d x %d\n", S.width, S.height); - printf ("Output size: %4d x %d\n", S.iwidth, S.iheight); - printf ("Raw colors: %d", P1.colors); - if (P1.filters) - { - printf ("\nFilter pattern: "); - if (!P1.cdesc[3]) P1.cdesc[3] = 'G'; - for (int i=0; i < 16; i++) - putchar (P1.cdesc[MyCoolRawProcessor.fc(i >> 1,i & 1)]); - } - printf ("\nDaylight multipliers:"); - for(int c=0;c<P1.colors;c++) printf (" %f", C.pre_mul[c]); - if (C.cam_mul[0] > 0) - { - printf ("\nCamera multipliers:"); - for(int c=0;c<4;c++) printf (" %f", C.cam_mul[c]); - } - char *csl[] = {"U","I","CO","L","CA"}; - printf("\nColor sources /Legend: (U)nknown, (I)nit, (CO)nstant, (L)oaded, (CA)lculated/:\n"); - printf("\tcurve=%s; rgb_cam=%s; cmatrix=%s, pre_mul=%s, cam_mul=%s", - csl[C.color_flags.curve_state],csl[C.color_flags.rgb_cam_state], - csl[C.color_flags.cmatrix_state],csl[C.color_flags.pre_mul_state], - csl[C.color_flags.cam_mul_state]); - putchar ('\n'); - printf("Cam->XYZ matrix:\n"); - for(int i=0; i< 4; i++) - printf("%6.4f\t%6.4f\t%6.4f\n",C.cam_xyz[i][0],C.cam_xyz[i][1],C.cam_xyz[i][2]); - } - else - { - if(print_unpack) - { - char frame[32]=""; - if(print_frame) - snprintf(frame,32,"%dx%dx%dx%d",S.left_margin,S.top_margin,S.right_margin,S.bottom_margin); - printf ("%s\t%s\t%s\t%s/%s\n", - av[i], - MyCoolRawProcessor.unpack_function_name(), - frame, - P1.make, P1.model); - } - else - printf ("%s is a %s %s image.\n", av[i],P1.make, P1.model); - } - MyCoolRawProcessor.recycle(); - }// endfor - return 0; -} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/mem_image.cpp libkdcraw/libkdcraw/libraw/samples/mem_image.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/mem_image.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/mem_image.cpp 2022-11-07 07:46:31.642795007 +0300 @@ -1,25 +1,24 @@ -/* +/* -*- C++ -*- * File: mem_image.cpp - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2010 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * - * LibRaw mem_image/mem_thumb API test. Resuls should be same (bitwise) as in dcraw [-4] [-e] - * Testing note: for ppm-thumbnails you should use dcraw -w -e for thumbnail extraction - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * LibRaw mem_image/mem_thumb API test. Results should be same (bitwise) to dcraw [-4] [-6] [-e] + * Testing note: for ppm-thumbnails you should use dcraw -w -e for thumbnail extraction + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of three licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + +3. LibRaw Software License 27032010 + (See file LICENSE.LibRaw.pdf provided in LibRaw distribution archive for details). + + */ #include <stdio.h> #include <string.h> @@ -58,7 +57,7 @@ */ #define SWAP(a,b) { a ^= b; a ^= (b ^= a); } if (img->bits == 16 && htons(0x55aa) != 0x55aa) - for(int i=0; i< img->data_size; i+=2) + for(unsigned i=0; i< img->data_size; i+=2) SWAP(img->data[i],img->data[i+1]); #undef SWAP @@ -91,10 +90,9 @@ int main(int ac, char *av[]) { - int i, ret, verbose=0, output_thumbs=0; + int i, ret, output_thumbs=0; // don't use fixed size buffers in real apps! - char outfn[1024],thumbfn[1024]; LibRaw RawProcessor; @@ -103,8 +101,8 @@ printf( "mem_image - LibRaw sample, to illustrate work for memory buffers. Emulates dcraw [-4] [-1] [-e]\n" "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n" - "\t-4 - output 16-bit PPM\n" - "\t-1 - gamma-correct 16-bit data\n" + "\t-6 - output 16-bit PPM\n" + "\t-4 - linear 16-bit data\n" "\t-e - extract thumbnails (same as dcraw -e in separate run)\n", av[0]); return 0; @@ -124,10 +122,13 @@ { if(av[i][0]=='-') { - if(av[i][1]=='4' && av[i][2]==0) + if(av[i][1]=='6' && av[i][2]==0) OUT.output_bps = 16; - if(av[i][1]=='1' && av[i][2]==0) - OUT.gamma_16bit = 1; + if(av[i][1]=='4' && av[i][2]==0) + { + OUT.output_bps = 16; + OUT.gamm[0] = OUT.gamm[1] = OUT.no_auto_bright = 1; + } if(av[i][1]=='e' && av[i][2]==0) output_thumbs++; continue; @@ -139,7 +140,6 @@ continue; // no recycle b/c open file will recycle itself } - if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret)); diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/raw-identify.cpp libkdcraw/libkdcraw/libraw/samples/raw-identify.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/raw-identify.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/samples/raw-identify.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,1684 @@ +/* -*- C++ -*- + * File: identify.cpp + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Mar 8, 2008 + * + * LibRaw C++ demo: emulates dcraw -i [-v] + * + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + + */ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <time.h> +#include <string> +#include <list> + +#include "libraw/libraw.h" + +#ifdef LIBRAW_WIN32_CALLS +#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +#endif + +#ifndef LIBRAW_WIN32_CALLS +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/time.h> +#ifndef MAX_PATH +#define MAX_PATH PATH_MAX +#endif +#endif + +#ifdef _MSC_VER +#if _MSC_VER < 1800 /* below MSVC 2013 */ +float roundf(float f) +{ + return floorf(f + 0.5); +} + +#endif +#endif + +struct starttime_t +{ +#ifdef LIBRAW_WIN32_CALLS + LARGE_INTEGER started; +#else + struct timeval started; +#endif +}; + +// clang-format off + +#define P1 MyCoolRawProcessor.imgdata.idata +#define P2 MyCoolRawProcessor.imgdata.other +#define P3 MyCoolRawProcessor.imgdata.makernotes.common + +#define mnLens MyCoolRawProcessor.imgdata.lens.makernotes +#define exifLens MyCoolRawProcessor.imgdata.lens +#define ShootingInfo MyCoolRawProcessor.imgdata.shootinginfo + +#define S MyCoolRawProcessor.imgdata.sizes +#define O MyCoolRawProcessor.imgdata.params +#define C MyCoolRawProcessor.imgdata.color +#define T MyCoolRawProcessor.imgdata.thumbnail + +#define Canon MyCoolRawProcessor.imgdata.makernotes.canon +#define Hasselblad MyCoolRawProcessor.imgdata.makernotes.hasselblad +#define Fuji MyCoolRawProcessor.imgdata.makernotes.fuji +#define Nikon MyCoolRawProcessor.imgdata.makernotes.nikon +#define Oly MyCoolRawProcessor.imgdata.makernotes.olympus +#define Sony MyCoolRawProcessor.imgdata.makernotes.sony + +void print_verbose(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_wbfun(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_jsonfun(FILE*, LibRaw& MyCoolRawProcessor, + std::string& fn, int fnum, int nfiles); +void print_compactfun(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_normfun(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_szfun(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_0fun(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_1fun(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_2fun(FILE*, LibRaw& MyCoolRawProcessor, std::string& fn); +void print_unpackfun(FILE*, LibRaw& MyCoolRawProcessor, int print_frame, std::string& fn); +void print_timer(FILE*, const starttime_t&, int c); + +/* +table of fluorescents: +12 = FL-D; Daylight fluorescent (D 5700K – 7100K) (F1,F5) +13 = FL-N; Day white fluorescent (N 4600K – 5400K) (F7,F8) +14 = FL-W; Cool white fluorescent (W 3900K – 4500K) (F2,F6, office, store,warehouse) +15 = FL-WW; White fluorescent (WW 3200K – 3700K) (F3, residential) +16 = FL-L; Soft/Warm white fluorescent (L 2600K - 3250K) (F4, kitchen, bath) +*/ + +static const struct { + const int NumId; + const char *StrId; + const char *hrStrId; // human-readable + const int aux_setting; +} WBToStr[] = { + {LIBRAW_WBI_Unknown, "WBI_Unknown", "Unknown", 0}, + {LIBRAW_WBI_Daylight, "WBI_Daylight", "Daylight", 0}, + {LIBRAW_WBI_Fluorescent, "WBI_Fluorescent", "Fluorescent", 0}, + {LIBRAW_WBI_Tungsten, "WBI_Tungsten", "Tungsten (Incandescent)", 0}, + {LIBRAW_WBI_Flash, "WBI_Flash", "Flash", 0}, + {LIBRAW_WBI_FineWeather, "WBI_FineWeather", "Fine Weather", 0}, + {LIBRAW_WBI_Cloudy, "WBI_Cloudy", "Cloudy", 0}, + {LIBRAW_WBI_Shade, "WBI_Shade", "Shade", 0}, + {LIBRAW_WBI_FL_D, "WBI_FL_D", "Daylight Fluorescent", 0}, + {LIBRAW_WBI_FL_N, "WBI_FL_N", "Day White Fluorescent", 0}, + {LIBRAW_WBI_FL_W, "WBI_FL_W", "Cool White Fluorescent", 0}, + {LIBRAW_WBI_FL_WW, "WBI_FL_WW", "White Fluorescent", 0}, + {LIBRAW_WBI_FL_L, "WBI_FL_L", "Warm White Fluorescent", 0}, + {LIBRAW_WBI_Ill_A, "WBI_Ill_A", "Illuminant A", 0}, + {LIBRAW_WBI_Ill_B, "WBI_Ill_B", "Illuminant B", 0}, + {LIBRAW_WBI_Ill_C, "WBI_Ill_C", "Illuminant C", 0}, + {LIBRAW_WBI_D55, "WBI_D55", "D55", 0}, + {LIBRAW_WBI_D65, "WBI_D65", "D65", 0}, + {LIBRAW_WBI_D75, "WBI_D75", "D75", 0}, + {LIBRAW_WBI_D50, "WBI_D50", "D50", 0}, + {LIBRAW_WBI_StudioTungsten, "WBI_StudioTungsten", "ISO Studio Tungsten", 0}, + {LIBRAW_WBI_BW, "WBI_BW", "BW", 0}, + {LIBRAW_WBI_Other, "WBI_Other", "Other", 0}, + {LIBRAW_WBI_Sunset, "WBI_Sunset", "Sunset", 1}, + {LIBRAW_WBI_Underwater, "WBI_Underwater", "Underwater", 1}, + {LIBRAW_WBI_FluorescentHigh, "WBI_FluorescentHigh", "Fluorescent High", 1}, + {LIBRAW_WBI_HT_Mercury, "WBI_HT_Mercury", "HT Mercury", 1}, + {LIBRAW_WBI_AsShot, "WBI_AsShot", "As Shot", 1}, + {LIBRAW_WBI_Measured, "WBI_Measured", "Camera Measured", 1}, + {LIBRAW_WBI_Auto, "WBI_Auto", "Camera Auto", 1}, + {LIBRAW_WBI_Auto1, "WBI_Auto1", "Camera Auto 1", 1}, + {LIBRAW_WBI_Auto2, "WBI_Auto2", "Camera Auto 2", 1}, + {LIBRAW_WBI_Auto3, "WBI_Auto3", "Camera Auto 3", 1}, + {LIBRAW_WBI_Auto4, "WBI_Auto4", "Camera Auto 4", 1}, + {LIBRAW_WBI_Custom, "WBI_Custom", "Custom", 1}, + {LIBRAW_WBI_Custom1, "WBI_Custom1", "Custom 1", 1}, + {LIBRAW_WBI_Custom2, "WBI_Custom2", "Custom 2", 1}, + {LIBRAW_WBI_Custom3, "WBI_Custom3", "Custom 3", 1}, + {LIBRAW_WBI_Custom4, "WBI_Custom4", "Custom 4", 1}, + {LIBRAW_WBI_Custom5, "WBI_Custom5", "Custom 5", 1}, + {LIBRAW_WBI_Custom6, "WBI_Custom6", "Custom 6", 1}, + {LIBRAW_WBI_PC_Set1, "WBI_PC_Set1", "PC Set 1", 1}, + {LIBRAW_WBI_PC_Set2, "WBI_PC_Set2", "PC Set 2", 1}, + {LIBRAW_WBI_PC_Set3, "WBI_PC_Set3", "PC Set 3", 1}, + {LIBRAW_WBI_PC_Set4, "WBI_PC_Set4", "PC Set 4", 1}, + {LIBRAW_WBI_PC_Set5, "WBI_PC_Set5", "PC Set 5", 1}, + {LIBRAW_WBI_Kelvin, "WBI_Kelvin", "Kelvin", 1}, +}; + +typedef struct +{ + unsigned long long id; + char const *name; +} id2hr_t; // id to human readable + +static id2hr_t MountNames[] = { + {LIBRAW_MOUNT_Alpa, "Alpa"}, + {LIBRAW_MOUNT_C, "C-mount"}, + {LIBRAW_MOUNT_Canon_EF_M, "Canon EF-M"}, + {LIBRAW_MOUNT_Canon_EF_S, "Canon EF-S"}, + {LIBRAW_MOUNT_Canon_EF, "Canon EF"}, + {LIBRAW_MOUNT_Canon_RF, "Canon RF"}, + {LIBRAW_MOUNT_Contax_N, "Contax N"}, + {LIBRAW_MOUNT_Contax645, "Contax 645"}, + {LIBRAW_MOUNT_FT, "4/3"}, + {LIBRAW_MOUNT_mFT, "m4/3"}, + {LIBRAW_MOUNT_Fuji_GF, "Fuji G"}, // Fujifilm G lenses, GFX cameras + {LIBRAW_MOUNT_Fuji_GX, "Fuji GX"}, // GX680 + {LIBRAW_MOUNT_Fuji_X, "Fuji X"}, + {LIBRAW_MOUNT_Hasselblad_H, "Hasselblad H"}, // Hn cameras, HC & HCD lenses + {LIBRAW_MOUNT_Hasselblad_V, "Hasselblad V"}, + {LIBRAW_MOUNT_Hasselblad_XCD, "Hasselblad XCD"}, // Xn cameras, XCD lenses + {LIBRAW_MOUNT_Leica_M, "Leica M"}, + {LIBRAW_MOUNT_Leica_R, "Leica R"}, + {LIBRAW_MOUNT_Leica_S, "Leica S"}, + {LIBRAW_MOUNT_Leica_SL, "Leica SL"}, // mounts on "L" throat + {LIBRAW_MOUNT_Leica_TL, "Leica TL"}, // mounts on "L" throat + {LIBRAW_MOUNT_LPS_L, "LPS L-mount"}, // throat, Leica / Panasonic / Sigma + {LIBRAW_MOUNT_Mamiya67, "Mamiya RZ/RB"}, // Mamiya RB67, RZ67 + {LIBRAW_MOUNT_Mamiya645, "Mamiya 645"}, + {LIBRAW_MOUNT_Minolta_A, "Sony/Minolta A"}, + {LIBRAW_MOUNT_Nikon_CX, "Nikkor 1"}, + {LIBRAW_MOUNT_Nikon_F, "Nikkor F"}, + {LIBRAW_MOUNT_Nikon_Z, "Nikkor Z"}, + {LIBRAW_MOUNT_Pentax_645, "Pentax 645"}, + {LIBRAW_MOUNT_Pentax_K, "Pentax K"}, + {LIBRAW_MOUNT_Pentax_Q, "Pentax Q"}, + {LIBRAW_MOUNT_RicohModule, "Ricoh module"}, + {LIBRAW_MOUNT_Rollei_bayonet, "Rollei bayonet"}, // Rollei Hy-6: Leaf AFi, Sinar Hy6- models + {LIBRAW_MOUNT_Samsung_NX_M, "Samsung NX-M"}, + {LIBRAW_MOUNT_Samsung_NX, "Samsung NX"}, + {LIBRAW_MOUNT_Sigma_X3F, "Sigma SA/X3F"}, + {LIBRAW_MOUNT_Sony_E, "Sony E"}, +// generic formats: + {LIBRAW_MOUNT_LF, "Large format"}, + {LIBRAW_MOUNT_DigitalBack, "Digital Back"}, + {LIBRAW_MOUNT_FixedLens, "Fixed Lens"}, + {LIBRAW_MOUNT_IL_UM, "Interchangeable lens, mount unknown"}, + {LIBRAW_MOUNT_Unknown, "Undefined Mount or Fixed Lens"}, + {LIBRAW_MOUNT_TheLastOne, "The Last One"}, +}; + +static id2hr_t FormatNames[] = { + {LIBRAW_FORMAT_1div2p3INCH, "1/2.3\""}, + {LIBRAW_FORMAT_1div1p7INCH, "1/1.7\""}, + {LIBRAW_FORMAT_1INCH, "1\""}, + {LIBRAW_FORMAT_FT, "4/3"}, + {LIBRAW_FORMAT_APSC, "APS-C"}, // Canon: 22.3x14.9mm; Sony et al: 23.6-23.7x15.6mm + {LIBRAW_FORMAT_Leica_DMR, "Leica DMR"}, // 26.4x 17.6mm + {LIBRAW_FORMAT_APSH, "APS-H"}, // Canon: 27.9x18.6mm + {LIBRAW_FORMAT_FF, "FF 35mm"}, + {LIBRAW_FORMAT_CROP645, "645 crop 44x33mm"}, + {LIBRAW_FORMAT_LeicaS, "Leica S 45x30mm"}, + {LIBRAW_FORMAT_3648, "48x36mm"}, + {LIBRAW_FORMAT_645, "6x4.5"}, + {LIBRAW_FORMAT_66, "6x6"}, + {LIBRAW_FORMAT_67, "6x7"}, + {LIBRAW_FORMAT_68, "6x8"}, + {LIBRAW_FORMAT_69, "6x9"}, + {LIBRAW_FORMAT_SigmaAPSC, "Sigma APS-C"}, // Sigma Foveon X3 orig: 20.7x13.8mm + {LIBRAW_FORMAT_SigmaMerrill, "Sigma Merrill"}, + {LIBRAW_FORMAT_SigmaAPSH, "Sigma APS-H"}, // Sigma "H" 26.7 x 17.9mm + {LIBRAW_FORMAT_MF, "Medium Format"}, + {LIBRAW_FORMAT_LF, "Large format"}, + {LIBRAW_FORMAT_Unknown, "Unknown"}, + {LIBRAW_FORMAT_TheLastOne, "The Last One"}, +}; + +static id2hr_t NikonCrops[] = { + {0, "Uncropped"}, {1, "1.3x"}, {2, "DX"}, + {3, "5:4"}, {4, "3:2"}, {6, "16:9"}, + {8, "2.7x"}, {9, "DX Movie"}, {10, "1.3x Movie"}, + {11, "FX Uncropped"}, {12, "DX Uncropped"}, {15, "1.5x Movie"}, + {17, "1:1"}, +}; +#define nNikonCrops (sizeof(NikonCrops) / sizeof(id2hr_t)) + +static id2hr_t FujiCrops[] = { + {0, "Uncropped"}, + {1, "GFX FF"}, + {2, "Sports Finder Mode"}, + {4, "Electronic Shutter 1.25x Crop"}, +}; +#define nFujiCrops (sizeof(FujiCrops) / sizeof(id2hr_t)) + +static id2hr_t FujiDriveModes[] = { + {0, "Single Frame"}, + {1, "Continuous Low"}, + {2, "Continuous High"}, +}; +#define nFujiDriveModes (sizeof(FujiDriveModes) / sizeof(id2hr_t)) + +static id2hr_t AspectRatios[] = { + {LIBRAW_IMAGE_ASPECT_UNKNOWN, "Unknown"}, {LIBRAW_IMAGE_ASPECT_3to2, "3:2"}, + {LIBRAW_IMAGE_ASPECT_1to1, "1:1"}, {LIBRAW_IMAGE_ASPECT_4to3, "4:3"}, + {LIBRAW_IMAGE_ASPECT_16to9, "16:9"}, {LIBRAW_IMAGE_ASPECT_5to4, "5:4"}, + {LIBRAW_IMAGE_ASPECT_OTHER, "Other"}, +}; +#define nAspectRatios (sizeof(AspectRatios) / sizeof(id2hr_t)) + +static id2hr_t CanonRecordModes[] = { + {LIBRAW_Canon_RecordMode_JPEG, "JPEG"}, + {LIBRAW_Canon_RecordMode_CRW_THM, "CRW+THM"}, + {LIBRAW_Canon_RecordMode_AVI_THM, "AVI+THM"}, + {LIBRAW_Canon_RecordMode_TIF, "TIF"}, + {LIBRAW_Canon_RecordMode_TIF_JPEG, "TIF+JPEG"}, + {LIBRAW_Canon_RecordMode_CR2, "CR2"}, + {LIBRAW_Canon_RecordMode_CR2_JPEG, "CR2+JPEG"}, + {LIBRAW_Canon_RecordMode_UNKNOWN, "Unknown"}, + {LIBRAW_Canon_RecordMode_MOV, "MOV"}, + {LIBRAW_Canon_RecordMode_MP4, "MP4"}, + {LIBRAW_Canon_RecordMode_CRM, "CRM"}, + {LIBRAW_Canon_RecordMode_CR3, "CR3"}, + {LIBRAW_Canon_RecordMode_CR3_JPEG, "CR3+JPEG"}, + {LIBRAW_Canon_RecordMode_HEIF, "HEIF"}, + {LIBRAW_Canon_RecordMode_CR3_HEIF, "CR3+HEIF"}, +}; +#define nCanonRecordModes LIBRAW_Canon_RecordMode_TheLastOne + +static const struct { + const int NumId; + const char *StrId; +} CorpToStr[] = { + {LIBRAW_CAMERAMAKER_Agfa, "LIBRAW_CAMERAMAKER_Agfa"}, + {LIBRAW_CAMERAMAKER_Alcatel, "LIBRAW_CAMERAMAKER_Alcatel"}, + {LIBRAW_CAMERAMAKER_Apple, "LIBRAW_CAMERAMAKER_Apple"}, + {LIBRAW_CAMERAMAKER_Aptina, "LIBRAW_CAMERAMAKER_Aptina"}, + {LIBRAW_CAMERAMAKER_AVT, "LIBRAW_CAMERAMAKER_AVT"}, + {LIBRAW_CAMERAMAKER_Baumer, "LIBRAW_CAMERAMAKER_Baumer"}, + {LIBRAW_CAMERAMAKER_Broadcom, "LIBRAW_CAMERAMAKER_Broadcom"}, + {LIBRAW_CAMERAMAKER_Canon, "LIBRAW_CAMERAMAKER_Canon"}, + {LIBRAW_CAMERAMAKER_Casio, "LIBRAW_CAMERAMAKER_Casio"}, + {LIBRAW_CAMERAMAKER_CINE, "LIBRAW_CAMERAMAKER_CINE"}, + {LIBRAW_CAMERAMAKER_Clauss, "LIBRAW_CAMERAMAKER_Clauss"}, + {LIBRAW_CAMERAMAKER_Contax, "LIBRAW_CAMERAMAKER_Contax"}, + {LIBRAW_CAMERAMAKER_Creative, "LIBRAW_CAMERAMAKER_Creative"}, + {LIBRAW_CAMERAMAKER_DJI, "LIBRAW_CAMERAMAKER_DJI"}, + {LIBRAW_CAMERAMAKER_DXO, "LIBRAW_CAMERAMAKER_DXO"}, + {LIBRAW_CAMERAMAKER_Epson, "LIBRAW_CAMERAMAKER_Epson"}, + {LIBRAW_CAMERAMAKER_Foculus, "LIBRAW_CAMERAMAKER_Foculus"}, + {LIBRAW_CAMERAMAKER_Fujifilm, "LIBRAW_CAMERAMAKER_Fujifilm"}, + {LIBRAW_CAMERAMAKER_Generic, "LIBRAW_CAMERAMAKER_Generic"}, + {LIBRAW_CAMERAMAKER_Gione, "LIBRAW_CAMERAMAKER_Gione"}, + {LIBRAW_CAMERAMAKER_GITUP, "LIBRAW_CAMERAMAKER_GITUP"}, + {LIBRAW_CAMERAMAKER_Google, "LIBRAW_CAMERAMAKER_Google"}, + {LIBRAW_CAMERAMAKER_GoPro, "LIBRAW_CAMERAMAKER_GoPro"}, + {LIBRAW_CAMERAMAKER_Hasselblad, "LIBRAW_CAMERAMAKER_Hasselblad"}, + {LIBRAW_CAMERAMAKER_HTC, "LIBRAW_CAMERAMAKER_HTC"}, + {LIBRAW_CAMERAMAKER_I_Mobile, "LIBRAW_CAMERAMAKER_I_Mobile"}, + {LIBRAW_CAMERAMAKER_Imacon, "LIBRAW_CAMERAMAKER_Imacon"}, + {LIBRAW_CAMERAMAKER_Kodak, "LIBRAW_CAMERAMAKER_Kodak"}, + {LIBRAW_CAMERAMAKER_Konica, "LIBRAW_CAMERAMAKER_Konica"}, + {LIBRAW_CAMERAMAKER_Leaf, "LIBRAW_CAMERAMAKER_Leaf"}, + {LIBRAW_CAMERAMAKER_Leica, "LIBRAW_CAMERAMAKER_Leica"}, + {LIBRAW_CAMERAMAKER_Lenovo, "LIBRAW_CAMERAMAKER_Lenovo"}, + {LIBRAW_CAMERAMAKER_LG, "LIBRAW_CAMERAMAKER_LG"}, + {LIBRAW_CAMERAMAKER_Logitech, "LIBRAW_CAMERAMAKER_Logitech"}, + {LIBRAW_CAMERAMAKER_Mamiya, "LIBRAW_CAMERAMAKER_Mamiya"}, + {LIBRAW_CAMERAMAKER_Matrix, "LIBRAW_CAMERAMAKER_Matrix"}, + {LIBRAW_CAMERAMAKER_Meizu, "LIBRAW_CAMERAMAKER_Meizu"}, + {LIBRAW_CAMERAMAKER_Micron, "LIBRAW_CAMERAMAKER_Micron"}, + {LIBRAW_CAMERAMAKER_Minolta, "LIBRAW_CAMERAMAKER_Minolta"}, + {LIBRAW_CAMERAMAKER_Motorola, "LIBRAW_CAMERAMAKER_Motorola"}, + {LIBRAW_CAMERAMAKER_NGM, "LIBRAW_CAMERAMAKER_NGM"}, + {LIBRAW_CAMERAMAKER_Nikon, "LIBRAW_CAMERAMAKER_Nikon"}, + {LIBRAW_CAMERAMAKER_Nokia, "LIBRAW_CAMERAMAKER_Nokia"}, + {LIBRAW_CAMERAMAKER_Olympus, "LIBRAW_CAMERAMAKER_Olympus"}, + {LIBRAW_CAMERAMAKER_OmniVison, "LIBRAW_CAMERAMAKER_OmniVison"}, + {LIBRAW_CAMERAMAKER_Panasonic, "LIBRAW_CAMERAMAKER_Panasonic"}, + {LIBRAW_CAMERAMAKER_Parrot, "LIBRAW_CAMERAMAKER_Parrot"}, + {LIBRAW_CAMERAMAKER_Pentax, "LIBRAW_CAMERAMAKER_Pentax"}, + {LIBRAW_CAMERAMAKER_PhaseOne, "LIBRAW_CAMERAMAKER_PhaseOne"}, + {LIBRAW_CAMERAMAKER_PhotoControl, "LIBRAW_CAMERAMAKER_PhotoControl"}, + {LIBRAW_CAMERAMAKER_Photron, "LIBRAW_CAMERAMAKER_Photron"}, + {LIBRAW_CAMERAMAKER_Pixelink, "LIBRAW_CAMERAMAKER_Pixelink"}, + {LIBRAW_CAMERAMAKER_Polaroid, "LIBRAW_CAMERAMAKER_Polaroid"}, + {LIBRAW_CAMERAMAKER_RED, "LIBRAW_CAMERAMAKER_RED"}, + {LIBRAW_CAMERAMAKER_Ricoh, "LIBRAW_CAMERAMAKER_Ricoh"}, + {LIBRAW_CAMERAMAKER_Rollei, "LIBRAW_CAMERAMAKER_Rollei"}, + {LIBRAW_CAMERAMAKER_RoverShot, "LIBRAW_CAMERAMAKER_RoverShot"}, + {LIBRAW_CAMERAMAKER_Samsung, "LIBRAW_CAMERAMAKER_Samsung"}, + {LIBRAW_CAMERAMAKER_Sigma, "LIBRAW_CAMERAMAKER_Sigma"}, + {LIBRAW_CAMERAMAKER_Sinar, "LIBRAW_CAMERAMAKER_Sinar"}, + {LIBRAW_CAMERAMAKER_SMaL, "LIBRAW_CAMERAMAKER_SMaL"}, + {LIBRAW_CAMERAMAKER_Sony, "LIBRAW_CAMERAMAKER_Sony"}, + {LIBRAW_CAMERAMAKER_ST_Micro, "LIBRAW_CAMERAMAKER_ST_Micro"}, + {LIBRAW_CAMERAMAKER_THL, "LIBRAW_CAMERAMAKER_THL"}, + {LIBRAW_CAMERAMAKER_Xiaomi, "LIBRAW_CAMERAMAKER_Xiaomi"}, + {LIBRAW_CAMERAMAKER_XIAOYI, "LIBRAW_CAMERAMAKER_XIAOYI"}, + {LIBRAW_CAMERAMAKER_YI, "LIBRAW_CAMERAMAKER_YI"}, + {LIBRAW_CAMERAMAKER_Yuneec, "LIBRAW_CAMERAMAKER_Yuneec"}, + {LIBRAW_CAMERAMAKER_Zeiss, "LIBRAW_CAMERAMAKER_Zeiss"}, +}; + +static const struct { + const int NumId; + const char *StrId; +} ColorSpaceToStr[] = { + {LIBRAW_COLORSPACE_NotFound, "Not Found"}, + {LIBRAW_COLORSPACE_sRGB, "sRGB"}, + {LIBRAW_COLORSPACE_AdobeRGB, "Adobe RGB"}, + {LIBRAW_COLORSPACE_WideGamutRGB, "Wide Gamut RGB"}, + {LIBRAW_COLORSPACE_ProPhotoRGB, "ProPhoto RGB"}, + {LIBRAW_COLORSPACE_ICC, "ICC profile (embedded)"}, + {LIBRAW_COLORSPACE_Uncalibrated, "Uncalibrated"}, + {LIBRAW_COLORSPACE_CameraLinearUniWB, "Camera Linear, no WB"}, + {LIBRAW_COLORSPACE_CameraLinear, "Camera Linear"}, + {LIBRAW_COLORSPACE_CameraGammaUniWB, "Camera non-Linear, no WB"}, + {LIBRAW_COLORSPACE_CameraGamma, "Camera non-Linear"}, + {LIBRAW_COLORSPACE_MonochromeLinear, "Monochrome Linear"}, + {LIBRAW_COLORSPACE_MonochromeGamma, "Monochrome non-Linear"}, + {LIBRAW_COLORSPACE_Unknown, "Unknown"}, +}; + +static const struct { + const int NumId; + const int LibRawId; + const char *StrId; +} Fujifilm_WhiteBalance2Str[] = { + {0x000, LIBRAW_WBI_Auto, "Auto"}, + {0x100, LIBRAW_WBI_Daylight, "Daylight"}, + {0x200, LIBRAW_WBI_Cloudy, "Cloudy"}, + {0x300, LIBRAW_WBI_FL_D, "Daylight Fluorescent"}, + {0x301, LIBRAW_WBI_FL_N, "Day White Fluorescent"}, + {0x302, LIBRAW_WBI_FL_W, "White Fluorescent"}, + {0x303, LIBRAW_WBI_FL_WW, "Warm White Fluorescent"}, + {0x304, LIBRAW_WBI_FL_L, "Living Room Warm White Fluorescent"}, + {0x400, LIBRAW_WBI_Tungsten, "Incandescent"}, + {0x500, LIBRAW_WBI_Flash, "Flash"}, + {0x600, LIBRAW_WBI_Underwater, "Underwater"}, + {0xf00, LIBRAW_WBI_Custom, "Custom"}, + {0xf01, LIBRAW_WBI_Custom2, "Custom2"}, + {0xf02, LIBRAW_WBI_Custom3, "Custom3"}, + {0xf03, LIBRAW_WBI_Custom4, "Custom4"}, + {0xf04, LIBRAW_WBI_Custom5, "Custom5"}, + {0xff0, LIBRAW_WBI_Kelvin, "Kelvin"}, +}; + +static const struct { + const int NumId; + const char *StrId; +} Fujifilm_FilmModeToStr[] = { + {0x000, "F0/Standard (Provia)"}, + {0x100, "F1/Studio Portrait"}, + {0x110, "F1a/Studio Portrait Enhanced Saturation"}, + {0x120, "F1b/Studio Portrait Smooth Skin Tone (Astia)"}, + {0x130, "F1c/Studio Portrait Increased Sharpness"}, + {0x200, "F2/Fujichrome (Velvia)"}, + {0x300, "F3/Studio Portrait Ex"}, + {0x400, "F4/Velvia"}, + {0x500, "Pro Neg. Std"}, + {0x501, "Pro Neg. Hi"}, + {0x600, "Classic Chrome"}, + {0x700, "Eterna"}, + {0x800, "Classic Negative"}, +}; + +static const struct { + const int NumId; + const char *StrId; +} Fujifilm_DynamicRangeSettingToStr[] = { + {0x0000, "Auto (100-400%)"}, + {0x0001, "Manual"}, + {0x0100, "Standard (100%)"}, + {0x0200, "Wide1 (230%)"}, + {0x0201, "Wide2 (400%)"}, + {0x8000, "Film Simulation"}, +}; + +//clang-format on + +id2hr_t *lookup_id2hr(unsigned long long id, id2hr_t *table, ushort nEntries) +{ + for (int k = 0; k < nEntries; k++) + if (id == table[k].id) + return &table[k]; + return 0; +} + +const char *ColorSpace_idx2str(ushort ColorSpace) { + for (unsigned i = 0; i < (sizeof ColorSpaceToStr / sizeof *ColorSpaceToStr); i++) + if(ColorSpaceToStr[i].NumId == ColorSpace) + return ColorSpaceToStr[i].StrId; + return 0; +} + +const char *CameraMaker_idx2str(unsigned maker) { + for (unsigned i = 0; i < (sizeof CorpToStr / sizeof *CorpToStr); i++) + if(CorpToStr[i].NumId == (int)maker) + return CorpToStr[i].StrId; + return 0; +} + +const char *WB_idx2str(unsigned WBi) { + for (int i = 0; i < int(sizeof WBToStr / sizeof *WBToStr); i++) + if(WBToStr[i].NumId == (int)WBi) + return WBToStr[i].StrId; + return 0; +} + +const char *WB_idx2hrstr(unsigned WBi) { + for (int i = 0; i < int(sizeof WBToStr / sizeof *WBToStr); i++) + if(WBToStr[i].NumId == (int)WBi) + return WBToStr[i].hrStrId; + return 0; +} + +const char *Fujifilm_WhiteBalance_idx2str(ushort WB) { + for (int i = 0; i < int(sizeof Fujifilm_WhiteBalance2Str / sizeof *Fujifilm_WhiteBalance2Str); i++) + if(Fujifilm_WhiteBalance2Str[i].NumId == WB) + return Fujifilm_WhiteBalance2Str[i].StrId; + return 0; +} + +const char *Fujifilm_FilmMode_idx2str(ushort FilmMode) { + for (int i = 0; i < int(sizeof Fujifilm_FilmModeToStr / sizeof *Fujifilm_FilmModeToStr); i++) + if(Fujifilm_FilmModeToStr[i].NumId == FilmMode) + return Fujifilm_FilmModeToStr[i].StrId; + return 0; +} + +const char *Fujifilm_DynamicRangeSetting_idx2str(ushort DynamicRangeSetting) { + for (int i = 0; i < int(sizeof Fujifilm_DynamicRangeSettingToStr / sizeof *Fujifilm_DynamicRangeSettingToStr); i++) + if(Fujifilm_DynamicRangeSettingToStr[i].NumId == DynamicRangeSetting) + return Fujifilm_DynamicRangeSettingToStr[i].StrId; + return 0; +} + +void trimSpaces(char *s) +{ + char *p = s; + if (!strncasecmp(p, "NO=", 3)) + p = p + 3; /* fix for Nikon D70, D70s */ + int l = strlen(p); + if (!l) + return; + while (isspace(p[l - 1])) + p[--l] = 0; /* trim trailing spaces */ + while (*p && isspace(*p)) + ++p, --l; /* trim leading spaces */ + memmove(s, p, l + 1); +} + +struct file_mapping +{ + void *map; + INT64 fsize; +#ifdef LIBRAW_WIN32_CALLS + HANDLE fd,fd_map; + file_mapping() : map(0), fsize(0), fd(INVALID_HANDLE_VALUE), fd_map(INVALID_HANDLE_VALUE){} +#else + int fd; + file_mapping() : map(0), fsize(0), fd(-1){} +#endif +}; + + + +void timer_start(starttime_t& r) +{ +#ifdef LIBRAW_WIN32_CALLS + QueryPerformanceCounter(&r.started); +#else + gettimeofday(&r.started,NULL); +#endif +} + +double timer_elapsed(const starttime_t& start) +{ +#ifdef LIBRAW_WIN32_CALLS + LARGE_INTEGER ended, freq; + QueryPerformanceCounter(&ended); + QueryPerformanceFrequency(&freq); + return double(ended.QuadPart - start.started.QuadPart) / double(freq.QuadPart); +#else + struct timeval ended; + gettimeofday(&ended, NULL); + return double(ended.tv_sec - start.started.tv_sec) + double(ended.tv_usec - start.started.tv_usec) / 1000000.0; +#endif +} + + +void create_mapping(struct file_mapping& data, const std::string& fn) +{ +#ifdef LIBRAW_WIN32_CALLS + std::wstring fpath(fn.begin(), fn.end()); + if ((data.fd = CreateFileW(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) return; + LARGE_INTEGER fs; + if(!GetFileSizeEx(data.fd,&fs)) return; + data.fsize = fs.QuadPart; + if((data.fd_map = ::CreateFileMapping(data.fd, 0, PAGE_READONLY, fs.HighPart, fs.LowPart, 0)) == INVALID_HANDLE_VALUE) return; + data.map = MapViewOfFile(data.fd_map,FILE_MAP_READ,0,0,data.fsize); +#else + struct stat stt; + if ((data.fd = open(fn.c_str(), O_RDONLY)) < 0) return; + if (fstat(data.fd, &stt) != 0) return; + data.fsize = stt.st_size; + data.map = mmap(0, data.fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, data.fd, 0); + return; +#endif +} + +void close_mapping(struct file_mapping& data) +{ +#ifdef LIBRAW_WIN32_CALLS + if (data.map) UnmapViewOfFile(data.map); + if (data.fd_map != INVALID_HANDLE_VALUE) CloseHandle(data.fd_map); + if (data.fd != INVALID_HANDLE_VALUE) CloseHandle(data.fd); + data.map = 0; + data.fsize = 0; + data.fd = data.fd_map = INVALID_HANDLE_VALUE; +#else + if (data.map) + munmap(data.map, data.fsize); + if (data.fd>=0) + close(data.fd); + data.map = 0; + data.fsize = 0; + data.fd = -1; +#endif +} + +void print_usage(const char *pname) +{ + printf("Usage: %s [options] inputfiles\n", pname); + printf("Options:\n" + "\t-c\tcompact output\n" + "\t-n\tprint make/model and norm. make/model\n" + "\t-v\tverbose output\n" + "\t-w\tprint white balance\n" + "\t-j\tprint JSON\n" + "\t-u\tprint unpack function\n" + "\t-f\tprint frame size (only w/ -u)\n" + "\t-s\tprint output image size\n" + "\t-h\tforce half-size mode (only for -s)\n" + "\t-M\tdisable use of raw-embedded color data\n" + "\t+M\tforce use of raw-embedded color data\n" + "\t-L filename\tread input files list from filename\n" + "\t-o filename\toutput to filename\n"); +} + +int main(int ac, char *av[]) +{ + int ret; + int verbose = 0, print_sz = 0, print_unpack = 0, print_frame = 0, + print_wb = 0, print_json = 0, use_map = 0, use_timing = 0; + struct file_mapping mapping; + int compact = 0, normalized = 0, print_0 = 0, print_1 = 0, print_2 = 0; + LibRaw MyCoolRawProcessor; + char *filelistfile = NULL; + char *outputfilename = NULL; + FILE *outfile = stdout; + std::vector <std::string> filelist; + starttime_t started; + + filelist.reserve(ac - 1); + + for (int i = 1; i < ac; i++) + { + if (av[i][0] == '-') + { + if (!strcmp(av[i], "-c")) compact++; + if (!strcmp(av[i], "-n")) normalized++; + if (!strcmp(av[i], "-v")) verbose++; + if (!strcmp(av[i], "-w")) print_wb++; + if (!strcmp(av[i], "-j")) print_json++; + if (!strcmp(av[i], "-u")) print_unpack++; + if (!strcmp(av[i], "-m")) use_map++; + if (!strcmp(av[i], "-t")) use_timing++; + if (!strcmp(av[i], "-s")) print_sz++; + if (!strcmp(av[i], "-h")) O.half_size = 1; + if (!strcmp(av[i], "-f")) print_frame++; + if (!strcmp(av[i], "-0")) print_0++; + if (!strcmp(av[i], "-1")) print_1++; + if (!strcmp(av[i], "-2")) print_2++; + if (!strcmp(av[i], "-M")) MyCoolRawProcessor.imgdata.params.use_camera_matrix = 0; + if (!strcmp(av[i], "-L") && i < ac - 1) + { + filelistfile = av[i + 1]; + i++; + } + if (!strcmp(av[i], "-o") && i < ac - 1) + { + outputfilename = av[i + 1]; + i++; + } + continue; + } + else if (!strcmp(av[i], "+M")) + { + MyCoolRawProcessor.imgdata.params.use_camera_matrix = 3; + continue; + } + filelist.push_back(av[i]); + } + if(filelistfile) + { + char *p; + char path[MAX_PATH + 1]; + FILE *f = fopen(filelistfile, "r"); + if (f) + { + while (fgets(path,MAX_PATH,f)) + { + if ((p = strchr(path, '\n'))) *p = 0; + if ((p = strchr(path, '\r'))) *p = 0; + filelist.push_back(path); + } + fclose(f); + } + } + if (filelist.size()<1) + { + print_usage(av[0]); + return 1; + } + if (outputfilename) + outfile = fopen(outputfilename, "wt"); + + timer_start(started); + for (int i = 0; i < (int)filelist.size(); i++) + { + if (use_map) + { + create_mapping(mapping, filelist[i]); + if (!mapping.map) + { + fprintf(stderr, "Cannot map %s\n", filelist[i].c_str()); + close_mapping(mapping); + continue; + } + + if ((ret = MyCoolRawProcessor.open_buffer(mapping.map, mapping.fsize)) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot decode %s: %s\n", filelist[i].c_str(), libraw_strerror(ret)); + close_mapping(mapping); + continue; + } + } + else + if ((ret = MyCoolRawProcessor.open_file(filelist[i].c_str())) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot decode %s: %s\n", filelist[i].c_str(), libraw_strerror(ret)); + continue; // no recycle, open_file will recycle + } + + if (use_timing) + { + /* nothing!*/ + } + else if (print_sz) + print_szfun(outfile, MyCoolRawProcessor, filelist[i]); + else if (print_0) + print_0fun(outfile, MyCoolRawProcessor, filelist[i]); + else if (print_1) + print_1fun(outfile, MyCoolRawProcessor, filelist[i]); + else if (print_2) + print_2fun(outfile, MyCoolRawProcessor, filelist[i]); + else if (verbose) + print_verbose(outfile, MyCoolRawProcessor, filelist[i]); + else if (print_unpack) + print_unpackfun(outfile, MyCoolRawProcessor, print_frame, filelist[i]); + else if (print_wb) + print_wbfun(outfile, MyCoolRawProcessor, filelist[i]); + else if (compact) + print_compactfun(outfile, MyCoolRawProcessor, filelist[i]); + else if (normalized) + print_normfun(outfile, MyCoolRawProcessor, filelist[i]); + else if (print_json) + print_jsonfun(outfile, MyCoolRawProcessor, filelist[i], i, filelist.size()); + else + fprintf(outfile, "%s is a %s %s image.\n", filelist[i].c_str(), P1.make, P1.model); + + MyCoolRawProcessor.recycle(); + if (use_map) + close_mapping(mapping); + } // endfor + + if (use_timing && filelist.size() > 0) + print_timer(outfile, started, filelist.size()); + return 0; +} + +void print_timer(FILE* outfile, const starttime_t& started, int files) +{ + double elapsed = timer_elapsed(started); + if (elapsed > 1.0) + fprintf(outfile, "%d files processed in %5.3f sec, %5.3g files/sec\n", files, elapsed, files / elapsed); + else if (elapsed > 0.001) // 1msec + { + double msec = elapsed * 1000.0; + fprintf(outfile, "%d files processed in %5.3f msec, %5.3g files/sec\n", files, msec, files / elapsed); + } + else if (elapsed > 0.000001) + { + double usec = elapsed * 1000000.0; + fprintf(outfile, "%d files processed in %5.3f usec, %5.3g files/sec\n", files, usec, files / elapsed); + } + else + fprintf(outfile, "%d files processed, time too small to estimate\n", files); +} + +void print_jsonfun(FILE* outfile, LibRaw& MyCoolRawProcessor, + std::string& fn, int fnum, int nfiles) { + + const int tab_width = 4; + int n_tabs; + const char tab_char = ' '; + const char *CamMakerName = CameraMaker_idx2str(P1.maker_index); + int WBi; + int data_present = 0; + + if (fnum == 0) fprintf (outfile, "{\n"); + n_tabs = 1; + fprintf (outfile, "%*c\"file_%05d\":{\n", + n_tabs*tab_width, tab_char, fnum); + n_tabs++; + + fprintf (outfile, "%*c\"file_name\":", n_tabs*tab_width, tab_char); + if (fn.c_str()[0]) fprintf (outfile, "\"%s\",\n", fn.c_str()); + else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"cam_maker\":", n_tabs*tab_width, tab_char); + if (CamMakerName[0]) fprintf (outfile, "\"%s\",\n", CamMakerName); + else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"norm_model\":", n_tabs*tab_width, tab_char); + if (P1.normalized_model[0]) fprintf (outfile, "\"%s\",\n", P1.normalized_model); + else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"body_serial\":", n_tabs*tab_width, tab_char); + if (ShootingInfo.BodySerial[0] && + strcmp(ShootingInfo.BodySerial, "0")) { + trimSpaces(ShootingInfo.BodySerial); + fprintf (outfile, "\"%s\",\n", ShootingInfo.BodySerial); + } else if (C.model2[0] && + (!strncasecmp(P1.normalized_make, "Kodak", 5))) { + trimSpaces(C.model2); + fprintf (outfile, "\"%s\",\n", C.model2); + } else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"int_serial\":", n_tabs*tab_width, tab_char); + if (ShootingInfo.InternalBodySerial[0]) { + trimSpaces(ShootingInfo.InternalBodySerial); + fprintf (outfile, "\"%s\",\n", ShootingInfo.InternalBodySerial); + } else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"dng\":%s,\n", + n_tabs*tab_width, tab_char, P1.dng_version?"true":"false"); + + fprintf (outfile, "%*c\"ISO\":", n_tabs*tab_width, tab_char); + if (P2.iso_speed > 0.1f) fprintf (outfile, "%d,\n", int(P2.iso_speed)); + else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"BLE\":", n_tabs*tab_width, tab_char); + if (int(C.dng_levels.baseline_exposure) != -999) + fprintf (outfile, "%g,\n", C.dng_levels.baseline_exposure); + else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"CameraCalibration\":", n_tabs*tab_width, tab_char); + for (int n = 0; n < 2; n++) { + if (fabsf(C.dng_color[n].calibration[0][0]) > 0) { + int numel = 3; + if (fabsf(C.dng_color[n].calibration[3][3]) > 0) numel = 4; + if (!data_present) { + fprintf (outfile, "{"); + n_tabs++; + } else fprintf (outfile, ","); + fprintf (outfile, "\n%*c\"%s\":", + n_tabs*tab_width, tab_char, WB_idx2str(C.dng_color[n].illuminant)); + for (int cnt = 0; cnt < numel; cnt++) { + fprintf (outfile, "%s%g%s", (!cnt)?"[":"", + C.dng_color[n].calibration[cnt][cnt], (cnt < (numel - 1))?",":"]"); + } + data_present++; + } + } + if (data_present) { + data_present = 0; + n_tabs--; + fprintf (outfile, "\n%*c},\n", n_tabs*tab_width, tab_char); + } else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"ColorMatrix\":", n_tabs*tab_width, tab_char); + for (int n = 0; n < 2; n++) { + if (fabsf(C.dng_color[n].colormatrix[0][0]) > 0) { + int numel = 3; + if (!data_present) { + fprintf (outfile, "{"); + n_tabs++; + } else fprintf (outfile, ","); + fprintf (outfile, "\n%*c\"%s\":", + n_tabs*tab_width, tab_char, WB_idx2str(C.dng_color[n].illuminant)); + for (int i = 0; i < P1.colors; i++) { + for (int cnt = 0; cnt < numel; cnt++) { + fprintf (outfile, "%s%g%s", (!i&&!cnt)?"[":"", + C.dng_color[n].colormatrix[i][cnt], + ((i<(P1.colors-1)) || (cnt < (numel - 1)))?",":"]"); + } + } + data_present++; + } + } + if (data_present) { + data_present = 0; + n_tabs--; + fprintf (outfile, "\n%*c},\n", n_tabs*tab_width, tab_char); + } else fprintf (outfile, "null,\n"); + + fprintf (outfile, "%*c\"WB data\":", + n_tabs*tab_width, tab_char); + + if (C.cam_mul[0]) { + if (!data_present) { + fprintf (outfile, "{"); + n_tabs++; + } else fprintf (outfile, ","); + fprintf (outfile, "\n%*c\"%s\":", + n_tabs*tab_width, tab_char, WB_idx2str(LIBRAW_WBI_AsShot)); + for (int i = 0; i < 4; i++) { + fprintf (outfile, "%s%g%s", (!i)?"[":"", + C.cam_mul[i], (i < 3)?",":"]"); + } + data_present++; + } + + for (int cnt = 0; cnt < int(sizeof WBToStr / sizeof *WBToStr); cnt++) { + WBi = WBToStr[cnt].NumId; + if (C.WB_Coeffs[WBi][0]) { + if (!data_present) { + fprintf (outfile, "{"); + n_tabs++; + } else fprintf (outfile, ","); + fprintf (outfile, "\n%*c\"%s\":", + n_tabs*tab_width, tab_char, WBToStr[cnt].StrId); + for (int i = 0; i < 4; i++) { + fprintf (outfile, "%s%d%s", (!i)?"[":"", + C.WB_Coeffs[WBi][i], (i < 3)?",":"]"); + } + data_present++; + } + } + + for (int cnt = 0; cnt < 64; cnt++) { + if (C.WBCT_Coeffs[cnt][0]) { + if (!data_present) { + fprintf (outfile, "{"); + n_tabs++; + } else fprintf (outfile, ","); + fprintf (outfile, "\n%*c\"%g\":", + n_tabs*tab_width, tab_char, C.WBCT_Coeffs[cnt][0]); + for (int i = 1; i < 5; i++) { + fprintf (outfile, "%s%g%s", (i == 1)?"[":"", + C.WBCT_Coeffs[cnt][i], (i < 4)?",":"]"); + } + data_present++; + } + } + + if (data_present) { + data_present = 0; + n_tabs--; + fprintf (outfile, "\n%*c}\n", n_tabs*tab_width, tab_char); + } else fprintf (outfile, "null\n"); + + n_tabs--; + fprintf (outfile, "%*c}\n", n_tabs*tab_width, tab_char); + + if ((fnum+1) == nfiles) fprintf (outfile, "}\n"); + else fprintf (outfile, ","); +} + +#define PRINTMATRIX3x4(of,mat,clrs) \ + do{ \ + for(int r = 0; r < 3; r++) \ + if(clrs==4) \ + fprintf(of, "%6.4f\t%6.4f\t%6.4f\t%6.4f\n", mat[r][0],mat[r][1],mat[r][2],mat[r][3]); \ + else \ + fprintf(of, "%6.4f\t%6.4f\t%6.4f\n", mat[r][0],mat[r][1],mat[r][2]); \ + }while(0) + +#define PRINTMATRIX4x3(of,mat,clrs) \ + do{ \ + for(int r = 0; r < clrs && r < 4; r++) \ + fprintf(of, "%6.4f\t%6.4f\t%6.4f\n", mat[r][0],mat[r][1],mat[r][2]); \ + }while(0) + + +void print_verbose(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + id2hr_t *MountName, *FormatName, *Aspect, *Crop, *DriveMode; + const char *CamMakerName = LibRaw::cameramakeridx2maker(P1.maker_index); + const char *ColorSpaceName = ColorSpace_idx2str(P3.ColorSpace); + int WBi; + float denom; + int ret; + + if ((ret = MyCoolRawProcessor.adjust_sizes_info_only())) + { + fprintf(outfile, "Cannot decode %s: %s\n", fn.c_str(), libraw_strerror(ret)); + return; // no recycle, open_file will recycle + } + + fprintf(outfile, "\nFilename: %s\n", fn.c_str()); + if (C.OriginalRawFileName[0]) + fprintf(outfile, "OriginalRawFileName: =%s=\n", C.OriginalRawFileName); + fprintf(outfile, "Timestamp: %s", ctime(&(P2.timestamp))); + fprintf(outfile, "Camera: %s %s ID: 0x%llx\n", P1.make, P1.model, mnLens.CamID); + fprintf(outfile, "Normalized Make/Model: =%s/%s= ", P1.normalized_make, + P1.normalized_model); + fprintf(outfile, "CamMaker ID: %d, ", P1.maker_index); + if (CamMakerName) + fprintf(outfile, "%s\n", CamMakerName); + else + fprintf(outfile, "Undefined\n"); + { + int i = 0; + char sep[] = ", "; + if (C.UniqueCameraModel[0]) { + i++; + fprintf(outfile, "UniqueCameraModel: =%s=", C.UniqueCameraModel); + } + if (C.LocalizedCameraModel[0]) { + if (i) { + fprintf(outfile, "%s", sep); + i++; + } + fprintf(outfile, "LocalizedCameraModel: =%s=", C.LocalizedCameraModel); + } + if (i) { + fprintf(outfile, "\n"); + i = 0; + } + if (C.ImageUniqueID[0]) { + if (i) fprintf(outfile, "%s", sep); + i++; + fprintf(outfile, "ImageUniqueID: =%s=", C.ImageUniqueID); + } + if (C.RawDataUniqueID[0]) { + if (i) fprintf(outfile, "%s", sep); + i++; + fprintf(outfile, "RawDataUniqueID: =%s=", C.RawDataUniqueID); + } + if (i) fprintf(outfile, "\n"); + } + + if (ShootingInfo.BodySerial[0] && strcmp(ShootingInfo.BodySerial, "0")) + { + trimSpaces(ShootingInfo.BodySerial); + fprintf(outfile, "Body#: %s", ShootingInfo.BodySerial); + } + else if (C.model2[0] && (!strncasecmp(P1.normalized_make, "Kodak", 5))) + { + trimSpaces(C.model2); + fprintf(outfile, "Body#: %s", C.model2); + } + if (ShootingInfo.InternalBodySerial[0]) + { + trimSpaces(ShootingInfo.InternalBodySerial); + fprintf(outfile, " BodyAssy#: %s", ShootingInfo.InternalBodySerial); + } + if (exifLens.LensSerial[0]) + { + trimSpaces(exifLens.LensSerial); + fprintf(outfile, " Lens#: %s", exifLens.LensSerial); + } + if (exifLens.InternalLensSerial[0]) + { + trimSpaces(exifLens.InternalLensSerial); + fprintf(outfile, " LensAssy#: %s", exifLens.InternalLensSerial); + } + if (P2.artist[0]) + fprintf(outfile, " Owner: %s\n", P2.artist); + if (P1.dng_version) + { + fprintf(outfile, " DNG Version: "); + for (int i = 24; i >= 0; i -= 8) + fprintf(outfile, "%d%c", P1.dng_version >> i & 255, i ? '.' : '\n'); + } + fprintf(outfile, "\nEXIF:\n"); + fprintf(outfile, "\tMinFocal: %0.1f mm\n", exifLens.MinFocal); + fprintf(outfile, "\tMaxFocal: %0.1f mm\n", exifLens.MaxFocal); + fprintf(outfile, "\tMaxAp @MinFocal: f/%0.1f\n", exifLens.MaxAp4MinFocal); + fprintf(outfile, "\tMaxAp @MaxFocal: f/%0.1f\n", exifLens.MaxAp4MaxFocal); + fprintf(outfile, "\tCurFocal: %0.1f mm\n", P2.focal_len); + fprintf(outfile, "\tMaxAperture @CurFocal: f/%0.1f\n", exifLens.EXIF_MaxAp); + fprintf(outfile, "\tFocalLengthIn35mmFormat: %d mm\n", + exifLens.FocalLengthIn35mmFormat); + fprintf(outfile, "\tLensMake: %s\n", exifLens.LensMake); + fprintf(outfile, "\tLens: %s\n", exifLens.Lens); + fprintf(outfile, "\n"); + + fprintf(outfile, "\nMakernotes:\n"); + fprintf(outfile, "\tDriveMode: %d\n", ShootingInfo.DriveMode); + fprintf(outfile, "\tFocusMode: %d\n", ShootingInfo.FocusMode); + fprintf(outfile, "\tMeteringMode: %d\n", ShootingInfo.MeteringMode); + fprintf(outfile, "\tAFPoint: %d\n", ShootingInfo.AFPoint); + fprintf(outfile, "\tExposureMode: %d\n", ShootingInfo.ExposureMode); + fprintf(outfile, "\tExposureProgram: %d\n", ShootingInfo.ExposureProgram); + fprintf(outfile, "\tImageStabilization: %d\n", ShootingInfo.ImageStabilization); + if (mnLens.body[0]) + { + fprintf(outfile, "\tHost Body: %s\n", mnLens.body); + } + if (Hasselblad.CaptureSequenceInitiator[0]) + { + fprintf(outfile, "\tInitiator: %s\n", Hasselblad.CaptureSequenceInitiator); + } + if (Hasselblad.SensorUnitConnector[0]) + { + fprintf(outfile, "\tSU Connector: %s\n", Hasselblad.SensorUnitConnector); + } + fprintf(outfile, "\tCameraFormat: %d, ", mnLens.CameraFormat); + FormatName = lookup_id2hr(mnLens.CameraFormat, FormatNames, LIBRAW_FORMAT_TheLastOne); + if (FormatName) + fprintf(outfile, "%s\n", FormatName->name); + else + fprintf(outfile, "Unknown\n"); + + if (!strncasecmp(P1.make, "Nikon", 5) && Nikon.SensorHighSpeedCrop.cwidth) + { + fprintf(outfile, "\tNikon crop: %d, ", Nikon.HighSpeedCropFormat); + Crop = lookup_id2hr(Nikon.HighSpeedCropFormat, NikonCrops, nNikonCrops); + if (Crop) + fprintf(outfile, "%s\n", Crop->name); + else + fprintf(outfile, "Unknown\n"); + fprintf(outfile, "\tSensor used area %d x %d; crop from: %d x %d at top left " + "pixel: (%d, %d)\n", + Nikon.SensorWidth, Nikon.SensorHeight, + Nikon.SensorHighSpeedCrop.cwidth, + Nikon.SensorHighSpeedCrop.cheight, + Nikon.SensorHighSpeedCrop.cleft, Nikon.SensorHighSpeedCrop.ctop); + } + + fprintf(outfile, "\tCameraMount: %d, ", mnLens.CameraMount); + MountName = lookup_id2hr(mnLens.CameraMount, MountNames, LIBRAW_MOUNT_TheLastOne); + if (MountName) + fprintf(outfile, "%s\n", MountName->name); + else + fprintf(outfile, "Unknown\n"); + + if (mnLens.LensID == 0xffffffff) + fprintf(outfile, "\tLensID: n/a\n"); + else + fprintf(outfile, "\tLensID: %llu 0x%0llx\n", mnLens.LensID, mnLens.LensID); + + fprintf(outfile, "\tLens: %s\n", mnLens.Lens); + fprintf(outfile, "\tLensFormat: %d, ", mnLens.LensFormat); + FormatName = lookup_id2hr(mnLens.LensFormat, FormatNames, LIBRAW_FORMAT_TheLastOne); + if (FormatName) + fprintf(outfile, "%s\n", FormatName->name); + else + fprintf(outfile, "Unknown\n"); + + fprintf(outfile, "\tLensMount: %d, ", mnLens.LensMount); + MountName = lookup_id2hr(mnLens.LensMount, MountNames, LIBRAW_MOUNT_TheLastOne); + if (MountName) + fprintf(outfile, "%s\n", MountName->name); + else + fprintf(outfile, "Unknown\n"); + + fprintf(outfile, "\tFocalType: %d, ", mnLens.FocalType); + switch (mnLens.FocalType) + { + case LIBRAW_FT_UNDEFINED: + fprintf(outfile, "Undefined\n"); + break; + case LIBRAW_FT_PRIME_LENS: + fprintf(outfile, "Prime lens\n"); + break; + case LIBRAW_FT_ZOOM_LENS: + fprintf(outfile, "Zoom lens\n"); + break; + default: + fprintf(outfile, "Unknown\n"); + break; + } + fprintf(outfile, "\tLensFeatures_pre: %s\n", mnLens.LensFeatures_pre); + fprintf(outfile, "\tLensFeatures_suf: %s\n", mnLens.LensFeatures_suf); + fprintf(outfile, "\tMinFocal: %0.1f mm\n", mnLens.MinFocal); + fprintf(outfile, "\tMaxFocal: %0.1f mm\n", mnLens.MaxFocal); + fprintf(outfile, "\tMaxAp @MinFocal: f/%0.1f\n", mnLens.MaxAp4MinFocal); + fprintf(outfile, "\tMaxAp @MaxFocal: f/%0.1f\n", mnLens.MaxAp4MaxFocal); + fprintf(outfile, "\tMinAp @MinFocal: f/%0.1f\n", mnLens.MinAp4MinFocal); + fprintf(outfile, "\tMinAp @MaxFocal: f/%0.1f\n", mnLens.MinAp4MaxFocal); + fprintf(outfile, "\tMaxAp: f/%0.1f\n", mnLens.MaxAp); + fprintf(outfile, "\tMinAp: f/%0.1f\n", mnLens.MinAp); + fprintf(outfile, "\tCurFocal: %0.1f mm\n", mnLens.CurFocal); + fprintf(outfile, "\tCurAp: f/%0.1f\n", mnLens.CurAp); + fprintf(outfile, "\tMaxAp @CurFocal: f/%0.1f\n", mnLens.MaxAp4CurFocal); + fprintf(outfile, "\tMinAp @CurFocal: f/%0.1f\n", mnLens.MinAp4CurFocal); + + if (exifLens.makernotes.FocalLengthIn35mmFormat > 1.0f) + fprintf(outfile, "\tFocalLengthIn35mmFormat: %0.1f mm\n", + exifLens.makernotes.FocalLengthIn35mmFormat); + + if (exifLens.nikon.EffectiveMaxAp > 0.1f) + fprintf(outfile, "\tEffectiveMaxAp: f/%0.1f\n", + exifLens.nikon.EffectiveMaxAp); + + if (exifLens.makernotes.LensFStops > 0.1f) + fprintf(outfile, "\tLensFStops @CurFocal: %0.2f\n", + exifLens.makernotes.LensFStops); + + fprintf(outfile, "\tTeleconverterID: %lld\n", mnLens.TeleconverterID); + fprintf(outfile, "\tTeleconverter: %s\n", mnLens.Teleconverter); + fprintf(outfile, "\tAdapterID: %lld\n", mnLens.AdapterID); + fprintf(outfile, "\tAdapter: %s\n", mnLens.Adapter); + fprintf(outfile, "\tAttachmentID: %lld\n", mnLens.AttachmentID); + fprintf(outfile, "\tAttachment: %s\n", mnLens.Attachment); + fprintf(outfile, "\n"); + + fprintf(outfile, "ISO speed: %d\n", (int)P2.iso_speed); + if (P3.real_ISO > 0.1f) + fprintf(outfile, "real ISO speed: %d\n", (int)P3.real_ISO); + fprintf(outfile, "Shutter: "); + if (P2.shutter > 0 && P2.shutter < 1) + P2.shutter = fprintf(outfile, "1/%0.1f\n", 1.0f / P2.shutter); + else if (P2.shutter >= 1) + fprintf(outfile, "%0.1f sec\n", P2.shutter); + else /* negative*/ + fprintf(outfile, " negative value\n"); + fprintf(outfile, "Aperture: f/%0.1f\n", P2.aperture); + fprintf(outfile, "Focal length: %0.1f mm\n", P2.focal_len); + if (P3.exifAmbientTemperature > -273.15f) + fprintf(outfile, "Ambient temperature (exif data): %6.2f° C\n", + P3.exifAmbientTemperature); + if (P3.CameraTemperature > -273.15f) + fprintf(outfile, "Camera temperature: %6.2f° C\n", P3.CameraTemperature); + if (P3.SensorTemperature > -273.15f) + fprintf(outfile, "Sensor temperature: %6.2f° C\n", P3.SensorTemperature); + if (P3.SensorTemperature2 > -273.15f) + fprintf(outfile, "Sensor temperature2: %6.2f° C\n", P3.SensorTemperature2); + if (P3.LensTemperature > -273.15f) + fprintf(outfile, "Lens temperature: %6.2f° C\n", P3.LensTemperature); + if (P3.AmbientTemperature > -273.15f) + fprintf(outfile, "Ambient temperature: %6.2f° C\n", P3.AmbientTemperature); + if (P3.BatteryTemperature > -273.15f) + fprintf(outfile, "Battery temperature: %6.2f° C\n", P3.BatteryTemperature); + if (P3.FlashGN > 1.0f) + fprintf(outfile, "Flash Guide Number: %6.2f\n", P3.FlashGN); + fprintf(outfile, "Flash exposure compensation: %0.2f EV\n", P3.FlashEC); + if (C.profile) + fprintf(outfile, "Embedded ICC profile: yes, %d bytes\n", C.profile_length); + else + fprintf(outfile, "Embedded ICC profile: no\n"); + + if (C.dng_levels.baseline_exposure > -999.f) + fprintf(outfile, "Baseline exposure: %04.3f\n", C.dng_levels.baseline_exposure); + + fprintf(outfile, "Number of raw images: %d\n", P1.raw_count); + + if (Fuji.DriveMode != -1) + { + fprintf(outfile, "Fuji Drive Mode: %d, ", Fuji.DriveMode); + DriveMode = + lookup_id2hr(Fuji.DriveMode, FujiDriveModes, nFujiDriveModes); + if (DriveMode) + fprintf(outfile, "%s\n", DriveMode->name); + else + fprintf(outfile, "Unknown\n"); + } + + if (Fuji.CropMode) + { + fprintf(outfile, "Fuji Crop Mode: %d, ", Fuji.CropMode); + Crop = lookup_id2hr(Fuji.CropMode, FujiCrops, nFujiCrops); + if (Crop) + fprintf(outfile, "%s\n", Crop->name); + else + fprintf(outfile, "Unknown\n"); + } + + if (Fuji.WB_Preset != 0xffff) + fprintf(outfile, "Fuji WB preset: 0x%03x, %s\n", Fuji.WB_Preset, Fujifilm_WhiteBalance_idx2str(Fuji.WB_Preset)); + if (Fuji.ExpoMidPointShift > -999.f) // tag 0x9650 + fprintf(outfile, "Fuji Exposure shift: %04.3f\n", Fuji.ExpoMidPointShift); + if (Fuji.DynamicRange != 0xffff) + fprintf(outfile, "Fuji Dynamic Range (0x1400): %d, %s\n", + Fuji.DynamicRange, Fuji.DynamicRange==1?"Standard":"Wide"); + if (Fuji.FilmMode != 0xffff) + fprintf(outfile, "Fuji Film Mode (0x1401): 0x%03x, %s\n", Fuji.FilmMode, Fujifilm_FilmMode_idx2str(Fuji.FilmMode)); + if (Fuji.DynamicRangeSetting != 0xffff) + fprintf(outfile, "Fuji Dynamic Range Setting (0x1402): 0x%04x, %s\n", + Fuji.DynamicRangeSetting, Fujifilm_DynamicRangeSetting_idx2str(Fuji.DynamicRangeSetting)); + if (Fuji.DevelopmentDynamicRange != 0xffff) + fprintf(outfile, "Fuji Development Dynamic Range (0x1403): %d\n", + Fuji.DevelopmentDynamicRange); + if (Fuji.AutoDynamicRange != 0xffff) + fprintf(outfile, "Fuji Auto Dynamic Range (0x140b): %d\n", Fuji.AutoDynamicRange); + if (Fuji.DRangePriority != 0xffff) + fprintf(outfile, "Fuji Dynamic Range priority (0x1443): %d, %s\n", + Fuji.DRangePriority, Fuji.DRangePriority?"Fixed":"Auto"); + if (Fuji.DRangePriorityAuto) + fprintf(outfile, "Fuji Dynamic Range priority Auto (0x1444): %d, %s\n", + Fuji.DRangePriorityAuto, Fuji.DRangePriorityAuto==1?"Weak":"Strong"); + if (Fuji.DRangePriorityFixed) + fprintf(outfile, "Fuji Dynamic Range priority Fixed (0x1445): %d, %s\n", + Fuji.DRangePriorityFixed, Fuji.DRangePriorityFixed==1?"Weak":"Strong"); + + if (S.pixel_aspect != 1) + fprintf(outfile, "Pixel Aspect Ratio: %0.6f\n", S.pixel_aspect); + if (T.tlength) + fprintf(outfile, "Thumb size: %4d x %d\n", T.twidth, T.theight); + fprintf(outfile, "Full size: %4d x %d\n", S.raw_width, S.raw_height); + + if (S.raw_inset_crop.cwidth) + { + fprintf(outfile, "Raw inset, width x height: %4d x %d ", S.raw_inset_crop.cwidth, + S.raw_inset_crop.cheight); + if (S.raw_inset_crop.cleft != 0xffff) + fprintf(outfile, "left: %d ", S.raw_inset_crop.cleft); + if (S.raw_inset_crop.ctop != 0xffff) + fprintf(outfile, "top: %d", S.raw_inset_crop.ctop); + fprintf(outfile, "\n"); + } + + fprintf(outfile, "Aspect: "); + Aspect = + lookup_id2hr(S.raw_inset_crop.aspect, AspectRatios, nAspectRatios); + if (Aspect) + fprintf(outfile, "%s\n", Aspect->name); + else + fprintf(outfile, "Other %d\n", S.raw_inset_crop.aspect); + + fprintf(outfile, "Image size: %4d x %d\n", S.width, S.height); + fprintf(outfile, "Output size: %4d x %d\n", S.iwidth, S.iheight); + fprintf(outfile, "Image flip: %d\n", S.flip); + + if (Canon.RecordMode) { + id2hr_t *RecordMode = + lookup_id2hr(Canon.RecordMode, CanonRecordModes, nCanonRecordModes); + fprintf(outfile, "Canon record mode: %d, %s\n", Canon.RecordMode, RecordMode->name); + } + if (Canon.SensorWidth) + fprintf(outfile, "SensorWidth = %d\n", Canon.SensorWidth); + if (Canon.SensorHeight) + fprintf(outfile, "SensorHeight = %d\n", Canon.SensorHeight); + if (Canon.SensorLeftBorder != -1) + fprintf(outfile, "SensorLeftBorder = %d\n", Canon.SensorLeftBorder); + if (Canon.SensorTopBorder != -1) + fprintf(outfile, "SensorTopBorder = %d\n", Canon.SensorTopBorder); + if (Canon.SensorRightBorder) + fprintf(outfile, "SensorRightBorder = %d\n", Canon.SensorRightBorder); + if (Canon.SensorBottomBorder) + fprintf(outfile, "SensorBottomBorder = %d\n", Canon.SensorBottomBorder); + if (Canon.BlackMaskLeftBorder) + fprintf(outfile, "BlackMaskLeftBorder = %d\n", Canon.BlackMaskLeftBorder); + if (Canon.BlackMaskTopBorder) + fprintf(outfile, "BlackMaskTopBorder = %d\n", Canon.BlackMaskTopBorder); + if (Canon.BlackMaskRightBorder) + fprintf(outfile, "BlackMaskRightBorder = %d\n", Canon.BlackMaskRightBorder); + if (Canon.BlackMaskBottomBorder) + fprintf(outfile, "BlackMaskBottomBorder= %d\n", Canon.BlackMaskBottomBorder); + + if (Hasselblad.BaseISO) + fprintf(outfile, "Hasselblad base ISO: %d\n", Hasselblad.BaseISO); + if (Hasselblad.Gain) + fprintf(outfile, "Hasselblad gain: %g\n", Hasselblad.Gain); + + fprintf(outfile, "Raw colors: %d", P1.colors); + if (P1.filters) + { + fprintf(outfile, "\nFilter pattern: "); + if (!P1.cdesc[3]) + P1.cdesc[3] = 'G'; + for (int i = 0; i < 16; i++) + putchar(P1.cdesc[MyCoolRawProcessor.fcol(i >> 1, i & 1)]); + } + + if (Canon.ChannelBlackLevel[0]) + fprintf(outfile, "\nCanon makernotes, ChannelBlackLevel: %d %d %d %d", + Canon.ChannelBlackLevel[0], Canon.ChannelBlackLevel[1], + Canon.ChannelBlackLevel[2], Canon.ChannelBlackLevel[3]); + + if (C.black) + { + fprintf(outfile, "\nblack: %d", C.black); + } + if (C.cblack[0] != 0) + { + fprintf(outfile, "\ncblack[0 .. 3]:"); + for (int c = 0; c < 4; c++) + fprintf(outfile, " %d", C.cblack[c]); + } + if ((C.cblack[4] * C.cblack[5]) > 0) + { + fprintf(outfile, "\nBlackLevelRepeatDim: %d x %d\n", C.cblack[4], C.cblack[5]); + int n = C.cblack[4] * C.cblack[5]; + fprintf(outfile, "cblack[6 .. %d]:", 6 + n - 1); + for (int c = 6; c < 6 + n; c++) + fprintf(outfile, " %d", C.cblack[c]); + } + + if (C.linear_max[0] != 0) + { + fprintf(outfile, "\nHighlight linearity limits:"); + for (int c = 0; c < 4; c++) + fprintf(outfile, " %ld", C.linear_max[c]); + } + + if (P1.colors > 1) + { + fprintf(outfile, "\nMakernotes WB data: coeffs EVs"); + if ((C.cam_mul[0] > 0) && (C.cam_mul[1] > 0)) { + fprintf(outfile, "\n %-23s %g %g %g %g %5.2f %5.2f %5.2f %5.2f", + "As shot", + C.cam_mul[0], C.cam_mul[1], C.cam_mul[2], C.cam_mul[3], + roundf(log2(C.cam_mul[0] / C.cam_mul[1])*100.0f)/100.0f, + 0.0f, + roundf(log2(C.cam_mul[2] / C.cam_mul[1])*100.0f)/100.0f, + C.cam_mul[3]?roundf(log2(C.cam_mul[3] / C.cam_mul[1])*100.0f)/100.0f:0.0f); + } + + for (int cnt = 0; cnt < int(sizeof WBToStr / sizeof *WBToStr); cnt++) { + WBi = WBToStr[cnt].NumId; + if ((C.WB_Coeffs[WBi][0] > 0) && (C.WB_Coeffs[WBi][1] > 0)) { + denom = (float)C.WB_Coeffs[WBi][1]; + fprintf(outfile, "\n %-23s %4d %4d %4d %4d %5.2f %5.2f %5.2f %5.2f", + WBToStr[cnt].hrStrId, + C.WB_Coeffs[WBi][0], C.WB_Coeffs[WBi][1], C.WB_Coeffs[WBi][2], C.WB_Coeffs[WBi][3], + roundf(log2((float)C.WB_Coeffs[WBi][0] / denom)*100.0f)/100.0f, + 0.0f, + roundf(log2((float)C.WB_Coeffs[WBi][2] / denom)*100.0f)/100.0f, + C.WB_Coeffs[3]?roundf(log2((float)C.WB_Coeffs[WBi][3] / denom)*100.0f)/100.0f:0.0f); + } + } + + if ((Nikon.ME_WB[0] != 0.0f) && (Nikon.ME_WB[0] != 1.0f)) + { + fprintf(outfile, "\nNikon multi-exposure WB multipliers:"); + for (int c = 0; c < 4; c++) + fprintf(outfile, " %g", Nikon.ME_WB[c]); + } + + if (C.rgb_cam[0][0] > 0.0001) + { + fprintf(outfile, "\n\nCamera2RGB matrix (mode: %d):\n", MyCoolRawProcessor.imgdata.params.use_camera_matrix); + PRINTMATRIX3x4(outfile,C.rgb_cam,P1.colors); + } + + fprintf(outfile, "\nXYZ->CamRGB matrix:\n"); + PRINTMATRIX4x3(outfile,C.cam_xyz,P1.colors); + + for (int cnt = 0; cnt < 2; cnt++) { + if (fabsf(C.P1_color[cnt].romm_cam[0]) > 0) + { + fprintf(outfile, "\nPhaseOne Matrix %d:\n", cnt+1); + for (int i = 0; i < 3; i++) + fprintf(outfile, "%6.4f\t%6.4f\t%6.4f\n", C.P1_color[cnt].romm_cam[i * 3], + C.P1_color[cnt].romm_cam[i * 3 + 1], + C.P1_color[cnt].romm_cam[i * 3 + 2]); + } + } + + if (fabsf(C.cmatrix[0][0]) > 0) + { + fprintf(outfile, "\ncamRGB -> sRGB Matrix:\n"); + PRINTMATRIX3x4(outfile,C.cmatrix,P1.colors); + } + + if (fabsf(C.ccm[0][0]) > 0) + { + fprintf(outfile, "\nColor Correction Matrix:\n"); + PRINTMATRIX3x4(outfile,C.ccm,P1.colors); + } + + for (int cnt = 0; cnt < 2; cnt++) { + if (C.dng_color[cnt].illuminant != LIBRAW_WBI_None) { + if (C.dng_color[cnt].illuminant <= LIBRAW_WBI_StudioTungsten) { + fprintf(outfile, "\nDNG Illuminant %d: %s", + cnt + 1, WB_idx2hrstr(C.dng_color[cnt].illuminant)); + } + else if (C.dng_color[cnt].illuminant == LIBRAW_WBI_Other) { + fprintf(outfile, "\nDNG Illuminant %d: Other", cnt + 1); + } + else { + fprintf(outfile, "\nDNG Illuminant %d is out of EXIF LightSources range [0:24, 255]: %d", + cnt + 1, C.dng_color[cnt].illuminant); + } + } + } + + for (int n=0; n<2; n++) { + if (fabsf(C.dng_color[n].colormatrix[0][0]) > 0) + { + fprintf(outfile, "\nDNG color matrix %d:\n", n+1); + PRINTMATRIX4x3(outfile,C.dng_color[n].colormatrix,P1.colors); + } + } + + for (int n=0; n<2; n++) { + if (fabsf(C.dng_color[n].calibration[0][0]) > 0) + { + fprintf(outfile, "\nDNG calibration matrix %d:\n", n+1); + for (int i = 0; i < P1.colors && i < 4; i++) + { + for (int j = 0; j < P1.colors && j < 4; j++) + fprintf(outfile, "%6.4f\t", C.dng_color[n].calibration[j][i]); + fprintf(outfile, "\n"); + } + } + } + + for (int n=0; n<2; n++) { + if (fabsf(C.dng_color[n].forwardmatrix[0][0]) > 0) + { + fprintf(outfile, "\nDNG forward matrix %d:\n", n+1); + PRINTMATRIX3x4(outfile,C.dng_color[n].forwardmatrix,P1.colors); + } + } + + fprintf(outfile, "\nDerived D65 multipliers:"); + for (int c = 0; c < P1.colors; c++) + fprintf(outfile, " %f", C.pre_mul[c]); + } + fprintf(outfile, "\nColor space (makernotes) : %d, %s", P3.ColorSpace, ColorSpaceName); + fprintf(outfile, "\n"); + + if (Sony.PixelShiftGroupID) + { + fprintf(outfile, "\nSony PixelShiftGroupPrefix 0x%x PixelShiftGroupID %d, ", + Sony.PixelShiftGroupPrefix, Sony.PixelShiftGroupID); + if (Sony.numInPixelShiftGroup) + { + fprintf(outfile, "shot# %d (starts at 1) of total %d\n", + Sony.numInPixelShiftGroup, Sony.nShotsInPixelShiftGroup); + } + else + { + fprintf(outfile, "shots in PixelShiftGroup %d, already ARQ\n", + Sony.nShotsInPixelShiftGroup); + } + } + + if (Sony.Sony0x9400_version) + fprintf(outfile, "\nSONY Sequence data, tag 0x9400 version '%x'\n" + "\tReleaseMode2: %d\n" + "\tSequenceImageNumber: %d (starts at zero)\n" + "\tSequenceLength1: %d shot(s)\n" + "\tSequenceFileNumber: %d (starts at zero, exiftool starts at 1)\n" + "\tSequenceLength2: %d file(s)\n", + Sony.Sony0x9400_version, Sony.Sony0x9400_ReleaseMode2, + Sony.Sony0x9400_SequenceImageNumber, + Sony.Sony0x9400_SequenceLength1, + Sony.Sony0x9400_SequenceFileNumber, + Sony.Sony0x9400_SequenceLength2); +} + +void print_wbfun(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + int WBi; + float denom; + const char *CamMakerName = CameraMaker_idx2str(P1.maker_index); + fprintf(outfile, "// %s %s\n", P1.make, P1.model); + for (int cnt = 0; cnt < int(sizeof WBToStr / sizeof *WBToStr); cnt++) { + WBi = WBToStr[cnt].NumId; + if (C.WB_Coeffs[WBi][0] && C.WB_Coeffs[WBi][1] && !WBToStr[cnt].aux_setting) { + denom = (float) C.WB_Coeffs[WBi][1]; + fprintf(outfile, "{%s, \"%s\", %s, {%6.5ff, 1.0f, %6.5ff, ", CamMakerName, + P1.normalized_model, WBToStr[cnt].StrId, + C.WB_Coeffs[WBi][0] / denom, + C.WB_Coeffs[WBi][2] / denom); + if (C.WB_Coeffs[WBi][1] == C.WB_Coeffs[WBi][3]) + fprintf(outfile, "1.0f}},\n"); + else + fprintf(outfile, "%6.5ff}},\n", + C.WB_Coeffs[WBi][3] / denom); + } + } + + for (int cnt = 0; cnt < 64; cnt++) + if (C.WBCT_Coeffs[cnt][0]) + { + fprintf(outfile, "{%s, \"%s\", %d, {%6.5ff, 1.0f, %6.5ff, ", CamMakerName, + P1.normalized_model, (int)C.WBCT_Coeffs[cnt][0], + C.WBCT_Coeffs[cnt][1] / C.WBCT_Coeffs[cnt][2], + C.WBCT_Coeffs[cnt][3] / C.WBCT_Coeffs[cnt][2]); + if (C.WBCT_Coeffs[cnt][2] == C.WBCT_Coeffs[cnt][4]) + fprintf(outfile, "1.0f}},\n"); + else + fprintf(outfile, "%6.5ff}},\n", + C.WBCT_Coeffs[cnt][4] / C.WBCT_Coeffs[cnt][2]); + } + else + break; + fprintf(outfile, "\n"); +} + +void print_szfun(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + fprintf(outfile, "%s\t%s\t%s\t%d\t%d\n", fn.c_str(), P1.make, P1.model, S.width, + S.height); + /* + fprintf(outfile, "\n%s\t%s\t%s\n", filelist[i].c_str(), P1.make, P1.model); + fprintf(outfile, "\tCoffin:\traw %dx%d mrg %d %d img %dx%d\n", + S.raw_width, S.raw_height, S.left_margin, S.top_margin, S.width, S.height); + fprintf (outfile, "\tmnote: \t"); + if (Canon.SensorWidth) + fprintf (outfile, "sensor %dx%d ", Canon.SensorWidth, Canon.SensorHeight); + if (Nikon.SensorWidth) + fprintf (outfile, "sensor %dx%d ", Nikon.SensorWidth, Nikon.SensorHeight); + fprintf(outfile, "inset: start %d %d img %dx%d aspect calc: %f Aspect in file:", + S.raw_inset_crop.cleft, S.raw_inset_crop.ctop, + S.raw_inset_crop.cwidth, S.raw_inset_crop.cheight, + ((float)S.raw_inset_crop.cwidth / + (float)S.raw_inset_crop.cheight)); + Aspect = + lookup_id2hr(S.raw_inset_crop.aspect, AspectRatios, nAspectRatios); + if (Aspect) fprintf (outfile, "%s\n", Aspect->name); + else fprintf (outfile, "Other %d\n", S.raw_inset_crop.aspect); + + if (Nikon.SensorHighSpeedCrop.cwidth) { + fprintf(outfile, "\tHighSpeed crop from: %d x %d at top left pixel: (%d, %d)\n", + Nikon.SensorHighSpeedCrop.cwidth, Nikon.SensorHighSpeedCrop.cheight, + Nikon.SensorHighSpeedCrop.cleft, Nikon.SensorHighSpeedCrop.ctop); + } + */ +} +void print_0fun(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + /* + printf ("filename\t%s\tmodel\t%s\tisTSNERDTS\t%d\tRAF + version\t%s\tRAF data version\t0x%x\tis4K\t%d\n", av[i], P1.model, + Fuji.isTSNERDTS, Fuji.RAFVersion, Fuji.RAFDataVersion, + P2.is_4K_RAFdata); + */ + +} + +void print_1fun(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + char frame[64] = ""; + snprintf(frame, 64, "rw %d rh %d lm %d tm %d", S.raw_width, S.raw_height, + S.left_margin, S.top_margin); + fprintf(outfile, "%s=%s=nFms %02d=%s=bps %02d=%s", P1.normalized_make, P1.normalized_model, P1.raw_count, + MyCoolRawProcessor.unpack_function_name(), C.raw_bps, frame); + fprintf(outfile, "\n"); +} + +void print_2fun(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + fprintf(outfile, "// %s %s", P1.make, P1.model); + if (C.cam_mul[0] > 0) + { + fprintf(outfile, "\n'As shot' WB:"); + for (int c = 0; c < 4; c++) + fprintf(outfile, " %.3f", C.cam_mul[c]); + } + if (C.WB_Coeffs[LIBRAW_WBI_Auto][0] > 0) + { + fprintf(outfile, "\n'Camera Auto' WB:"); + for (int c = 0; c < 4; c++) + fprintf(outfile, " %d", C.WB_Coeffs[LIBRAW_WBI_Auto][c]); + } + if (C.WB_Coeffs[LIBRAW_WBI_Measured][0] > 0) + { + fprintf(outfile, "\n'Camera Measured' WB:"); + for (int c = 0; c < 4; c++) + fprintf(outfile, " %d", C.WB_Coeffs[LIBRAW_WBI_Measured][c]); + } + fprintf(outfile, "\n\n"); +} + +void print_compactfun(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + trimSpaces(P1.make); + trimSpaces(P1.model); + trimSpaces(C.model2); + trimSpaces(ShootingInfo.BodySerial); + trimSpaces(ShootingInfo.InternalBodySerial); + fprintf(outfile, "%s=%s", P1.make, P1.model); + if (ShootingInfo.BodySerial[0] && + !(ShootingInfo.BodySerial[0] == 48 && !ShootingInfo.BodySerial[1])) + fprintf(outfile, "=Body#: %s", ShootingInfo.BodySerial); + else if (C.model2[0] && (!strncasecmp(P1.normalized_make, "Kodak", 5))) + fprintf(outfile, "=Body#: %s", C.model2); + if (ShootingInfo.InternalBodySerial[0]) + fprintf(outfile, "=Assy#: %s", ShootingInfo.InternalBodySerial); + if (exifLens.LensSerial[0]) + fprintf(outfile, "=Lens#: %s", exifLens.LensSerial); + if (exifLens.InternalLensSerial[0]) + fprintf(outfile, "=LensAssy#: %s", exifLens.InternalLensSerial); + fprintf(outfile, "=\n"); +} + +void print_normfun(FILE* outfile, LibRaw& MyCoolRawProcessor, std::string& fn) +{ + trimSpaces(P1.make); + trimSpaces(P1.model); + fprintf(outfile, "\nFilename: %s\n", fn.c_str()); + fprintf(outfile, "make/model: =%s/%s= ID: 0x%llx norm. make/model: =%s/%s=\n", + P1.make, P1.model, mnLens.CamID, P1.normalized_make, P1.normalized_model); +} + +void print_unpackfun(FILE* outfile, LibRaw& MyCoolRawProcessor, int print_frame, std::string& fn) +{ + char frame[48] = ""; + if (print_frame) + { + ushort right_margin = S.raw_width - S.width - S.left_margin; + ushort bottom_margin = S.raw_height - S.height - S.top_margin; + snprintf(frame, 48, "F=%dx%dx%dx%d RS=%dx%d", S.left_margin, + S.top_margin, right_margin, bottom_margin, S.raw_width, + S.raw_height); + } + fprintf(outfile, "%s\t%s\t%s\t%s/%s\n", fn.c_str(),MyCoolRawProcessor.unpack_function_name(), frame, P1.make, P1.model); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/rawtextdump.cpp libkdcraw/libkdcraw/libraw/samples/rawtextdump.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/rawtextdump.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/samples/rawtextdump.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,144 @@ +/* -*- C++ -*- + * File: raw2text.cpp + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sun Sept 01, 2020 + * + * LibRaw sample + * Dumps (small) selection of RAW data to text file + * + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + + */ +#include <stdio.h> +#include <string.h> +#include <math.h> +#ifndef WIN32 +#include <netinet/in.h> +#else +#include <winsock2.h> +#endif + +#include "libraw/libraw.h" + +void usage(const char *av) +{ + printf( + "Dump (small) selecton of RAW file as tab-separated text file\n" + "Usage: %s inputfile COL ROW [CHANNEL] [width] [height]\n" + " COL - start column\n" + " ROW - start row\n" + " CHANNEL - raw channel to dump, default is 0 (red for rggb)\n" + " width - area width to dump, default is 16\n" + " height - area height to dump, default is 4\n" + , av); +} + +unsigned subtract_bl(unsigned int val, int bl) +{ + return val > (unsigned)bl ? val - (unsigned)bl : 0; +} + +class LibRaw_bl : public LibRaw +{ + public: + void adjust_blacklevel() { LibRaw::adjust_bl(); } +}; + +int main(int ac, char *av[]) +{ + if (ac < 4) + { + usage(av[0]); + exit(1); + } + int colstart = atoi(av[2]); + int rowstart = atoi(av[3]); + int channel = 0; + if (ac > 4) channel = atoi(av[4]); + int width = 16; + if (ac > 5) width = atoi(av[5]); + int height = 4; + if (ac > 6) height = atoi(av[6]); + if (width <1 || height<1) + { + usage(av[0]); + exit(1); + } + + LibRaw_bl lr; + + if (lr.open_file(av[1]) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Unable to open file %s\n", av[1]); + exit(1); + } + if ((lr.imgdata.idata.colors == 1 && channel>0) || (channel >3)) + { + fprintf(stderr, "Incorrect CHANNEL specified: %d\n", channel); + exit(1); + } + if (lr.unpack() != LIBRAW_SUCCESS) + { + fprintf(stderr, "Unable to unpack raw data from %s\n", av[1]); + exit(1); + } + lr.adjust_blacklevel(); + printf("%s\t%d-%d-%dx%d\tchannel: %d\n", av[1], colstart, rowstart, width, height, channel); + + printf("%6s", "R\\C"); + for (int col = colstart; col < colstart + width && col < lr.imgdata.sizes.raw_width; col++) + printf("%6u", col); + printf("\n"); + + if (lr.imgdata.rawdata.raw_image) + { + for (int row = rowstart; row < rowstart + height && row < lr.imgdata.sizes.raw_height; row++) + { + unsigned rcolors[48]; + if (lr.imgdata.idata.colors > 1) + for (int c = 0; c < 48; c++) + rcolors[c] = lr.COLOR(row, c); + else + memset(rcolors, 0, sizeof(rcolors)); + unsigned short *rowdata = &lr.imgdata.rawdata.raw_image[row * lr.imgdata.sizes.raw_pitch / 2]; + printf("%6u", row); + for (int col = colstart; col < colstart + width && col < lr.imgdata.sizes.raw_width; col++) + if (rcolors[col % 48] == (unsigned)channel) printf("%6u", subtract_bl(rowdata[col],lr.imgdata.color.cblack[channel])); + else printf(" -"); + printf("\n"); + } + } + else if (lr.imgdata.rawdata.color4_image && channel < 4) + { + for (int row = rowstart; row < rowstart + height && row < lr.imgdata.sizes.raw_height; row++) + { + unsigned short(*rowdata)[4] = &lr.imgdata.rawdata.color4_image[row * lr.imgdata.sizes.raw_pitch / 8]; + printf("%6u", row); + for (int col = colstart; col < colstart + width && col < lr.imgdata.sizes.raw_width; col++) + printf("%6u", subtract_bl(rowdata[col][channel],lr.imgdata.color.cblack[channel])); + printf("\n"); + } + } + else if (lr.imgdata.rawdata.color3_image && channel < 3) + { + for (int row = rowstart; row < rowstart + height && row < lr.imgdata.sizes.raw_height; row++) + { + unsigned short(*rowdata)[3] = &lr.imgdata.rawdata.color3_image[row * lr.imgdata.sizes.raw_pitch / 6]; + printf("%6u", row); + for (int col = colstart; col < colstart + width && col < lr.imgdata.sizes.raw_width; col++) + printf("%6u", subtract_bl(rowdata[col][channel],lr.imgdata.color.cblack[channel])); + printf("\n"); + } + } + else + printf("Unsupported file data (e.g. floating point format), or incorrect channel specified\n"); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/simple_dcraw.cpp libkdcraw/libkdcraw/libraw/samples/simple_dcraw.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/simple_dcraw.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/simple_dcraw.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -1,213 +1,189 @@ -/* +/* -*- C++ -*- * File: simple_dcraw.cpp - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> - * Created: Sat Mar 8 , 2008 + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * Created: Sat Mar 8, 2008 * - * LibRaw simple C++ API (emulates call to "dcraw [-D] [-T] [-v] [-e] [-4]") - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * LibRaw simple C++ API: emulates call to "dcraw [-D] [-T] [-v] [-e] [-4]" + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ #include <stdio.h> #include <string.h> #include <math.h> -#ifndef WIN32 +#include "libraw/libraw.h" + +#ifndef LIBRAW_WIN32_CALLS #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> #endif -#include "libraw/libraw.h" - -#ifdef WIN32 +#ifdef LIBRAW_WIN32_CALLS #define snprintf _snprintf #endif -int my_progress_callback(void *unused_data,enum LibRaw_progress state,int iter, int expected) +int my_progress_callback(void *unused_data, enum LibRaw_progress state, + int iter, int expected) { - if(iter==0) - printf("CB: state=%x, expected %d iterations\n",state,expected); - return 0; + if (iter == 0) + printf("CB: state=%x, expected %d iterations\n", state, expected); + return 0; } +char *customCameras[] = { + (char *)"43704960,4080,5356, 0, 0, 0, 0,0,148,0,0, Dalsa, FTF4052C Full,0", + (char *)"42837504,4008,5344, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 3:4", + (char *)"32128128,4008,4008, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 1:1", + (char *)"24096096,4008,3006, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 4:3", + (char *)"18068064,4008,2254, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 16:9", + (char *)"67686894,5049,6703, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C Full", + (char *)"66573312,4992,6668, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 3:4", + (char *)"49840128,4992,4992, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 1:1", + (char *)"37400064,4992,3746, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 4:3", + (char *)"28035072,4992,2808, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 16:9", + NULL}; int main(int ac, char *av[]) { - int i, ret, verbose=0, output_thumbs=0,use_mmap=0,msize; - void *file_buffer; + int i, ret, verbose = 0, output_thumbs = 0; + + // don't use fixed size buffers in real apps! + char outfn[1024], thumbfn[1024]; + + LibRaw* RawProcessor = new LibRaw; + RawProcessor->imgdata.params.custom_camera_strings = customCameras; + if (ac < 2) + { + printf("simple_dcraw - LibRaw %s sample. Emulates dcraw [-D] [-T] [-v] " + "[-e] [-E]\n" + " %d cameras supported\n" + "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n" + "\t-4 - 16-bit mode\n" + "\t-L - list supported cameras and exit\n" + "\t-v - verbose output\n" + "\t-T - output TIFF files instead of .pgm/ppm\n" + "\t-e - extract thumbnails (same as dcraw -e in separate run)\n", + LibRaw::version(), LibRaw::cameraCount(), av[0]); + delete RawProcessor; + return 0; + } - // don't use fixed size buffers in real apps! - char outfn[1024],thumbfn[1024]; + putenv((char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field - LibRaw RawProcessor; - if(ac<2) +#define P1 RawProcessor->imgdata.idata +#define S RawProcessor->imgdata.sizes +#define C RawProcessor->imgdata.color +#define T RawProcessor->imgdata.thumbnail +#define P2 RawProcessor->imgdata.other +#define OUT RawProcessor->imgdata.params + + for (i = 1; i < ac; i++) + { + if (av[i][0] == '-') + { + if (av[i][1] == 'T' && av[i][2] == 0) + OUT.output_tiff = 1; + if (av[i][1] == 'v' && av[i][2] == 0) + verbose++; + if (av[i][1] == 'e' && av[i][2] == 0) + output_thumbs++; + if (av[i][1] == '4' && av[i][2] == 0) + OUT.output_bps = 16; + if (av[i][1] == 'C' && av[i][2] == 0) + RawProcessor->set_progress_handler(my_progress_callback, NULL); + if (av[i][1] == 'L' && av[i][2] == 0) + { + const char **clist = LibRaw::cameraList(); + const char **cc = clist; + while (*cc) { - printf( - "simple_dcraw - LibRaw %s sample. Emulates dcraw [-D] [-T] [-v] [-e] [-B]\n" - " %d cameras supported\n" - "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n" - "\t-D - document mode emulation\n" - "\t-4 - 16-bit mode\n" - "\t-v - verbose output\n" - "\t-T - output TIFF files instead of .pgm/ppm\n" -#ifndef WIN32 - "\t-B - use mmap()-ed I/O (Unix only)\n" -#endif - "\t-e - extract thumbnails (same as dcraw -e in separate run)\n",LibRaw::version(), - LibRaw::cameraCount(), - av[0]); - return 0; + printf("%s\n", *cc); + cc++; + } + delete RawProcessor; + exit(0); + } + continue; + } + + if (verbose) + printf("Processing file %s\n", av[i]); + + if ((ret = RawProcessor->open_file(av[i])) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot open_file %s: %s\n", av[i], libraw_strerror(ret)); + continue; // no recycle b/c open file will recycle itself + } + + if (!output_thumbs) // No unpack for thumb extraction + if ((ret = RawProcessor->unpack()) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret)); + continue; + } + + // thumbnail unpacking and output in the middle of main + // image processing - for test purposes! + if (output_thumbs) + { + if ((ret = RawProcessor->unpack_thumb()) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot unpack_thumb %s: %s\n", av[i], + libraw_strerror(ret)); + if (LIBRAW_FATAL_ERROR(ret)) + continue; // skip to next file + } + else + { + snprintf(thumbfn, sizeof(thumbfn), "%s.%s", av[i], + T.tformat == LIBRAW_THUMBNAIL_JPEG ? "thumb.jpg" + : "thumb.ppm"); + + if (verbose) + printf("Writing thumbnail file %s\n", thumbfn); + if (LIBRAW_SUCCESS != (ret = RawProcessor->dcraw_thumb_writer(thumbfn))) + { + fprintf(stderr, "Cannot write %s: %s\n", thumbfn, + libraw_strerror(ret)); + if (LIBRAW_FATAL_ERROR(ret)) + continue; } - - putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field + } + continue; + } + + ret = RawProcessor->dcraw_process(); + + if (LIBRAW_SUCCESS != ret) + { + fprintf(stderr, "Cannot do postpocessing on %s: %s\n", av[i], + libraw_strerror(ret)); + if (LIBRAW_FATAL_ERROR(ret)) + continue; + } + snprintf(outfn, sizeof(outfn), "%s.%s", av[i], + OUT.output_tiff ? "tiff" : (P1.colors > 1 ? "ppm" : "pgm")); + + if (verbose) + printf("Writing file %s\n", outfn); -#define P1 RawProcessor.imgdata.idata -#define S RawProcessor.imgdata.sizes -#define C RawProcessor.imgdata.color -#define T RawProcessor.imgdata.thumbnail -#define P2 RawProcessor.imgdata.other -#define OUT RawProcessor.imgdata.params + if (LIBRAW_SUCCESS != (ret = RawProcessor->dcraw_ppm_tiff_writer(outfn))) + fprintf(stderr, "Cannot write %s: %s\n", outfn, libraw_strerror(ret)); + RawProcessor->recycle(); // just for show this call + } - for (i=1;i<ac;i++) - { - if(av[i][0]=='-') - { - if(av[i][1]=='T' && av[i][2]==0) - OUT.output_tiff=1; - if(av[i][1]=='v' && av[i][2]==0) - verbose++; - if(av[i][1]=='e' && av[i][2]==0) - output_thumbs++; - if(av[i][1]=='D' && av[i][2]==0) - OUT.document_mode=2; - if(av[i][1]=='B' && av[i][2]==0) - use_mmap=1; - if(av[i][1]=='4' && av[i][2]==0) - OUT.output_bps=16; - if(av[i][1]=='C' && av[i][2]==0) - RawProcessor.set_progress_handler(my_progress_callback,NULL); - continue; - } - - if(verbose) printf("Processing file %s\n",av[i]); - -#ifndef WIN32 - if(use_mmap) - { - int file = open(av[i],O_RDONLY); - struct stat st; - if(file<0) - { - fprintf(stderr,"Cannot open %s: %s\n",av[i],strerror(errno)); - continue; - } - if(fstat(file,&st)) - { - fprintf(stderr,"Cannot stat %s: %s\n",av[i],strerror(errno)); - close(file); - continue; - } - int pgsz = getpagesize(); - msize = ((st.st_size+pgsz-1)/pgsz)*pgsz; - file_buffer = mmap(NULL,msize,PROT_READ,MAP_PRIVATE,file,0); - if(!file_buffer) - { - fprintf(stderr,"Cannot mmap %s: %s\n",av[i],strerror(errno)); - close(file); - continue; - } - close(file); - if( (ret = RawProcessor.open_buffer(file_buffer,st.st_size) != LIBRAW_SUCCESS)) - { - fprintf(stderr,"Cannot open_buffer %s: %s\n",av[i],libraw_strerror(ret)); - continue; // no recycle b/c open file will recycle itself - } - } - else -#endif - { - if( (ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot open_file %s: %s\n",av[i],libraw_strerror(ret)); - continue; // no recycle b/c open file will recycle itself - } - } - - if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret)); - continue; - } - - // thumbnail unpacking and output in the middle of main - // image processing - for test purposes! - if(output_thumbs) - { - if( (ret = RawProcessor.unpack_thumb() ) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot unpack_thumb %s: %s\n",av[i],libraw_strerror(ret)); - if(LIBRAW_FATAL_ERROR(ret)) - continue; // skip to next file - } - else - { - snprintf(thumbfn,sizeof(thumbfn),"%s.%s", - av[i],T.tformat == LIBRAW_THUMBNAIL_JPEG ? "thumb.jpg" : "thumb.ppm"); - - if(verbose) printf("Writing thumbnail file %s\n",thumbfn); - if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_thumb_writer(thumbfn))) - { - fprintf(stderr,"Cannot write %s: %s\n",thumbfn,libraw_strerror(ret)); - if(LIBRAW_FATAL_ERROR(ret)) - continue; - } - } - } - - if(OUT.document_mode) - ret = RawProcessor.dcraw_document_mode_processing(); - else - ret = RawProcessor.dcraw_process(); - - if(LIBRAW_SUCCESS !=ret) - { - fprintf(stderr,"Cannot do postpocessing on %s: %s\n", - av[i],libraw_strerror(ret)); - if(LIBRAW_FATAL_ERROR(ret)) - continue; - } - snprintf(outfn,sizeof(outfn), - "%s.%s", - av[i], OUT.output_tiff ? "tiff" : (P1.colors>1?"ppm":"pgm")); - - if(verbose) printf("Writing file %s\n",outfn); - - if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) - fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); - -#ifndef WIN32 - if(use_mmap && file_buffer) - { - munmap(file_buffer,msize); - file_buffer=0; - } -#endif - RawProcessor.recycle(); // just for show this call - } - return 0; + delete RawProcessor; + return 0; } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/samples/unprocessed_raw.cpp libkdcraw/libkdcraw/libraw/samples/unprocessed_raw.cpp --- libkdcraw-wrk/libkdcraw/libraw/samples/unprocessed_raw.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/samples/unprocessed_raw.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -1,156 +1,318 @@ -/* +/* -*- C++ -*- * File: unprocessed_raw.cpp - * Copyright 2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2009-2020 LibRaw LLC (info@libraw.org) * Created: Fri Jan 02, 2009 * * LibRaw sample - * Generates unprocessed raw image: with masked pixels and without black subtraction + * Generates unprocessed raw image: with masked pixels and without black +subtraction * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ #include <stdio.h> #include <string.h> #include <math.h> -#ifndef WIN32 +#include <time.h> + +#include "libraw/libraw.h" + +#ifndef LIBRAW_WIN32_CALLS #include <netinet/in.h> #else +#include <sys/utime.h> #include <winsock2.h> #endif -#include "libraw/libraw.h" - -#ifdef WIN32 +#ifdef LIBRAW_WIN32_CALLS #define snprintf _snprintf #endif +#if !(LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 14)) +#error This code is for LibRaw 0.14+ only +#endif + +void gamma_curve(unsigned short curve[]); +void write_ppm(unsigned width, unsigned height, unsigned short *bitmap, + const char *basename); +void write_tiff(int width, int height, unsigned short *bitmap, + const char *basename); + int main(int ac, char *av[]) { - int i, ret; - int verbose=1,autoscale=0; - char outfn[1024],thumbfn[1024]; - - LibRaw RawProcessor; - if(ac<2) - { - usage: - printf( - "unprocessed_raw - LibRaw %s sample. %d cameras supported\n" - "Usage: %s [-q] [-A] [-g] [-s N] [-N] raw-files....\n" - "\t-q - be quiet\n" - "\t-s N - select Nth image in file (default=0)\n" - "\t-g - use gamma correction with gamma 2.2 (not precise,use for visual inspection only)\n" - "\t-A - autoscaling (by integer factor)\n" - "\t-N - no raw curve\n" - ,LibRaw::version(), - LibRaw::cameraCount(), - av[0]); - return 0; - } - -#define P1 RawProcessor.imgdata.idata + int i, ret; + int verbose = 1, autoscale = 0, use_gamma = 0, out_tiff = 0; + char outfn[1024]; + + LibRaw RawProcessor; + if (ac < 2) + { + usage: + printf("unprocessed_raw - LibRaw %s sample. %d cameras supported\n" + "Usage: %s [-q] [-A] [-g] [-s N] raw-files....\n" + "\t-q - be quiet\n" + "\t-s N - select Nth image in file (default=0)\n" + "\t-g - use gamma correction with gamma 2.2 (not precise,use for " + "visual inspection only)\n" + "\t-A - autoscaling (by integer factor)\n" + "\t-T - write tiff instead of pgm\n", + LibRaw::version(), LibRaw::cameraCount(), av[0]); + return 0; + } + #define S RawProcessor.imgdata.sizes -#define C RawProcessor.imgdata.color -#define T RawProcessor.imgdata.thumbnail -#define P2 RawProcessor.imgdata.other #define OUT RawProcessor.imgdata.params - OUT.document_mode=2; - OUT.output_bps=16; - OUT.output_tiff=1; - OUT.user_flip=0; - OUT.no_auto_bright = 1; - OUT.filtering_mode=(LibRaw_filtering)( LIBRAW_FILTERING_NOBLACKS|LIBRAW_FILTERING_NOZEROES); - for (i=1;i<ac;i++) - { - if(av[i][0]=='-') - { - if(av[i][1]=='q' && av[i][2]==0) - verbose=0; - else if(av[i][1]=='A' && av[i][2]==0) - autoscale=1; - else if(av[i][1]=='g' && av[i][2]==0) - OUT.gamma_16bit=1; - else if(av[i][1]=='N' && av[i][2]==0) - OUT.filtering_mode=LIBRAW_FILTERING_NONE; - else if(av[i][1]=='s' && av[i][2]==0) - { - i++; - OUT.shot_select=atoi(av[i]); - } - else - goto usage; - continue; - } - int r,c; - if(verbose) printf("Processing file %s\n",av[i]); - if( (ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot open %s: %s\n",av[i],libraw_strerror(ret)); - continue; // no recycle b/c open file will recycle itself - } - if(verbose) - { - printf("Image size: %dx%d\nRaw size: %dx%d\n",S.width,S.height,S.raw_width,S.raw_height); - printf("Margins: top=%d, left=%d, right=%d, bottom=%d\n", - S.top_margin,S.left_margin,S.right_margin,S.bottom_margin); - } - - if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot unpack %s: %s\n",av[i],libraw_strerror(ret)); - continue; - } - if(verbose) - printf("Unpacked....\n"); - - if( (ret = RawProcessor.add_masked_borders_to_bitmap() ) != LIBRAW_SUCCESS) - { - fprintf(stderr,"Cannot add mask data to bitmap %s\n",av[i]); - } - for(int r=0;r<S.iheight;r++) - for(c=0;c<S.iwidth;c++) - RawProcessor.imgdata.image[r*S.iwidth+c][0] - = RawProcessor.imgdata.image[r*S.iwidth+c][RawProcessor.FC(r,c)]; - - P1.colors=1; - if(autoscale) - { - unsigned max=0,scale; - for(int j=0; j<S.iheight*S.iwidth; j++) - if(max < RawProcessor.imgdata.image[j][0]) - max = RawProcessor.imgdata.image[j][0]; - if (max >0 && max< 1<<15) - { - scale = (1<<16)/max; - if(verbose) - printf("Scaling with multiplier=%d (max=%d)\n",scale,max); - - for(int j=0; j<S.iheight*S.iwidth; j++) - RawProcessor.imgdata.image[j][0] *= scale; - } - } - - if(OUT.shot_select) - snprintf(outfn,sizeof(outfn),"%s-%d.tiff",av[i],OUT.shot_select); - else - snprintf(outfn,sizeof(outfn),"%s.tiff",av[i]); - - if(verbose) printf("Writing file %s\n",outfn); - if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) - fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); - } - return 0; + for (i = 1; i < ac; i++) + { + if (av[i][0] == '-') + { + if (av[i][1] == 'q' && av[i][2] == 0) + verbose = 0; + else if (av[i][1] == 'A' && av[i][2] == 0) + autoscale = 1; + else if (av[i][1] == 'g' && av[i][2] == 0) + use_gamma = 1; + else if (av[i][1] == 'T' && av[i][2] == 0) + out_tiff = 1; + else if (av[i][1] == 's' && av[i][2] == 0) + { + i++; + OUT.shot_select = av[i] ? atoi(av[i]) : 0; + } + else + goto usage; + continue; + } + + if (verbose) + printf("Processing file %s\n", av[i]); + if ((ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot open %s: %s\n", av[i], libraw_strerror(ret)); + continue; // no recycle b/c open file will recycle itself + } + if (verbose) + { + printf("Image size: %dx%d\nRaw size: %dx%d\n", S.width, S.height, + S.raw_width, S.raw_height); + printf("Margins: top=%d, left=%d\n", S.top_margin, S.left_margin); + } + + if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS) + { + fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret)); + continue; + } + + if (verbose) + printf("Unpacked....\n"); + + if (!(RawProcessor.imgdata.idata.filters || + RawProcessor.imgdata.idata.colors == 1)) + { + printf("Only Bayer-pattern RAW files supported, sorry....\n"); + continue; + } + + if (autoscale) + { + unsigned max = 0, scale; + for (int j = 0; j < S.raw_height * S.raw_width; j++) + if (max < RawProcessor.imgdata.rawdata.raw_image[j]) + max = RawProcessor.imgdata.rawdata.raw_image[j]; + if (max > 0 && max < 1 << 15) + { + scale = (1 << 16) / max; + if (verbose) + printf("Scaling with multiplier=%d (max=%d)\n", scale, max); + + for (int j = 0; j < S.raw_height * S.raw_width; j++) + RawProcessor.imgdata.rawdata.raw_image[j] *= scale; + } + } + if (use_gamma) + { + unsigned short curve[0x10000]; + gamma_curve(curve); + for (int j = 0; j < S.raw_height * S.raw_width; j++) + RawProcessor.imgdata.rawdata.raw_image[j] = + curve[RawProcessor.imgdata.rawdata.raw_image[j]]; + if (verbose) + printf("Gamma-corrected....\n"); + } + + if (OUT.shot_select) + snprintf(outfn, sizeof(outfn), "%s-%d.%s", av[i], OUT.shot_select, + out_tiff ? "tiff" : "pgm"); + else + snprintf(outfn, sizeof(outfn), "%s.%s", av[i], out_tiff ? "tiff" : "pgm"); + + if (out_tiff) + write_tiff(S.raw_width, S.raw_height, + RawProcessor.imgdata.rawdata.raw_image, outfn); + else + write_ppm(S.raw_width, S.raw_height, + RawProcessor.imgdata.rawdata.raw_image, outfn); + + if (verbose) + printf("Stored to file %s\n", outfn); + } + return 0; +} + +void write_ppm(unsigned width, unsigned height, unsigned short *bitmap, + const char *fname) +{ + if (!bitmap) + return; + + FILE *f = fopen(fname, "wb"); + if (!f) + return; + int bits = 16; + fprintf(f, "P5\n%d %d\n%d\n", width, height, (1 << bits) - 1); + unsigned char *data = (unsigned char *)bitmap; + unsigned data_size = width * height * 2; +#define SWAP(a, b) \ + { \ + a ^= b; \ + a ^= (b ^= a); \ + } + for (unsigned i = 0; i < data_size; i += 2) + SWAP(data[i], data[i + 1]); +#undef SWAP + fwrite(data, data_size, 1, f); + fclose(f); +} + +/* == gamma curve and tiff writer - simplified cut'n'paste from dcraw.c */ + +#define SQR(x) ((x) * (x)) + +void gamma_curve(unsigned short *curve) +{ + + double pwr = 1.0 / 2.2; + double ts = 0.0; + int imax = 0xffff; + int mode = 2; + int i; + double g[6], bnd[2] = {0, 0}, r; + + g[0] = pwr; + g[1] = ts; + g[2] = g[3] = g[4] = 0; + bnd[g[1] >= 1] = 1; + if (g[1] && (g[1] - 1) * (g[0] - 1) <= 0) + { + for (i = 0; i < 48; i++) + { + g[2] = (bnd[0] + bnd[1]) / 2; + if (g[0]) + bnd[(pow(g[2] / g[1], -g[0]) - 1) / g[0] - 1 / g[2] > -1] = g[2]; + else + bnd[g[2] / exp(1 - 1 / g[2]) < g[1]] = g[2]; + } + g[3] = g[2] / g[1]; + if (g[0]) + g[4] = g[2] * (1 / g[0] - 1); + } + if (g[0]) + g[5] = 1 / (g[1] * SQR(g[3]) / 2 - g[4] * (1 - g[3]) + + (1 - pow(g[3], 1 + g[0])) * (1 + g[4]) / (1 + g[0])) - + 1; + else + g[5] = 1 / (g[1] * SQR(g[3]) / 2 + 1 - g[2] - g[3] - + g[2] * g[3] * (log(g[3]) - 1)) - + 1; + for (i = 0; i < 0x10000; i++) + { + curve[i] = 0xffff; + if ((r = (double)i / imax) < 1) + curve[i] = + 0x10000 * + (mode ? (r < g[3] ? r * g[1] + : (g[0] ? pow(r, g[0]) * (1 + g[4]) - g[4] + : log(r) * g[2] + 1)) + : (r < g[2] ? r / g[1] + : (g[0] ? pow((r + g[4]) / (1 + g[4]), 1 / g[0]) + : exp((r - 1) / g[2])))); + } +} + +void tiff_set(ushort *ntag, ushort tag, ushort type, int count, int val) +{ + struct libraw_tiff_tag *tt; + int c; + + tt = (struct libraw_tiff_tag *)(ntag + 1) + (*ntag)++; + tt->tag = tag; + tt->type = type; + tt->count = count; + if ((type < LIBRAW_EXIFTAG_TYPE_SHORT) && (count <= 4)) + for (c = 0; c < 4; c++) + tt->val.c[c] = val >> (c << 3); + else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) && (count <= 2)) + for (c = 0; c < 2; c++) + tt->val.s[c] = val >> (c << 4); + else + tt->val.i = val; +} +#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) + +void tiff_head(int width, int height, struct tiff_hdr *th) +{ + int c; + time_t timestamp = time(NULL); + struct tm *t; + + memset(th, 0, sizeof *th); + th->t_order = htonl(0x4d4d4949) >> 16; + th->magic = 42; + th->ifd = 10; + 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, 1, 16); + for (c = 0; c < 4; c++) + th->bps[c] = 16; + tiff_set(&th->ntag, 259, 3, 1, 1); + tiff_set(&th->ntag, 262, 3, 1, 1); + tiff_set(&th->ntag, 273, 4, 1, sizeof *th); + tiff_set(&th->ntag, 277, 3, 1, 1); + tiff_set(&th->ntag, 278, 4, 1, height); + tiff_set(&th->ntag, 279, 4, 1, height * width * 2); + 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, 306, 2, 20, TOFF(th->date)); + th->rat[0] = th->rat[2] = 300; + th->rat[1] = th->rat[3] = 1; + t = localtime(×tamp); + if (t) + 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); +} + +void write_tiff(int width, int height, unsigned short *bitmap, const char *fn) +{ + struct tiff_hdr th; + + FILE *ofp = fopen(fn, "wb"); + if (!ofp) + return; + tiff_head(width, height, &th); + fwrite(&th, sizeof th, 1, ofp); + fwrite(bitmap, 2, width * height, ofp); + fclose(ofp); } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/Makefile libkdcraw/libkdcraw/libraw/src/Makefile --- libkdcraw-wrk/libkdcraw/libraw/src/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/Makefile 2022-11-07 07:46:31.642795007 +0300 @@ -0,0 +1,2 @@ +all: + (cd ..; make library) diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/canon_600.cpp libkdcraw/libkdcraw/libraw/src/decoders/canon_600.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/canon_600.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/canon_600.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,224 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::canon_600_fixed_wb(int temp) +{ + static const short mul[4][5] = {{667, 358, 397, 565, 452}, + {731, 390, 367, 499, 517}, + {1119, 396, 348, 448, 537}, + {1399, 485, 431, 508, 688}}; + int lo, hi, i; + float frac = 0; + + for (lo = 4; --lo;) + if (*mul[lo] <= temp) + break; + for (hi = 0; hi < 3; hi++) + if (*mul[hi] >= temp) + break; + if (lo != hi) + frac = (float)(temp - *mul[lo]) / (*mul[hi] - *mul[lo]); + for (i = 1; i < 5; i++) + pre_mul[i - 1] = 1 / (frac * mul[hi][i] + (1 - frac) * mul[lo][i]); +} + +/* Return values: 0 = white 1 = near white 2 = not white */ +int LibRaw::canon_600_color(int ratio[2], int mar) +{ + int clipped = 0, target, miss; + + if (flash_used) + { + if (ratio[1] < -104) + { + ratio[1] = -104; + clipped = 1; + } + if (ratio[1] > 12) + { + ratio[1] = 12; + clipped = 1; + } + } + else + { + if (ratio[1] < -264 || ratio[1] > 461) + return 2; + if (ratio[1] < -50) + { + ratio[1] = -50; + clipped = 1; + } + if (ratio[1] > 307) + { + ratio[1] = 307; + clipped = 1; + } + } + target = flash_used || ratio[1] < 197 ? -38 - (398 * ratio[1] >> 10) + : -123 + (48 * ratio[1] >> 10); + if (target - mar <= ratio[0] && target + 20 >= ratio[0] && !clipped) + return 0; + miss = target - ratio[0]; + if (abs(miss) >= mar * 4) + return 2; + if (miss < -20) + miss = -20; + if (miss > mar) + miss = mar; + ratio[0] = target - miss; + return 1; +} + +void LibRaw::canon_600_auto_wb() +{ + int mar, row, col, i, j, st, count[] = {0, 0}; + int test[8], total[2][8], ratio[2][2], stat[2]; + + memset(&total, 0, sizeof total); + i = canon_ev + 0.5; + if (i < 10) + mar = 150; + else if (i > 12) + mar = 20; + else + mar = 280 - 20 * i; + if (flash_used) + mar = 80; + for (row = 14; row < height - 14; row += 4) + for (col = 10; col < width; col += 2) + { + for (i = 0; i < 8; i++) + test[(i & 4) + FC(row + (i >> 1), col + (i & 1))] = + BAYER(row + (i >> 1), col + (i & 1)); + for (i = 0; i < 8; i++) + if (test[i] < 150 || test[i] > 1500) + goto next; + for (i = 0; i < 4; i++) + if (abs(test[i] - test[i + 4]) > 50) + goto next; + for (i = 0; i < 2; i++) + { + for (j = 0; j < 4; j += 2) + ratio[i][j >> 1] = + ((test[i * 4 + j + 1] - test[i * 4 + j]) << 10) / test[i * 4 + j]; + stat[i] = canon_600_color(ratio[i], mar); + } + if ((st = stat[0] | stat[1]) > 1) + goto next; + for (i = 0; i < 2; i++) + if (stat[i]) + for (j = 0; j < 2; j++) + test[i * 4 + j * 2 + 1] = + test[i * 4 + j * 2] * (0x400 + ratio[i][j]) >> 10; + for (i = 0; i < 8; i++) + total[st][i] += test[i]; + count[st]++; + next:; + } + if (count[0] | count[1]) + { + st = count[0] * 200 < count[1]; + for (i = 0; i < 4; i++) + pre_mul[i] = 1.0 / (total[st][i] + total[st][i + 4]); + } +} + +void LibRaw::canon_600_coeff() +{ + static const short table[6][12] = { + {-190, 702, -1878, 2390, 1861, -1349, 905, -393, -432, 944, 2617, -2105}, + {-1203, 1715, -1136, 1648, 1388, -876, 267, 245, -1641, 2153, 3921, + -3409}, + {-615, 1127, -1563, 2075, 1437, -925, 509, 3, -756, 1268, 2519, -2007}, + {-190, 702, -1886, 2398, 2153, -1641, 763, -251, -452, 964, 3040, -2528}, + {-190, 702, -1878, 2390, 1861, -1349, 905, -393, -432, 944, 2617, -2105}, + {-807, 1319, -1785, 2297, 1388, -876, 769, -257, -230, 742, 2067, -1555}}; + int t = 0, i, c; + float mc, yc; + + mc = pre_mul[1] / pre_mul[2]; + yc = pre_mul[3] / pre_mul[2]; + if (mc > 1 && mc <= 1.28 && yc < 0.8789) + t = 1; + if (mc > 1.28 && mc <= 2) + { + if (yc < 0.8789) + t = 3; + else if (yc <= 2) + t = 4; + } + if (flash_used) + t = 5; + for (raw_color = i = 0; i < 3; i++) + FORCC rgb_cam[i][c] = table[t][i * 4 + c] / 1024.0; +} + +void LibRaw::canon_600_load_raw() +{ + uchar data[1120], *dp; + ushort *pix; + int irow, row; + + for (irow = row = 0; irow < height; irow++) + { + checkCancel(); + if (fread(data, 1, 1120, ifp) < 1120) + derror(); + pix = raw_image + row * raw_width; + for (dp = data; dp < data + 1120; dp += 10, pix += 8) + { + pix[0] = (dp[0] << 2) + (dp[1] >> 6); + pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); + pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); + pix[3] = (dp[4] << 2) + (dp[1] & 3); + pix[4] = (dp[5] << 2) + (dp[9] & 3); + pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); + pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); + pix[7] = (dp[8] << 2) + (dp[9] >> 6); + } + if ((row += 2) > height) + row = 1; + } +} + +void LibRaw::canon_600_correct() +{ + int row, col, val; + static const short mul[4][2] = { + {1141, 1145}, {1128, 1109}, {1178, 1149}, {1128, 1109}}; + + for (row = 0; row < height; row++) + { + checkCancel(); + for (col = 0; col < width; col++) + { + if ((val = BAYER(row, col) - black) < 0) + val = 0; + val = val * mul[row & 3][col & 1] >> 9; + BAYER(row, col) = val; + } + } + canon_600_fixed_wb(1311); + canon_600_auto_wb(); + canon_600_coeff(); + maximum = (0x3ff - black) * 1109 >> 9; + black = 0; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/crx.cpp libkdcraw/libkdcraw/libraw/src/decoders/crx.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/crx.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/crx.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,2544 @@ +/* -*- C++ -*- + * File: libraw_crxdec.cpp + * Copyright (C) 2018-2019 Alexey Danilchenko + * Copyright (C) 2019 Alex Tutubalin, LibRaw LLC + * + Canon CR3 file decoder + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#ifdef _abs +#undef _abs +#undef _min +#undef _constrain +#endif +#define _abs(x) (((x) ^ ((int32_t)(x) >> 31)) - ((int32_t)(x) >> 31)) +#define _min(a, b) ((a) < (b) ? (a) : (b)) +#define _constrain(x, l, u) ((x) < (l) ? (l) : ((x) > (u) ? (u) : (x))) + +#if defined(__clang__) || defined(__GNUG__) +#define libraw_inline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) && _MSC_VER > 1400 +#define libraw_inline __forceinline +#else +#define libraw_inline inline +#endif + +// this should be divisible by 4 +#define CRX_BUF_SIZE 0x10000 +#if !defined(_WIN32) || (defined (__GNUC__) && !defined(__INTRINSIC_SPECIAL__BitScanReverse)) +/* __INTRINSIC_SPECIAL__BitScanReverse found in MinGW32-W64 v7.30 headers, may be there is a better solution? */ +typedef uint32_t DWORD; +libraw_inline void _BitScanReverse(DWORD *Index, unsigned long Mask) +{ + *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask); +} +#if LibRawBigEndian +#define _byteswap_ulong(x) (x) +#else +#define _byteswap_ulong(x) __builtin_bswap32(x) +#endif +#endif + +struct CrxBitstream +{ + uint8_t mdatBuf[CRX_BUF_SIZE]; + uint64_t mdatSize; + uint64_t curBufOffset; + uint32_t curPos; + uint32_t curBufSize; + uint32_t bitData; + int32_t bitsLeft; + LibRaw_abstract_datastream *input; +}; + +struct CrxBandParam +{ + CrxBitstream bitStream; + int16_t subbandWidth; + int16_t subbandHeight; + int32_t roundedBitsMask; + int32_t roundedBits; + int16_t curLine; + int32_t *lineBuf0; + int32_t *lineBuf1; + int32_t *lineBuf2; + int32_t sParam; + int32_t kParam; + int32_t *paramData; + int32_t *nonProgrData; + int8_t supportsPartial; +}; + +struct CrxWaveletTransform +{ + int32_t *subband0Buf; + int32_t *subband1Buf; + int32_t *subband2Buf; + int32_t *subband3Buf; + int32_t *lineBuf[8]; + int16_t curLine; + int16_t curH; + int8_t fltTapH; + int16_t height; + int16_t width; +}; + +struct CrxSubband +{ + CrxBandParam *bandParam; + uint64_t mdatOffset; + uint8_t *bandBuf; + int32_t bandSize; + uint64_t dataSize; + int8_t supportsPartial; + int32_t quantValue; + uint16_t width; + uint16_t height; + int32_t paramK; + int64_t dataOffset; +}; + +struct CrxPlaneComp +{ + uint8_t *compBuf; + CrxSubband *subBands; + CrxWaveletTransform *waveletTransform; + int8_t compNumber; + int64_t dataOffset; + int32_t compSize; + int8_t supportsPartial; + int32_t roundedBitsMask; + int8_t tileFlag; +}; + +struct CrxTile +{ + CrxPlaneComp *comps; + int8_t tileFlag; + int8_t tileNumber; + int64_t dataOffset; + int32_t tileSize; + uint16_t width; + uint16_t height; +}; + +struct CrxImage +{ + uint8_t nPlanes; + uint16_t planeWidth; + uint16_t planeHeight; + uint8_t samplePrecision; + uint8_t subbandCount; + uint8_t levels; + uint8_t nBits; + uint8_t encType; + uint8_t tileCols; + uint8_t tileRows; + CrxTile *tiles; + uint64_t mdatOffset; + uint64_t mdatSize; + int16_t *outBufs[4]; // one per plane + int16_t *planeBuf; + LibRaw_abstract_datastream *input; +#ifdef LIBRAW_CR3_MEMPOOL + libraw_memmgr memmgr; + CrxImage() : memmgr(0){} +#endif +}; + +enum TileFlags +{ + E_HAS_TILES_ON_THE_RIGHT = 1, + E_HAS_TILES_ON_THE_LEFT = 2, + E_HAS_TILES_ON_THE_BOTTOM = 4, + E_HAS_TILES_ON_THE_TOP = 8 +}; + +int32_t exCoefNumTbl[0x120] = { + // level 1 + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + // level 2 + 1, 1, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 3, 2, 1, 0, 1, 0, 0, 0, 0, 0, 1, + 2, 4, 4, 2, 1, 2, 1, 0, 0, 0, 0, 1, 1, 4, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 3, 2, 1, 0, 1, 0, 0, 0, 0, 0, 1, 2, 4, + 4, 2, 1, 2, 1, 0, 0, 0, 0, 1, 1, 4, 3, 1, 1, 1, 1, 0, 0, 0, 0, + + // level 3 + 1, 1, 7, 7, 1, 1, 3, 3, 1, 1, 1, 1, 1, 0, 7, 6, 1, 0, 3, 2, 1, 0, 1, 0, 1, + 2, 10, 10, 2, 2, 5, 4, 2, 1, 2, 1, 1, 1, 10, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, + 1, 9, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 0, 9, 8, 1, 1, 4, 3, 1, 1, 1, 1, 1, 2, + 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1}; + +uint32_t JS[32] = {1, 1, 1, 1, 2, 2, 2, 2, + 4, 4, 4, 4, 8, 8, 8, 8, + 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; + +uint32_t J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + +static inline void crxFillBuffer(CrxBitstream *bitStrm) +{ + if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize) + { + bitStrm->curPos = 0; + bitStrm->curBufOffset += bitStrm->curBufSize; +#ifdef LIBRAW_USE_OPENMP +#pragma omp critical +#endif + { +#ifndef LIBRAW_USE_OPENMP + bitStrm->input->lock(); +#endif + bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET); + bitStrm->curBufSize = bitStrm->input->read( + bitStrm->mdatBuf, 1, _min(bitStrm->mdatSize, CRX_BUF_SIZE)); +#ifndef LIBRAW_USE_OPENMP + bitStrm->input->unlock(); +#endif + if (bitStrm->curBufSize < 1) // nothing read + throw LIBRAW_EXCEPTION_IO_EOF; + bitStrm->mdatSize -= bitStrm->curBufSize; + } + } +} + +libraw_inline int crxBitstreamGetZeros(CrxBitstream *bitStrm) +{ + uint32_t nonZeroBit = 0; + uint64_t nextData = 0; + int32_t result = 0; + + if (bitStrm->bitData) + { + _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)bitStrm->bitData); + result = 31 - nonZeroBit; + bitStrm->bitData <<= 32 - nonZeroBit; + bitStrm->bitsLeft -= 32 - nonZeroBit; + } + else + { + uint32_t bitsLeft = bitStrm->bitsLeft; + while (1) + { + while (bitStrm->curPos + 4 <= bitStrm->curBufSize) + { + nextData = + _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + if (nextData) + { + _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); + result = bitsLeft + 31 - nonZeroBit; + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + return result; + } + bitsLeft += 32; + } + if (bitStrm->curBufSize < bitStrm->curPos + 1) + break; // error + nextData = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + if (nextData) + break; + bitsLeft += 8; + } + _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); + result = (uint32_t)(bitsLeft + 7 - nonZeroBit); + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + } + return result; +} + +libraw_inline uint32_t crxBitstreamGetBits(CrxBitstream *bitStrm, int bits) +{ + int bitsLeft = bitStrm->bitsLeft; + uint32_t bitData = bitStrm->bitData; + uint32_t nextWord; + uint8_t nextByte; + uint32_t result; + + if (bitsLeft < bits) + { + // get them from stream + if (bitStrm->curPos + 4 <= bitStrm->curBufSize) + { + nextWord = + _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + bitStrm->bitsLeft = 32 - (bits - bitsLeft); + result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits); + bitStrm->bitData = nextWord << (bits - bitsLeft); + return result; + } + // less than a word left - read byte at a time + do + { + if (bitStrm->curPos >= bitStrm->curBufSize) + break; // error + bitsLeft += 8; + nextByte = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + bitData |= nextByte << (32 - bitsLeft); + } while (bitsLeft < bits); + } + result = bitData >> (32 - bits); // 32-bits + bitStrm->bitData = bitData << bits; + bitStrm->bitsLeft = bitsLeft - bits; + return result; +} + +libraw_inline int crxPredictKParameter(int32_t prevK, int32_t bitCode, + int32_t maxVal = 0) +{ + int32_t newKParam = prevK - (bitCode < (1 << prevK >> 1)) + + ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5); + + return !maxVal || newKParam < maxVal ? newKParam : maxVal; +} + +libraw_inline void crxDecodeSymbolL1(CrxBandParam *param, + int32_t doMedianPrediction, + int32_t notEOL = 0) +{ + if (doMedianPrediction) + { + int32_t symb[4]; + + int32_t delta = param->lineBuf0[1] - param->lineBuf0[0]; + symb[2] = param->lineBuf1[0]; + symb[0] = symb[1] = delta + symb[2]; + symb[3] = param->lineBuf0[1]; + + param->lineBuf1[1] = + symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0))]; + } + else + param->lineBuf1[1] = param->lineBuf0[1]; + + // get next error symbol + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + + // add converted (+/-) error code to predicted value + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + + // for not end of the line - use one symbol ahead to estimate next K + if (notEOL) + { + int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1; + bitCode = (bitCode + _abs(nextDelta)) >> 1; + ++param->lineBuf0; + } + + // update K parameter + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + + ++param->lineBuf1; +} + +int crxDecodeLine(CrxBandParam *param) +{ + int length = param->subbandWidth; + + param->lineBuf1[0] = param->lineBuf0[1]; + for (; length > 1; --length) + { + if (param->lineBuf1[0] != param->lineBuf0[1] || + param->lineBuf1[0] != param->lineBuf0[2]) + { + crxDecodeSymbolL1(param, 1, 1); + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + } + + if (length > 0) + crxDecodeSymbolL1(param, 0, (length > 1)); + } + } + + if (length == 1) + crxDecodeSymbolL1(param, 1, 0); + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +libraw_inline void crxDecodeSymbolL1Rounded(CrxBandParam *param, + int32_t doSym = 1, + int32_t doCode = 1) +{ + int32_t sym = param->lineBuf0[1]; + + if (doSym) + { + // calculate the next symbol gradient + int32_t symb[4]; + int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0]; + symb[2] = param->lineBuf1[0]; + symb[0] = symb[1] = deltaH + symb[2]; + symb[3] = param->lineBuf0[1]; + sym = + symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0))]; + } + + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + int32_t code = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code >> 31) + sym; + + if (doCode) + { + if (param->lineBuf0[2] > param->lineBuf0[1]) + code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask - + 1) >> + param->roundedBits; + else + code = -( + (param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >> + param->roundedBits); + + param->kParam = crxPredictKParameter(param->kParam, + (bitCode + 2 * _abs(code)) >> 1, 15); + } + else + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + + ++param->lineBuf1; +} + +int crxDecodeLineRounded(CrxBandParam *param) +{ + int32_t valueReached = 0; + + param->lineBuf0[0] = param->lineBuf0[1]; + param->lineBuf1[0] = param->lineBuf0[1]; + int32_t length = param->subbandWidth; + + for (; length > 1; --length) + { + if (_abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask) + { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = 1; + } + else if (valueReached || _abs(param->lineBuf0[0] - param->lineBuf1[0]) > + param->roundedBitsMask) + { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = 0; + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + } + if (nSyms > length) + return -1; + } + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length > 1) + { + crxDecodeSymbolL1Rounded(param, 0); + ++param->lineBuf0; + valueReached = _abs(param->lineBuf0[1] - param->lineBuf0[0]) > + param->roundedBitsMask; + } + else if (length == 1) + crxDecodeSymbolL1Rounded(param, 0, 0); + } + } + if (length == 1) + crxDecodeSymbolL1Rounded(param, 1, 0); + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +int crxDecodeLineNoRefPrevLine(CrxBandParam *param) +{ + int32_t i = 0; + + for (; i < param->subbandWidth - 1; i++) + { + if (param->lineBuf0[i + 2] | param->lineBuf0[i + 1] | param->lineBuf1[i]) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + if (param->lineBuf2[i + 1] - param->kParam <= 1) + { + if (param->kParam >= 15) + param->kParam = 15; + } + else + ++param->kParam; + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + if (i != param->subbandWidth - 1) + { + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (i + nSyms > param->subbandWidth) + { + nSyms = param->subbandWidth - i; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (i + nSyms == param->subbandWidth) + break; + } + if (i + nSyms < param->subbandWidth) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + } + if (i + nSyms > param->subbandWidth) + return -1; + } + } + else if (i > param->subbandWidth) + return -1; + + if (nSyms > 0) + { + memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(int32_t)); + memset(param->lineBuf2 + i, 0, nSyms * sizeof(int32_t)); + i += nSyms; + } + + if (i >= param->subbandWidth - 1) + { + if (i == param->subbandWidth - 1) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; + } + continue; + } + else + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + if (param->lineBuf2[i + 1] - param->kParam <= 1) + { + if (param->kParam >= 15) + param->kParam = 15; + } + else + ++param->kParam; + } + } + param->lineBuf2[i] = param->kParam; + } + if (i == param->subbandWidth - 1) + { + int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; + } + + return 0; +} + +int crxDecodeTopLine(CrxBandParam *param) +{ + param->lineBuf1[0] = 0; + + int32_t length = param->subbandWidth; + + // read the line from bitstream + for (; length > 1; --length) + { + if (param->lineBuf1[0]) + param->lineBuf1[1] = param->lineBuf1[0]; + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) + break; + } + + param->lineBuf1[1] = 0; + } + + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + if (length == 1) + { + param->lineBuf1[1] = param->lineBuf1[0]; + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +int crxDecodeTopLineRounded(CrxBandParam *param) +{ + param->lineBuf1[0] = 0; + + int32_t length = param->subbandWidth; + + // read the line from bitstream + for (; length > 1; --length) + { + if (_abs(param->lineBuf1[0]) > param->roundedBitsMask) + param->lineBuf1[1] = param->lineBuf1[0]; + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) + break; + + param->lineBuf1[1] = 0; + } + + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + + int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + if (length == 1) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +int crxDecodeTopLineNoRefPrevLine(CrxBandParam *param) +{ + param->lineBuf0[0] = 0; + param->lineBuf1[0] = 0; + int32_t length = param->subbandWidth; + for (; length > 1; --length) + { + if (param->lineBuf1[0]) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf2[0] = 0; + param->lineBuf1[1] = 0; + ++param->lineBuf1; + ++param->lineBuf2; + } + + if (length <= 0) + break; + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + param->lineBuf2[0] = param->kParam; + ++param->lineBuf2; + ++param->lineBuf1; + } + + if (length == 1) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[0] = param->kParam; + ++param->lineBuf1; + } + + param->lineBuf1[1] = 0; + + return 0; +} + +int crxDecodeLine(CrxBandParam *param, uint8_t *bandBuf) +{ + if (!param || !bandBuf) + return -1; + if (param->curLine >= param->subbandHeight) + return -1; + + if (param->curLine == 0) + { + int32_t lineLength = param->subbandWidth + 2; + + param->sParam = 0; + param->kParam = 0; + if (param->supportsPartial) + { + if (param->roundedBitsMask <= 0) + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeTopLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + else + { + param->roundedBits = 1; + if (param->roundedBitsMask & ~1) + { + while (param->roundedBitsMask >> param->roundedBits) + ++param->roundedBits; + } + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeTopLineRounded(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + } + else + { + param->lineBuf2 = (int32_t *)param->nonProgrData; + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeTopLineNoRefPrevLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + } + else if (!param->supportsPartial) + { + int32_t lineLength = param->subbandWidth + 2; + param->lineBuf2 = (int32_t *)param->nonProgrData; + if (param->curLine & 1) + { + param->lineBuf1 = (int32_t *)param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } + else + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeLineNoRefPrevLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + else if (param->roundedBitsMask <= 0) + { + int32_t lineLength = param->subbandWidth + 2; + if (param->curLine & 1) + { + param->lineBuf1 = (int32_t *)param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } + else + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + else + { + int32_t lineLength = param->subbandWidth + 2; + if (param->curLine & 1) + { + param->lineBuf1 = (int32_t *)param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } + else + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeLineRounded(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + return 0; +} + +int crxDecodeLineWithIQuantization(CrxSubband *subband) +{ + int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48}; + + if (!subband->dataSize) + { + memset(subband->bandBuf, 0, subband->bandSize); + return 0; + } + + if (subband->supportsPartial) + { + uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream); + if (bitCode >= 23) + bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8); + else if (subband->paramK) + bitCode = + crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) | + (bitCode << subband->paramK); + + subband->quantValue += + -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer + subband->paramK = crxPredictKParameter(subband->paramK, bitCode); + if (subband->paramK > 7) + return -1; + } + if (crxDecodeLine(subband->bandParam, subband->bandBuf)) + return -1; + + if (subband->width <= 0) + return 0LL; + + // update subband buffers + int32_t *bandBuf = (int32_t *)subband->bandBuf; + int32_t qScale = + q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6); + if (subband->quantValue / 6 >= 6) + qScale = q_step_tbl[subband->quantValue % 6] * + (1 << (subband->quantValue / 6 + 26)); + + if (qScale != 1) + for (int32_t i = 0; i < subband->width; i++) + bandBuf[i] *= qScale; + + return 0; +} + +void crxHorizontal53(int32_t *lineBufLA, int32_t *lineBufLB, + CrxWaveletTransform *wavelet, uint32_t tileFlag) +{ + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + int32_t *band2Buf = wavelet->subband2Buf; + int32_t *band3Buf = wavelet->subband3Buf; + + if (wavelet->width <= 1) + { + lineBufLA[0] = band0Buf[0]; + lineBufLB[0] = band2Buf[0]; + } + else + { + if (tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } + else + { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + ++band0Buf; + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1); + lineBufLA[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1); + lineBufLB[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufLA += 2; + lineBufLB += 2; + } + if (tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1); + + int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1); + + if (wavelet->width & 1) + { + lineBufLA[2] = deltaA; + lineBufLB[2] = deltaB; + } + } + else if (wavelet->width & 1) + { + lineBufLA[1] = + band1Buf[0] + + ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1); + lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + + lineBufLB[1] = + band3Buf[0] + + ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1); + lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + else + { + lineBufLA[1] = lineBufLA[0] + band1Buf[0]; + lineBufLB[1] = lineBufLB[0] + band3Buf[0]; + } + } +} + +int32_t *crxIdwt53FilterGetLine(CrxPlaneComp *comp, int32_t level) +{ + int32_t *result = comp->waveletTransform[level] + .lineBuf[(comp->waveletTransform[level].fltTapH - + comp->waveletTransform[level].curH + 5) % + 5 + + 3]; + comp->waveletTransform[level].curH--; + return result; +} + +int crxIdwt53FilterDecode(CrxPlaneComp *comp, int32_t level) +{ + if (comp->waveletTransform[level].curH) + return 0; + + CrxSubband *sband = comp->subBands + 3 * level; + + if (comp->waveletTransform[level].height - 3 <= + comp->waveletTransform[level].curLine && + !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) + { + if (comp->waveletTransform[level].height & 1) + { + if (level) + { + if (crxIdwt53FilterDecode(comp, level - 1)) + return -1; + } + else if (crxDecodeLineWithIQuantization(sband)) + return -1; + + if (crxDecodeLineWithIQuantization(sband + 1)) + return -1; + } + } + else + { + if (level) + { + if (crxIdwt53FilterDecode(comp, level - 1)) + return -1; + } + else if (crxDecodeLineWithIQuantization(sband)) // LL band + return -1; + + if (crxDecodeLineWithIQuantization(sband + 1) || // HL band + crxDecodeLineWithIQuantization(sband + 2) || // LH band + crxDecodeLineWithIQuantization(sband + 3)) // HH band + return -1; + } + + return 0; +} + +int crxIdwt53FilterTransform(CrxPlaneComp *comp, uint32_t level) +{ + CrxWaveletTransform *wavelet = comp->waveletTransform + level; + + if (wavelet->curH) + return 0; + + if (wavelet->curLine >= wavelet->height - 3) + { + if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) + { + if (wavelet->height & 1) + { + if (level) + { + if (!wavelet[-1].curH) + if (crxIdwt53FilterTransform(comp, level - 1)) + return -1; + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + + int32_t *lineBufL0 = wavelet->lineBuf[0]; + int32_t *lineBufL1 = wavelet->lineBuf[1]; + wavelet->lineBuf[1] = wavelet->lineBuf[2]; + wavelet->lineBuf[2] = lineBufL1; + + // process L bands + if (wavelet->width <= 1) + { + lineBufL0[0] = band0Buf[0]; + } + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } + else + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + } + ++band0Buf; + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = + band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + ++band0Buf; + ++band1Buf; + lineBufL0 += 2; + } + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t delta = + band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + if (wavelet->width & 1) + lineBufL0[2] = delta; + } + else if (wavelet->width & 1) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + } + else + lineBufL0[1] = band1Buf[0] + lineBufL0[0]; + } + + // process H bands + lineBufL0 = wavelet->lineBuf[0]; + lineBufL1 = wavelet->lineBuf[1]; + for (int32_t i = 0; i < wavelet->width; i++) + { + int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; + } + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } + else + { + int32_t *lineBufL2 = wavelet->lineBuf[2]; + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + wavelet->lineBuf[1] = lineBufL2; + wavelet->lineBuf[2] = wavelet->lineBuf[1]; + + for (int32_t i = 0; i < wavelet->width; i++) + lineBufH1[i] = lineBufH0[i] + lineBufL2[i]; + + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; + } + } + } + else + { + if (level) + { + if (!wavelet[-1].curH && crxIdwt53FilterTransform(comp, level - 1)) + return -1; + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + int32_t *band2Buf = wavelet->subband2Buf; + int32_t *band3Buf = wavelet->subband3Buf; + + int32_t *lineBufL0 = wavelet->lineBuf[0]; + int32_t *lineBufL1 = wavelet->lineBuf[1]; + int32_t *lineBufL2 = wavelet->lineBuf[2]; + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + + wavelet->lineBuf[1] = wavelet->lineBuf[2]; + wavelet->lineBuf[2] = lineBufL1; + + // process L bands + if (wavelet->width <= 1) + { + lineBufL0[0] = band0Buf[0]; + lineBufL1[0] = band2Buf[0]; + } + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } + else + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + ++band0Buf; + ++band2Buf; + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufL0 += 2; + lineBufL1 += 2; + } + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1); + + int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1); + + if (wavelet->width & 1) + { + lineBufL0[2] = deltaA; + lineBufL1[2] = deltaB; + } + } + else if (wavelet->width & 1) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + } + else + { + lineBufL0[1] = lineBufL0[0] + band1Buf[0]; + lineBufL1[1] = lineBufL1[0] + band3Buf[0]; + } + } + + // process H bands + lineBufL0 = wavelet->lineBuf[0]; + lineBufL1 = wavelet->lineBuf[1]; + lineBufL2 = wavelet->lineBuf[2]; + for (int32_t i = 0; i < wavelet->width; i++) + { + int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; + } + if (wavelet->curLine >= wavelet->height - 3 && wavelet->height & 1) + { + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } + else + { + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; + } + } + + return 0; +} + +int crxIdwt53FilterInitialize(CrxPlaneComp *comp, int32_t prevLevel) +{ + if (prevLevel < 0) + return 0; + + for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1; + curLevel++, curBand += 3) + { + CrxWaveletTransform *wavelet = comp->waveletTransform + curLevel; + if (curLevel) + wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1); + else if (crxDecodeLineWithIQuantization(comp->subBands + curBand)) + return -1; + + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + if (wavelet->height > 1) + { + if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) || + crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) || + crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)) + return -1; + + int32_t *lineBufL0 = wavelet->lineBuf[0]; + int32_t *lineBufL1 = wavelet->lineBuf[1]; + int32_t *lineBufL2 = wavelet->lineBuf[2]; + + if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP) + { + crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet, + comp->tileFlag); + if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) || + crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)) + return -1; + + int32_t *band2Buf = wavelet->subband2Buf; + int32_t *band3Buf = wavelet->subband3Buf; + + // process L band + if (wavelet->width <= 1) + lineBufL2[0] = band2Buf[0]; + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band3Buf; + } + else + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = + band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + + ++band2Buf; + ++band3Buf; + lineBufL2 += 2; + } + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t delta = + band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + if (wavelet->width & 1) + lineBufL2[2] = delta; + } + else if (wavelet->width & 1) + { + int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + } + else + { + lineBufL2[1] = band3Buf[0] + lineBufL2[0]; + } + } + + // process H band + for (int32_t i = 0; i < wavelet->width; i++) + lineBufH0[i] = + lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2); + } + else + { + crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet, + comp->tileFlag); + for (int i = 0; i < wavelet->width; i++) + lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1); + } + + if (crxIdwt53FilterDecode(comp, curLevel) || + crxIdwt53FilterTransform(comp, curLevel)) + return -1; + } + else + { + if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)) + return -1; + + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + + // process H band + if (wavelet->width <= 1) + lineBufH0[0] = band0Buf[0]; + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } + else + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + + ++band0Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + + ++band0Buf; + ++band1Buf; + lineBufH0 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } + else if (wavelet->width & 1) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } + else + { + lineBufH0[1] = band1Buf[0] + lineBufH0[0]; + } + } + ++wavelet->curLine; + ++wavelet->curH; + wavelet->fltTapH = (wavelet->fltTapH + 1) % 5; + } + } + + return 0; +} + +void crxFreeSubbandData(CrxImage *image, CrxPlaneComp *comp) +{ + if (comp->compBuf) + { + free(comp->compBuf); + comp->compBuf = 0; + } + + if (!comp->subBands) + return; + + for (int32_t i = 0; i < image->subbandCount; i++) + { + if (comp->subBands[i].bandParam) + { + free(comp->subBands[i].bandParam); + comp->subBands[i].bandParam = 0LL; + } + comp->subBands[i].bandBuf = 0; + comp->subBands[i].bandSize = 0; + } +} + +void crxConvertPlaneLine(CrxImage *img, int imageRow, int imageCol = 0, + int plane = 0, int32_t *lineData = 0, + int lineLength = 0) +{ + if (lineData) + { + uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol; + if (img->encType == 1) + { + int32_t maxVal = 1 << (img->nBits - 1); + int32_t minVal = -maxVal; + --maxVal; + for (int i = 0; i < lineLength; i++) + img->outBufs[plane][rawOffset + 2 * i] = + _constrain(lineData[i], minVal, maxVal); + } + else if (img->encType == 3) + { + // copy to intermediate planeBuf + rawOffset = plane * img->planeWidth * img->planeHeight + + img->planeWidth * imageRow + imageCol; + for (int i = 0; i < lineLength; i++) + img->planeBuf[rawOffset + i] = lineData[i]; + } + else if (img->nPlanes == 4) + { + int32_t median = 1 << (img->nBits - 1); + int32_t maxVal = (1 << img->nBits) - 1; + for (int i = 0; i < lineLength; i++) + img->outBufs[plane][rawOffset + 2 * i] = + _constrain(median + lineData[i], 0, maxVal); + } + else if (img->nPlanes == 1) + { + int32_t maxVal = (1 << img->nBits) - 1; + int32_t median = 1 << (img->nBits - 1); + rawOffset = img->planeWidth * imageRow + imageCol; + for (int i = 0; i < lineLength; i++) + img->outBufs[0][rawOffset + i] = + _constrain(median + lineData[i], 0, maxVal); + } + } + else if (img->encType == 3 && img->planeBuf) + { + int32_t planeSize = img->planeWidth * img->planeHeight; + int16_t *plane0 = img->planeBuf + imageRow * img->planeWidth; + int16_t *plane1 = plane0 + planeSize; + int16_t *plane2 = plane1 + planeSize; + int16_t *plane3 = plane2 + planeSize; + + int32_t median = 1 << (img->nBits - 1) << 10; + int32_t maxVal = (1 << img->nBits) - 1; + uint32_t rawLineOffset = 4 * img->planeWidth * imageRow; + + // for this stage - all except imageRow is ignored + for (int i = 0; i < img->planeWidth; i++) + { + int32_t gr = + median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i]; + int32_t val = 0; + if (gr < 0) + gr = -(((_abs(gr) + 512) >> 9) & ~1); + else + gr = ((_abs(gr) + 512) >> 9) & ~1; + + // Essentially R = round(median + P0 + 1.474*P3) + val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10; + img->outBufs[0][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3) + val = (plane2[i] + gr + 1) >> 1; + img->outBufs[1][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3) + val = (gr - plane2[i] + 1) >> 1; + img->outBufs[2][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + // Essentially B = round(median + P0 + 1.881*P1) + val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10; + img->outBufs[3][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + } + } +} + +int crxParamInit( +#ifdef LIBRAW_CR3_MEMPOOL + libraw_memmgr& mm, +#endif + CrxBandParam **param, uint64_t subbandMdatOffset, + uint64_t subbandDataSize, uint32_t subbandWidth, + uint32_t subbandHeight, int32_t supportsPartial, + uint32_t roundedBitsMask, LibRaw_abstract_datastream *input) +{ + int32_t progrDataSize = supportsPartial ? 0 : sizeof(int32_t) * subbandWidth; + int32_t paramLength = 2 * subbandWidth + 4; + uint8_t *paramBuf = (uint8_t *) +#ifdef LIBRAW_CR3_MEMPOOL + mm. +#endif + calloc( + 1, sizeof(CrxBandParam) + sizeof(int32_t) * paramLength + progrDataSize); + + if (!paramBuf) + return -1; + + *param = (CrxBandParam *)paramBuf; + + paramBuf += sizeof(CrxBandParam); + + (*param)->paramData = (int32_t *)paramBuf; + (*param)->nonProgrData = + progrDataSize ? (*param)->paramData + paramLength : 0; + (*param)->subbandWidth = subbandWidth; + (*param)->subbandHeight = subbandHeight; + (*param)->roundedBits = 0; + (*param)->curLine = 0; + (*param)->roundedBitsMask = roundedBitsMask; + (*param)->supportsPartial = supportsPartial; + (*param)->bitStream.bitData = 0; + (*param)->bitStream.bitsLeft = 0; + (*param)->bitStream.mdatSize = subbandDataSize; + (*param)->bitStream.curPos = 0; + (*param)->bitStream.curBufSize = 0; + (*param)->bitStream.curBufOffset = subbandMdatOffset; + (*param)->bitStream.input = input; + + crxFillBuffer(&(*param)->bitStream); + + return 0; +} + +int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp, + const CrxTile *tile, uint32_t mdatOffset) +{ + long compDataSize = 0; + long waveletDataOffset = 0; + long compCoeffDataOffset = 0; + int32_t toSubbands = 3 * img->levels + 1; + int32_t transformWidth = 0; + + CrxSubband *subbands = planeComp->subBands; + + // calculate sizes + for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) + { + subbands[subbandNum].bandSize = + subbands[subbandNum].width * sizeof(int32_t); // 4bytes + compDataSize += subbands[subbandNum].bandSize; + } + + if (img->levels) + { + int32_t encLevels = img->levels ? img->levels : 1; + waveletDataOffset = (compDataSize + 7) & ~7; + compDataSize = + (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7; + compCoeffDataOffset = compDataSize; + + // calc wavelet line buffer sizes (always at one level up from current) + for (int level = 0; level < img->levels; ++level) + if (level < img->levels - 1) + compDataSize += 8 * sizeof(int32_t) * + planeComp->subBands[3 * (level + 1) + 2].width; + else + compDataSize += 8 * sizeof(int32_t) * tile->width; + } + + // buffer allocation + planeComp->compBuf = (uint8_t *) +#ifdef LIBRAW_CR3_MEMPOOL + img->memmgr. +#endif + malloc(compDataSize); + if (!planeComp->compBuf) + return -1; + + // subbands buffer and sizes initialisation + uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset; + uint8_t *subbandBuf = planeComp->compBuf; + + for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) + { + subbands[subbandNum].bandBuf = subbandBuf; + subbandBuf += subbands[subbandNum].bandSize; + subbands[subbandNum].mdatOffset = + subbandMdatOffset + subbands[subbandNum].dataOffset; + } + + // wavelet data initialisation + if (img->levels) + { + CrxWaveletTransform *waveletTransforms = + (CrxWaveletTransform *)(planeComp->compBuf + waveletDataOffset); + int32_t *paramData = (int32_t *)(planeComp->compBuf + compCoeffDataOffset); + + planeComp->waveletTransform = waveletTransforms; + waveletTransforms[0].subband0Buf = (int32_t *)subbands->bandBuf; + + for (int level = 0; level < img->levels; ++level) + { + int32_t band = 3 * level + 1; + + if (level >= img->levels - 1) + { + waveletTransforms[level].height = tile->height; + transformWidth = tile->width; + } + else + { + waveletTransforms[level].height = subbands[band + 3].height; + transformWidth = subbands[band + 4].width; + } + waveletTransforms[level].width = transformWidth; + waveletTransforms[level].lineBuf[0] = paramData; + waveletTransforms[level].lineBuf[1] = + waveletTransforms[level].lineBuf[0] + transformWidth; + waveletTransforms[level].lineBuf[2] = + waveletTransforms[level].lineBuf[1] + transformWidth; + waveletTransforms[level].lineBuf[3] = + waveletTransforms[level].lineBuf[2] + transformWidth; + waveletTransforms[level].lineBuf[4] = + waveletTransforms[level].lineBuf[3] + transformWidth; + waveletTransforms[level].lineBuf[5] = + waveletTransforms[level].lineBuf[4] + transformWidth; + waveletTransforms[level].lineBuf[6] = + waveletTransforms[level].lineBuf[5] + transformWidth; + waveletTransforms[level].lineBuf[7] = + waveletTransforms[level].lineBuf[6] + transformWidth; + waveletTransforms[level].curLine = 0; + waveletTransforms[level].curH = 0; + waveletTransforms[level].fltTapH = 0; + waveletTransforms[level].subband1Buf = (int32_t *)subbands[band].bandBuf; + waveletTransforms[level].subband2Buf = + (int32_t *)subbands[band + 1].bandBuf; + waveletTransforms[level].subband3Buf = + (int32_t *)subbands[band + 2].bandBuf; + + paramData = waveletTransforms[level].lineBuf[7] + transformWidth; + } + } + + // decoding params and bitstream initialisation + for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) + { + if (subbands[subbandNum].dataSize) + { + int32_t supportsPartial = 0; + uint32_t roundedBitsMask = 0; + + if (planeComp->supportsPartial && subbandNum == 0) + { + roundedBitsMask = planeComp->roundedBitsMask; + supportsPartial = 1; + } + if (crxParamInit( +#ifdef LIBRAW_CR3_MEMPOOL + img->memmgr, +#endif + &subbands[subbandNum].bandParam, + subbands[subbandNum].mdatOffset, + subbands[subbandNum].dataSize, + subbands[subbandNum].width, subbands[subbandNum].height, + supportsPartial, roundedBitsMask, img->input)) + return -1; + } + } + + return 0; +} + +int LibRaw::crxDecodePlane(void *p, uint32_t planeNumber) +{ + CrxImage *img = (CrxImage *)p; + int imageRow = 0; + for (int tRow = 0; tRow < img->tileRows; tRow++) + { + int imageCol = 0; + for (int tCol = 0; tCol < img->tileCols; tCol++) + { + CrxTile *tile = img->tiles + tRow * img->tileCols + tCol; + CrxPlaneComp *planeComp = tile->comps + planeNumber; + uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset; + + // decode single tile + if (crxSetupSubbandData(img, planeComp, tile, tileMdatOffset)) + return -1; + + if (img->levels) + { + if (crxIdwt53FilterInitialize(planeComp, img->levels - 1)) + return -1; + for (int i = 0; i < tile->height; ++i) + { + if (crxIdwt53FilterDecode(planeComp, img->levels - 1) || + crxIdwt53FilterTransform(planeComp, img->levels - 1)) + return -1; + int32_t *lineData = + crxIdwt53FilterGetLine(planeComp, img->levels - 1); + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, + lineData, tile->width); + } + } + else + { + // we have the only subband in this case + if (!planeComp->subBands->dataSize) + { + memset(planeComp->subBands->bandBuf, 0, + planeComp->subBands->bandSize); + return 0; + } + + for (int i = 0; i < tile->height; ++i) + { + if (crxDecodeLine(planeComp->subBands->bandParam, + planeComp->subBands->bandBuf)) + return -1; + int32_t *lineData = (int32_t *)planeComp->subBands->bandBuf; + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, + lineData, tile->width); + } + } + imageCol += tile->width; + } + imageRow += img->tiles[tRow * img->tileCols].height; + } + + return 0; +} + +int crxReadSubbandHeaders(crx_data_header_t *hdr, CrxImage *img, CrxTile *tile, + CrxPlaneComp *comp, uint8_t **subbandMdatPtr, + int32_t *hdrSize) +{ + CrxSubband *band = comp->subBands + img->subbandCount - 1; // set to last band + uint32_t bandHeight = tile->height; + uint32_t bandWidth = tile->width; + int32_t bandWidthExCoef = 0; + int32_t bandHeightExCoef = 0; + if (img->levels) + { + // Build up subband sequences to crxDecode to a level in a header + + // Coefficient structure is a bit unclear and convoluted: + // 3 levels max - 8 groups (for tile width rounded to 8 bytes) + // of 3 band per level 4 sets of coefficients for each + int32_t *rowExCoef = + exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7); + int32_t *colExCoef = + exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7); + for (int level = 0; level < img->levels; ++level) + { + int32_t widthOddPixel = bandWidth & 1; + int32_t heightOddPixel = bandHeight & 1; + bandWidth = (widthOddPixel + bandWidth) >> 1; + bandHeight = (heightOddPixel + bandHeight) >> 1; + + int32_t bandWidthExCoef0 = 0; + int32_t bandWidthExCoef1 = 0; + int32_t bandHeightExCoef0 = 0; + int32_t bandHeightExCoef1 = 0; + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + bandWidthExCoef0 = rowExCoef[0]; + bandWidthExCoef1 = rowExCoef[1]; + } + if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT) + ++bandWidthExCoef0; + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) + { + bandHeightExCoef0 = colExCoef[0]; + bandHeightExCoef1 = colExCoef[1]; + } + if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP) + ++bandHeightExCoef0; + + band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-1].width = bandWidth + bandWidthExCoef1; + band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[-2].height = bandHeight + bandHeightExCoef1; + + rowExCoef += 4; + colExCoef += 4; + band -= 3; + } + bandWidthExCoef = bandHeightExCoef = 0; + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + bandWidthExCoef = + exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) + + 4 * (img->levels - 1) + 1]; + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) + bandHeightExCoef = + exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) + + 4 * (img->levels - 1) + 1]; + } + band->width = bandWidthExCoef + bandWidth; + band->height = bandHeightExCoef + bandHeight; + + if (!img->subbandCount) + return 0; + int32_t subbandOffset = 0; + band = comp->subBands; + for (int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++) + { + if (*hdrSize < 0xC) + return -1; + + if (LibRaw::sgetn(2, *subbandMdatPtr) != 0xFF03) + return -1; + + uint32_t bitData = LibRaw::sgetn(4, *subbandMdatPtr + 8); + uint32_t subbandSize = LibRaw::sgetn(4, *subbandMdatPtr + 4); + + if ((unsigned)curSubband != bitData >> 28) + { + band->dataSize = subbandSize; + return -1; + } + band->dataSize = subbandSize - (bitData & 0x7FF); + band->supportsPartial = bitData & 0x8000 ? 1 : 0; + band->dataOffset = subbandOffset; + band->quantValue = (bitData >> 19) & 0xFF; + band->paramK = 0; + band->bandParam = 0; + band->bandBuf = 0; + band->bandSize = 0; + + subbandOffset += subbandSize; + + *subbandMdatPtr += 0xC; + *hdrSize -= 0xC; + } + return 0; +} + +int crxReadImageHeaders(crx_data_header_t *hdr, CrxImage *img, uint8_t *mdatPtr, + int32_t hdrBufSize) +{ + int nTiles = img->tileRows * img->tileCols; + + if (!nTiles) + return -1; + + if (!img->tiles) + { + img->tiles = (CrxTile *) +#ifdef LIBRAW_CR3_MEMPOOL + img->memmgr. +#endif + calloc( + sizeof(CrxTile) * nTiles + + sizeof(CrxPlaneComp) * nTiles * img->nPlanes + + sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount,1); + if (!img->tiles) + return -1; + + // memory areas in allocated chunk + CrxTile *tile = img->tiles; + CrxPlaneComp *comps = (CrxPlaneComp *)(tile + nTiles); + CrxSubband *bands = (CrxSubband *)(comps + img->nPlanes * nTiles); + + for (int curTile = 0; curTile < nTiles; curTile++, tile++) + { + tile->tileFlag = 0; // tile neighbouring flags + tile->tileNumber = curTile; + tile->tileSize = 0; + tile->comps = comps + curTile * img->nPlanes; + + if ((curTile + 1) % img->tileCols) + { + // not the last tile in a tile row + tile->width = hdr->tileWidth; + if (img->tileCols > 1) + { + tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT; + if (curTile % img->tileCols) + // not the first tile in tile row + tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT; + } + } + else + { + // last tile in a tile row + tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1); + if (img->tileCols > 1) + tile->tileFlag = E_HAS_TILES_ON_THE_LEFT; + } + if (curTile < nTiles - img->tileCols) + { + // in first tile row + tile->height = hdr->tileHeight; + if (img->tileRows > 1) + { + tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM; + if (curTile >= img->tileCols) + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + } + else + { + // non first tile row + tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1); + if (img->tileRows > 1) + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + if (img->nPlanes) + { + CrxPlaneComp *comp = tile->comps; + CrxSubband *band = bands + curTile * img->nPlanes * img->subbandCount; + + for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++) + { + comp->compNumber = curComp; + comp->supportsPartial = 1; + comp->tileFlag = tile->tileFlag; + comp->subBands = band; + comp->compBuf = 0; + comp->waveletTransform = 0; + if (img->subbandCount) + { + for (int curBand = 0; curBand < img->subbandCount; + curBand++, band++) + { + band->supportsPartial = 0; + band->quantValue = 4; + band->bandParam = 0; + band->dataSize = 0; + } + } + } + } + } + } + + uint32_t tileOffset = 0; + int32_t dataSize = hdrBufSize; + uint8_t *dataPtr = mdatPtr; + CrxTile *tile = img->tiles; + + for (int curTile = 0; curTile < nTiles; curTile++, tile++) + { + if (dataSize < 0xC) + return -1; + + if (LibRaw::sgetn(2, dataPtr) != 0xFF01) + return -1; + if (LibRaw::sgetn(2, dataPtr + 8) != (unsigned)curTile) + return -1; + + dataSize -= 0xC; + + tile->tileSize = LibRaw::sgetn(4, dataPtr + 4); + tile->dataOffset = tileOffset; + + int32_t hdrExtraBytes = LibRaw::sgetn(2, dataPtr + 2) - 8; + tileOffset += tile->tileSize; + dataPtr += hdrExtraBytes + 0xC; + dataSize -= hdrExtraBytes; + + uint32_t compOffset = 0; + CrxPlaneComp *comp = tile->comps; + + for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++) + { + if (dataSize < 0xC) + return -1; + + if (LibRaw::sgetn(2, dataPtr) != 0xFF02) + return -1; + if (compNum != dataPtr[8] >> 4) + return -1; + + comp->compSize = LibRaw::sgetn(4, dataPtr + 4); + + int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3; + comp->supportsPartial = (dataPtr[8] & 8) != 0; + + comp->dataOffset = compOffset; + comp->tileFlag = tile->tileFlag; + + compOffset += comp->compSize; + dataSize -= 0xC; + dataPtr += 0xC; + + comp->roundedBitsMask = 0; + + if (compHdrRoundedBits) + { + if (img->levels || !comp->supportsPartial) + return -1; + + comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1); + } + + if (crxReadSubbandHeaders(hdr, img, tile, comp, &dataPtr, &dataSize)) + return -1; + } + } + return 0; +} + +int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf, + uint64_t mdatOffset, uint32_t mdatSize, int32_t hdrBufSize, + uint8_t *mdatHdrPtr) +{ + int IncrBitTable[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0}; + + img->planeWidth = hdr->f_width; + img->planeHeight = hdr->f_height; + + if (hdr->tileWidth < 0x16 || hdr->tileHeight < 0x16 || + img->planeWidth > 0x7FFF || img->planeHeight > 0x7FFF) + return -1; + + img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth; + img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight; + + if (img->tileCols > 0xFF || img->tileRows > 0xFF || + img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 || + img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16) + return -1; + + img->tiles = 0; + img->levels = hdr->imageLevels; + img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL + img->nPlanes = hdr->nPlanes; + img->nBits = hdr->nBits; + img->encType = hdr->encType; + img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1; + img->mdatOffset = mdatOffset + hdr->mdatHdrSize; + img->mdatSize = mdatSize; + img->planeBuf = 0; + img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = 0; + + // The encoding type 3 needs all 4 planes to be decoded to generate row of + // RGGB values. It seems to be using some other colour space for raw encoding + // It is a massive buffer so ideallly it will need a different approach: + // decode planes line by line and convert single line then without + // intermediate plane buffer. At the moment though it's too many changes so + // left as is. + if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8) + { + img->planeBuf = + (int16_t *) +#ifdef LIBRAW_CR3_MEMPOOL + img->memmgr. +#endif + malloc(img->planeHeight * img->planeWidth * img->nPlanes * + ((img->samplePrecision + 7) >> 3)); + if (!img->planeBuf) + return -1; + } + + int32_t rowSize = 2 * img->planeWidth; + + if (img->nPlanes == 1) + img->outBufs[0] = outBuf; + else + switch (hdr->cfaLayout) + { + case 0: + // R G + // G B + img->outBufs[0] = outBuf; + img->outBufs[1] = outBuf + 1; + img->outBufs[2] = outBuf + rowSize; + img->outBufs[3] = img->outBufs[2] + 1; + break; + case 1: + // G R + // B G + img->outBufs[1] = outBuf; + img->outBufs[0] = outBuf + 1; + img->outBufs[3] = outBuf + rowSize; + img->outBufs[2] = img->outBufs[3] + 1; + break; + case 2: + // G B + // R G + img->outBufs[2] = outBuf; + img->outBufs[3] = outBuf + 1; + img->outBufs[0] = outBuf + rowSize; + img->outBufs[1] = img->outBufs[0] + 1; + break; + case 3: + // B G + // G R + img->outBufs[3] = outBuf; + img->outBufs[2] = outBuf + 1; + img->outBufs[1] = outBuf + rowSize; + img->outBufs[0] = img->outBufs[1] + 1; + break; + } + + // read header + return crxReadImageHeaders(hdr, img, mdatHdrPtr, hdrBufSize); +} + +int crxFreeImageData(CrxImage *img) +{ +#ifdef LIBRAW_CR3_MEMPOOL + img->memmgr.cleanup(); +#else + CrxTile *tile = img->tiles; + int nTiles = img->tileRows * img->tileCols; + + if (img->tiles) + { + for (int32_t curTile = 0; curTile < nTiles; curTile++) + if (tile[curTile].comps) + for (int32_t curPlane = 0; curPlane < img->nPlanes; curPlane++) + crxFreeSubbandData(img, tile[curTile].comps + curPlane); + free(img->tiles); + img->tiles = 0; + } + + if (img->planeBuf) + { + free(img->planeBuf); + img->planeBuf = 0; + } +#endif + return 0; +} + +void LibRaw::crxLoadDecodeLoop(void *img, int nPlanes) +{ +#ifdef LIBRAW_USE_OPENMP + int results[4]; // nPlanes is always <= 4 +#pragma omp parallel for + for (int32_t plane = 0; plane < nPlanes; ++plane) + results[plane] = crxDecodePlane(img, plane); + + for (int32_t plane = 0; plane < nPlanes; ++plane) + if (results[plane]) + derror(); +#else + for (int32_t plane = 0; plane < nPlanes; ++plane) + if (crxDecodePlane(img, plane)) + derror(); +#endif +} + +void LibRaw::crxConvertPlaneLineDf(void *p, int imageRow) +{ + crxConvertPlaneLine((CrxImage *)p, imageRow); +} + +void LibRaw::crxLoadFinalizeLoopE3(void *p, int planeHeight) +{ +#ifdef LIBRAW_USE_OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < planeHeight; ++i) + crxConvertPlaneLineDf(p, i); +} + +void LibRaw::crxLoadRaw() +{ + if (libraw_internal_data.unpacker_data.CR3_Version != 0x100) + throw LIBRAW_EXCEPTION_DECODE_RAW; + CrxImage img; + if (libraw_internal_data.unpacker_data.crx_track_selected < 0 || + libraw_internal_data.unpacker_data.crx_track_selected >= + LIBRAW_CRXTRACKS_MAXCOUNT) + derror(); + crx_data_header_t hdr = + libraw_internal_data.unpacker_data + .crx_header[libraw_internal_data.unpacker_data.crx_track_selected]; + + img.input = libraw_internal_data.internal_data.input; + + // update sizes for the planes + if (hdr.nPlanes == 4) + { + hdr.f_width >>= 1; + hdr.f_height >>= 1; + hdr.tileWidth >>= 1; + hdr.tileHeight >>= 1; + } + + imgdata.color.maximum = (1 << hdr.nBits) - 1; + + uint8_t *hdrBuf = (uint8_t *)malloc(hdr.mdatHdrSize * 2); + + // read image header +#ifdef LIBRAW_USE_OPENMP +#pragma omp critical +#endif + { +#ifndef LIBRAW_USE_OPENMP + libraw_internal_data.internal_data.input->lock(); +#endif + libraw_internal_data.internal_data.input->seek( + libraw_internal_data.unpacker_data.data_offset, SEEK_SET); + libraw_internal_data.internal_data.input->read(hdrBuf, 1, hdr.mdatHdrSize); +#ifndef LIBRAW_USE_OPENMP + libraw_internal_data.internal_data.input->unlock(); +#endif + } + + // parse and setup the image data + if (crxSetupImageData(&hdr, &img, (int16_t *)imgdata.rawdata.raw_image, + libraw_internal_data.unpacker_data.data_offset, + libraw_internal_data.unpacker_data.data_size, hdr.mdatHdrSize*2, hdrBuf)) + derror(); + free(hdrBuf); + + crxLoadDecodeLoop(&img, hdr.nPlanes); + + if (img.encType == 3) + crxLoadFinalizeLoopE3(&img, img.planeHeight); + + crxFreeImageData(&img); +} + +int LibRaw::crxParseImageHeader(uchar *cmp1TagData, int nTrack) +{ + if (nTrack < 0 || nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) + return -1; + if (!cmp1TagData) + return -1; + + crx_data_header_t *hdr = + &libraw_internal_data.unpacker_data.crx_header[nTrack]; + + hdr->version = sgetn(2, cmp1TagData + 4); + hdr->f_width = sgetn(4, cmp1TagData + 8); + hdr->f_height = sgetn(4, cmp1TagData + 12); + hdr->tileWidth = sgetn(4, cmp1TagData + 16); + hdr->tileHeight = sgetn(4, cmp1TagData + 20); + hdr->nBits = cmp1TagData[24]; + hdr->nPlanes = cmp1TagData[25] >> 4; + hdr->cfaLayout = cmp1TagData[25] & 0xF; + hdr->encType = cmp1TagData[26] >> 4; + hdr->imageLevels = cmp1TagData[26] & 0xF; + hdr->hasTileCols = cmp1TagData[27] >> 7; + hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1; + hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28); + + // validation + if ((hdr->version != 0x100 && hdr->version != 0x200) || !hdr->mdatHdrSize) + return -1; + libraw_internal_data.unpacker_data.CR3_Version = hdr->version; + if (hdr->encType == 1) + { + if (hdr->nBits > 15) + return -1; + } + else + { + if (hdr->encType && hdr->encType != 3) + return -1; + if (hdr->nBits > 14) + return -1; + } + + if (hdr->nPlanes == 1) + { + if (hdr->cfaLayout || hdr->encType) + return -1; + if (hdr->nBits != 8) + return -1; + } + else if (hdr->nPlanes != 4 || hdr->f_width & 1 || hdr->f_height & 1 || + hdr->tileWidth & 1 || hdr->tileHeight & 1 || hdr->cfaLayout > 3 || + (hdr->encType && hdr->encType != 1 && hdr->encType != 3) || + hdr->nBits == 8) + return -1; + + if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height) + return -1; + + if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1) + return -1; + return 0; +} + +#undef _abs +#undef _min +#undef _constrain +#undef libraw_inline diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/decoders_dcraw.cpp libkdcraw/libkdcraw/libraw/src/decoders/decoders_dcraw.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/decoders_dcraw.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/decoders_dcraw.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,1815 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +unsigned LibRaw::getbithuff(int nbits, ushort *huff) +{ +#ifdef LIBRAW_NOTHREADS + static unsigned bitbuf = 0; + static int vbits = 0, reset = 0; +#else +#define bitbuf tls->getbits.bitbuf +#define vbits tls->getbits.vbits +#define reset tls->getbits.reset +#endif + unsigned c; + + if (nbits > 25) + return 0; + if (nbits < 0) + return bitbuf = vbits = reset = 0; + if (nbits == 0 || vbits < 0) + return 0; + while (!reset && vbits < nbits && (c = fgetc(ifp)) != (unsigned)EOF && + !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) + { + bitbuf = (bitbuf << 8) + (uchar)c; + vbits += 8; + } + c = vbits == 0 ? 0 : bitbuf << (32 - vbits) >> (32 - nbits); + if (huff) + { + vbits -= huff[c] >> 8; + c = (uchar)huff[c]; + } + else + vbits -= nbits; + if (vbits < 0) + derror(); + return c; +#ifndef LIBRAW_NOTHREADS +#undef bitbuf +#undef vbits +#undef reset +#endif +} + +/* + Construct a decode tree according the specification in *source. + The first 16 bytes specify how many codes should be 1-bit, 2-bit + 3-bit, etc. Bytes after that are the leaf values. + + For example, if the source is + + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + + then the code is + + 00 0x04 + 010 0x03 + 011 0x05 + 100 0x06 + 101 0x02 + 1100 0x07 + 1101 0x01 + 11100 0x08 + 11101 0x09 + 11110 0x00 + 111110 0x0a + 1111110 0x0b + 1111111 0xff + */ +ushort *LibRaw::make_decoder_ref(const uchar **source) +{ + int max, len, h, i, j; + const uchar *count; + ushort *huff; + + count = (*source += 16) - 17; + for (max = 16; max && !count[max]; max--) + ; + huff = (ushort *)calloc(1 + (1 << max), sizeof *huff); + merror(huff, "make_decoder()"); + huff[0] = max; + for (h = len = 1; len <= max; len++) + for (i = 0; i < count[len]; i++, ++*source) + for (j = 0; j < 1 << (max - len); j++) + if (h <= 1 << max) + huff[h++] = len << 8 | **source; + return huff; +} + +ushort *LibRaw::make_decoder(const uchar *source) +{ + return make_decoder_ref(&source); +} + +void LibRaw::crw_init_tables(unsigned table, ushort *huff[2]) +{ + static const uchar first_tree[3][29] = { + {0, 1, 4, 2, 3, 1, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0x04, 0x03, 0x05, 0x06, + 0x02, 0x07, 0x01, 0x08, 0x09, 0x00, 0x0a, 0x0b, 0xff}, + {0, 2, 2, 3, 1, 1, 1, 1, 2, 0, + 0, 0, 0, 0, 0, 0, 0x03, 0x02, 0x04, 0x01, + 0x05, 0x00, 0x06, 0x07, 0x09, 0x08, 0x0a, 0x0b, 0xff}, + {0, 0, 6, 3, 1, 1, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0x06, 0x05, 0x07, 0x04, + 0x08, 0x03, 0x09, 0x02, 0x00, 0x0a, 0x01, 0x0b, 0xff}, + }; + static const uchar second_tree[3][180] = { + {0, 2, 2, 2, 1, 4, 2, 1, 2, 5, 1, 1, + 0, 0, 0, 139, 0x03, 0x04, 0x02, 0x05, 0x01, 0x06, 0x07, 0x08, + 0x12, 0x13, 0x11, 0x14, 0x09, 0x15, 0x22, 0x00, 0x21, 0x16, 0x0a, 0xf0, + 0x23, 0x17, 0x24, 0x31, 0x32, 0x18, 0x19, 0x33, 0x25, 0x41, 0x34, 0x42, + 0x35, 0x51, 0x36, 0x37, 0x38, 0x29, 0x79, 0x26, 0x1a, 0x39, 0x56, 0x57, + 0x28, 0x27, 0x52, 0x55, 0x58, 0x43, 0x76, 0x59, 0x77, 0x54, 0x61, 0xf9, + 0x71, 0x78, 0x75, 0x96, 0x97, 0x49, 0xb7, 0x53, 0xd7, 0x74, 0xb6, 0x98, + 0x47, 0x48, 0x95, 0x69, 0x99, 0x91, 0xfa, 0xb8, 0x68, 0xb5, 0xb9, 0xd6, + 0xf7, 0xd8, 0x67, 0x46, 0x45, 0x94, 0x89, 0xf8, 0x81, 0xd5, 0xf6, 0xb4, + 0x88, 0xb1, 0x2a, 0x44, 0x72, 0xd9, 0x87, 0x66, 0xd4, 0xf5, 0x3a, 0xa7, + 0x73, 0xa9, 0xa8, 0x86, 0x62, 0xc7, 0x65, 0xc8, 0xc9, 0xa1, 0xf4, 0xd1, + 0xe9, 0x5a, 0x92, 0x85, 0xa6, 0xe7, 0x93, 0xe8, 0xc1, 0xc6, 0x7a, 0x64, + 0xe1, 0x4a, 0x6a, 0xe6, 0xb3, 0xf1, 0xd3, 0xa5, 0x8a, 0xb2, 0x9a, 0xba, + 0x84, 0xa4, 0x63, 0xe5, 0xc5, 0xf3, 0xd2, 0xc4, 0x82, 0xaa, 0xda, 0xe4, + 0xf2, 0xca, 0x83, 0xa3, 0xa2, 0xc3, 0xea, 0xc2, 0xe2, 0xe3, 0xff, 0xff}, + {0, 2, 2, 1, 4, 1, 4, 1, 3, 3, 1, 0, + 0, 0, 0, 140, 0x02, 0x03, 0x01, 0x04, 0x05, 0x12, 0x11, 0x06, + 0x13, 0x07, 0x08, 0x14, 0x22, 0x09, 0x21, 0x00, 0x23, 0x15, 0x31, 0x32, + 0x0a, 0x16, 0xf0, 0x24, 0x33, 0x41, 0x42, 0x19, 0x17, 0x25, 0x18, 0x51, + 0x34, 0x43, 0x52, 0x29, 0x35, 0x61, 0x39, 0x71, 0x62, 0x36, 0x53, 0x26, + 0x38, 0x1a, 0x37, 0x81, 0x27, 0x91, 0x79, 0x55, 0x45, 0x28, 0x72, 0x59, + 0xa1, 0xb1, 0x44, 0x69, 0x54, 0x58, 0xd1, 0xfa, 0x57, 0xe1, 0xf1, 0xb9, + 0x49, 0x47, 0x63, 0x6a, 0xf9, 0x56, 0x46, 0xa8, 0x2a, 0x4a, 0x78, 0x99, + 0x3a, 0x75, 0x74, 0x86, 0x65, 0xc1, 0x76, 0xb6, 0x96, 0xd6, 0x89, 0x85, + 0xc9, 0xf5, 0x95, 0xb4, 0xc7, 0xf7, 0x8a, 0x97, 0xb8, 0x73, 0xb7, 0xd8, + 0xd9, 0x87, 0xa7, 0x7a, 0x48, 0x82, 0x84, 0xea, 0xf4, 0xa6, 0xc5, 0x5a, + 0x94, 0xa4, 0xc6, 0x92, 0xc3, 0x68, 0xb5, 0xc8, 0xe4, 0xe5, 0xe6, 0xe9, + 0xa2, 0xa3, 0xe3, 0xc2, 0x66, 0x67, 0x93, 0xaa, 0xd4, 0xd5, 0xe7, 0xf8, + 0x88, 0x9a, 0xd7, 0x77, 0xc4, 0x64, 0xe2, 0x98, 0xa5, 0xca, 0xda, 0xe8, + 0xf3, 0xf6, 0xa9, 0xb2, 0xb3, 0xf2, 0xd2, 0x83, 0xba, 0xd3, 0xff, 0xff}, + {0, 0, 6, 2, 1, 3, 3, 2, 5, 1, 2, 2, + 8, 10, 0, 117, 0x04, 0x05, 0x03, 0x06, 0x02, 0x07, 0x01, 0x08, + 0x09, 0x12, 0x13, 0x14, 0x11, 0x15, 0x0a, 0x16, 0x17, 0xf0, 0x00, 0x22, + 0x21, 0x18, 0x23, 0x19, 0x24, 0x32, 0x31, 0x25, 0x33, 0x38, 0x37, 0x34, + 0x35, 0x36, 0x39, 0x79, 0x57, 0x58, 0x59, 0x28, 0x56, 0x78, 0x27, 0x41, + 0x29, 0x77, 0x26, 0x42, 0x76, 0x99, 0x1a, 0x55, 0x98, 0x97, 0xf9, 0x48, + 0x54, 0x96, 0x89, 0x47, 0xb7, 0x49, 0xfa, 0x75, 0x68, 0xb6, 0x67, 0x69, + 0xb9, 0xb8, 0xd8, 0x52, 0xd7, 0x88, 0xb5, 0x74, 0x51, 0x46, 0xd9, 0xf8, + 0x3a, 0xd6, 0x87, 0x45, 0x7a, 0x95, 0xd5, 0xf6, 0x86, 0xb4, 0xa9, 0x94, + 0x53, 0x2a, 0xa8, 0x43, 0xf5, 0xf7, 0xd4, 0x66, 0xa7, 0x5a, 0x44, 0x8a, + 0xc9, 0xe8, 0xc8, 0xe7, 0x9a, 0x6a, 0x73, 0x4a, 0x61, 0xc7, 0xf4, 0xc6, + 0x65, 0xe9, 0x72, 0xe6, 0x71, 0x91, 0x93, 0xa6, 0xda, 0x92, 0x85, 0x62, + 0xf3, 0xc5, 0xb2, 0xa4, 0x84, 0xba, 0x64, 0xa5, 0xb3, 0xd2, 0x81, 0xe5, + 0xd3, 0xaa, 0xc4, 0xca, 0xf2, 0xb1, 0xe4, 0xd1, 0x83, 0x63, 0xea, 0xc3, + 0xe2, 0x82, 0xf1, 0xa3, 0xc2, 0xa1, 0xc1, 0xe3, 0xa2, 0xe1, 0xff, 0xff}}; + if (table > 2) + table = 2; + huff[0] = make_decoder(first_tree[table]); + huff[1] = make_decoder(second_tree[table]); +} + +/* + Return 0 if the image starts with compressed data, + 1 if it starts with uncompressed low-order bits. + + In Canon compressed data, 0xff is always followed by 0x00. + */ +int LibRaw::canon_has_lowbits() +{ + uchar test[0x4000]; + int ret = 1, i; + + fseek(ifp, 0, SEEK_SET); + fread(test, 1, sizeof test, ifp); + for (i = 540; i < int(sizeof test - 1); i++) + if (test[i] == 0xff) + { + if (test[i + 1]) + return 1; + ret = 0; + } + return ret; +} + +void LibRaw::canon_load_raw() +{ + ushort *pixel, *prow, *huff[2]; + int nblocks, lowbits, i, c, row, r, save, val; + int block, diffbuf[64], leaf, len, diff, carry = 0, pnum = 0, base[2]; + + crw_init_tables(tiff_compress, huff); + lowbits = canon_has_lowbits(); + if (!lowbits) + maximum = 0x3ff; + fseek(ifp, 540 + lowbits * raw_height * raw_width / 4, SEEK_SET); + zero_after_ff = 1; + getbits(-1); + try + { + for (row = 0; row < raw_height; row += 8) + { + checkCancel(); + pixel = raw_image + row * raw_width; + nblocks = MIN(8, raw_height - row) * raw_width >> 6; + for (block = 0; block < nblocks; block++) + { + memset(diffbuf, 0, sizeof diffbuf); + for (i = 0; i < 64; i++) + { + leaf = gethuff(huff[i > 0]); + if (leaf == 0 && i) + break; + if (leaf == 0xff) + continue; + i += leaf >> 4; + len = leaf & 15; + if (len == 0) + continue; + diff = getbits(len); + if ((diff & (1 << (len - 1))) == 0) + diff -= (1 << len) - 1; + if (i < 64) + diffbuf[i] = diff; + } + diffbuf[0] += carry; + carry = diffbuf[0]; + for (i = 0; i < 64; i++) + { + if (pnum++ % raw_width == 0) + base[0] = base[1] = 512; + if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) + derror(); + } + } + if (lowbits) + { + save = ftell(ifp); + fseek(ifp, 26 + row * raw_width / 4, SEEK_SET); + for (prow = pixel, i = 0; i < raw_width * 2; i++) + { + c = fgetc(ifp); + for (r = 0; r < 8; r += 2, prow++) + { + val = (*prow << 2) + ((c >> r) & 3); + if (raw_width == 2672 && val < 512) + val += 2; + *prow = val; + } + } + fseek(ifp, save, SEEK_SET); + } + } + } + catch (...) + { + FORC(2) free(huff[c]); + throw; + } + FORC(2) free(huff[c]); +} + +int LibRaw::ljpeg_start(struct jhead *jh, int info_only) +{ + ushort c, tag, len; + int cnt = 0; + std::vector<uchar> data_buffer(0x10000); + uchar* data = &data_buffer[0]; + const uchar *dp; + + memset(jh, 0, sizeof *jh); + jh->restart = INT_MAX; + if (fread(data, 2, 1, ifp) != 1 || data[1] != 0xd8) + return 0; + do + { + if (feof(ifp)) + return 0; + if (cnt++ > 1024) + return 0; // 1024 tags limit + if (fread(data, 2, 2, ifp) != 2) + return 0; + tag = data[0] << 8 | data[1]; + len = (data[2] << 8 | data[3]) - 2; + if (tag <= 0xff00) + return 0; + if (fread(data, 1, len, ifp) != len) + return 0; + switch (tag) + { + case 0xffc3: // start of frame; lossless, Huffman + jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; + case 0xffc1: + case 0xffc0: + jh->algo = tag & 0xff; + jh->bits = data[0]; + jh->high = data[1] << 8 | data[2]; + jh->wide = data[3] << 8 | data[4]; + jh->clrs = data[5] + jh->sraw; + if (len == 9 && !dng_version) + getc(ifp); + break; + case 0xffc4: // define Huffman tables + if (info_only) + break; + for (dp = data; dp < data + len && !((c = *dp++) & -20);) + jh->free[c] = jh->huff[c] = make_decoder_ref(&dp); + break; + case 0xffda: // start of scan + jh->psv = data[1 + data[0] * 2]; + jh->bits -= data[3 + data[0] * 2] & 15; + break; + case 0xffdb: + FORC(64) jh->quant[c] = data[c * 2 + 1] << 8 | data[c * 2 + 2]; + break; + case 0xffdd: + jh->restart = data[0] << 8 | data[1]; + } + } while (tag != 0xffda); + if (jh->bits > 16 || jh->clrs > 6 || !jh->bits || !jh->high || !jh->wide || + !jh->clrs) + return 0; + if (info_only) + return 1; + if (!jh->huff[0]) + return 0; + FORC(19) if (!jh->huff[c + 1]) jh->huff[c + 1] = jh->huff[c]; + if (jh->sraw) + { + FORC(4) jh->huff[2 + c] = jh->huff[1]; + FORC(jh->sraw) jh->huff[1 + c] = jh->huff[0]; + } + jh->row = (ushort *)calloc(jh->wide * jh->clrs, 16); + merror(jh->row, "ljpeg_start()"); + return zero_after_ff = 1; +} + +void LibRaw::ljpeg_end(struct jhead *jh) +{ + int c; + FORC4 if (jh->free[c]) free(jh->free[c]); + free(jh->row); +} + +int LibRaw::ljpeg_diff(ushort *huff) +{ + int len, diff; + if (!huff) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + len = gethuff(huff); + if (len == 16 && (!dng_version || dng_version >= 0x1010000)) + return -32768; + diff = getbits(len); + + + if ((diff & (1 << (len - 1))) == 0) + diff -= (1 << len) - 1; + return diff; +} + +ushort *LibRaw::ljpeg_row(int jrow, struct jhead *jh) +{ + int col, c, diff, pred, spred = 0; + ushort mark = 0, *row[3]; + + // Use the optimized, unrolled version if possible. + if (!jh->sraw) + return ljpeg_row_unrolled(jrow, jh); + + if (jh->restart != 0 && jrow * jh->wide % jh->restart == 0) + { + FORC(6) jh->vpred[c] = 1 << (jh->bits - 1); + if (jrow) + { + fseek(ifp, -2, SEEK_CUR); + do + mark = (mark << 8) + (c = fgetc(ifp)); + while (c != EOF && mark >> 4 != 0xffd); + } + getbits(-1); + } + FORC3 row[c] = jh->row + jh->wide * jh->clrs * ((jrow + c) & 1); + for (col = 0; col < jh->wide; col++) + FORC(jh->clrs) + { + diff = ljpeg_diff(jh->huff[c]); + if (jh->sraw && c <= jh->sraw && (col | c)) + pred = spred; + else if (col) + pred = row[0][-jh->clrs]; + else + pred = (jh->vpred[c] += diff) - diff; + if (jrow && col) + switch (jh->psv) + { + case 1: + break; + case 2: + pred = row[1][0]; + break; + case 3: + pred = row[1][-jh->clrs]; + break; + case 4: + pred = pred + row[1][0] - row[1][-jh->clrs]; + break; + case 5: + pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); + break; + case 6: + pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); + break; + case 7: + pred = (pred + row[1][0]) >> 1; + break; + default: + pred = 0; + } + if ((**row = pred + diff) >> jh->bits) + if(!(load_flags & 512)) + derror(); + if (c <= jh->sraw) + spred = **row; + row[0]++; + row[1]++; + } + return row[2]; +} + +ushort *LibRaw::ljpeg_row_unrolled(int jrow, struct jhead *jh) +{ + int col, c, diff, pred; + ushort mark = 0, *row[3]; + + if (jh->restart != 0 && jrow * jh->wide % jh->restart == 0) + { + FORC(6) jh->vpred[c] = 1 << (jh->bits - 1); + if (jrow) + { + fseek(ifp, -2, SEEK_CUR); + do + mark = (mark << 8) + (c = fgetc(ifp)); + while (c != EOF && mark >> 4 != 0xffd); + } + getbits(-1); + } + FORC3 row[c] = jh->row + jh->wide * jh->clrs * ((jrow + c) & 1); + + // The first column uses one particular predictor. + FORC(jh->clrs) + { + diff = ljpeg_diff(jh->huff[c]); + pred = (jh->vpred[c] += diff) - diff; + if ((**row = pred + diff) >> jh->bits) + derror(); + row[0]++; + row[1]++; + } + + if (!jrow) + { + for (col = 1; col < jh->wide; col++) + FORC(jh->clrs) + { + diff = ljpeg_diff(jh->huff[c]); + pred = row[0][-jh->clrs]; + if ((**row = pred + diff) >> jh->bits) + derror(); + row[0]++; + row[1]++; + } + } + else if (jh->psv == 1) + { + for (col = 1; col < jh->wide; col++) + FORC(jh->clrs) + { + diff = ljpeg_diff(jh->huff[c]); + pred = row[0][-jh->clrs]; + if ((**row = pred + diff) >> jh->bits) + derror(); + row[0]++; + } + } + else + { + for (col = 1; col < jh->wide; col++) + FORC(jh->clrs) + { + diff = ljpeg_diff(jh->huff[c]); + pred = row[0][-jh->clrs]; + switch (jh->psv) + { + case 1: + break; + case 2: + pred = row[1][0]; + break; + case 3: + pred = row[1][-jh->clrs]; + break; + case 4: + pred = pred + row[1][0] - row[1][-jh->clrs]; + break; + case 5: + pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); + break; + case 6: + pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); + break; + case 7: + pred = (pred + row[1][0]) >> 1; + break; + default: + pred = 0; + } + if ((**row = pred + diff) >> jh->bits) + derror(); + row[0]++; + row[1]++; + } + } + return row[2]; +} + +void LibRaw::lossless_jpeg_load_raw() +{ + int jwide, jhigh, jrow, jcol, val, jidx, i, j, row = 0, col = 0; + struct jhead jh; + ushort *rp; + + if (!ljpeg_start(&jh, 0)) + return; + + if (jh.wide < 1 || jh.high < 1 || jh.clrs < 1 || jh.bits < 1) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + jwide = jh.wide * jh.clrs; + jhigh = jh.high; + if (jh.clrs == 4 && jwide >= raw_width * 2) + jhigh *= 2; + + try + { + for (jrow = 0; jrow < jh.high; jrow++) + { + checkCancel(); + rp = ljpeg_row(jrow, &jh); + if (load_flags & 1) + row = jrow & 1 ? height - 1 - jrow / 2 : jrow / 2; + for (jcol = 0; jcol < jwide; jcol++) + { + val = curve[*rp++]; + if (cr2_slice[0]) + { + jidx = jrow * jwide + jcol; + i = jidx / (cr2_slice[1] * raw_height); + if ((j = i >= cr2_slice[0])) + i = cr2_slice[0]; + jidx -= i * (cr2_slice[1] * raw_height); + row = jidx / cr2_slice[1 + j]; + col = jidx % cr2_slice[1 + j] + i * cr2_slice[1]; + } + if (raw_width == 3984 && (col -= 2) < 0) + col += (row--, raw_width); + if (row > raw_height) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if ((unsigned)row < raw_height) + RAW(row, col) = val; + if (++col >= raw_width) + col = (row++, 0); + } + } + } + catch (...) + { + ljpeg_end(&jh); + throw; + } + ljpeg_end(&jh); +} + +void LibRaw::canon_sraw_load_raw() +{ + struct jhead jh; + short *rp = 0, (*ip)[4]; + int jwide, slice, scol, ecol, row, col, jrow = 0, jcol = 0, pix[3], c; + int v[3] = {0, 0, 0}, ver, hue; + int saved_w = width, saved_h = height; + char *cp; + + if (!ljpeg_start(&jh, 0) || jh.clrs < 4) + return; + jwide = (jh.wide >>= 1) * jh.clrs; + + if (load_flags & 256) + { + width = raw_width; + height = raw_height; + } + + try + { + for (ecol = slice = 0; slice <= cr2_slice[0]; slice++) + { + scol = ecol; + ecol += cr2_slice[1] * 2 / jh.clrs; + if (!cr2_slice[0] || ecol > raw_width - 1) + ecol = raw_width & -2; + for (row = 0; row < height; row += (jh.clrs >> 1) - 1) + { + checkCancel(); + ip = (short(*)[4])image + row * width; + for (col = scol; col < ecol; col += 2, jcol += jh.clrs) + { + if ((jcol %= jwide) == 0) + rp = (short *)ljpeg_row(jrow++, &jh); + if (col >= width) + continue; + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) + { + FORC(jh.clrs - 2) + { + ip[col + (c >> 1) * width + (c & 1)][0] = rp[jcol + c]; + ip[col + (c >> 1) * width + (c & 1)][1] = + ip[col + (c >> 1) * width + (c & 1)][2] = 8192; + } + ip[col][1] = rp[jcol + jh.clrs - 2] - 8192; + ip[col][2] = rp[jcol + jh.clrs - 1] - 8192; + } + else if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SRAW_NO_RGB) + { + FORC(jh.clrs - 2) + ip[col + (c >> 1) * width + (c & 1)][0] = rp[jcol + c]; + ip[col][1] = rp[jcol + jh.clrs - 2] - 8192; + ip[col][2] = rp[jcol + jh.clrs - 1] - 8192; + } + else + { + FORC(jh.clrs - 2) + ip[col + (c >> 1) * width + (c & 1)][0] = rp[jcol + c]; + ip[col][1] = rp[jcol + jh.clrs - 2] - 16384; + ip[col][2] = rp[jcol + jh.clrs - 1] - 16384; + } + } + } + } + } + catch (...) + { + ljpeg_end(&jh); + throw; + } + + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) + { + ljpeg_end(&jh); + maximum = 0x3fff; + height = saved_h; + width = saved_w; + return; + } + + try + { + for (cp = model2; *cp && !isdigit(*cp); cp++) + ; + sscanf(cp, "%d.%d.%d", v, v + 1, v + 2); + ver = (v[0] * 1000 + v[1]) * 1000 + v[2]; + hue = (jh.sraw + 1) << 2; + if (unique_id >= 0x80000281ULL || + (unique_id == 0x80000218ULL && ver > 1000006)) + hue = jh.sraw << 1; + ip = (short(*)[4])image; + rp = ip[0]; + for (row = 0; row < height; row++, ip += width) + { + checkCancel(); + if (row & (jh.sraw >> 1)) + { + for (col = 0; col < width; col += 2) + for (c = 1; c < 3; c++) + if (row == height - 1) + { + ip[col][c] = ip[col - width][c]; + } + else + { + ip[col][c] = (ip[col - width][c] + ip[col + width][c] + 1) >> 1; + } + } + for (col = 1; col < width; col += 2) + for (c = 1; c < 3; c++) + if (col == width - 1) + ip[col][c] = ip[col - 1][c]; + else + ip[col][c] = (ip[col - 1][c] + ip[col + 1][c] + 1) >> 1; + } + if (!(imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SRAW_NO_RGB)) + for (; rp < ip[0]; rp += 4) + { + checkCancel(); + if ((unique_id == CanonID_EOS_5D_Mark_II) || + (unique_id == CanonID_EOS_7D) || + (unique_id == CanonID_EOS_50D) || + (unique_id == CanonID_EOS_1D_Mark_IV) || + (unique_id == CanonID_EOS_60D)) + { + rp[1] = (rp[1] << 2) + hue; + rp[2] = (rp[2] << 2) + hue; + pix[0] = rp[0] + ((50 * rp[1] + 22929 * rp[2]) >> 14); + pix[1] = rp[0] + ((-5640 * rp[1] - 11751 * rp[2]) >> 14); + pix[2] = rp[0] + ((29040 * rp[1] - 101 * rp[2]) >> 14); + } + else + { + if (unique_id < CanonID_EOS_5D_Mark_II) + rp[0] -= 512; + pix[0] = rp[0] + rp[2]; + pix[2] = rp[0] + rp[1]; + pix[1] = rp[0] + ((-778 * rp[1] - (rp[2] << 11)) >> 12); + } + FORC3 rp[c] = CLIP15(pix[c] * sraw_mul[c] >> 10); + } + } + catch (...) + { + ljpeg_end(&jh); + throw; + } + height = saved_h; + width = saved_w; + ljpeg_end(&jh); + maximum = 0x3fff; +} + +void LibRaw::ljpeg_idct(struct jhead *jh) +{ + int c, i, j, len, skip, coef; + float work[3][8][8]; + static float cs[106] = {0}; + static const uchar zigzag[80] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63}; + + if (!cs[0]) + FORC(106) cs[c] = cos((c & 31) * M_PI / 16) / 2; + memset(work, 0, sizeof work); + work[0][0][0] = jh->vpred[0] += ljpeg_diff(jh->huff[0]) * jh->quant[0]; + for (i = 1; i < 64; i++) + { + len = gethuff(jh->huff[16]); + i += skip = len >> 4; + if (!(len &= 15) && skip < 15) + break; + coef = getbits(len); + if ((coef & (1 << (len - 1))) == 0) + coef -= (1 << len) - 1; + ((float *)work)[zigzag[i]] = coef * jh->quant[i]; + } + FORC(8) work[0][0][c] *= M_SQRT1_2; + FORC(8) work[0][c][0] *= M_SQRT1_2; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + FORC(8) work[1][i][j] += work[0][i][c] * cs[(j * 2 + 1) * c]; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + FORC(8) work[2][i][j] += work[1][c][j] * cs[(i * 2 + 1) * c]; + + FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c] + 0.5); +} + +void LibRaw::pentax_load_raw() +{ + ushort bit[2][15], huff[4097]; + int dep, row, col, diff, c, i; + ushort vpred[2][2] = {{0, 0}, {0, 0}}, hpred[2]; + + fseek(ifp, meta_offset, SEEK_SET); + dep = (get2() + 12) & 15; + fseek(ifp, 12, SEEK_CUR); + FORC(dep) bit[0][c] = get2(); + FORC(dep) bit[1][c] = fgetc(ifp); + FORC(dep) + for (i = bit[0][c]; i <= ((bit[0][c] + (4096 >> bit[1][c]) - 1) & 4095);) + huff[++i] = bit[1][c] << 8 | c; + huff[0] = 12; + fseek(ifp, data_offset, SEEK_SET); + getbits(-1); + for (row = 0; row < raw_height; row++) + { + checkCancel(); + for (col = 0; col < raw_width; col++) + { + diff = ljpeg_diff(huff); + if (col < 2) + hpred[col] = vpred[row & 1][col] += diff; + else + hpred[col & 1] += diff; + RAW(row, col) = hpred[col & 1]; + if (hpred[col & 1] >> tiff_bps) + derror(); + } + } +} +void LibRaw::nikon_read_curve() +{ + ushort ver0, ver1, vpred[2][2], csize; + int i, step, max; + + fseek(ifp, meta_offset, SEEK_SET); + ver0 = fgetc(ifp); + ver1 = fgetc(ifp); + if (ver0 == 0x49 || ver1 == 0x58) + fseek(ifp, 2110, SEEK_CUR); + read_shorts(vpred[0], 4); + max = 1 << tiff_bps & 0x7fff; + if ((csize = get2()) > 1) + step = max / (csize - 1); + if (ver0 == 0x44 && (ver1 == 0x20 || (ver1 == 0x40 && step > 3)) && step > 0) + { + if (ver1 == 0x40) + { + step /= 4; + max /= 4; + } + for (i = 0; i < csize; i++) + curve[i * step] = get2(); + for (i = 0; i < max; i++) + curve[i] = (curve[i - i % step] * (step - i % step) + + curve[i - i % step + step] * (i % step)) / + step; + } + else if (ver0 != 0x46 && csize <= 0x4001) + read_shorts(curve, max = csize); +} + +void LibRaw::nikon_load_raw() +{ + static const uchar nikon_tree[][32] = { + {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, /* 12-bit lossy */ + 5, 4, 3, 6, 2, 7, 1, 0, 8, 9, 11, 10, 12}, + {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, + 0, 0, /* 12-bit lossy after split */ + 0x39, 0x5a, 0x38, 0x27, 0x16, 5, 4, 3, 2, 1, 0, 11, 12, 12}, + + {0, 1, 4, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 12-bit lossless */ + 5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, 11, 12}, + {0, 1, 4, 3, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, /* 14-bit lossy */ + 5, 6, 4, 7, 8, 3, 9, 2, 1, 0, 10, 11, 12, 13, 14}, + {0, 1, 5, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, + 0, /* 14-bit lossy after split */ + 8, 0x5c, 0x4b, 0x3a, 0x29, 7, 6, 5, 4, 3, 2, 1, 0, 13, 14}, + {0, 1, 4, 2, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, /* 14-bit lossless */ + 7, 6, 8, 5, 9, 4, 10, 3, 11, 12, 2, 0, 1, 13, 14}}; + ushort *huff, ver0, ver1, vpred[2][2], hpred[2]; + int i, min, max, tree = 0, split = 0, row, col, len, shl, diff; + + fseek(ifp, meta_offset, SEEK_SET); + ver0 = fgetc(ifp); + ver1 = fgetc(ifp); + if (ver0 == 0x49 || ver1 == 0x58) + fseek(ifp, 2110, SEEK_CUR); + if (ver0 == 0x46) + tree = 2; + if (tiff_bps == 14) + tree += 3; + read_shorts(vpred[0], 4); + max = 1 << tiff_bps & 0x7fff; + if (ver0 == 0x44 && (ver1 == 0x20 || ver1 == 0x40)) + { + if (ver1 == 0x40) + max /= 4; + fseek(ifp, meta_offset + 562, SEEK_SET); + split = get2(); + } + + while (max > 2 && (curve[max - 2] == curve[max - 1])) + max--; + huff = make_decoder(nikon_tree[tree]); + fseek(ifp, data_offset, SEEK_SET); + getbits(-1); + try + { + for (min = row = 0; row < height; row++) + { + checkCancel(); + if (split && row == split) + { + free(huff); + huff = make_decoder(nikon_tree[tree + 1]); + max += (min = 16) << 1; + } + for (col = 0; col < raw_width; col++) + { + i = gethuff(huff); + len = i & 15; + shl = i >> 4; + diff = ((getbits(len - shl) << 1) + 1) << shl >> 1; + if (len > 0 && (diff & (1 << (len - 1))) == 0) + diff -= (1 << len) - !shl; + if (col < 2) + hpred[col] = vpred[row & 1][col] += diff; + else + hpred[col & 1] += diff; + if ((ushort)(hpred[col & 1] + min) >= max) + derror(); + RAW(row, col) = curve[LIM((short)hpred[col & 1], 0, 0x3fff)]; + } + } + } + catch (...) + { + free(huff); + throw; + } + free(huff); +} + +void LibRaw::nikon_yuv_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + int row, col, yuv[4], rgb[3], b, c; + UINT64 bitbuf = 0; + float cmul[4]; + FORC4 { cmul[c] = cam_mul[c] > 0.001f ? cam_mul[c] : 1.f; } + for (row = 0; row < raw_height; row++) + { + checkCancel(); + + for (col = 0; col < raw_width; col++) + { + if (!(b = col & 1)) + { + bitbuf = 0; + FORC(6) bitbuf |= (UINT64)fgetc(ifp) << c * 8; + FORC(4) yuv[c] = (bitbuf >> c * 12 & 0xfff) - (c >> 1 << 11); + } + rgb[0] = yuv[b] + 1.370705 * yuv[3]; + rgb[1] = yuv[b] - 0.337633 * yuv[2] - 0.698001 * yuv[3]; + rgb[2] = yuv[b] + 1.732446 * yuv[2]; + FORC3 image[row * width + col][c] = + curve[LIM(rgb[c], 0, 0xfff)] / cmul[c]; + } + } +} + +void LibRaw::rollei_load_raw() +{ + uchar pixel[10]; + unsigned iten = 0, isix, i, buffer = 0, todo[16]; + if (raw_width > 32767 || raw_height > 32767) + throw LIBRAW_EXCEPTION_IO_BADFILE; + unsigned maxpixel = raw_width * (raw_height + 7); + + isix = raw_width * raw_height * 5 / 8; + while (fread(pixel, 1, 10, ifp) == 10) + { + checkCancel(); + for (i = 0; i < 10; i += 2) + { + todo[i] = iten++; + todo[i + 1] = pixel[i] << 8 | pixel[i + 1]; + buffer = pixel[i] >> 2 | buffer << 6; + } + for (; i < 16; i += 2) + { + todo[i] = isix++; + todo[i + 1] = buffer >> (14 - i) * 5; + } + for (i = 0; i < 16; i += 2) + if (todo[i] < maxpixel) + raw_image[todo[i]] = (todo[i + 1] & 0x3ff); + else + derror(); + } + maximum = 0x3ff; +} + +void LibRaw::nokia_load_raw() +{ + uchar *data, *dp; + int rev, dwide, row, col, c; + double sum[] = {0, 0}; + + rev = 3 * (order == 0x4949); + dwide = (raw_width * 5 + 1) / 4; +#ifdef USE_6BY9RPI + if (raw_stride) + dwide = raw_stride; +#endif + data = (uchar *)malloc(dwide * 2); + merror(data, "nokia_load_raw()"); + try + { + for (row = 0; row < raw_height; row++) + { + checkCancel(); + if (fread(data + dwide, 1, dwide, ifp) < dwide) + derror(); + FORC(dwide) data[c] = data[dwide + (c ^ rev)]; + for (dp = data, col = 0; col < raw_width; dp += 5, col += 4) + FORC4 RAW(row, col + c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); + } + } + catch (...) + { + free(data); + throw; + } + free(data); + maximum = 0x3ff; +#ifdef USE_6BY9RPI + if (!strcmp(make, "OmniVision") || + !strcmp(make, "Sony") || + !strcmp(make, "RaspberryPi")) return; +#else + if (strncmp(make, "OmniVision", 10)) + return; +#endif + row = raw_height / 2; + FORC(width - 1) + { + sum[c & 1] += SQR(RAW(row, c) - RAW(row + 1, c + 1)); + sum[~c & 1] += SQR(RAW(row + 1, c) - RAW(row, c + 1)); + } + if (sum[1] > sum[0]) + filters = 0x4b4b4b4b; +} + +void LibRaw::canon_rmf_load_raw() +{ + int row, col, bits, orow, ocol, c; + + int *words = (int *)malloc(sizeof(int) * (raw_width / 3 + 1)); + merror(words, "canon_rmf_load_raw"); + for (row = 0; row < raw_height; row++) + { + checkCancel(); + fread(words, sizeof(int), raw_width / 3, ifp); + for (col = 0; col < raw_width - 2; col += 3) + { + bits = words[col / 3]; + FORC3 + { + orow = row; + if ((ocol = col + c - 4) < 0) + { + ocol += raw_width; + if ((orow -= 2) < 0) + orow += raw_height; + } + RAW(orow, ocol) = curve[bits >> (10 * c + 2) & 0x3ff]; + } + } + } + free(words); + maximum = curve[0x3ff]; +} + +unsigned LibRaw::pana_data(int nb, unsigned *bytes) +{ +#ifndef LIBRAW_NOTHREADS +#define vpos tls->pana_data.vpos +#define buf tls->pana_data.buf +#else + static uchar buf[0x4002]; + static int vpos; +#endif + int byte; + + if (!nb && !bytes) + return vpos = 0; + + if (!vpos) + { + fread(buf + load_flags, 1, 0x4000 - load_flags, ifp); + fread(buf, 1, load_flags, ifp); + } + + if (pana_encoding == 5) + { + for (byte = 0; byte < 16; byte++) + { + bytes[byte] = buf[vpos++]; + vpos &= 0x3FFF; + } + } + else + { + vpos = (vpos - nb) & 0x1ffff; + byte = vpos >> 3 ^ 0x3ff0; + return (buf[byte] | buf[byte + 1] << 8) >> (vpos & 7) & ~((~0u) << nb); + } + return 0; +#ifndef LIBRAW_NOTHREADS +#undef vpos +#undef buf +#endif +} + +void LibRaw::panasonic_load_raw() +{ + int row, col, i, j, sh = 0, pred[2], nonz[2]; + unsigned bytes[16]; + ushort *raw_block_data; + + pana_data(0, 0); + + int enc_blck_size = pana_bpp == 12 ? 10 : 9; + if (pana_encoding == 5) + { + for (row = 0; row < raw_height; row++) + { + raw_block_data = raw_image + row * raw_width; + checkCancel(); + for (col = 0; col < raw_width; col += enc_blck_size) + { + pana_data(0, bytes); + + if (pana_bpp == 12) + { + raw_block_data[col] = ((bytes[1] & 0xF) << 8) + bytes[0]; + raw_block_data[col + 1] = 16 * bytes[2] + (bytes[1] >> 4); + raw_block_data[col + 2] = ((bytes[4] & 0xF) << 8) + bytes[3]; + raw_block_data[col + 3] = 16 * bytes[5] + (bytes[4] >> 4); + raw_block_data[col + 4] = ((bytes[7] & 0xF) << 8) + bytes[6]; + raw_block_data[col + 5] = 16 * bytes[8] + (bytes[7] >> 4); + raw_block_data[col + 6] = ((bytes[10] & 0xF) << 8) + bytes[9]; + raw_block_data[col + 7] = 16 * bytes[11] + (bytes[10] >> 4); + raw_block_data[col + 8] = ((bytes[13] & 0xF) << 8) + bytes[12]; + raw_block_data[col + 9] = 16 * bytes[14] + (bytes[13] >> 4); + } + else if (pana_bpp == 14) + { + raw_block_data[col] = bytes[0] + ((bytes[1] & 0x3F) << 8); + raw_block_data[col + 1] = + (bytes[1] >> 6) + 4 * (bytes[2]) + ((bytes[3] & 0xF) << 10); + raw_block_data[col + 2] = + (bytes[3] >> 4) + 16 * (bytes[4]) + ((bytes[5] & 3) << 12); + raw_block_data[col + 3] = ((bytes[5] & 0xFC) >> 2) + (bytes[6] << 6); + raw_block_data[col + 4] = bytes[7] + ((bytes[8] & 0x3F) << 8); + raw_block_data[col + 5] = + (bytes[8] >> 6) + 4 * bytes[9] + ((bytes[10] & 0xF) << 10); + raw_block_data[col + 6] = + (bytes[10] >> 4) + 16 * bytes[11] + ((bytes[12] & 3) << 12); + raw_block_data[col + 7] = + ((bytes[12] & 0xFC) >> 2) + (bytes[13] << 6); + raw_block_data[col + 8] = bytes[14] + ((bytes[15] & 0x3F) << 8); + } + } + } + } + else + { + for (row = 0; row < raw_height; row++) + { + checkCancel(); + for (col = 0; col < raw_width; col++) + { + if ((i = col % 14) == 0) + pred[0] = pred[1] = nonz[0] = nonz[1] = 0; + if (i % 3 == 2) + sh = 4 >> (3 - pana_data(2, 0)); + if (nonz[i & 1]) + { + if ((j = pana_data(8, 0))) + { + if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) + pred[i & 1] &= ~((~0u) << sh); + pred[i & 1] += j << sh; + } + } + else if ((nonz[i & 1] = pana_data(8, 0)) || i > 11) + pred[i & 1] = nonz[i & 1] << 4 | pana_data(4, 0); + if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width && + row < height) + derror(); + } + } + } +} + +void LibRaw::olympus_load_raw() +{ + ushort huff[4096]; + int row, col, nbits, sign, low, high, i, c, w, n, nw; + int acarry[2][3], *carry, pred, diff; + + huff[n = 0] = 0xc0c; + for (i = 12; i--;) + FORC(2048 >> i) huff[++n] = (i + 1) << 8 | i; + fseek(ifp, 7, SEEK_CUR); + getbits(-1); + for (row = 0; row < height; row++) + { + checkCancel(); + memset(acarry, 0, sizeof acarry); + for (col = 0; col < raw_width; col++) + { + carry = acarry[col & 1]; + i = 2 * (carry[2] < 3); + for (nbits = 2 + i; (ushort)carry[0] >> (nbits + i); nbits++) + ; + low = (sign = getbits(3)) & 3; + sign = sign << 29 >> 31; + if ((high = getbithuff(12, huff)) == 12) + high = getbits(16 - nbits) >> 1; + carry[0] = (high << nbits) | getbits(nbits); + diff = (carry[0] ^ sign) + carry[1]; + carry[1] = (diff * 3 + carry[1]) >> 5; + carry[2] = carry[0] > 16 ? 0 : carry[2] + 1; + if (col >= width) + continue; + if (row < 2 && col < 2) + pred = 0; + else if (row < 2) + pred = RAW(row, col - 2); + else if (col < 2) + pred = RAW(row - 2, col); + else + { + w = RAW(row, col - 2); + n = RAW(row - 2, col); + nw = RAW(row - 2, col - 2); + if ((w < nw && nw < n) || (n < nw && nw < w)) + { + if (ABS(w - nw) > 32 || ABS(n - nw) > 32) + pred = w + n - nw; + else + pred = (w + n) >> 1; + } + else + pred = ABS(w - nw) > ABS(n - nw) ? w : n; + } + if ((RAW(row, col) = pred + ((diff << 2) | low)) >> 12) + derror(); + } + } +} + +void LibRaw::minolta_rd175_load_raw() +{ + uchar pixel[768]; + unsigned irow, box, row, col; + + for (irow = 0; irow < 1481; irow++) + { + checkCancel(); + if (fread(pixel, 1, 768, ifp) < 768) + derror(); + box = irow / 82; + row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box - 12) * 2); + switch (irow) + { + case 1477: + case 1479: + continue; + case 1476: + row = 984; + break; + case 1480: + row = 985; + break; + case 1478: + row = 985; + box = 1; + } + if ((box < 12) && (box & 1)) + { + for (col = 0; col < 1533; col++, row ^= 1) + if (col != 1) + RAW(row, col) = (col + 1) & 2 + ? pixel[col / 2 - 1] + pixel[col / 2 + 1] + : pixel[col / 2] << 1; + RAW(row, 1) = pixel[1] << 1; + RAW(row, 1533) = pixel[765] << 1; + } + else + for (col = row & 1; col < 1534; col += 2) + RAW(row, col) = pixel[col / 2] << 1; + } + maximum = 0xff << 1; +} + +void LibRaw::quicktake_100_load_raw() +{ + std::vector<uchar> pixel_buffer(484 * 644, 0x80); + uchar* pixel = &pixel_buffer[0]; + static const short gstep[16] = {-89, -60, -44, -32, -22, -15, -8, -2, + 2, 8, 15, 22, 32, 44, 60, 89}; + static const short rstep[6][4] = {{-3, -1, 1, 3}, {-5, -1, 1, 5}, + {-8, -2, 2, 8}, {-13, -3, 3, 13}, + {-19, -4, 4, 19}, {-28, -6, 6, 28}}; + static const short t_curve[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 88, 90, + 92, 94, 97, 99, 101, 103, 105, 107, 110, 112, 114, 116, 118, 120, + 123, 125, 127, 129, 131, 134, 136, 138, 140, 142, 144, 147, 149, 151, + 153, 155, 158, 160, 162, 164, 166, 168, 171, 173, 175, 177, 179, 181, + 184, 186, 188, 190, 192, 195, 197, 199, 201, 203, 205, 208, 210, 212, + 214, 216, 218, 221, 223, 226, 230, 235, 239, 244, 248, 252, 257, 261, + 265, 270, 274, 278, 283, 287, 291, 296, 300, 305, 309, 313, 318, 322, + 326, 331, 335, 339, 344, 348, 352, 357, 361, 365, 370, 374, 379, 383, + 387, 392, 396, 400, 405, 409, 413, 418, 422, 426, 431, 435, 440, 444, + 448, 453, 457, 461, 466, 470, 474, 479, 483, 487, 492, 496, 500, 508, + 519, 531, 542, 553, 564, 575, 587, 598, 609, 620, 631, 643, 654, 665, + 676, 687, 698, 710, 721, 732, 743, 754, 766, 777, 788, 799, 810, 822, + 833, 844, 855, 866, 878, 889, 900, 911, 922, 933, 945, 956, 967, 978, + 989, 1001, 1012, 1023}; + int rb, row, col, sharp, val = 0; + + if (width > 640 || height > 480) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + getbits(-1); + for (row = 2; row < height + 2; row++) + { + checkCancel(); + for (col = 2 + (row & 1); col < width + 2; col += 2) + { + val = ((pixel[(row - 1) * 644 + col - 1] + 2 * pixel[(row - 1) * 644 + col + 1] + pixel[row * 644 + col - 2]) >> 2) + gstep[getbits(4)]; + pixel[row * 644 + col] = val = LIM(val, 0, 255); + if (col < 4) + pixel[row * 644 + col - 2] = pixel[(row + 1) * 644 + (~row & 1)] = val; + if (row == 2) + pixel[(row - 1) * 644 + col + 1] = pixel[(row - 1) * 644 + col + 3] = val; + } + pixel[row * 644 + col] = val; + } + for (rb = 0; rb < 2; rb++) + for (row = 2 + rb; row < height + 2; row += 2) + { + checkCancel(); + for (col = 3 - (row & 1); col < width + 2; col += 2) + { + if (row < 4 || col < 4) + sharp = 2; + else + { + val = ABS(pixel[(row - 2) * 644 + col] - pixel[row * 644 + col - 2]) + ABS(pixel[(row - 2) * 644 + col] - pixel[(row - 2) * 644 + col - 2]) + + ABS(pixel[row * 644 + col - 2] - pixel[(row - 2) * 644 + col - 2]); + sharp = val < 4 + ? 0 + : val < 8 + ? 1 + : val < 16 ? 2 : val < 32 ? 3 : val < 48 ? 4 : 5; + } + val = ((pixel[(row - 2) * 644 + col] + pixel[row * 644 + col - 2]) >> 1) + rstep[sharp][getbits(2)]; + pixel[row * 644 + col] = val = LIM(val, 0, 255); + if (row < 4) + pixel[(row - 2) * 644 + col + 2] = val; + if (col < 4) + pixel[(row + 2) * 644 + col - 2] = val; + } + } + for (row = 2; row < height + 2; row++) + { + checkCancel(); + for (col = 3 - (row & 1); col < width + 2; col += 2) + { + val = ((pixel[row * 644 + col - 1] + (pixel[row * 644 + col] << 2) + pixel[row * 644 + col + 1]) >> 1) - 0x100; + pixel[row * 644 + col] = LIM(val, 0, 255); + } + } + for (row = 0; row < height; row++) + { + checkCancel(); + for (col = 0; col < width; col++) + RAW(row, col) = t_curve[pixel[(row + 2) * 644 + col + 2]]; + } + maximum = 0x3ff; +} + +void LibRaw::sony_load_raw() +{ + uchar head[40]; + ushort *pixel; + unsigned i, key, row, col; + + fseek(ifp, 200896, SEEK_SET); + fseek(ifp, (unsigned)fgetc(ifp) * 4 - 1, SEEK_CUR); + order = 0x4d4d; + key = get4(); + + fseek(ifp, 164600, SEEK_SET); + fread(head, 1, 40, ifp); + sony_decrypt((unsigned *)head, 10, 1, key); + for (i = 26; i-- > 22;) + key = key << 8 | head[i]; + + fseek(ifp, data_offset, SEEK_SET); + for (row = 0; row < raw_height; row++) + { + checkCancel(); + pixel = raw_image + row * raw_width; + if (fread(pixel, 2, raw_width, ifp) < raw_width) + derror(); + sony_decrypt((unsigned *)pixel, raw_width / 2, !row, key); + for (col = 0; col < raw_width; col++) + if ((pixel[col] = ntohs(pixel[col])) >> 14) + derror(); + } + maximum = 0x3ff0; +} + +void LibRaw::sony_arw_load_raw() +{ + std::vector<ushort> huff_buffer(32770); + ushort* huff = &huff_buffer[0]; + static const ushort tab[18] = {0xf11, 0xf10, 0xe0f, 0xd0e, 0xc0d, 0xb0c, + 0xa0b, 0x90a, 0x809, 0x708, 0x607, 0x506, + 0x405, 0x304, 0x303, 0x300, 0x202, 0x201}; + int i, c, n, col, row, sum = 0; + + huff[0] = 15; + for (n = i = 0; i < 18; i++) + FORC(32768 >> (tab[i] >> 8)) huff[++n] = tab[i]; + getbits(-1); + for (col = raw_width; col--;) + { + checkCancel(); + for (row = 0; row < raw_height + 1; row += 2) + { + if (row == raw_height) + row = 1; + if ((sum += ljpeg_diff(huff)) >> 12) + derror(); + if (row < height) + RAW(row, col) = sum; + } + } +} + +void LibRaw::sony_arw2_load_raw() +{ + uchar *data, *dp; + ushort pix[16]; + int row, col, val, max, min, imax, imin, sh, bit, i; + + data = (uchar *)malloc(raw_width + 1); + merror(data, "sony_arw2_load_raw()"); + try + { + for (row = 0; row < height; row++) + { + checkCancel(); + fread(data, 1, raw_width, ifp); + for (dp = data, col = 0; col < raw_width - 30; dp += 16) + { + max = 0x7ff & (val = sget4(dp)); + min = 0x7ff & val >> 11; + imax = 0x0f & val >> 22; + imin = 0x0f & val >> 26; + for (sh = 0; sh < 4 && 0x80 << sh <= max - min; sh++) + ; + /* flag checks if outside of loop */ + if (!(imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SONYARW2_ALLFLAGS) // no flag set + || (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE)) + { + for (bit = 30, i = 0; i < 16; i++) + if (i == imax) + pix[i] = max; + else if (i == imin) + pix[i] = min; + else + { + pix[i] = + ((sget2(dp + (bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; + if (pix[i] > 0x7ff) + pix[i] = 0x7ff; + bit += 7; + } + } + else if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SONYARW2_BASEONLY) + { + for (bit = 30, i = 0; i < 16; i++) + if (i == imax) + pix[i] = max; + else if (i == imin) + pix[i] = min; + else + pix[i] = 0; + } + else if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SONYARW2_DELTAONLY) + { + for (bit = 30, i = 0; i < 16; i++) + if (i == imax) + pix[i] = 0; + else if (i == imin) + pix[i] = 0; + else + { + pix[i] = + ((sget2(dp + (bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; + if (pix[i] > 0x7ff) + pix[i] = 0x7ff; + bit += 7; + } + } + else if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE) + { + for (bit = 30, i = 0; i < 16; i++) + if (i == imax) + pix[i] = 0; + else if (i == imin) + pix[i] = 0; + else + { + pix[i] = ((sget2(dp + (bit >> 3)) >> (bit & 7) & 0x7f) << sh); + if (pix[i] > 0x7ff) + pix[i] = 0x7ff; + bit += 7; + } + } + + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) + { + for (i = 0; i < 16; i++, col += 2) + { + unsigned slope = + pix[i] < 1001 ? 2 + : curve[pix[i] << 1] - curve[(pix[i] << 1) - 2]; + unsigned step = 1 << sh; + RAW(row, col) = + curve[pix[i] << 1] > + black + imgdata.params.sony_arw2_posterization_thr + ? LIM(((slope * step * 1000) / + (curve[pix[i] << 1] - black)), + 0, 10000) + : 0; + } + } + else + for (i = 0; i < 16; i++, col += 2) + RAW(row, col) = curve[pix[i] << 1]; + col -= col & 1 ? 1 : 31; + } + } + } + catch (...) + { + free(data); + throw; + } + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) + maximum = 10000; + free(data); +} + +void LibRaw::samsung_load_raw() +{ + int row, col, c, i, dir, op[4], len[4]; + if (raw_width > 32768 || + raw_height > 32768) // definitely too much for old samsung + throw LIBRAW_EXCEPTION_IO_BADFILE; + unsigned maxpixels = raw_width * (raw_height + 7); + + order = 0x4949; + for (row = 0; row < raw_height; row++) + { + checkCancel(); + fseek(ifp, strip_offset + row * 4, SEEK_SET); + fseek(ifp, data_offset + get4(), SEEK_SET); + ph1_bits(-1); + FORC4 len[c] = row < 2 ? 7 : 4; + for (col = 0; col < raw_width; col += 16) + { + dir = ph1_bits(1); + FORC4 op[c] = ph1_bits(2); + FORC4 switch (op[c]) + { + case 3: + len[c] = ph1_bits(4); + break; + case 2: + len[c]--; + break; + case 1: + len[c]++; + } + for (c = 0; c < 16; c += 2) + { + i = len[((c & 1) << 1) | (c >> 3)]; + unsigned idest = RAWINDEX(row, col + c); + unsigned isrc = (dir ? RAWINDEX(row + (~c | -2), col + c) + : col ? RAWINDEX(row, col + (c | -2)) : 0); + if (idest < maxpixels && + isrc < + maxpixels) // less than zero is handled by unsigned conversion + RAW(row, col + c) = (i > 0 ? ((signed)ph1_bits(i) << (32 - i) >> (32 - i)) : 0) + + (dir ? RAW(row + (~c | -2), col + c) : col ? RAW(row, col + (c | -2)) : 128); + else + derror(); + if (c == 14) + c = -1; + } + } + } + for (row = 0; row < raw_height - 1; row += 2) + for (col = 0; col < raw_width - 1; col += 2) + SWAP(RAW(row, col + 1), RAW(row + 1, col)); +} + +void LibRaw::samsung2_load_raw() +{ + static const ushort tab[14] = {0x304, 0x307, 0x206, 0x205, 0x403, + 0x600, 0x709, 0x80a, 0x90b, 0xa0c, + 0xa0d, 0x501, 0x408, 0x402}; + ushort huff[1026], vpred[2][2] = {{0, 0}, {0, 0}}, hpred[2]; + int i, c, n, row, col, diff; + + huff[0] = 10; + for (n = i = 0; i < 14; i++) + FORC(1024 >> (tab[i] >> 8)) huff[++n] = tab[i]; + getbits(-1); + for (row = 0; row < raw_height; row++) + { + checkCancel(); + for (col = 0; col < raw_width; col++) + { + diff = ljpeg_diff(huff); + if (col < 2) + hpred[col] = vpred[row & 1][col] += diff; + else + hpred[col & 1] += diff; + RAW(row, col) = hpred[col & 1]; + if (hpred[col & 1] >> tiff_bps) + derror(); + } + } +} + +void LibRaw::samsung3_load_raw() +{ + int opt, init, mag, pmode, row, tab, col, pred, diff, i, c; + ushort lent[3][2], len[4], *prow[2]; + order = 0x4949; + fseek(ifp, 9, SEEK_CUR); + opt = fgetc(ifp); + init = (get2(), get2()); + for (row = 0; row < raw_height; row++) + { + checkCancel(); + fseek(ifp, (data_offset - ftell(ifp)) & 15, SEEK_CUR); + ph1_bits(-1); + mag = 0; + pmode = 7; + FORC(6)((ushort *)lent)[c] = row < 2 ? 7 : 4; + prow[row & 1] = &RAW(row - 1, 1 - ((row & 1) << 1)); // green + prow[~row & 1] = &RAW(row - 2, 0); // red and blue + for (tab = 0; tab + 15 < raw_width; tab += 16) + { + if (~opt & 4 && !(tab & 63)) + { + i = ph1_bits(2); + mag = i < 3 ? mag - '2' + "204"[i] : ph1_bits(12); + } + if (opt & 2) + pmode = 7 - 4 * ph1_bits(1); + else if (!ph1_bits(1)) + pmode = ph1_bits(3); + if (opt & 1 || !ph1_bits(1)) + { + FORC4 len[c] = ph1_bits(2); + FORC4 + { + i = ((row & 1) << 1 | (c & 1)) % 3; + if (i < 0) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + len[c] = len[c] < 3 ? lent[i][0] - '1' + "120"[len[c]] : ph1_bits(4); + lent[i][0] = lent[i][1]; + lent[i][1] = len[c]; + } + } + FORC(16) + { + col = tab + (((c & 7) << 1) ^ (c >> 3) ^ (row & 1)); + if (col < 0) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if (pmode < 0) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if (pmode != 7 && row >= 2 && (col - '4' + "0224468"[pmode]) < 0) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + pred = (pmode == 7 || row < 2) + ? (tab ? RAW(row, tab - 2 + (col & 1)) : init) + : (prow[col & 1][col - '4' + "0224468"[pmode]] + + prow[col & 1][col - '4' + "0244668"[pmode]] + 1) >> + 1; + diff = ph1_bits(i = len[c >> 2]); + if (i > 0 && diff >> (i - 1)) + diff -= 1 << i; + diff = diff * (mag * 2 + 1) + mag; + RAW(row, col) = pred + diff; + } + } + } +} + +void LibRaw::redcine_load_raw() +{ +#ifndef NO_JASPER + int c, row, col; + jas_stream_t *in; + jas_image_t *jimg; + jas_matrix_t *jmat; + jas_seqent_t *data; + ushort *img, *pix; + + jas_init(); + in = (jas_stream_t *)ifp->make_jas_stream(); + if (!in) + throw LIBRAW_EXCEPTION_DECODE_JPEG2000; + jas_stream_seek(in, data_offset + 20, SEEK_SET); + jimg = jas_image_decode(in, -1, 0); + if (!jimg) + { + jas_stream_close(in); + throw LIBRAW_EXCEPTION_DECODE_JPEG2000; + } + jmat = jas_matrix_create(height / 2, width / 2); + merror(jmat, "redcine_load_raw()"); + img = (ushort *)calloc((height + 2), (width + 2) * 2); + merror(img, "redcine_load_raw()"); + bool fastexitflag = false; + try + { + FORC4 + { + checkCancel(); + jas_image_readcmpt(jimg, c, 0, 0, width / 2, height / 2, jmat); + data = jas_matrix_getref(jmat, 0, 0); + for (row = c >> 1; row < height; row += 2) + for (col = c & 1; col < width; col += 2) + img[(row + 1) * (width + 2) + col + 1] = + data[(row / 2) * (width / 2) + col / 2]; + } + for (col = 1; col <= width; col++) + { + img[col] = img[2 * (width + 2) + col]; + img[(height + 1) * (width + 2) + col] = + img[(height - 1) * (width + 2) + col]; + } + for (row = 0; row < height + 2; row++) + { + img[row * (width + 2)] = img[row * (width + 2) + 2]; + img[(row + 1) * (width + 2) - 1] = img[(row + 1) * (width + 2) - 3]; + } + for (row = 1; row <= height; row++) + { + checkCancel(); + pix = img + row * (width + 2) + (col = 1 + (FC(row, 1) & 1)); + for (; col <= width; col += 2, pix += 2) + { + c = (((pix[0] - 0x800) << 3) + pix[-(width + 2)] + pix[width + 2] + + pix[-1] + pix[1]) >> + 2; + pix[0] = LIM(c, 0, 4095); + } + } + for (row = 0; row < height; row++) + { + checkCancel(); + for (col = 0; col < width; col++) + RAW(row, col) = curve[img[(row + 1) * (width + 2) + col + 1]]; + } + } + catch (...) + { + fastexitflag = true; + } + free(img); + jas_matrix_destroy(jmat); + jas_image_destroy(jimg); + jas_stream_close(in); + if (fastexitflag) + throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; +#endif +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/decoders_libraw.cpp libkdcraw/libkdcraw/libraw/src/decoders/decoders_libraw.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/decoders_libraw.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/decoders_libraw.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,609 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +void LibRaw::sony_arq_load_raw() +{ + int row, col; + read_shorts(imgdata.rawdata.raw_image, + imgdata.sizes.raw_width * imgdata.sizes.raw_height * 4); + libraw_internal_data.internal_data.input->seek( + -2, SEEK_CUR); // avoid wrong eof error + + if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_ARQ_SKIP_CHANNEL_SWAP) + return; + + for (row = 0; row < imgdata.sizes.raw_height; row++) + { + unsigned short(*rowp)[4] = + (unsigned short(*)[4]) & + imgdata.rawdata.raw_image[row * imgdata.sizes.raw_width * 4]; + for (col = 0; col < imgdata.sizes.raw_width; col++) + { + unsigned short g2 = rowp[col][2]; + rowp[col][2] = rowp[col][3]; + rowp[col][3] = g2; + if (((unsigned)(row - imgdata.sizes.top_margin) < imgdata.sizes.height) && + ((unsigned)(col - imgdata.sizes.left_margin) < imgdata.sizes.width) && + (MAX(MAX(rowp[col][0], rowp[col][1]), + MAX(rowp[col][2], rowp[col][3])) > imgdata.color.maximum)) + derror(); + } + } +} + +void LibRaw::pentax_4shot_load_raw() +{ + ushort *plane = (ushort *)malloc(imgdata.sizes.raw_width * + imgdata.sizes.raw_height * sizeof(ushort)); + int alloc_sz = imgdata.sizes.raw_width * (imgdata.sizes.raw_height + 16) * 4 * + sizeof(ushort); + ushort(*result)[4] = (ushort(*)[4])malloc(alloc_sz); + struct movement_t + { + int row, col; + } _move[4] = { + {1, 1}, + {0, 1}, + {0, 0}, + {1, 0}, + }; + + int tidx = 0; + for (int i = 0; i < 4; i++) + { + int move_row, move_col; + if (imgdata.params.p4shot_order[i] >= '0' && + imgdata.params.p4shot_order[i] <= '3') + { + move_row = ((imgdata.params.p4shot_order[i] - '0') & 2) ? 1 : 0; + move_col = ((imgdata.params.p4shot_order[i] - '0') & 1) ? 1 : 0; + } + else + { + move_row = _move[i].row; + move_col = _move[i].col; + } + for (; tidx < 16; tidx++) + if (tiff_ifd[tidx].t_width == imgdata.sizes.raw_width && + tiff_ifd[tidx].t_height == imgdata.sizes.raw_height && + tiff_ifd[tidx].bps > 8 && tiff_ifd[tidx].samples == 1) + break; + if (tidx >= 16) + break; + imgdata.rawdata.raw_image = plane; + ID.input->seek(tiff_ifd[tidx].offset, SEEK_SET); + imgdata.idata.filters = 0xb4b4b4b4; + libraw_internal_data.unpacker_data.data_offset = tiff_ifd[tidx].offset; + (this->*pentax_component_load_raw)(); + for (int row = 0; row < imgdata.sizes.raw_height - move_row; row++) + { + int colors[2]; + for (int c = 0; c < 2; c++) + colors[c] = COLOR(row, c); + ushort *srcrow = &plane[imgdata.sizes.raw_width * row]; + ushort(*dstrow)[4] = + &result[(imgdata.sizes.raw_width) * (row + move_row) + move_col]; + for (int col = 0; col < imgdata.sizes.raw_width - move_col; col++) + dstrow[col][colors[col % 2]] = srcrow[col]; + } + tidx++; + } + + if (imgdata.color.cblack[4] == 2 && imgdata.color.cblack[5] == 2) + for (int c = 0; c < 4; c++) + imgdata.color.cblack[FC(c / 2, c % 2)] += + imgdata.color.cblack[6 + + c / 2 % imgdata.color.cblack[4] * + imgdata.color.cblack[5] + + c % 2 % imgdata.color.cblack[5]]; + imgdata.color.cblack[4] = imgdata.color.cblack[5] = 0; + + // assign things back: + imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 8; + imgdata.idata.filters = 0; + imgdata.rawdata.raw_alloc = imgdata.rawdata.color4_image = result; + free(plane); + imgdata.rawdata.raw_image = 0; +} + +void LibRaw::hasselblad_full_load_raw() +{ + int row, col; + + for (row = 0; row < S.height; row++) + for (col = 0; col < S.width; col++) + { + read_shorts(&imgdata.image[row * S.width + col][2], 1); // B + read_shorts(&imgdata.image[row * S.width + col][1], 1); // G + read_shorts(&imgdata.image[row * S.width + col][0], 1); // R + } +} + +static inline void unpack7bytesto4x16(unsigned char *src, unsigned short *dest) +{ + dest[0] = (src[0] << 6) | (src[1] >> 2); + dest[1] = ((src[1] & 0x3) << 12) | (src[2] << 4) | (src[3] >> 4); + dest[2] = (src[3] & 0xf) << 10 | (src[4] << 2) | (src[5] >> 6); + dest[3] = ((src[5] & 0x3f) << 8) | src[6]; +} + +static inline void unpack28bytesto16x16ns(unsigned char *src, + unsigned short *dest) +{ + dest[0] = (src[3] << 6) | (src[2] >> 2); + dest[1] = ((src[2] & 0x3) << 12) | (src[1] << 4) | (src[0] >> 4); + dest[2] = (src[0] & 0xf) << 10 | (src[7] << 2) | (src[6] >> 6); + dest[3] = ((src[6] & 0x3f) << 8) | src[5]; + dest[4] = (src[4] << 6) | (src[11] >> 2); + dest[5] = ((src[11] & 0x3) << 12) | (src[10] << 4) | (src[9] >> 4); + dest[6] = (src[9] & 0xf) << 10 | (src[8] << 2) | (src[15] >> 6); + dest[7] = ((src[15] & 0x3f) << 8) | src[14]; + dest[8] = (src[13] << 6) | (src[12] >> 2); + dest[9] = ((src[12] & 0x3) << 12) | (src[19] << 4) | (src[18] >> 4); + dest[10] = (src[18] & 0xf) << 10 | (src[17] << 2) | (src[16] >> 6); + dest[11] = ((src[16] & 0x3f) << 8) | src[23]; + dest[12] = (src[22] << 6) | (src[21] >> 2); + dest[13] = ((src[21] & 0x3) << 12) | (src[20] << 4) | (src[27] >> 4); + dest[14] = (src[27] & 0xf) << 10 | (src[26] << 2) | (src[25] >> 6); + dest[15] = ((src[25] & 0x3f) << 8) | src[24]; +} + +#define swab32(x) \ + ((unsigned int)((((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \ + (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \ + (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \ + (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24))) + +static inline void swab32arr(unsigned *arr, unsigned len) +{ + for (unsigned i = 0; i < len; i++) + arr[i] = swab32(arr[i]); +} +#undef swab32 + +static inline void unpack7bytesto4x16_nikon(unsigned char *src, + unsigned short *dest) +{ + dest[3] = (src[6] << 6) | (src[5] >> 2); + dest[2] = ((src[5] & 0x3) << 12) | (src[4] << 4) | (src[3] >> 4); + dest[1] = (src[3] & 0xf) << 10 | (src[2] << 2) | (src[1] >> 6); + dest[0] = ((src[1] & 0x3f) << 8) | src[0]; +} + +void LibRaw::nikon_14bit_load_raw() +{ + const unsigned linelen = + (unsigned)(ceilf((float)(S.raw_width * 7 / 4) / 16.0)) * + 16; // 14512; // S.raw_width * 7 / 4; + const unsigned pitch = S.raw_pitch ? S.raw_pitch / 2 : S.raw_width; + unsigned char *buf = (unsigned char *)malloc(linelen); + merror(buf, "nikon_14bit_load_raw()"); + for (int row = 0; row < S.raw_height; row++) + { + unsigned bytesread = + libraw_internal_data.internal_data.input->read(buf, 1, linelen); + unsigned short *dest = &imgdata.rawdata.raw_image[pitch * row]; + // swab32arr((unsigned *)buf, bytesread / 4); + for (unsigned int sp = 0, dp = 0; + dp < pitch - 3 && sp < linelen - 6 && sp < bytesread - 6; + sp += 7, dp += 4) + unpack7bytesto4x16_nikon(buf + sp, dest + dp); + } + free(buf); +} + +void LibRaw::fuji_14bit_load_raw() +{ + const unsigned linelen = S.raw_width * 7 / 4; + const unsigned pitch = S.raw_pitch ? S.raw_pitch / 2 : S.raw_width; + unsigned char *buf = (unsigned char *)malloc(linelen); + merror(buf, "fuji_14bit_load_raw()"); + + for (int row = 0; row < S.raw_height; row++) + { + unsigned bytesread = + libraw_internal_data.internal_data.input->read(buf, 1, linelen); + unsigned short *dest = &imgdata.rawdata.raw_image[pitch * row]; + if (bytesread % 28) + { + swab32arr((unsigned *)buf, bytesread / 4); + for (unsigned int sp = 0, dp = 0; + dp < pitch - 3 && sp < linelen - 6 && sp < bytesread - 6; + sp += 7, dp += 4) + unpack7bytesto4x16(buf + sp, dest + dp); + } + else + for (unsigned int sp = 0, dp = 0; + dp < pitch - 15 && sp < linelen - 27 && sp < bytesread - 27; + sp += 28, dp += 16) + unpack28bytesto16x16ns(buf + sp, dest + dp); + } + free(buf); +} +void LibRaw::nikon_load_padded_packed_raw() // 12 bit per pixel, padded to 16 + // bytes +{ + // libraw_internal_data.unpacker_data.load_flags -> row byte count + if (libraw_internal_data.unpacker_data.load_flags < 2000 || + libraw_internal_data.unpacker_data.load_flags > 64000) + return; + unsigned char *buf = + (unsigned char *)malloc(libraw_internal_data.unpacker_data.load_flags); + for (int row = 0; row < S.raw_height; row++) + { + checkCancel(); + libraw_internal_data.internal_data.input->read( + buf, libraw_internal_data.unpacker_data.load_flags, 1); + for (int icol = 0; icol < S.raw_width / 2; icol++) + { + imgdata.rawdata.raw_image[(row)*S.raw_width + (icol * 2)] = + ((buf[icol * 3 + 1] & 0xf) << 8) | buf[icol * 3]; + imgdata.rawdata.raw_image[(row)*S.raw_width + (icol * 2 + 1)] = + buf[icol * 3 + 2] << 4 | ((buf[icol * 3 + 1] & 0xf0) >> 4); + } + } + free(buf); +} + +void LibRaw::nikon_load_striped_packed_raw() +{ + int vbits = 0, bwide, rbits, bite, row, col, i; + + UINT64 bitbuf = 0; + unsigned load_flags = 24; // libraw_internal_data.unpacker_data.load_flags; + unsigned tiff_bps = libraw_internal_data.unpacker_data.tiff_bps; + + struct tiff_ifd_t *ifd = &tiff_ifd[0]; + while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] && + ifd->offset != libraw_internal_data.unpacker_data.data_offset) + ++ifd; + if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds]) + throw LIBRAW_EXCEPTION_DECODE_RAW; + + if (!ifd->rows_per_strip || !ifd->strip_offsets_count) + return; // not unpacked + int stripcnt = 0; + + bwide = S.raw_width * tiff_bps / 8; + bwide += bwide & load_flags >> 7; + rbits = bwide * 8 - S.raw_width * tiff_bps; + if (load_flags & 1) + bwide = bwide * 16 / 15; + bite = 8 + (load_flags & 24); + for (row = 0; row < S.raw_height; row++) + { + checkCancel(); + if (!(row % ifd->rows_per_strip)) + { + if (stripcnt >= ifd->strip_offsets_count) + return; // run out of data + libraw_internal_data.internal_data.input->seek( + ifd->strip_offsets[stripcnt], SEEK_SET); + stripcnt++; + } + for (col = 0; col < S.raw_width; col++) + { + for (vbits -= tiff_bps; vbits < 0; vbits += bite) + { + bitbuf <<= bite; + for (i = 0; i < bite; i += 8) + bitbuf |= + (unsigned)(libraw_internal_data.internal_data.input->get_char() + << i); + } + imgdata.rawdata.raw_image[(row)*S.raw_width + (col)] = + bitbuf << (64 - tiff_bps - vbits) >> (64 - tiff_bps); + } + vbits -= rbits; + } +} + +struct pana_cs6_page_decoder +{ + unsigned int pixelbuffer[14], lastoffset, maxoffset; + unsigned char current, *buffer; + pana_cs6_page_decoder(unsigned char *_buffer, unsigned int bsize) + : lastoffset(0), maxoffset(bsize), current(0), buffer(_buffer) + { + } + void read_page(); // will throw IO error if not enough space in buffer + unsigned int nextpixel() { return current < 14 ? pixelbuffer[current++] : 0; } +}; + +void pana_cs6_page_decoder::read_page() +{ + if (!buffer || (maxoffset - lastoffset < 16)) + throw LIBRAW_EXCEPTION_IO_EOF; +#define wbuffer(i) ((unsigned short)buffer[lastoffset + 15 - i]) + pixelbuffer[0] = (wbuffer(0) << 6) | (wbuffer(1) >> 2); // 14 bit + pixelbuffer[1] = + (((wbuffer(1) & 0x3) << 12) | (wbuffer(2) << 4) | (wbuffer(3) >> 4)) & + 0x3fff; + pixelbuffer[2] = (wbuffer(3) >> 2) & 0x3; + pixelbuffer[3] = ((wbuffer(3) & 0x3) << 8) | wbuffer(4); + pixelbuffer[4] = (wbuffer(5) << 2) | (wbuffer(6) >> 6); + pixelbuffer[5] = ((wbuffer(6) & 0x3f) << 4) | (wbuffer(7) >> 4); + pixelbuffer[6] = (wbuffer(7) >> 2) & 0x3; + pixelbuffer[7] = ((wbuffer(7) & 0x3) << 8) | wbuffer(8); + pixelbuffer[8] = ((wbuffer(9) << 2) & 0x3fc) | (wbuffer(10) >> 6); + pixelbuffer[9] = ((wbuffer(10) << 4) | (wbuffer(11) >> 4)) & 0x3ff; + pixelbuffer[10] = (wbuffer(11) >> 2) & 0x3; + pixelbuffer[11] = ((wbuffer(11) & 0x3) << 8) | wbuffer(12); + pixelbuffer[12] = (((wbuffer(13) << 2) & 0x3fc) | wbuffer(14) >> 6) & 0x3ff; + pixelbuffer[13] = ((wbuffer(14) << 4) | (wbuffer(15) >> 4)) & 0x3ff; +#undef wbuffer + current = 0; + lastoffset += 16; +} + +void LibRaw::panasonicC6_load_raw() +{ + const int rowstep = 16; + const int blocksperrow = imgdata.sizes.raw_width / 11; + const int rowbytes = blocksperrow * 16; + unsigned char *iobuf = (unsigned char *)malloc(rowbytes * rowstep); + merror(iobuf, "panasonicC6_load_raw()"); + + for (int row = 0; row < imgdata.sizes.raw_height - rowstep + 1; + row += rowstep) + { + int rowstoread = MIN(rowstep, imgdata.sizes.raw_height - row); + if (libraw_internal_data.internal_data.input->read( + iobuf, rowbytes, rowstoread) != rowstoread) + throw LIBRAW_EXCEPTION_IO_EOF; + pana_cs6_page_decoder page(iobuf, rowbytes * rowstoread); + for (int crow = 0, col = 0; crow < rowstoread; crow++, col = 0) + { + unsigned short *rowptr = + &imgdata.rawdata + .raw_image[(row + crow) * imgdata.sizes.raw_pitch / 2]; + for (int rblock = 0; rblock < blocksperrow; rblock++) + { + page.read_page(); + unsigned oddeven[2] = {0, 0}, nonzero[2] = {0, 0}; + unsigned pmul = 0, pixel_base = 0; + for (int pix = 0; pix < 11; pix++) + { + if (pix % 3 == 2) + { + unsigned base = page.nextpixel(); + if (base > 3) + throw LIBRAW_EXCEPTION_IO_CORRUPT; // not possible b/c of 2-bit + // field, but.... + if (base == 3) + base = 4; + pixel_base = 0x200 << base; + pmul = 1 << base; + } + unsigned epixel = page.nextpixel(); + if (oddeven[pix % 2]) + { + epixel *= pmul; + if (pixel_base < 0x2000 && nonzero[pix % 2] > pixel_base) + epixel += nonzero[pix % 2] - pixel_base; + nonzero[pix % 2] = epixel; + } + else + { + oddeven[pix % 2] = epixel; + if (epixel) + nonzero[pix % 2] = epixel; + else + epixel = nonzero[pix % 2]; + } + unsigned spix = epixel - 0xf; + if (spix <= 0xffff) + rowptr[col++] = spix & 0xffff; + else + { + epixel = (((signed int)(epixel + 0x7ffffff1)) >> 0x1f); + rowptr[col++] = epixel & 0x3fff; + } + } + } + } + } + free(iobuf); +} + +void LibRaw::panasonicC7_load_raw() +{ + const int rowstep = 16; + int pixperblock = libraw_internal_data.unpacker_data.pana_bpp == 14 ? 9 : 10; + int rowbytes = imgdata.sizes.raw_width / pixperblock * 16; + unsigned char *iobuf = (unsigned char *)malloc(rowbytes * rowstep); + merror(iobuf, "panasonicC7_load_raw()"); + for (int row = 0; row < imgdata.sizes.raw_height - rowstep + 1; + row += rowstep) + { + int rowstoread = MIN(rowstep, imgdata.sizes.raw_height - row); + if (libraw_internal_data.internal_data.input->read( + iobuf, rowbytes, rowstoread) != rowstoread) + throw LIBRAW_EXCEPTION_IO_EOF; + unsigned char *bytes = iobuf; + for (int crow = 0; crow < rowstoread; crow++) + { + unsigned short *rowptr = + &imgdata.rawdata + .raw_image[(row + crow) * imgdata.sizes.raw_pitch / 2]; + for (int col = 0; col < imgdata.sizes.raw_width - pixperblock + 1; + col += pixperblock, bytes += 16) + { + if (libraw_internal_data.unpacker_data.pana_bpp == 14) + { + rowptr[col] = bytes[0] + ((bytes[1] & 0x3F) << 8); + rowptr[col + 1] = + (bytes[1] >> 6) + 4 * (bytes[2]) + ((bytes[3] & 0xF) << 10); + rowptr[col + 2] = + (bytes[3] >> 4) + 16 * (bytes[4]) + ((bytes[5] & 3) << 12); + rowptr[col + 3] = ((bytes[5] & 0xFC) >> 2) + (bytes[6] << 6); + rowptr[col + 4] = bytes[7] + ((bytes[8] & 0x3F) << 8); + rowptr[col + 5] = + (bytes[8] >> 6) + 4 * bytes[9] + ((bytes[10] & 0xF) << 10); + rowptr[col + 6] = + (bytes[10] >> 4) + 16 * bytes[11] + ((bytes[12] & 3) << 12); + rowptr[col + 7] = ((bytes[12] & 0xFC) >> 2) + (bytes[13] << 6); + rowptr[col + 8] = bytes[14] + ((bytes[15] & 0x3F) << 8); + } + else if (libraw_internal_data.unpacker_data.pana_bpp == + 12) // have not seen in the wild yet + { + rowptr[col] = ((bytes[1] & 0xF) << 8) + bytes[0]; + rowptr[col + 1] = 16 * bytes[2] + (bytes[1] >> 4); + rowptr[col + 2] = ((bytes[4] & 0xF) << 8) + bytes[3]; + rowptr[col + 3] = 16 * bytes[5] + (bytes[4] >> 4); + rowptr[col + 4] = ((bytes[7] & 0xF) << 8) + bytes[6]; + rowptr[col + 5] = 16 * bytes[8] + (bytes[7] >> 4); + rowptr[col + 6] = ((bytes[10] & 0xF) << 8) + bytes[9]; + rowptr[col + 7] = 16 * bytes[11] + (bytes[10] >> 4); + rowptr[col + 8] = ((bytes[13] & 0xF) << 8) + bytes[12]; + rowptr[col + 9] = 16 * bytes[14] + (bytes[13] >> 4); + } + } + } + } + free(iobuf); +} + +void LibRaw::unpacked_load_raw_fuji_f700s20() +{ + int base_offset = 0; + int row_size = imgdata.sizes.raw_width * 2; // in bytes + if (imgdata.idata.raw_count == 2 && imgdata.params.shot_select) + { + libraw_internal_data.internal_data.input->seek(-row_size, SEEK_CUR); + base_offset = row_size; // in bytes + } + unsigned char *buffer = (unsigned char *)malloc(row_size * 2); + for (int row = 0; row < imgdata.sizes.raw_height; row++) + { + read_shorts((ushort *)buffer, imgdata.sizes.raw_width * 2); + memmove(&imgdata.rawdata.raw_image[row * imgdata.sizes.raw_pitch / 2], + buffer + base_offset, row_size); + } + free(buffer); +} + +void LibRaw::nikon_load_sraw() +{ + // We're already seeked to data! + unsigned char *rd = + (unsigned char *)malloc(3 * (imgdata.sizes.raw_width + 2)); + if (!rd) + throw LIBRAW_EXCEPTION_ALLOC; + try + { + int row, col; + for (row = 0; row < imgdata.sizes.raw_height; row++) + { + checkCancel(); + libraw_internal_data.internal_data.input->read(rd, 3, + imgdata.sizes.raw_width); + for (col = 0; col < imgdata.sizes.raw_width - 1; col += 2) + { + int bi = col * 3; + ushort bits1 = (rd[bi + 1] & 0xf) << 8 | rd[bi]; // 3,0,1 + ushort bits2 = rd[bi + 2] << 4 | ((rd[bi + 1] >> 4) & 0xf); // 452 + ushort bits3 = ((rd[bi + 4] & 0xf) << 8) | rd[bi + 3]; // 967 + ushort bits4 = rd[bi + 5] << 4 | ((rd[bi + 4] >> 4) & 0xf); // ab8 + imgdata.image[row * imgdata.sizes.raw_width + col][0] = bits1; + imgdata.image[row * imgdata.sizes.raw_width + col][1] = bits3; + imgdata.image[row * imgdata.sizes.raw_width + col][2] = bits4; + imgdata.image[row * imgdata.sizes.raw_width + col + 1][0] = bits2; + imgdata.image[row * imgdata.sizes.raw_width + col + 1][1] = 2048; + imgdata.image[row * imgdata.sizes.raw_width + col + 1][2] = 2048; + } + } + } + catch (...) + { + free(rd); + throw; + } + free(rd); + C.maximum = 0xfff; // 12 bit? + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) + { + return; // no CbCr interpolation + } + // Interpolate CC channels + int row, col; + for (row = 0; row < imgdata.sizes.raw_height; row++) + { + checkCancel(); // will throw out + for (col = 0; col < imgdata.sizes.raw_width; col += 2) + { + int col2 = col < imgdata.sizes.raw_width - 2 ? col + 2 : col; + imgdata.image[row * imgdata.sizes.raw_width + col + 1][1] = + (unsigned short)(int(imgdata.image[row * imgdata.sizes.raw_width + + col][1] + + imgdata.image[row * imgdata.sizes.raw_width + + col2][1]) / + 2); + imgdata.image[row * imgdata.sizes.raw_width + col + 1][2] = + (unsigned short)(int(imgdata.image[row * imgdata.sizes.raw_width + + col][2] + + imgdata.image[row * imgdata.sizes.raw_width + + col2][2]) / + 2); + } + } + if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_RGB) + return; + + for (row = 0; row < imgdata.sizes.raw_height; row++) + { + checkCancel(); // will throw out + for (col = 0; col < imgdata.sizes.raw_width; col++) + { + float Y = + float(imgdata.image[row * imgdata.sizes.raw_width + col][0]) / 2549.f; + float Ch2 = + float(imgdata.image[row * imgdata.sizes.raw_width + col][1] - 1280) / + 1536.f; + float Ch3 = + float(imgdata.image[row * imgdata.sizes.raw_width + col][2] - 1280) / + 1536.f; + if (Y > 1.f) + Y = 1.f; + if (Y > 0.803f) + Ch2 = Ch3 = 0.5f; + float r = Y + 1.40200f * (Ch3 - 0.5f); + if (r < 0.f) + r = 0.f; + if (r > 1.f) + r = 1.f; + float g = Y - 0.34414f * (Ch2 - 0.5f) - 0.71414 * (Ch3 - 0.5f); + if (g > 1.f) + g = 1.f; + if (g < 0.f) + g = 0.f; + float b = Y + 1.77200 * (Ch2 - 0.5f); + if (b > 1.f) + b = 1.f; + if (b < 0.f) + b = 0.f; + imgdata.image[row * imgdata.sizes.raw_width + col][0] = + imgdata.color.curve[int(r * 3072.f)]; + imgdata.image[row * imgdata.sizes.raw_width + col][1] = + imgdata.color.curve[int(g * 3072.f)]; + imgdata.image[row * imgdata.sizes.raw_width + col][2] = + imgdata.color.curve[int(b * 3072.f)]; + } + } + C.maximum = 16383; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/decoders_libraw_dcrdefs.cpp libkdcraw/libkdcraw/libraw/src/decoders/decoders_libraw_dcrdefs.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/decoders_libraw_dcrdefs.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/decoders_libraw_dcrdefs.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,285 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::nikon_coolscan_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + int bypp = tiff_bps <= 8 ? 1 : 2; + int bufsize = width * 3 * bypp; + unsigned char *buf = (unsigned char *)malloc(bufsize); + unsigned short *ubuf = (unsigned short *)buf; + + if (tiff_bps <= 8) + gamma_curve(1.0 / imgdata.params.coolscan_nef_gamma, 0., 1, 255); + else + gamma_curve(1.0 / imgdata.params.coolscan_nef_gamma, 0., 1, 65535); + fseek(ifp, data_offset, SEEK_SET); + for (int row = 0; row < raw_height; row++) + { + if(tiff_bps <=8) + fread(buf, 1, bufsize, ifp); + else + read_shorts(ubuf,width*3); + unsigned short(*ip)[4] = (unsigned short(*)[4])image + row * width; + if (is_NikonTransfer == 2) + { // it is also (tiff_bps == 8) + for (int col = 0; col < width; col++) + { + ip[col][0] = ((float)curve[buf[col * 3]]) / 255.0f; + ip[col][1] = ((float)curve[buf[col * 3 + 1]]) / 255.0f; + ip[col][2] = ((float)curve[buf[col * 3 + 2]]) / 255.0f; + ip[col][3] = 0; + } + } + else if (tiff_bps <= 8) + { + for (int col = 0; col < width; col++) + { + ip[col][0] = curve[buf[col * 3]]; + ip[col][1] = curve[buf[col * 3 + 1]]; + ip[col][2] = curve[buf[col * 3 + 2]]; + ip[col][3] = 0; + } + } + else + { + for (int col = 0; col < width; col++) + { + ip[col][0] = curve[ubuf[col * 3]]; + ip[col][1] = curve[ubuf[col * 3 + 1]]; + ip[col][2] = curve[ubuf[col * 3 + 2]]; + ip[col][3] = 0; + } + } + } + free(buf); +} + +void LibRaw::broadcom_load_raw() +{ + + uchar *data, *dp; + int rev, row, col, c; + ushort _raw_stride = (ushort)load_flags; + rev = 3 * (order == 0x4949); + data = (uchar *)malloc(raw_stride * 2); + merror(data, "broadcom_load_raw()"); + + for (row = 0; row < raw_height; row++) + { + if (fread(data + _raw_stride, 1, _raw_stride, ifp) < _raw_stride) + derror(); + FORC(_raw_stride) data[c] = data[_raw_stride + (c ^ rev)]; + for (dp = data, col = 0; col < raw_width; dp += 5, col += 4) + FORC4 RAW(row, col + c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); + } + free(data); +} + +void LibRaw::android_tight_load_raw() +{ + uchar *data, *dp; + int bwide, row, col, c; + + bwide = -(-5 * raw_width >> 5) << 3; + data = (uchar *)malloc(bwide); + merror(data, "android_tight_load_raw()"); + for (row = 0; row < raw_height; row++) + { + if (fread(data, 1, bwide, ifp) < bwide) + derror(); + for (dp = data, col = 0; col < raw_width; dp += 5, col += 4) + FORC4 RAW(row, col + c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); + } + free(data); +} + +void LibRaw::android_loose_load_raw() +{ + uchar *data, *dp; + int bwide, row, col, c; + UINT64 bitbuf = 0; + + bwide = (raw_width + 5) / 6 << 3; + data = (uchar *)malloc(bwide); + merror(data, "android_loose_load_raw()"); + for (row = 0; row < raw_height; row++) + { + if (fread(data, 1, bwide, ifp) < bwide) + derror(); + for (dp = data, col = 0; col < raw_width; dp += 8, col += 6) + { + FORC(8) bitbuf = (bitbuf << 8) | dp[c ^ 7]; + FORC(6) RAW(row, col + c) = (bitbuf >> c * 10) & 0x3ff; + } + } + free(data); +} + +void LibRaw::unpacked_load_raw_reversed() +{ + int row, col, bits = 0; + while (1 << ++bits < (int)maximum) + ; + for (row = raw_height - 1; row >= 0; row--) + { + checkCancel(); + read_shorts(&raw_image[row * raw_width], raw_width); + for (col = 0; col < raw_width; col++) + if ((RAW(row, col) >>= load_flags) >> bits && + (unsigned)(row - top_margin) < height && + (unsigned)(col - left_margin) < width) + derror(); + } +} + +#ifdef USE_6BY9RPI + +void LibRaw::rpi_load_raw8() +{ + uchar *data, *dp; + int rev, dwide, row, col, c; + double sum[] = { 0,0 }; + rev = 3 * (order == 0x4949); + if (raw_stride == 0) + dwide = raw_width; + else + dwide = raw_stride; + data = (uchar *)malloc(dwide * 2); + merror(data, "rpi_load_raw8()"); + for (row = 0; row < raw_height; row++) { + if (fread(data + dwide, 1, dwide, ifp) < dwide) derror(); + FORC(dwide) data[c] = data[dwide + (c ^ rev)]; + for (dp = data, col = 0; col < raw_width; dp++, col++) + RAW(row, col + c) = dp[c]; + } + free(data); + maximum = 0xff; + if (!strcmp(make, "OmniVision") || + !strcmp(make, "Sony") || + !strcmp(make, "RaspberryPi")) return; + + row = raw_height / 2; + FORC(width - 1) { + sum[c & 1] += SQR(RAW(row, c) - RAW(row + 1, c + 1)); + sum[~c & 1] += SQR(RAW(row + 1, c) - RAW(row, c + 1)); + } + if (sum[1] > sum[0]) filters = 0x4b4b4b4b; +} + +void LibRaw::rpi_load_raw12() +{ + uchar *data, *dp; + int rev, dwide, row, col, c; + double sum[] = { 0,0 }; + rev = 3 * (order == 0x4949); + if (raw_stride == 0) + dwide = (raw_width * 3 + 1) / 2; + else + dwide = raw_stride; + data = (uchar *)malloc(dwide * 2); + merror(data, "rpi_load_raw12()"); + for (row = 0; row < raw_height; row++) { + if (fread(data + dwide, 1, dwide, ifp) < dwide) derror(); + FORC(dwide) data[c] = data[dwide + (c ^ rev)]; + for (dp = data, col = 0; col < raw_width; dp += 3, col += 2) + FORC(2) RAW(row, col + c) = (dp[c] << 4) | (dp[2] >> (c << 2) & 0xF); + } + free(data); + maximum = 0xfff; + if (!strcmp(make, "OmniVision") || + !strcmp(make, "Sony") || + !strcmp(make, "RaspberryPi")) return; + + row = raw_height / 2; + FORC(width - 1) { + sum[c & 1] += SQR(RAW(row, c) - RAW(row + 1, c + 1)); + sum[~c & 1] += SQR(RAW(row + 1, c) - RAW(row, c + 1)); + } + if (sum[1] > sum[0]) filters = 0x4b4b4b4b; +} + +void LibRaw::rpi_load_raw14() +{ + uchar *data, *dp; + int rev, dwide, row, col, c; + double sum[] = { 0,0 }; + rev = 3 * (order == 0x4949); + if (raw_stride == 0) + dwide = ((raw_width * 7) + 3) >> 2; + else + dwide = raw_stride; + data = (uchar *)malloc(dwide * 2); + merror(data, "rpi_load_raw14()"); + for (row = 0; row < raw_height; row++) { + if (fread(data + dwide, 1, dwide, ifp) < dwide) derror(); + FORC(dwide) data[c] = data[dwide + (c ^ rev)]; + for (dp = data, col = 0; col < raw_width; dp += 7, col += 4) { + RAW(row, col + 0) = (dp[0] << 6) | (dp[4] >> 2); + RAW(row, col + 1) = (dp[1] << 6) | ((dp[4] & 0x3) << 4) | ((dp[5] & 0xf0) >> 4); + RAW(row, col + 2) = (dp[2] << 6) | ((dp[5] & 0xf) << 2) | ((dp[6] & 0xc0) >> 6); + RAW(row, col + 3) = (dp[3] << 6) | ((dp[6] & 0x3f) << 2); + } + } + free(data); + maximum = 0x3fff; + if (!strcmp(make, "OmniVision") || + !strcmp(make, "Sony") || + !strcmp(make, "RaspberryPi")) return; + + row = raw_height / 2; + FORC(width - 1) { + sum[c & 1] += SQR(RAW(row, c) - RAW(row + 1, c + 1)); + sum[~c & 1] += SQR(RAW(row + 1, c) - RAW(row, c + 1)); + } + if (sum[1] > sum[0]) filters = 0x4b4b4b4b; +} + +void LibRaw::rpi_load_raw16() +{ + uchar *data, *dp; + int rev, dwide, row, col, c; + double sum[] = { 0,0 }; + rev = 3 * (order == 0x4949); + if (raw_stride == 0) + dwide = (raw_width * 2); + else + dwide = raw_stride; + data = (uchar *)malloc(dwide * 2); + merror(data, "rpi_load_raw16()"); + for (row = 0; row < raw_height; row++) { + if (fread(data + dwide, 1, dwide, ifp) < dwide) derror(); + FORC(dwide) data[c] = data[dwide + (c ^ rev)]; + for (dp = data, col = 0; col < raw_width; dp += 2, col++) + RAW(row, col + c) = (dp[1] << 8) | dp[0]; + } + free(data); + maximum = 0xffff; + if (!strcmp(make, "OmniVision") || + !strcmp(make, "Sony") || + !strcmp(make, "RaspberryPi")) return; + + row = raw_height / 2; + FORC(width - 1) { + sum[c & 1] += SQR(RAW(row, c) - RAW(row + 1, c + 1)); + sum[~c & 1] += SQR(RAW(row + 1, c) - RAW(row, c + 1)); + } + if (sum[1] > sum[0]) filters = 0x4b4b4b4b; +} + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/dng.cpp libkdcraw/libkdcraw/libraw/src/decoders/dng.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/dng.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/dng.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,271 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::vc5_dng_load_raw_placeholder() +{ + // placeholder only, real decoding implemented in GPR SDK + throw LIBRAW_EXCEPTION_DECODE_RAW; +} + +void LibRaw::adobe_copy_pixel(unsigned row, unsigned col, ushort **rp) +{ + int c; + + if (tiff_samples == 2 && shot_select) + (*rp)++; + if (raw_image) + { + if (row < raw_height && col < raw_width) + RAW(row, col) = curve[**rp]; + *rp += tiff_samples; + } + else + { + if (row < raw_height && col < raw_width) + FORC(int(tiff_samples)) + image[row * raw_width + col][c] = curve[(*rp)[c]]; + *rp += tiff_samples; + } + if (tiff_samples == 2 && shot_select) + (*rp)--; +} +void LibRaw::lossless_dng_load_raw() +{ + unsigned save, trow = 0, tcol = 0, jwide, jrow, jcol, row, col, i, j; + struct jhead jh; + ushort *rp; + + int ss = shot_select; + shot_select = libraw_internal_data.unpacker_data.dng_frames[LIM(ss,0,(LIBRAW_IFD_MAXCOUNT*2-1))] & 0xff; + + while (trow < raw_height) + { + checkCancel(); + save = ftell(ifp); + if (tile_length < INT_MAX) + fseek(ifp, get4(), SEEK_SET); + if (!ljpeg_start(&jh, 0)) + break; + jwide = jh.wide; + if (filters) + jwide *= jh.clrs; + + if(filters && (tiff_samples == 2)) // Fuji Super CCD + jwide /= 2; + try + { + switch (jh.algo) + { + case 0xc1: + jh.vpred[0] = 16384; + getbits(-1); + for (jrow = 0; jrow + 7 < (unsigned)jh.high; jrow += 8) + { + checkCancel(); + for (jcol = 0; jcol + 7 < (unsigned)jh.wide; jcol += 8) + { + ljpeg_idct(&jh); + rp = jh.idct; + row = trow + jcol / tile_width + jrow * 2; + col = tcol + jcol % tile_width; + for (i = 0; i < 16; i += 2) + for (j = 0; j < 8; j++) + adobe_copy_pixel(row + i, col + j, &rp); + } + } + break; + case 0xc3: + for (row = col = jrow = 0; jrow < (unsigned)jh.high; jrow++) + { + checkCancel(); + rp = ljpeg_row(jrow, &jh); + if (tiff_samples == 1 && jh.clrs > 1 && jh.clrs * jwide == raw_width) + for (jcol = 0; jcol < jwide * jh.clrs; jcol++) + { + adobe_copy_pixel(trow + row, tcol + col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + else + for (jcol = 0; jcol < jwide; jcol++) + { + adobe_copy_pixel(trow + row, tcol + col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + } + } + } + catch (...) + { + ljpeg_end(&jh); + shot_select = ss; + throw; + } + fseek(ifp, save + 4, SEEK_SET); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); + ljpeg_end(&jh); + } + shot_select = ss; +} + +void LibRaw::packed_dng_load_raw() +{ + ushort *pixel, *rp; + unsigned row, col; + + int ss = shot_select; + shot_select = libraw_internal_data.unpacker_data.dng_frames[LIM(ss,0,(LIBRAW_IFD_MAXCOUNT*2-1))] & 0xff; + + pixel = (ushort *)calloc(raw_width, tiff_samples * sizeof *pixel); + merror(pixel, "packed_dng_load_raw()"); + try + { + for (row = 0; row < raw_height; row++) + { + checkCancel(); + if (tiff_bps == 16) + read_shorts(pixel, raw_width * tiff_samples); + else + { + getbits(-1); + for (col = 0; col < raw_width * tiff_samples; col++) + pixel[col] = getbits(tiff_bps); + } + for (rp = pixel, col = 0; col < raw_width; col++) + adobe_copy_pixel(row, col, &rp); + } + } + catch (...) + { + free(pixel); + shot_select = ss; + throw; + } + free(pixel); + shot_select = ss; +} +#ifdef NO_JPEG +void LibRaw::lossy_dng_load_raw() {} +#else + +static void jpegErrorExit_d(j_common_ptr cinfo) +{ + throw LIBRAW_EXCEPTION_DECODE_JPEG; +} + +void LibRaw::lossy_dng_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + struct jpeg_decompress_struct cinfo; + JSAMPARRAY buf; + JSAMPLE(*pixel)[3]; + unsigned sorder = order, ntags, opcode, deg, i, j, c; + unsigned save = data_offset - 4, trow = 0, tcol = 0, row, col; + ushort cur[3][256]; + double coeff[9], tot; + + if (meta_offset) + { + fseek(ifp, meta_offset, SEEK_SET); + order = 0x4d4d; + ntags = get4(); + while (ntags--) + { + opcode = get4(); + get4(); + get4(); + if (opcode != 8) + { + fseek(ifp, get4(), SEEK_CUR); + continue; + } + fseek(ifp, 20, SEEK_CUR); + if ((c = get4()) > 2) + break; + fseek(ifp, 12, SEEK_CUR); + if ((deg = get4()) > 8) + break; + for (i = 0; i <= deg && i < 9; i++) + coeff[i] = getreal(LIBRAW_EXIFTAG_TYPE_DOUBLE); + for (i = 0; i < 256; i++) + { + for (tot = j = 0; j <= deg; j++) + tot += coeff[j] * pow(i / 255.0, (int)j); + cur[c][i] = tot * 0xffff; + } + } + order = sorder; + } + else + { + gamma_curve(1 / 2.4, 12.92, 1, 255); + FORC3 memcpy(cur[c], curve, sizeof cur[0]); + } + + struct jpeg_error_mgr pub; + cinfo.err = jpeg_std_error(&pub); + pub.error_exit = jpegErrorExit_d; + + jpeg_create_decompress(&cinfo); + + while (trow < raw_height) + { + fseek(ifp, save += 4, SEEK_SET); + if (tile_length < INT_MAX) + fseek(ifp, get4(), SEEK_SET); + if (libraw_internal_data.internal_data.input->jpeg_src(&cinfo) == -1) + { + jpeg_destroy_decompress(&cinfo); + throw LIBRAW_EXCEPTION_DECODE_JPEG; + } + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + buf = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, + cinfo.output_width * 3, 1); + try + { + while (cinfo.output_scanline < cinfo.output_height && + (row = trow + cinfo.output_scanline) < height) + { + checkCancel(); + jpeg_read_scanlines(&cinfo, buf, 1); + pixel = (JSAMPLE(*)[3])buf[0]; + for (col = 0; col < cinfo.output_width && tcol + col < width; col++) + { + FORC3 image[row * width + tcol + col][c] = cur[c][pixel[col][c]]; + } + } + } + catch (...) + { + jpeg_destroy_decompress(&cinfo); + throw; + } + jpeg_abort_decompress(&cinfo); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); + } + jpeg_destroy_decompress(&cinfo); + maximum = 0xffff; +} +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/fp_dng.cpp libkdcraw/libkdcraw/libraw/src/decoders/fp_dng.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/fp_dng.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/fp_dng.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,538 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#ifdef USE_ZLIB +inline unsigned int __DNG_HalfToFloat(ushort halfValue) +{ + int sign = (halfValue >> 15) & 0x00000001; + int exponent = (halfValue >> 10) & 0x0000001f; + int mantissa = halfValue & 0x000003ff; + if (exponent == 0) + { + if (mantissa == 0) + { + return (unsigned int)(sign << 31); + } + else + { + while (!(mantissa & 0x00000400)) + { + mantissa <<= 1; + exponent -= 1; + } + exponent += 1; + mantissa &= ~0x00000400; + } + } + else if (exponent == 31) + { + if (mantissa == 0) + { + return (unsigned int)((sign << 31) | ((0x1eL + 127 - 15) << 23) | + (0x3ffL << 13)); + } + else + { + return 0; + } + } + exponent += (127 - 15); + mantissa <<= 13; + return (unsigned int)((sign << 31) | (exponent << 23) | mantissa); +} + +inline unsigned int __DNG_FP24ToFloat(const unsigned char *input) +{ + int sign = (input[0] >> 7) & 0x01; + int exponent = (input[0]) & 0x7F; + int mantissa = (((int)input[1]) << 8) | input[2]; + if (exponent == 0) + { + if (mantissa == 0) + { + return (unsigned int)(sign << 31); + } + else + { + while (!(mantissa & 0x00010000)) + { + mantissa <<= 1; + exponent -= 1; + } + exponent += 1; + mantissa &= ~0x00010000; + } + } + else if (exponent == 127) + { + if (mantissa == 0) + { + return (unsigned int)((sign << 31) | ((0x7eL + 128 - 64) << 23) | + (0xffffL << 7)); + } + else + { + // Nan -- Just set to zero. + return 0; + } + } + exponent += (128 - 64); + mantissa <<= 7; + return (uint32_t)((sign << 31) | (exponent << 23) | mantissa); +} + +inline void DecodeDeltaBytes(unsigned char *bytePtr, int cols, int channels) +{ + if (channels == 1) + { + unsigned char b0 = bytePtr[0]; + bytePtr += 1; + for (uint32_t col = 1; col < cols; ++col) + { + b0 += bytePtr[0]; + bytePtr[0] = b0; + bytePtr += 1; + } + } + else if (channels == 3) + { + unsigned char b0 = bytePtr[0]; + unsigned char b1 = bytePtr[1]; + unsigned char b2 = bytePtr[2]; + bytePtr += 3; + for (int col = 1; col < cols; ++col) + { + b0 += bytePtr[0]; + b1 += bytePtr[1]; + b2 += bytePtr[2]; + bytePtr[0] = b0; + bytePtr[1] = b1; + bytePtr[2] = b2; + bytePtr += 3; + } + } + else if (channels == 4) + { + unsigned char b0 = bytePtr[0]; + unsigned char b1 = bytePtr[1]; + unsigned char b2 = bytePtr[2]; + unsigned char b3 = bytePtr[3]; + bytePtr += 4; + for (uint32_t col = 1; col < cols; ++col) + { + b0 += bytePtr[0]; + b1 += bytePtr[1]; + b2 += bytePtr[2]; + b3 += bytePtr[3]; + bytePtr[0] = b0; + bytePtr[1] = b1; + bytePtr[2] = b2; + bytePtr[3] = b3; + bytePtr += 4; + } + } + else + { + for (int col = 1; col < cols; ++col) + { + for (int chan = 0; chan < channels; ++chan) + { + bytePtr[chan + channels] += bytePtr[chan]; + } + bytePtr += channels; + } + } +} + +static void DecodeFPDelta(unsigned char *input, unsigned char *output, int cols, + int channels, int bytesPerSample) +{ + DecodeDeltaBytes(input, cols * bytesPerSample, channels); + int32_t rowIncrement = cols * channels; + + if (bytesPerSample == 2) + { + +#if LibRawBigEndian + const unsigned char *input0 = input; + const unsigned char *input1 = input + rowIncrement; +#else + const unsigned char *input1 = input; + const unsigned char *input0 = input + rowIncrement; +#endif + for (int col = 0; col < rowIncrement; ++col) + { + output[0] = input0[col]; + output[1] = input1[col]; + output += 2; + } + } + else if (bytesPerSample == 3) + { + const unsigned char *input0 = input; + const unsigned char *input1 = input + rowIncrement; + const unsigned char *input2 = input + rowIncrement * 2; + for (int col = 0; col < rowIncrement; ++col) + { + output[0] = input0[col]; + output[1] = input1[col]; + output[2] = input2[col]; + output += 3; + } + } + else + { +#if LibRawBigEndian + const unsigned char *input0 = input; + const unsigned char *input1 = input + rowIncrement; + const unsigned char *input2 = input + rowIncrement * 2; + const unsigned char *input3 = input + rowIncrement * 3; +#else + const unsigned char *input3 = input; + const unsigned char *input2 = input + rowIncrement; + const unsigned char *input1 = input + rowIncrement * 2; + const unsigned char *input0 = input + rowIncrement * 3; +#endif + for (int col = 0; col < rowIncrement; ++col) + { + output[0] = input0[col]; + output[1] = input1[col]; + output[2] = input2[col]; + output[3] = input3[col]; + output += 4; + } + } +} + +static float expandFloats(unsigned char *dst, int tileWidth, int bytesps) +{ + float max = 0.f; + if (bytesps == 2) + { + uint16_t *dst16 = (ushort *)dst; + uint32_t *dst32 = (unsigned int *)dst; + float *f32 = (float *)dst; + for (int index = tileWidth - 1; index >= 0; --index) + { + dst32[index] = __DNG_HalfToFloat(dst16[index]); + max = MAX(max, f32[index]); + } + } + else if (bytesps == 3) + { + uint8_t *dst8 = ((unsigned char *)dst) + (tileWidth - 1) * 3; + uint32_t *dst32 = (unsigned int *)dst; + float *f32 = (float *)dst; + for (int index = tileWidth - 1; index >= 0; --index, dst8 -= 3) + { + dst32[index] = __DNG_FP24ToFloat(dst8); + max = MAX(max, f32[index]); + } + } + else if (bytesps == 4) + { + float *f32 = (float *)dst; + for (int index = 0; index < tileWidth; index++) + max = MAX(max, f32[index]); + } + return max; +} + +void LibRaw::deflate_dng_load_raw() +{ + int iifd = find_ifd_by_offset(libraw_internal_data.unpacker_data.data_offset); + if(iifd < 0 || iifd > libraw_internal_data.identify_data.tiff_nifds) + throw LIBRAW_EXCEPTION_DECODE_RAW; + struct tiff_ifd_t *ifd = &tiff_ifd[iifd]; + + float *float_raw_image = 0; + float max = 0.f; + + if (ifd->samples != 1 && ifd->samples != 3 && ifd->samples != 4) + throw LIBRAW_EXCEPTION_DECODE_RAW; // Only float deflated supported + + if (libraw_internal_data.unpacker_data.tiff_samples != ifd->samples) + throw LIBRAW_EXCEPTION_DECODE_RAW; // Wrong IFD + + size_t tilesH = (imgdata.sizes.raw_width + + libraw_internal_data.unpacker_data.tile_width - 1) / + libraw_internal_data.unpacker_data.tile_width; + size_t tilesV = (imgdata.sizes.raw_height + + libraw_internal_data.unpacker_data.tile_length - 1) / + libraw_internal_data.unpacker_data.tile_length; + size_t tileCnt = tilesH * tilesV; + + if (ifd->sample_format == 3) + { // Floating point data + float_raw_image = (float *)calloc( + tileCnt * libraw_internal_data.unpacker_data.tile_length * + libraw_internal_data.unpacker_data.tile_width * ifd->samples, + sizeof(float)); + // imgdata.color.maximum = 65535; + // imgdata.color.black = 0; + // memset(imgdata.color.cblack,0,sizeof(imgdata.color.cblack)); + } + else + throw LIBRAW_EXCEPTION_DECODE_RAW; // Only float deflated supported + + int xFactor; + switch (ifd->predictor) + { + case 3: + default: + xFactor = 1; + break; + case 34894: + xFactor = 2; + break; + case 34895: + xFactor = 4; + break; + } + + if (libraw_internal_data.unpacker_data.tile_length < INT_MAX) + { + if (tileCnt < 1 || tileCnt > 1000000) + throw LIBRAW_EXCEPTION_DECODE_RAW; + + size_t *tOffsets = (size_t *)malloc(tileCnt * sizeof(size_t)); + for (int t = 0; t < tileCnt; ++t) + tOffsets[t] = get4(); + + size_t *tBytes = (size_t *)malloc(tileCnt * sizeof(size_t)); + unsigned long maxBytesInTile = 0; + if (tileCnt == 1) + tBytes[0] = maxBytesInTile = ifd->bytes; + else + { + libraw_internal_data.internal_data.input->seek(ifd->bytes, SEEK_SET); + for (size_t t = 0; t < tileCnt; ++t) + { + tBytes[t] = get4(); + maxBytesInTile = MAX(maxBytesInTile, tBytes[t]); + } + } + unsigned tilePixels = libraw_internal_data.unpacker_data.tile_width * + libraw_internal_data.unpacker_data.tile_length; + unsigned pixelSize = sizeof(float) * ifd->samples; + unsigned tileBytes = tilePixels * pixelSize; + unsigned tileRowBytes = + libraw_internal_data.unpacker_data.tile_width * pixelSize; + + unsigned char *cBuffer = (unsigned char *)malloc(maxBytesInTile); + unsigned char *uBuffer = (unsigned char *)malloc( + tileBytes + tileRowBytes); // extra row for decoding + + for (size_t y = 0, t = 0; y < imgdata.sizes.raw_height; + y += libraw_internal_data.unpacker_data.tile_length) + { + for (size_t x = 0; x < imgdata.sizes.raw_width; + x += libraw_internal_data.unpacker_data.tile_width, ++t) + { + libraw_internal_data.internal_data.input->seek(tOffsets[t], SEEK_SET); + libraw_internal_data.internal_data.input->read(cBuffer, 1, tBytes[t]); + unsigned long dstLen = tileBytes; + int err = + uncompress(uBuffer + tileRowBytes, &dstLen, cBuffer, tBytes[t]); + if (err != Z_OK) + { + free(tOffsets); + free(tBytes); + free(cBuffer); + free(uBuffer); + throw LIBRAW_EXCEPTION_DECODE_RAW; + return; + } + else + { + int bytesps = ifd->bps >> 3; + size_t rowsInTile = + y + libraw_internal_data.unpacker_data.tile_length > + imgdata.sizes.raw_height + ? imgdata.sizes.raw_height - y + : libraw_internal_data.unpacker_data.tile_length; + size_t colsInTile = + x + libraw_internal_data.unpacker_data.tile_width > + imgdata.sizes.raw_width + ? imgdata.sizes.raw_width - x + : libraw_internal_data.unpacker_data.tile_width; + + for (size_t row = 0; row < rowsInTile; + ++row) // do not process full tile if not needed + { + unsigned char *dst = + uBuffer + row * libraw_internal_data.unpacker_data.tile_width * + bytesps * ifd->samples; + unsigned char *src = dst + tileRowBytes; + DecodeFPDelta(src, dst, + libraw_internal_data.unpacker_data.tile_width / + xFactor, + ifd->samples * xFactor, bytesps); + float lmax = expandFloats( + dst, + libraw_internal_data.unpacker_data.tile_width * ifd->samples, + bytesps); + max = MAX(max, lmax); + unsigned char *dst2 = (unsigned char *)&float_raw_image + [((y + row) * imgdata.sizes.raw_width + x) * ifd->samples]; + memmove(dst2, dst, colsInTile * ifd->samples * sizeof(float)); + } + } + } + } + free(tOffsets); + free(tBytes); + free(cBuffer); + free(uBuffer); + } + imgdata.color.fmaximum = max; + + // Set fields according to data format + + imgdata.rawdata.raw_alloc = float_raw_image; + if (ifd->samples == 1) + { + imgdata.rawdata.float_image = float_raw_image; + imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = + imgdata.sizes.raw_width * 4; + } + else if (ifd->samples == 3) + { + imgdata.rawdata.float3_image = (float(*)[3])float_raw_image; + imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = + imgdata.sizes.raw_width * 12; + } + else if (ifd->samples == 4) + { + imgdata.rawdata.float4_image = (float(*)[4])float_raw_image; + imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = + imgdata.sizes.raw_width * 16; + } + + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT) + convertFloatToInt(); // with default settings +} +#else +void LibRaw::deflate_dng_load_raw() { throw LIBRAW_EXCEPTION_DECODE_RAW; } +#endif +void LibRaw::float_dng_load_raw_placeholder() +{ + // placeholder only, real decoding implemented in DNG SDK + throw LIBRAW_EXCEPTION_DECODE_RAW; +} + +int LibRaw::is_floating_point() +{ + struct tiff_ifd_t *ifd = &tiff_ifd[0]; + while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] && + ifd->offset != libraw_internal_data.unpacker_data.data_offset) + ++ifd; + if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds]) + return 0; + + return ifd->sample_format == 3; +} + +int LibRaw::have_fpdata() +{ + return imgdata.rawdata.float_image || imgdata.rawdata.float3_image || + imgdata.rawdata.float4_image; +} + +void LibRaw::convertFloatToInt(float dmin /* =4096.f */, + float dmax /* =32767.f */, + float dtarget /*= 16383.f */) +{ + int samples = 0; + float *data = 0; + if (imgdata.rawdata.float_image) + { + samples = 1; + data = imgdata.rawdata.float_image; + } + else if (imgdata.rawdata.float3_image) + { + samples = 3; + data = (float *)imgdata.rawdata.float3_image; + } + else if (imgdata.rawdata.float4_image) + { + samples = 4; + data = (float *)imgdata.rawdata.float4_image; + } + else + return; + + ushort *raw_alloc = (ushort *)malloc( + imgdata.sizes.raw_height * imgdata.sizes.raw_width * + libraw_internal_data.unpacker_data.tiff_samples * sizeof(ushort)); + float tmax = MAX(imgdata.color.maximum, 1); + float datamax = imgdata.color.fmaximum; + + tmax = MAX(tmax, datamax); + tmax = MAX(tmax, 1.f); + + float multip = 1.f; + if (tmax < dmin || tmax > dmax) + { + imgdata.rawdata.color.fnorm = imgdata.color.fnorm = multip = dtarget / tmax; + imgdata.rawdata.color.maximum = imgdata.color.maximum = dtarget; + imgdata.rawdata.color.black = imgdata.color.black = + (float)imgdata.color.black * multip; + for (int i = 0; + i < int(sizeof(imgdata.color.cblack)/sizeof(imgdata.color.cblack[0])); + i++) + if (i != 4 && i != 5) + imgdata.rawdata.color.cblack[i] = imgdata.color.cblack[i] = + (float)imgdata.color.cblack[i] * multip; + } + else + imgdata.rawdata.color.fnorm = imgdata.color.fnorm = 0.f; + + for (size_t i = 0; i < imgdata.sizes.raw_height * imgdata.sizes.raw_width * + libraw_internal_data.unpacker_data.tiff_samples; + ++i) + { + float val = MAX(data[i], 0.f); + raw_alloc[i] = (ushort)(val * multip); + } + + if (samples == 1) + { + imgdata.rawdata.raw_alloc = imgdata.rawdata.raw_image = raw_alloc; + imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = + imgdata.sizes.raw_width * 2; + } + else if (samples == 3) + { + imgdata.rawdata.raw_alloc = imgdata.rawdata.color3_image = + (ushort(*)[3])raw_alloc; + imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = + imgdata.sizes.raw_width * 6; + } + else if (samples == 4) + { + imgdata.rawdata.raw_alloc = imgdata.rawdata.color4_image = + (ushort(*)[4])raw_alloc; + imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = + imgdata.sizes.raw_width * 8; + } + free(data); // remove old allocation + imgdata.rawdata.float_image = 0; + imgdata.rawdata.float3_image = 0; + imgdata.rawdata.float4_image = 0; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/fuji_compressed.cpp libkdcraw/libkdcraw/libraw/src/decoders/fuji_compressed.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/fuji_compressed.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/fuji_compressed.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,1132 @@ +/* -*- C++ -*- + * File: libraw_fuji_compressed.cpp + * Copyright (C) 2016-2019 Alexey Danilchenko + * + * Adopted to LibRaw by Alex Tutubalin, lexa@lexa.ru + * LibRaw Fujifilm/compressed decoder + +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#ifdef _abs +#undef _abs +#undef _min +#undef _max +#endif +#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)) + +struct int_pair +{ + int value1; + int value2; +}; + +enum _xt_lines +{ + _R0 = 0, + _R1, + _R2, + _R3, + _R4, + _G0, + _G1, + _G2, + _G3, + _G4, + _G5, + _G6, + _G7, + _B0, + _B1, + _B2, + _B3, + _B4, + _ltotal +}; + +struct fuji_compressed_block +{ + int cur_bit; // current bit being read (from left to right) + int cur_pos; // current position in a buffer + INT64 cur_buf_offset; // offset of this buffer in a file + unsigned max_read_size; // Amount of data to be read + int cur_buf_size; // buffer size + uchar *cur_buf; // currently read block + int fillbytes; // Counter to add extra byte for block size N*16 + LibRaw_abstract_datastream *input; + struct int_pair grad_even[3][41]; // tables of gradients + struct int_pair grad_odd[3][41]; + ushort *linealloc; + ushort *linebuf[_ltotal]; +}; + +void LibRaw::init_fuji_compr(struct fuji_compressed_params *info) +{ + int cur_val; + int8_t *qt; + + if ((libraw_internal_data.unpacker_data.fuji_block_width % 3 && + libraw_internal_data.unpacker_data.fuji_raw_type == 16) || + (libraw_internal_data.unpacker_data.fuji_block_width & 1 && + libraw_internal_data.unpacker_data.fuji_raw_type == 0)) + derror(); + + info->q_table = + (int8_t *)malloc(2 << libraw_internal_data.unpacker_data.fuji_bits); + merror(info->q_table, "init_fuji_compr()"); + + if (libraw_internal_data.unpacker_data.fuji_raw_type == 16) + info->line_width = + (libraw_internal_data.unpacker_data.fuji_block_width * 2) / 3; + else + info->line_width = libraw_internal_data.unpacker_data.fuji_block_width >> 1; + + info->q_point[0] = 0; + info->q_point[1] = 0x12; + info->q_point[2] = 0x43; + info->q_point[3] = 0x114; + info->q_point[4] = (1 << libraw_internal_data.unpacker_data.fuji_bits) - 1; + info->min_value = 0x40; + + cur_val = -info->q_point[4]; + for (qt = info->q_table; cur_val <= info->q_point[4]; ++qt, ++cur_val) + { + if (cur_val <= -info->q_point[3]) + *qt = -4; + else if (cur_val <= -info->q_point[2]) + *qt = -3; + else if (cur_val <= -info->q_point[1]) + *qt = -2; + else if (cur_val < 0) + *qt = -1; + else if (cur_val == 0) + *qt = 0; + else if (cur_val < info->q_point[1]) + *qt = 1; + else if (cur_val < info->q_point[2]) + *qt = 2; + else if (cur_val < info->q_point[3]) + *qt = 3; + else + *qt = 4; + } + + // populting gradients + info->total_values = (1 << libraw_internal_data.unpacker_data.fuji_bits); + info->raw_bits = libraw_internal_data.unpacker_data.fuji_bits; + info->max_bits = 4 * info->raw_bits; + info->maxDiff = info->total_values >> 6; +} + +#define XTRANS_BUF_SIZE 0x10000 + +static inline void fuji_fill_buffer(struct fuji_compressed_block *info) +{ + if (info->cur_pos >= info->cur_buf_size) + { + info->cur_pos = 0; + info->cur_buf_offset += info->cur_buf_size; +#ifdef LIBRAW_USE_OPENMP +#pragma omp critical +#endif + { +#ifndef LIBRAW_USE_OPENMP + info->input->lock(); +#endif + info->input->seek(info->cur_buf_offset, SEEK_SET); + info->cur_buf_size = info->input->read( + info->cur_buf, 1, _min(info->max_read_size, XTRANS_BUF_SIZE)); +#ifndef LIBRAW_USE_OPENMP + info->input->unlock(); +#endif + if (info->cur_buf_size < 1) // nothing read + { + if (info->fillbytes > 0) + { + int ls = _max(1, _min(info->fillbytes, XTRANS_BUF_SIZE)); + memset(info->cur_buf, 0, ls); + info->fillbytes -= ls; + } + else + throw LIBRAW_EXCEPTION_IO_EOF; + } + info->max_read_size -= info->cur_buf_size; + } + } +} + +void LibRaw::init_fuji_block(struct fuji_compressed_block *info, + const struct fuji_compressed_params *params, + INT64 raw_offset, unsigned dsize) +{ + info->linealloc = + (ushort *)calloc(sizeof(ushort), _ltotal * (params->line_width + 2)); + merror(info->linealloc, "init_fuji_block()"); + + INT64 fsize = libraw_internal_data.internal_data.input->size(); + info->max_read_size = + _min(unsigned(fsize - raw_offset), dsize); // Data size may be incorrect? + info->fillbytes = 1; + + info->input = libraw_internal_data.internal_data.input; + info->linebuf[_R0] = info->linealloc; + for (int i = _R1; i <= _B4; i++) + info->linebuf[i] = info->linebuf[i - 1] + params->line_width + 2; + + // init buffer + info->cur_buf = (uchar *)malloc(XTRANS_BUF_SIZE); + merror(info->cur_buf, "init_fuji_block()"); + info->cur_bit = 0; + info->cur_pos = 0; + info->cur_buf_offset = raw_offset; + for (int j = 0; j < 3; j++) + for (int i = 0; i < 41; i++) + { + info->grad_even[j][i].value1 = params->maxDiff; + info->grad_even[j][i].value2 = 1; + info->grad_odd[j][i].value1 = params->maxDiff; + info->grad_odd[j][i].value2 = 1; + } + + info->cur_buf_size = 0; + fuji_fill_buffer(info); +} + +void LibRaw::copy_line_to_xtrans(struct fuji_compressed_block *info, + int cur_line, int cur_block, + int cur_block_width) +{ + ushort *lineBufB[3]; + ushort *lineBufG[6]; + ushort *lineBufR[3]; + unsigned pixel_count; + ushort *line_buf; + int index; + + int offset = libraw_internal_data.unpacker_data.fuji_block_width * cur_block + + 6 * imgdata.sizes.raw_width * cur_line; + ushort *raw_block_data = imgdata.rawdata.raw_image + offset; + int row_count = 0; + + for (int i = 0; i < 3; i++) + { + lineBufR[i] = info->linebuf[_R2 + i] + 1; + lineBufB[i] = info->linebuf[_B2 + i] + 1; + } + for (int i = 0; i < 6; i++) + lineBufG[i] = info->linebuf[_G2 + i] + 1; + + while (row_count < 6) + { + pixel_count = 0; + while (pixel_count < (unsigned)cur_block_width) + { + switch (imgdata.idata.xtrans_abs[row_count][(pixel_count % 6)]) + { + case 0: // red + line_buf = lineBufR[row_count >> 1]; + break; + case 1: // green + default: // to make static analyzer happy + line_buf = lineBufG[row_count]; + break; + case 2: // blue + line_buf = lineBufB[row_count >> 1]; + break; + } + + index = (((pixel_count * 2 / 3) & 0x7FFFFFFE) | ((pixel_count % 3) & 1)) + + ((pixel_count % 3) >> 1); + raw_block_data[pixel_count] = line_buf[index]; + + ++pixel_count; + } + ++row_count; + raw_block_data += imgdata.sizes.raw_width; + } +} + +void LibRaw::copy_line_to_bayer(struct fuji_compressed_block *info, + int cur_line, int cur_block, + int cur_block_width) +{ + ushort *lineBufB[3]; + ushort *lineBufG[6]; + ushort *lineBufR[3]; + unsigned pixel_count; + ushort *line_buf; + + int fuji_bayer[2][2]; + for (int r = 0; r < 2; r++) + for (int c = 0; c < 2; c++) + fuji_bayer[r][c] = FC(r, c); // We'll downgrade G2 to G below + + int offset = libraw_internal_data.unpacker_data.fuji_block_width * cur_block + + 6 * imgdata.sizes.raw_width * cur_line; + ushort *raw_block_data = imgdata.rawdata.raw_image + offset; + int row_count = 0; + + for (int i = 0; i < 3; i++) + { + lineBufR[i] = info->linebuf[_R2 + i] + 1; + lineBufB[i] = info->linebuf[_B2 + i] + 1; + } + for (int i = 0; i < 6; i++) + lineBufG[i] = info->linebuf[_G2 + i] + 1; + + while (row_count < 6) + { + pixel_count = 0; + while (pixel_count < (unsigned)cur_block_width) + { + switch (fuji_bayer[row_count & 1][pixel_count & 1]) + { + case 0: // red + line_buf = lineBufR[row_count >> 1]; + break; + case 1: // green + case 3: // second green + default: // to make static analyzer happy + line_buf = lineBufG[row_count]; + break; + case 2: // blue + line_buf = lineBufB[row_count >> 1]; + break; + } + + raw_block_data[pixel_count] = line_buf[pixel_count >> 1]; + ++pixel_count; + } + ++row_count; + raw_block_data += imgdata.sizes.raw_width; + } +} + +#define fuji_quant_gradient(i, v1, v2) \ + (9 * i->q_table[i->q_point[4] + (v1)] + i->q_table[i->q_point[4] + (v2)]) + +static inline void fuji_zerobits(struct fuji_compressed_block *info, int *count) +{ + uchar zero = 0; + *count = 0; + while (zero == 0) + { + zero = (info->cur_buf[info->cur_pos] >> (7 - info->cur_bit)) & 1; + info->cur_bit++; + info->cur_bit &= 7; + if (!info->cur_bit) + { + ++info->cur_pos; + fuji_fill_buffer(info); + } + if (zero) + break; + ++*count; + } +} + +static inline void fuji_read_code(struct fuji_compressed_block *info, int *data, + int bits_to_read) +{ + uchar bits_left = bits_to_read; + uchar bits_left_in_byte = 8 - (info->cur_bit & 7); + *data = 0; + if (!bits_to_read) + return; + if (bits_to_read >= bits_left_in_byte) + { + do + { + *data <<= bits_left_in_byte; + bits_left -= bits_left_in_byte; + *data |= info->cur_buf[info->cur_pos] & ((1 << bits_left_in_byte) - 1); + ++info->cur_pos; + fuji_fill_buffer(info); + bits_left_in_byte = 8; + } while (bits_left >= 8); + } + if (!bits_left) + { + info->cur_bit = (8 - (bits_left_in_byte & 7)) & 7; + return; + } + *data <<= bits_left; + bits_left_in_byte -= bits_left; + *data |= ((1 << bits_left) - 1) & + ((unsigned)info->cur_buf[info->cur_pos] >> bits_left_in_byte); + info->cur_bit = (8 - (bits_left_in_byte & 7)) & 7; +} + +static inline int bitDiff(int value1, int value2) +{ + int decBits = 0; + if (value2 < value1) + while (decBits <= 14 && (value2 << ++decBits) < value1) + ; + return decBits; +} + +static inline int +fuji_decode_sample_even(struct fuji_compressed_block *info, + const struct fuji_compressed_params *params, + ushort *line_buf, int pos, struct int_pair *grads) +{ + int interp_val = 0; + // ushort decBits; + int errcnt = 0; + + int sample = 0, code = 0; + ushort *line_buf_cur = line_buf + pos; + int Rb = line_buf_cur[-2 - params->line_width]; + int Rc = line_buf_cur[-3 - params->line_width]; + int Rd = line_buf_cur[-1 - params->line_width]; + int Rf = line_buf_cur[-4 - 2 * params->line_width]; + + int grad, gradient, diffRcRb, diffRfRb, diffRdRb; + + grad = fuji_quant_gradient(params, Rb - Rf, Rc - Rb); + gradient = _abs(grad); + diffRcRb = _abs(Rc - Rb); + diffRfRb = _abs(Rf - Rb); + diffRdRb = _abs(Rd - Rb); + + if (diffRcRb > diffRfRb && diffRcRb > diffRdRb) + interp_val = Rf + Rd + 2 * Rb; + else if (diffRdRb > diffRcRb && diffRdRb > diffRfRb) + interp_val = Rf + Rc + 2 * Rb; + else + interp_val = Rd + Rc + 2 * Rb; + + fuji_zerobits(info, &sample); + + if (sample < params->max_bits - params->raw_bits - 1) + { + int decBits = bitDiff(grads[gradient].value1, grads[gradient].value2); + fuji_read_code(info, &code, decBits); + code += sample << decBits; + } + else + { + fuji_read_code(info, &code, params->raw_bits); + code++; + } + + if (code < 0 || code >= params->total_values) + errcnt++; + + if (code & 1) + code = -1 - code / 2; + else + code /= 2; + + grads[gradient].value1 += _abs(code); + if (grads[gradient].value2 == params->min_value) + { + grads[gradient].value1 >>= 1; + grads[gradient].value2 >>= 1; + } + grads[gradient].value2++; + if (grad < 0) + interp_val = (interp_val >> 2) - code; + else + interp_val = (interp_val >> 2) + code; + if (interp_val < 0) + interp_val += params->total_values; + else if (interp_val > params->q_point[4]) + interp_val -= params->total_values; + + if (interp_val >= 0) + line_buf_cur[0] = _min(interp_val, params->q_point[4]); + else + line_buf_cur[0] = 0; + return errcnt; +} + +static inline int +fuji_decode_sample_odd(struct fuji_compressed_block *info, + const struct fuji_compressed_params *params, + ushort *line_buf, int pos, struct int_pair *grads) +{ + int interp_val = 0; + int errcnt = 0; + + int sample = 0, code = 0; + ushort *line_buf_cur = line_buf + pos; + int Ra = line_buf_cur[-1]; + int Rb = line_buf_cur[-2 - params->line_width]; + int Rc = line_buf_cur[-3 - params->line_width]; + int Rd = line_buf_cur[-1 - params->line_width]; + int Rg = line_buf_cur[1]; + + int grad, gradient; + + grad = fuji_quant_gradient(params, Rb - Rc, Rc - Ra); + gradient = _abs(grad); + + if ((Rb > Rc && Rb > Rd) || (Rb < Rc && Rb < Rd)) + interp_val = (Rg + Ra + 2 * Rb) >> 2; + else + interp_val = (Ra + Rg) >> 1; + + fuji_zerobits(info, &sample); + + if (sample < params->max_bits - params->raw_bits - 1) + { + int decBits = bitDiff(grads[gradient].value1, grads[gradient].value2); + fuji_read_code(info, &code, decBits); + code += sample << decBits; + } + else + { + fuji_read_code(info, &code, params->raw_bits); + code++; + } + + if (code < 0 || code >= params->total_values) + errcnt++; + + if (code & 1) + code = -1 - code / 2; + else + code /= 2; + + grads[gradient].value1 += _abs(code); + if (grads[gradient].value2 == params->min_value) + { + grads[gradient].value1 >>= 1; + grads[gradient].value2 >>= 1; + } + grads[gradient].value2++; + if (grad < 0) + interp_val -= code; + else + interp_val += code; + if (interp_val < 0) + interp_val += params->total_values; + else if (interp_val > params->q_point[4]) + interp_val -= params->total_values; + + if (interp_val >= 0) + line_buf_cur[0] = _min(interp_val, params->q_point[4]); + else + line_buf_cur[0] = 0; + return errcnt; +} + +static void fuji_decode_interpolation_even(int line_width, ushort *line_buf, + int pos) +{ + ushort *line_buf_cur = line_buf + pos; + int Rb = line_buf_cur[-2 - line_width]; + int Rc = line_buf_cur[-3 - line_width]; + int Rd = line_buf_cur[-1 - line_width]; + int Rf = line_buf_cur[-4 - 2 * line_width]; + int diffRcRb = _abs(Rc - Rb); + int diffRfRb = _abs(Rf - Rb); + int diffRdRb = _abs(Rd - Rb); + if (diffRcRb > diffRfRb && diffRcRb > diffRdRb) + *line_buf_cur = (Rf + Rd + 2 * Rb) >> 2; + else if (diffRdRb > diffRcRb && diffRdRb > diffRfRb) + *line_buf_cur = (Rf + Rc + 2 * Rb) >> 2; + else + *line_buf_cur = (Rd + Rc + 2 * Rb) >> 2; +} + +static void fuji_extend_generic(ushort *linebuf[_ltotal], int line_width, + int start, int end) +{ + for (int i = start; i <= end; i++) + { + linebuf[i][0] = linebuf[i - 1][1]; + linebuf[i][line_width + 1] = linebuf[i - 1][line_width]; + } +} + +static void fuji_extend_red(ushort *linebuf[_ltotal], int line_width) +{ + fuji_extend_generic(linebuf, line_width, _R2, _R4); +} + +static void fuji_extend_green(ushort *linebuf[_ltotal], int line_width) +{ + fuji_extend_generic(linebuf, line_width, _G2, _G7); +} + +static void fuji_extend_blue(ushort *linebuf[_ltotal], int line_width) +{ + fuji_extend_generic(linebuf, line_width, _B2, _B4); +} + +void LibRaw::xtrans_decode_block(struct fuji_compressed_block *info, + const struct fuji_compressed_params *params, + int cur_line) +{ + int r_even_pos = 0, r_odd_pos = 1; + int g_even_pos = 0, g_odd_pos = 1; + int b_even_pos = 0, b_odd_pos = 1; + + int errcnt = 0; + + const int line_width = params->line_width; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + fuji_decode_interpolation_even(line_width, info->linebuf[_R2] + 1, + r_even_pos); + r_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G2] + 1, + g_even_pos, info->grad_even[0]); + g_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_R2] + 1, + r_odd_pos, info->grad_odd[0]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G2] + 1, + g_odd_pos, info->grad_odd[0]); + g_odd_pos += 2; + } + } + + fuji_extend_red(info->linebuf, line_width); + fuji_extend_green(info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G3] + 1, + g_even_pos, info->grad_even[1]); + g_even_pos += 2; + fuji_decode_interpolation_even(line_width, info->linebuf[_B2] + 1, + b_even_pos); + b_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G3] + 1, + g_odd_pos, info->grad_odd[1]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_B2] + 1, + b_odd_pos, info->grad_odd[1]); + b_odd_pos += 2; + } + } + + fuji_extend_green(info->linebuf, line_width); + fuji_extend_blue(info->linebuf, line_width); + + r_even_pos = 0, r_odd_pos = 1; + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + if (r_even_pos & 3) + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_R3] + 1, + r_even_pos, info->grad_even[2]); + else + fuji_decode_interpolation_even(line_width, info->linebuf[_R3] + 1, + r_even_pos); + r_even_pos += 2; + fuji_decode_interpolation_even(line_width, info->linebuf[_G4] + 1, + g_even_pos); + g_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_R3] + 1, + r_odd_pos, info->grad_odd[2]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G4] + 1, + g_odd_pos, info->grad_odd[2]); + g_odd_pos += 2; + } + } + + fuji_extend_red(info->linebuf, line_width); + fuji_extend_green(info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + b_even_pos = 0, b_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G5] + 1, + g_even_pos, info->grad_even[0]); + g_even_pos += 2; + if ((b_even_pos & 3) == 2) + fuji_decode_interpolation_even(line_width, info->linebuf[_B3] + 1, + b_even_pos); + else + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_B3] + 1, + b_even_pos, info->grad_even[0]); + b_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G5] + 1, + g_odd_pos, info->grad_odd[0]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_B3] + 1, + b_odd_pos, info->grad_odd[0]); + b_odd_pos += 2; + } + } + + fuji_extend_green(info->linebuf, line_width); + fuji_extend_blue(info->linebuf, line_width); + + r_even_pos = 0, r_odd_pos = 1; + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + if ((r_even_pos & 3) == 2) + fuji_decode_interpolation_even(line_width, info->linebuf[_R4] + 1, + r_even_pos); + else + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_R4] + 1, + r_even_pos, info->grad_even[1]); + r_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G6] + 1, + g_even_pos, info->grad_even[1]); + g_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_R4] + 1, + r_odd_pos, info->grad_odd[1]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G6] + 1, + g_odd_pos, info->grad_odd[1]); + g_odd_pos += 2; + } + } + + fuji_extend_red(info->linebuf, line_width); + fuji_extend_green(info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + b_even_pos = 0, b_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + fuji_decode_interpolation_even(line_width, info->linebuf[_G7] + 1, + g_even_pos); + g_even_pos += 2; + if (b_even_pos & 3) + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_B4] + 1, + b_even_pos, info->grad_even[2]); + else + fuji_decode_interpolation_even(line_width, info->linebuf[_B4] + 1, + b_even_pos); + b_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G7] + 1, + g_odd_pos, info->grad_odd[2]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_B4] + 1, + b_odd_pos, info->grad_odd[2]); + b_odd_pos += 2; + } + } + + fuji_extend_green(info->linebuf, line_width); + fuji_extend_blue(info->linebuf, line_width); + + if (errcnt) + derror(); +} + +void LibRaw::fuji_bayer_decode_block( + struct fuji_compressed_block *info, + const struct fuji_compressed_params *params, int cur_line) +{ + int r_even_pos = 0, r_odd_pos = 1; + int g_even_pos = 0, g_odd_pos = 1; + int b_even_pos = 0, b_odd_pos = 1; + + int errcnt = 0; + + const int line_width = params->line_width; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_R2] + 1, + r_even_pos, info->grad_even[0]); + r_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G2] + 1, + g_even_pos, info->grad_even[0]); + g_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_R2] + 1, + r_odd_pos, info->grad_odd[0]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G2] + 1, + g_odd_pos, info->grad_odd[0]); + g_odd_pos += 2; + } + } + + fuji_extend_red(info->linebuf, line_width); + fuji_extend_green(info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G3] + 1, + g_even_pos, info->grad_even[1]); + g_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_B2] + 1, + b_even_pos, info->grad_even[1]); + b_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G3] + 1, + g_odd_pos, info->grad_odd[1]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_B2] + 1, + b_odd_pos, info->grad_odd[1]); + b_odd_pos += 2; + } + } + + fuji_extend_green(info->linebuf, line_width); + fuji_extend_blue(info->linebuf, line_width); + + r_even_pos = 0, r_odd_pos = 1; + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_R3] + 1, + r_even_pos, info->grad_even[2]); + r_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G4] + 1, + g_even_pos, info->grad_even[2]); + g_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_R3] + 1, + r_odd_pos, info->grad_odd[2]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G4] + 1, + g_odd_pos, info->grad_odd[2]); + g_odd_pos += 2; + } + } + + fuji_extend_red(info->linebuf, line_width); + fuji_extend_green(info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + b_even_pos = 0, b_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G5] + 1, + g_even_pos, info->grad_even[0]); + g_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_B3] + 1, + b_even_pos, info->grad_even[0]); + b_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G5] + 1, + g_odd_pos, info->grad_odd[0]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_B3] + 1, + b_odd_pos, info->grad_odd[0]); + b_odd_pos += 2; + } + } + + fuji_extend_green(info->linebuf, line_width); + fuji_extend_blue(info->linebuf, line_width); + + r_even_pos = 0, r_odd_pos = 1; + g_even_pos = 0, g_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_R4] + 1, + r_even_pos, info->grad_even[1]); + r_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G6] + 1, + g_even_pos, info->grad_even[1]); + g_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_R4] + 1, + r_odd_pos, info->grad_odd[1]); + r_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G6] + 1, + g_odd_pos, info->grad_odd[1]); + g_odd_pos += 2; + } + } + + fuji_extend_red(info->linebuf, line_width); + fuji_extend_green(info->linebuf, line_width); + + g_even_pos = 0, g_odd_pos = 1; + b_even_pos = 0, b_odd_pos = 1; + + while (g_even_pos < line_width || g_odd_pos < line_width) + { + if (g_even_pos < line_width) + { + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_G7] + 1, + g_even_pos, info->grad_even[2]); + g_even_pos += 2; + errcnt += fuji_decode_sample_even(info, params, info->linebuf[_B4] + 1, + b_even_pos, info->grad_even[2]); + b_even_pos += 2; + } + if (g_even_pos > 8) + { + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_G7] + 1, + g_odd_pos, info->grad_odd[2]); + g_odd_pos += 2; + errcnt += fuji_decode_sample_odd(info, params, info->linebuf[_B4] + 1, + b_odd_pos, info->grad_odd[2]); + b_odd_pos += 2; + } + } + + fuji_extend_green(info->linebuf, line_width); + fuji_extend_blue(info->linebuf, line_width); + + if (errcnt) + derror(); +} + +void LibRaw::fuji_decode_strip(const struct fuji_compressed_params *info_common, + int cur_block, INT64 raw_offset, unsigned dsize) +{ + int cur_block_width, cur_line; + unsigned line_size; + struct fuji_compressed_block info; + + init_fuji_block(&info, info_common, raw_offset, dsize); + line_size = sizeof(ushort) * (info_common->line_width + 2); + + cur_block_width = libraw_internal_data.unpacker_data.fuji_block_width; + if (cur_block + 1 == libraw_internal_data.unpacker_data.fuji_total_blocks) + { + cur_block_width = + imgdata.sizes.raw_width - + (libraw_internal_data.unpacker_data.fuji_block_width * cur_block); + /* Old code, may get incorrect results on GFX50, but luckily large optical + black cur_block_width = imgdata.sizes.raw_width % + libraw_internal_data.unpacker_data.fuji_block_width; + */ + } + + struct i_pair + { + int a, b; + }; + const i_pair mtable[6] = {{_R0, _R3}, {_R1, _R4}, {_G0, _G6}, + {_G1, _G7}, {_B0, _B3}, {_B1, _B4}}, + ztable[3] = {{_R2, 3}, {_G2, 6}, {_B2, 3}}; + for (cur_line = 0; + cur_line < libraw_internal_data.unpacker_data.fuji_total_lines; + cur_line++) + { + if (libraw_internal_data.unpacker_data.fuji_raw_type == 16) + xtrans_decode_block(&info, info_common, cur_line); + else + fuji_bayer_decode_block(&info, info_common, cur_line); + + // copy data from line buffers and advance + for (int i = 0; i < 6; i++) + memcpy(info.linebuf[mtable[i].a], info.linebuf[mtable[i].b], line_size); + + if (libraw_internal_data.unpacker_data.fuji_raw_type == 16) + copy_line_to_xtrans(&info, cur_line, cur_block, cur_block_width); + else + copy_line_to_bayer(&info, cur_line, cur_block, cur_block_width); + + for (int i = 0; i < 3; i++) + { + memset(info.linebuf[ztable[i].a], 0, ztable[i].b * line_size); + info.linebuf[ztable[i].a][0] = info.linebuf[ztable[i].a - 1][1]; + info.linebuf[ztable[i].a][info_common->line_width + 1] = + info.linebuf[ztable[i].a - 1][info_common->line_width]; + } + } + + // release data + free(info.linealloc); + free(info.cur_buf); +} + +void LibRaw::fuji_compressed_load_raw() +{ + struct fuji_compressed_params common_info; + int cur_block; + unsigned *block_sizes; + INT64 raw_offset, *raw_block_offsets; + // struct fuji_compressed_block info; + + init_fuji_compr(&common_info); + + // read block sizes + block_sizes = (unsigned *)malloc( + sizeof(unsigned) * libraw_internal_data.unpacker_data.fuji_total_blocks); + merror(block_sizes, "fuji_compressed_load_raw()"); + raw_block_offsets = (INT64 *)malloc( + sizeof(INT64) * libraw_internal_data.unpacker_data.fuji_total_blocks); + merror(raw_block_offsets, "fuji_compressed_load_raw()"); + + raw_offset = + sizeof(unsigned) * libraw_internal_data.unpacker_data.fuji_total_blocks; + if (raw_offset & 0xC) + raw_offset += 0x10 - (raw_offset & 0xC); + + raw_offset += libraw_internal_data.unpacker_data.data_offset; + + libraw_internal_data.internal_data.input->seek( + libraw_internal_data.unpacker_data.data_offset, SEEK_SET); + libraw_internal_data.internal_data.input->read( + block_sizes, 1, + sizeof(unsigned) * libraw_internal_data.unpacker_data.fuji_total_blocks); + + raw_block_offsets[0] = raw_offset; + // calculating raw block offsets + for (cur_block = 0; + cur_block < libraw_internal_data.unpacker_data.fuji_total_blocks; + cur_block++) + { + unsigned bsize = sgetn(4, (uchar *)(block_sizes + cur_block)); + block_sizes[cur_block] = bsize; + } + + for (cur_block = 1; + cur_block < libraw_internal_data.unpacker_data.fuji_total_blocks; + cur_block++) + raw_block_offsets[cur_block] = + raw_block_offsets[cur_block - 1] + block_sizes[cur_block - 1]; + + fuji_decode_loop(&common_info, + libraw_internal_data.unpacker_data.fuji_total_blocks, + raw_block_offsets, block_sizes); + + free(block_sizes); + free(raw_block_offsets); + free(common_info.q_table); +} + +void LibRaw::fuji_decode_loop(const struct fuji_compressed_params *common_info, + int count, INT64 *raw_block_offsets, + unsigned *block_sizes) +{ + int cur_block; +#ifdef LIBRAW_USE_OPENMP +#pragma omp parallel for private(cur_block) +#endif + for (cur_block = 0; cur_block < count; cur_block++) + { + fuji_decode_strip(common_info, cur_block, raw_block_offsets[cur_block], + block_sizes[cur_block]); + } +} + +void LibRaw::parse_fuji_compressed_header() +{ + unsigned signature, version, h_raw_type, h_raw_bits, h_raw_height, + h_raw_rounded_width, h_raw_width, h_block_size, h_blocks_in_row, + h_total_lines; + + uchar header[16]; + + libraw_internal_data.internal_data.input->seek( + libraw_internal_data.unpacker_data.data_offset, SEEK_SET); + libraw_internal_data.internal_data.input->read(header, 1, sizeof(header)); + + // read all header + signature = sgetn(2, header); + version = header[2]; + h_raw_type = header[3]; + h_raw_bits = header[4]; + h_raw_height = sgetn(2, header + 5); + h_raw_rounded_width = sgetn(2, header + 7); + h_raw_width = sgetn(2, header + 9); + h_block_size = sgetn(2, header + 11); + h_blocks_in_row = header[13]; + h_total_lines = sgetn(2, header + 14); + + // general validation + if (signature != 0x4953 || version != 1 || h_raw_height > 0x3000 || + h_raw_height < 6 || h_raw_height % 6 || h_block_size < 1 || + h_raw_width > 0x3000 || h_raw_width < 0x300 || h_raw_width % 24 || + h_raw_rounded_width > 0x3000 || h_raw_rounded_width < h_block_size || + h_raw_rounded_width % h_block_size || + h_raw_rounded_width - h_raw_width >= h_block_size || + h_block_size != 0x300 || h_blocks_in_row > 0x10 || h_blocks_in_row == 0 || + h_blocks_in_row != h_raw_rounded_width / h_block_size || + h_total_lines > 0x800 || h_total_lines == 0 || + h_total_lines != h_raw_height / 6 || + (h_raw_bits != 12 && h_raw_bits != 14 && h_raw_bits != 16) || + (h_raw_type != 16 && h_raw_type != 0)) + return; + + // modify data + libraw_internal_data.unpacker_data.fuji_total_lines = h_total_lines; + libraw_internal_data.unpacker_data.fuji_total_blocks = h_blocks_in_row; + libraw_internal_data.unpacker_data.fuji_block_width = h_block_size; + libraw_internal_data.unpacker_data.fuji_bits = h_raw_bits; + libraw_internal_data.unpacker_data.fuji_raw_type = h_raw_type; + imgdata.sizes.raw_width = h_raw_width; + imgdata.sizes.raw_height = h_raw_height; + libraw_internal_data.unpacker_data.data_offset += 16; + load_raw = &LibRaw::fuji_compressed_load_raw; +} + +#undef _abs +#undef _min diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/generic.cpp libkdcraw/libkdcraw/libraw/src/decoders/generic.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/generic.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/generic.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,112 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::unpacked_load_raw() +{ + int row, col, bits = 0; + while (1 << ++bits < (int)maximum) + ; + read_shorts(raw_image, raw_width * raw_height); + fseek(ifp, -2, SEEK_CUR); // avoid EOF error + if (maximum < 0xffff || load_flags) + for (row = 0; row < raw_height; row++) + { + checkCancel(); + for (col = 0; col < raw_width; col++) + if ((RAW(row, col) >>= load_flags) >> bits && + (unsigned)(row - top_margin) < height && + (unsigned)(col - left_margin) < width) + derror(); + } +} + +void LibRaw::packed_load_raw() +{ + int vbits = 0, bwide, rbits, bite, half, irow, row, col, val, i; + UINT64 bitbuf = 0; + + bwide = raw_width * tiff_bps / 8; + bwide += bwide & load_flags >> 7; + rbits = bwide * 8 - raw_width * tiff_bps; + if (load_flags & 1) + bwide = bwide * 16 / 15; + bite = 8 + (load_flags & 24); + half = (raw_height + 1) >> 1; + for (irow = 0; irow < raw_height; irow++) + { + checkCancel(); + row = irow; + if (load_flags & 2 && (row = irow % half * 2 + irow / half) == 1 && + load_flags & 4) + { + if (vbits = 0, tiff_compress) + fseek(ifp, data_offset - (-half * bwide & -2048), SEEK_SET); + else + { + fseek(ifp, 0, SEEK_END); + fseek(ifp, ftell(ifp) >> 3 << 2, SEEK_SET); + } + } + if (feof(ifp)) + throw LIBRAW_EXCEPTION_IO_EOF; + for (col = 0; col < raw_width; col++) + { + for (vbits -= tiff_bps; vbits < 0; vbits += bite) + { + bitbuf <<= bite; + for (i = 0; i < bite; i += 8) + bitbuf |= (unsigned(fgetc(ifp)) << i); + } + val = bitbuf << (64 - tiff_bps - vbits) >> (64 - tiff_bps); + RAW(row, col ^ (load_flags >> 6 & 1)) = val; + if (load_flags & 1 && (col % 10) == 9 && fgetc(ifp) && + row < height + top_margin && col < width + left_margin) + derror(); + } + vbits -= rbits; + } +} + +void LibRaw::eight_bit_load_raw() +{ + uchar *pixel; + unsigned row, col; + + pixel = (uchar *)calloc(raw_width, sizeof *pixel); + merror(pixel, "eight_bit_load_raw()"); + try + { + for (row = 0; row < raw_height; row++) + { + checkCancel(); + if (fread(pixel, 1, raw_width, ifp) < raw_width) + derror(); + for (col = 0; col < raw_width; col++) + RAW(row, col) = curve[pixel[col]]; + } + } + catch (...) + { + free(pixel); + throw; + } + free(pixel); + maximum = curve[0xff]; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/kodak_decoders.cpp libkdcraw/libkdcraw/libraw/src/decoders/kodak_decoders.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/kodak_decoders.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/kodak_decoders.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,543 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +#define radc_token(tree) ((signed char)getbithuff(8, huff + (tree) * 256)) + +#define FORYX \ + for (y = 1; y < 3; y++) \ + for (x = col + 1; x >= col; x--) + +#define PREDICTOR \ + (c ? (buf[c][y - 1][x] + buf[c][y][x + 1]) / 2 \ + : (buf[c][y - 1][x + 1] + 2 * buf[c][y - 1][x] + buf[c][y][x + 1]) / 4) + +#ifdef __GNUC__ +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +#pragma GCC optimize("no-aggressive-loop-optimizations") +#endif +#endif + +void LibRaw::kodak_radc_load_raw() +{ + // All kodak radc images are 768x512 + if (width > 768 || raw_width > 768 || height > 512 || raw_height > 512) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + static const signed char src[] = { + 1, 1, 2, 3, 3, 4, 4, 2, 5, 7, 6, 5, 7, 6, 7, 8, 1, 0, + 2, 1, 3, 3, 4, 4, 5, 2, 6, 7, 7, 6, 8, 5, 8, 8, 2, 1, + 2, 3, 3, 0, 3, 2, 3, 4, 4, 6, 5, 5, 6, 7, 6, 8, 2, 0, + 2, 1, 2, 3, 3, 2, 4, 4, 5, 6, 6, 7, 7, 5, 7, 8, 2, 1, + 2, 4, 3, 0, 3, 2, 3, 3, 4, 7, 5, 5, 6, 6, 6, 8, 2, 3, + 3, 1, 3, 2, 3, 4, 3, 5, 3, 6, 4, 7, 5, 0, 5, 8, 2, 3, + 2, 6, 3, 0, 3, 1, 4, 4, 4, 5, 4, 7, 5, 2, 5, 8, 2, 4, + 2, 7, 3, 3, 3, 6, 4, 1, 4, 2, 4, 5, 5, 0, 5, 8, 2, 6, + 3, 1, 3, 3, 3, 5, 3, 7, 3, 8, 4, 0, 5, 2, 5, 4, 2, 0, + 2, 1, 3, 2, 3, 3, 4, 4, 4, 5, 5, 6, 5, 7, 4, 8, 1, 0, + 2, 2, 2, -2, 1, -3, 1, 3, 2, -17, 2, -5, 2, 5, 2, 17, 2, -7, + 2, 2, 2, 9, 2, 18, 2, -18, 2, -9, 2, -2, 2, 7, 2, -28, 2, 28, + 3, -49, 3, -9, 3, 9, 4, 49, 5, -79, 5, 79, 2, -1, 2, 13, 2, 26, + 3, 39, 4, -16, 5, 55, 6, -37, 6, 76, 2, -26, 2, -13, 2, 1, 3, -39, + 4, 16, 5, -55, 6, -76, 6, 37}; + std::vector<ushort> huff_buffer(19 * 256); + ushort* huff = &huff_buffer[0]; + int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; + short last[3] = {16, 16, 16}, mul[3], buf[3][3][386]; + static const ushort pt[] = {0, 0, 1280, 1344, 2320, 3616, + 3328, 8000, 4095, 16383, 65535, 16383}; + + for (i = 2; i < 12; i += 2) + for (c = pt[i - 2]; c <= pt[i]; c++) + curve[c] = (float)(c - pt[i - 2]) / (pt[i] - pt[i - 2]) * + (pt[i + 1] - pt[i - 1]) + + pt[i - 1] + 0.5; + for (s = i = 0; i < int(sizeof src); i += 2) + FORC(256 >> src[i]) + ((ushort *)huff)[s++] = src[i] << 8 | (uchar)src[i + 1]; + s = kodak_cbpp == 243 ? 2 : 3; + FORC(256) huff[18 * 256 + c] = (8 - s) << 8 | c >> s << s | 1 << (s - 1); + getbits(-1); + for (i = 0; i < int(sizeof(buf) / sizeof(short)); i++) + ((short *)buf)[i] = 2048; + for (row = 0; row < height; row += 4) + { + checkCancel(); + FORC3 mul[c] = getbits(6); + if (!mul[0] || !mul[1] || !mul[2]) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + FORC3 + { + val = ((0x1000000 / last[c] + 0x7ff) >> 12) * mul[c]; + s = val > 65564 ? 10 : 12; + x = ~((~0u) << (s - 1)); + val <<= 12 - s; + for (i = 0; i < int(sizeof(buf[0]) / sizeof(short)); i++) + ((short *)buf[c])[i] = MIN(0x7FFFFFFF, (((short *)buf[c])[i] * static_cast<long long>(val) + x)) >> s; + last[c] = mul[c]; + for (r = 0; r <= !c; r++) + { + buf[c][1][width / 2] = buf[c][2][width / 2] = mul[c] << 7; + for (tree = 1, col = width / 2; col > 0;) + { + if ((tree = radc_token(tree))) + { + col -= 2; + if (col >= 0) + { + if (tree == 8) + FORYX buf[c][y][x] = (uchar)radc_token(18) * mul[c]; + else + FORYX buf[c][y][x] = radc_token(tree + 10) * 16 + PREDICTOR; + } + } + else + do + { + nreps = (col > 2) ? radc_token(9) + 1 : 1; + for (rep = 0; rep < 8 && rep < nreps && col > 0; rep++) + { + col -= 2; + if (col >= 0) + FORYX buf[c][y][x] = PREDICTOR; + if (rep & 1) + { + step = radc_token(10) << 4; + FORYX buf[c][y][x] += step; + } + } + } while (nreps == 9); + } + for (y = 0; y < 2; y++) + for (x = 0; x < width / 2; x++) + { + val = (buf[c][y + 1][x] << 4) / mul[c]; + if (val < 0) + val = 0; + if (c) + RAW(row + y * 2 + c - 1, x * 2 + 2 - c) = val; + else + RAW(row + r * 2 + y, x * 2 + y) = val; + } + memcpy(buf[c][0] + !c, buf[c][2], sizeof buf[c][0] - 2 * !c); + } + } + for (y = row; y < row + 4; y++) + for (x = 0; x < width; x++) + if ((x + y) & 1) + { + r = x ? x - 1 : x + 1; + s = x + 1 < width ? x + 1 : x - 1; + val = (RAW(y, x) - 2048) * 2 + (RAW(y, r) + RAW(y, s)) / 2; + if (val < 0) + val = 0; + RAW(y, x) = val; + } + } + for (i = 0; i < height * width; i++) + raw_image[i] = curve[raw_image[i]]; + maximum = 0x3fff; +} + +#undef FORYX +#undef PREDICTOR + +#ifdef NO_JPEG +void LibRaw::kodak_jpeg_load_raw() {} +#else +static void jpegErrorExit_k(j_common_ptr cinfo) +{ + throw LIBRAW_EXCEPTION_DECODE_JPEG; +} + +// LibRaw's Kodak_jpeg_load_raw +void LibRaw::kodak_jpeg_load_raw() +{ + if (data_size < 1) + throw LIBRAW_EXCEPTION_DECODE_JPEG; + + int row, col; + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr pub; + cinfo.err = jpeg_std_error(&pub); + pub.error_exit = jpegErrorExit_k; + + unsigned char *jpg_buf = (unsigned char *)malloc(data_size); + merror(jpg_buf, "kodak_jpeg_load_raw"); + unsigned char *pixel_buf = (unsigned char *)malloc(width * 3); + jpeg_create_decompress(&cinfo); + merror(pixel_buf, "kodak_jpeg_load_raw"); + + fread(jpg_buf, data_size, 1, ifp); + swab((char *)jpg_buf, (char *)jpg_buf, data_size); + try + { + jpeg_mem_src(&cinfo, jpg_buf, data_size); + int rc = jpeg_read_header(&cinfo, TRUE); + if (rc != 1) + throw LIBRAW_EXCEPTION_DECODE_JPEG; + + jpeg_start_decompress(&cinfo); + if ((cinfo.output_width != width) || (cinfo.output_height * 2 != height) || + (cinfo.output_components != 3)) + { + throw LIBRAW_EXCEPTION_DECODE_JPEG; + } + + unsigned char *buf[1]; + buf[0] = pixel_buf; + + while (cinfo.output_scanline < cinfo.output_height) + { + checkCancel(); + row = cinfo.output_scanline * 2; + jpeg_read_scanlines(&cinfo, buf, 1); + unsigned char(*pixel)[3] = (unsigned char(*)[3])buf[0]; + for (col = 0; col < width; col += 2) + { + RAW(row + 0, col + 0) = pixel[col + 0][1] << 1; + RAW(row + 1, col + 1) = pixel[col + 1][1] << 1; + RAW(row + 0, col + 1) = pixel[col][0] + pixel[col + 1][0]; + RAW(row + 1, col + 0) = pixel[col][2] + pixel[col + 1][2]; + } + } + } + catch (...) + { + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + free(jpg_buf); + free(pixel_buf); + throw; + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + free(jpg_buf); + free(pixel_buf); + maximum = 0xff << 1; +} +#endif + +void LibRaw::kodak_dc120_load_raw() +{ + static const int mul[4] = {162, 192, 187, 92}; + static const int add[4] = {0, 636, 424, 212}; + uchar pixel[848]; + int row, shift, col; + + for (row = 0; row < height; row++) + { + checkCancel(); + if (fread(pixel, 1, 848, ifp) < 848) + derror(); + shift = row * mul[row & 3] + add[row & 3]; + for (col = 0; col < width; col++) + RAW(row, col) = (ushort)pixel[(col + shift) % 848]; + } + maximum = 0xff; +} +void LibRaw::kodak_c330_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *)calloc(raw_width, 2 * sizeof *pixel); + merror(pixel, "kodak_c330_load_raw()"); + try + { + for (row = 0; row < height; row++) + { + checkCancel(); + if (fread(pixel, raw_width, 2, ifp) < 2) + derror(); + if (load_flags && (row & 31) == 31) + fseek(ifp, raw_width * 32, SEEK_CUR); + for (col = 0; col < width; col++) + { + y = pixel[col * 2]; + cb = pixel[(col * 2 & -4) | 1] - 128; + cr = pixel[(col * 2 & -4) | 3] - 128; + rgb[1] = y - ((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row * width + col][c] = curve[LIM(rgb[c], 0, 255)]; + } + } + } + catch (...) + { + free(pixel); + throw; + } + free(pixel); + maximum = curve[0xff]; +} + +void LibRaw::kodak_c603_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *)calloc(raw_width, 3 * sizeof *pixel); + merror(pixel, "kodak_c603_load_raw()"); + try + { + for (row = 0; row < height; row++) + { + checkCancel(); + if (~row & 1) + if (fread(pixel, raw_width, 3, ifp) < 3) + derror(); + for (col = 0; col < width; col++) + { + y = pixel[width * 2 * (row & 1) + col]; + cb = pixel[width + (col & -2)] - 128; + cr = pixel[width + (col & -2) + 1] - 128; + rgb[1] = y - ((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row * width + col][c] = curve[LIM(rgb[c], 0, 255)]; + } + } + } + catch (...) + { + free(pixel); + throw; + } + free(pixel); + maximum = curve[0xff]; +} + +void LibRaw::kodak_262_load_raw() +{ + static const uchar kodak_tree[2][26] = { + {0, 1, 5, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 3, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; + ushort *huff[2]; + uchar *pixel; + int *strip, ns, c, row, col, chess, pi = 0, pi1, pi2, pred, val; + + FORC(2) huff[c] = make_decoder(kodak_tree[c]); + ns = (raw_height + 63) >> 5; + pixel = (uchar *)malloc(raw_width * 32 + ns * 4); + merror(pixel, "kodak_262_load_raw()"); + strip = (int *)(pixel + raw_width * 32); + order = 0x4d4d; + FORC(ns) strip[c] = get4(); + try + { + for (row = 0; row < raw_height; row++) + { + checkCancel(); + if ((row & 31) == 0) + { + fseek(ifp, strip[row >> 5], SEEK_SET); + getbits(-1); + pi = 0; + } + for (col = 0; col < raw_width; col++) + { + chess = (row + col) & 1; + pi1 = chess ? pi - 2 : pi - raw_width - 1; + pi2 = chess ? pi - 2 * raw_width : pi - raw_width + 1; + if (col <= chess) + pi1 = -1; + if (pi1 < 0) + pi1 = pi2; + if (pi2 < 0) + pi2 = pi1; + if (pi1 < 0 && col > 1) + pi1 = pi2 = pi - 2; + pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; + pixel[pi] = val = pred + ljpeg_diff(huff[chess]); + if (val >> 8) + derror(); + val = curve[pixel[pi++]]; + RAW(row, col) = val; + } + } + } + catch (...) + { + free(pixel); + throw; + } + free(pixel); + FORC(2) free(huff[c]); +} + +int LibRaw::kodak_65000_decode(short *out, int bsize) +{ + uchar c, blen[768]; + ushort raw[6]; + INT64 bitbuf = 0; + int save, bits = 0, i, j, len, diff; + + save = ftell(ifp); + bsize = (bsize + 3) & -4; + for (i = 0; i < bsize; i += 2) + { + c = fgetc(ifp); + if ((blen[i] = c & 15) > 12 || (blen[i + 1] = c >> 4) > 12) + { + fseek(ifp, save, SEEK_SET); + for (i = 0; i < bsize; i += 8) + { + read_shorts(raw, 6); + out[i] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; + out[i + 1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; + for (j = 0; j < 6; j++) + out[i + 2 + j] = raw[j] & 0xfff; + } + return 1; + } + } + if ((bsize & 7) == 4) + { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + for (i = 0; i < bsize; i++) + { + len = blen[i]; + if (bits < len) + { + for (j = 0; j < 32; j += 8) + bitbuf += (INT64)fgetc(ifp) << (bits + (j ^ 8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16 - len)); + bitbuf >>= len; + bits -= len; + if (len > 0 && (diff & (1 << (len - 1))) == 0) + diff -= (1 << len) - 1; + out[i] = diff; + } + return 0; +} + +void LibRaw::kodak_65000_load_raw() +{ + short buf[272]; /* 264 looks enough */ + int row, col, len, pred[2], ret, i; + + for (row = 0; row < height; row++) + { + checkCancel(); + for (col = 0; col < width; col += 256) + { + pred[0] = pred[1] = 0; + len = MIN(256, width - col); + ret = kodak_65000_decode(buf, len); + for (i = 0; i < len; i++) + { + int idx = ret ? buf[i] : (pred[i & 1] += buf[i]); + if (idx >= 0 && idx < 0xffff) + { + if ((RAW(row, col + i) = curve[idx]) >> 12) + derror(); + } + else + derror(); + } + } + } +} + +void LibRaw::kodak_ycbcr_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + short buf[384], *bp; + int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; + ushort *ip; + + unsigned int bits = + (load_flags && load_flags > 9 && load_flags < 17) ? load_flags : 10; + for (row = 0; row < height; row += 2) + { + checkCancel(); + for (col = 0; col < width; col += 128) + { + len = MIN(128, width - col); + kodak_65000_decode(buf, len * 3); + y[0][1] = y[1][1] = cb = cr = 0; + for (bp = buf, i = 0; i < len; i += 2, bp += 2) + { + cb += bp[4]; + cr += bp[5]; + rgb[1] = -((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) + { + if ((y[j][k] = y[j][k ^ 1] + *bp++) >> bits) + derror(); + ip = image[(row + j) * width + col + i + k]; + FORC3 ip[c] = curve[LIM(y[j][k] + rgb[c], 0, 0xfff)]; + } + } + } + } +} + +void LibRaw::kodak_rgb_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + short buf[768], *bp; + int row, col, len, c, i, rgb[3], ret; + ushort *ip = image[0]; + + for (row = 0; row < height; row++) + { + checkCancel(); + for (col = 0; col < width; col += 256) + { + len = MIN(256, width - col); + ret = kodak_65000_decode(buf, len * 3); + memset(rgb, 0, sizeof rgb); + for (bp = buf, i = 0; i < len; i++, ip += 4) + if (load_flags == 12) + FORC3 ip[c] = ret ? (*bp++) : (rgb[c] += *bp++); + else + FORC3 if ((ip[c] = ret ? (*bp++) : (rgb[c] += *bp++)) >> 12) derror(); + } + } +} + +void LibRaw::kodak_thumb_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + int row, col; + colors = thumb_misc >> 5; + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) + read_shorts(image[row * width + col], colors); + maximum = (1 << (thumb_misc & 31)) - 1; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/load_mfbacks.cpp libkdcraw/libkdcraw/libraw/src/decoders/load_mfbacks.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/load_mfbacks.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/load_mfbacks.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,770 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +int LibRaw::p1raw(unsigned row, unsigned col) +{ + return (row < raw_height && col < raw_width) ? RAW(row, col) : 0; +} + +void LibRaw::phase_one_flat_field(int is_float, int nc) +{ + ushort head[8]; + unsigned wide, high, y, x, c, rend, cend, row, col; + float *mrow, num, mult[4]; + + read_shorts(head, 8); + if (head[2] == 0 || head[3] == 0 || head[4] == 0 || head[5] == 0) + return; + 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 < high; y++) + { + checkCancel(); + for (x = 0; x < wide; x++) + for (c = 0; c < (unsigned)nc; c += 2) + { + num = is_float ? getreal(LIBRAW_EXIFTAG_TYPE_FLOAT) : get2() / 32768.0; + if (y == 0) + mrow[c * wide + x] = num; + else + mrow[(c + 1) * wide + x] = (num - mrow[c * wide + x]) / head[5]; + } + if (y == 0) + continue; + rend = head[1] + y * head[5]; + for (row = rend - head[5]; + row < raw_height && row < rend && row < unsigned(head[1] + head[3] - head[5]); + row++) + { + for (x = 1; x < wide; x++) + { + for (c = 0; c < (unsigned)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 < unsigned(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]; + RAW(row, col) = LIM(c, 0, 65535); + } + for (c = 0; c < (unsigned)nc; c += 2) + mult[c] += mult[c + 1]; + } + } + for (x = 0; x < wide; x++) + for (c = 0; c < (unsigned)nc; c += 2) + mrow[c * wide + x] += mrow[(c + 1) * wide + x]; + } + } + free(mrow); +} + +int LibRaw::phase_one_correct() +{ + unsigned entries, tag, data, save, col, row, type; + int len, i, j, k, cip, val[4], dev[4], sum, max; + int head[9], diff, mindiff = INT_MAX, off_412 = 0; + /* static */ const signed char dir[12][2] = { + {-1, -1}, {-1, 1}, {1, -1}, {1, 1}, {-2, 0}, {0, -2}, + {0, 2}, {2, 0}, {-2, -2}, {-2, 2}, {2, -2}, {2, 2}}; + float poly[8], num, cfrac, frac, mult[2], *yval[2] = {NULL, NULL}; + ushort *xval[2]; + int qmult_applied = 0, qlin_applied = 0; + + if (!meta_length) + return 0; + fseek(ifp, meta_offset, SEEK_SET); + order = get2(); + fseek(ifp, 6, SEEK_CUR); + fseek(ifp, meta_offset + get4(), SEEK_SET); + entries = get4(); + get4(); + + try + { + while (entries--) + { + checkCancel(); + tag = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek(ifp, meta_offset + data, SEEK_SET); + if (tag == 0x0419) + { /* Polynomial curve */ + for (get4(), i = 0; i < 8; i++) + poly[i] = getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; + for (i = 0; i < 0x10000; i++) + { + num = (poly[5] * i + poly[3]) * i + poly[1]; + curve[i] = LIM(num, 0, 65535); + } + goto apply; /* apply to right half */ + } + else if (tag == 0x041a) + { /* Polynomial curve */ + for (i = 0; i < 4; i++) + poly[i] = getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + for (i = 0; i < 0x10000; i++) + { + for (num = 0, j = 4; j--;) + num = num * i + poly[j]; + curve[i] = LIM(num + i, 0, 65535); + } + apply: /* apply to whole image */ + for (row = 0; row < raw_height; row++) + { + checkCancel(); + for (col = (tag & 1) * ph1.split_col; col < raw_width; col++) + RAW(row, col) = curve[RAW(row, col)]; + } + } + else if (tag == 0x0400) + { /* Sensor defects */ + while ((len -= 8) >= 0) + { + col = get2(); + row = get2(); + type = get2(); + get2(); + if (col >= raw_width) + continue; + if (type == 131 || type == 137) /* Bad column */ + for (row = 0; row < raw_height; row++) + if (FC(row - top_margin, col - left_margin) == 1) + { + for (sum = i = 0; i < 4; i++) + sum += val[i] = p1raw(row + dir[i][0], col + dir[i][1]); + for (max = i = 0; i < 4; i++) + { + dev[i] = abs((val[i] << 2) - sum); + if (dev[max] < dev[i]) + max = i; + } + RAW(row, col) = (sum - val[max]) / 3.0 + 0.5; + } + else + { + for (sum = 0, i = 8; i < 12; i++) + sum += p1raw(row + dir[i][0], col + dir[i][1]); + RAW(row, col) = + 0.5 + sum * 0.0732233 + + (p1raw(row, col - 2) + p1raw(row, col + 2)) * 0.3535534; + } + else if (type == 129) + { /* Bad pixel */ + if (row >= raw_height) + continue; + j = (FC(row - top_margin, col - left_margin) != 1) * 4; + for (sum = 0, i = j; i < j + 8; i++) + sum += p1raw(row + dir[i][0], col + dir[i][1]); + RAW(row, col) = (sum + 4) >> 3; + } + } + } + else if (tag == 0x0401) + { /* All-color flat fields */ + phase_one_flat_field(1, 2); + } + else if (tag == 0x0416 || tag == 0x0410) + { + phase_one_flat_field(0, 2); + } + else if (tag == 0x040b) + { /* Red+blue flat field */ + phase_one_flat_field(0, 4); + } + else if (tag == 0x0412) + { + fseek(ifp, 36, SEEK_CUR); + diff = abs(get2() - ph1.tag_21a); + if (mindiff > diff) + { + mindiff = diff; + off_412 = ftell(ifp) - 38; + } + } + else if (tag == 0x041f && !qlin_applied) + { /* Quadrant linearization */ + ushort lc[2][2][16], ref[16]; + int qr, qc; + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 16; i++) + lc[qr][qc][i] = get4(); + 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; + } + for (qr = 0; qr < 2; qr++) + { + for (qc = 0; qc < 2; qc++) + { + int cx[19], cf[19]; + 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]; + cf[18] = cx[18] = 65535; + cubic_spline(cx, cf, 19); + + for (row = (qr ? ph1.split_row : 0); + row < unsigned(qr ? raw_height : ph1.split_row); row++) + { + checkCancel(); + for (col = (qc ? ph1.split_col : 0); + col < unsigned(qc ? raw_width : ph1.split_col); col++) + RAW(row, col) = curve[RAW(row, col)]; + } + } + } + qlin_applied = 1; + } + else if (tag == 0x041e && !qmult_applied) + { /* Quadrant multipliers */ + float qmult[2][2] = {{1, 1}, {1, 1}}; + get4(); + get4(); + get4(); + get4(); + qmult[0][0] = 1.0 + getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + get4(); + get4(); + get4(); + get4(); + get4(); + qmult[0][1] = 1.0 + getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + get4(); + get4(); + get4(); + qmult[1][0] = 1.0 + getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + get4(); + get4(); + get4(); + qmult[1][1] = 1.0 + getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + for (row = 0; row < raw_height; row++) + { + checkCancel(); + for (col = 0; col < raw_width; col++) + { + i = qmult[row >= (unsigned)ph1.split_row][col >= (unsigned)ph1.split_col] * + RAW(row, col); + RAW(row, col) = LIM(i, 0, 65535); + } + } + qmult_applied = 1; + } + else if (tag == 0x0431 && !qmult_applied) + { /* Quadrant combined */ + ushort lc[2][2][7], ref[7]; + int qr, qc; + for (i = 0; i < 7; i++) + ref[i] = get4(); + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 7; i++) + lc[qr][qc][i] = get4(); + for (qr = 0; qr < 2; qr++) + { + for (qc = 0; qc < 2; qc++) + { + int cx[9], cf[9]; + for (i = 0; i < 7; i++) + { + cx[1 + i] = ref[i]; + cf[1 + i] = ((unsigned)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 < unsigned(qr ? raw_height : ph1.split_row); row++) + { + checkCancel(); + for (col = (qc ? ph1.split_col : 0); + col < unsigned(qc ? raw_width : ph1.split_col); col++) + RAW(row, col) = curve[RAW(row, col)]; + } + } + } + qmult_applied = 1; + qlin_applied = 1; + } + fseek(ifp, save, SEEK_SET); + } + if (off_412) + { + fseek(ifp, off_412, SEEK_SET); + for (i = 0; i < 9; i++) + head[i] = get4() & 0x7fff; + yval[0] = (float *)calloc(head[1] * head[3] + head[2] * head[4], 6); + merror(yval[0], "phase_one_correct()"); + yval[1] = (float *)(yval[0] + head[1] * head[3]); + xval[0] = (ushort *)(yval[1] + head[2] * head[4]); + xval[1] = (ushort *)(xval[0] + head[1] * head[3]); + get2(); + for (i = 0; i < 2; i++) + for (j = 0; j < head[i + 1] * head[i + 3]; j++) + yval[i][j] = getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + for (i = 0; i < 2; i++) + for (j = 0; j < head[i + 1] * head[i + 3]; j++) + xval[i][j] = get2(); + for (row = 0; row < raw_height; row++) + { + checkCancel(); + for (col = 0; col < raw_width; col++) + { + cfrac = (float)col * head[3] / raw_width; + cfrac -= cip = cfrac; + num = RAW(row, col) * 0.5; + for (i = cip; i < cip + 2; i++) + { + for (k = j = 0; j < head[1]; j++) + if (num < xval[0][k = head[1] * i + j]) + break; + frac = (j == 0 || j == head[1]) + ? 0 + : (xval[0][k] - num) / (xval[0][k] - xval[0][k - 1]); + mult[i - cip] = yval[0][k - 1] * frac + yval[0][k] * (1 - frac); + } + i = ((mult[0] * (1 - cfrac) + mult[1] * cfrac) * row + num) * 2; + RAW(row, col) = LIM(i, 0, 65535); + } + } + free(yval[0]); + } + } + catch (...) + { + if (yval[0]) + free(yval[0]); + return LIBRAW_CANCELLED_BY_CALLBACK; + } + return 0; +} + +void LibRaw::phase_one_load_raw() +{ + int a, b, i; + ushort akey, bkey, t_mask; + + fseek(ifp, ph1.key_off, SEEK_SET); + akey = get2(); + bkey = get2(); + t_mask = ph1.format == 1 ? 0x5555 : 0x1354; + if (ph1.black_col || ph1.black_row) + { + imgdata.rawdata.ph1_cblack = + (short(*)[2])calloc(raw_height * 2, sizeof(ushort)); + merror(imgdata.rawdata.ph1_cblack, "phase_one_load_raw()"); + imgdata.rawdata.ph1_rblack = + (short(*)[2])calloc(raw_width * 2, sizeof(ushort)); + merror(imgdata.rawdata.ph1_rblack, "phase_one_load_raw()"); + if (ph1.black_col) + { + fseek(ifp, ph1.black_col, SEEK_SET); + read_shorts((ushort *)imgdata.rawdata.ph1_cblack[0], raw_height * 2); + } + if (ph1.black_row) + { + fseek(ifp, ph1.black_row, SEEK_SET); + read_shorts((ushort *)imgdata.rawdata.ph1_rblack[0], raw_width * 2); + } + } + fseek(ifp, data_offset, SEEK_SET); + read_shorts(raw_image, raw_width * raw_height); + if (ph1.format) + for (i = 0; i < raw_width * raw_height; i += 2) + { + a = raw_image[i + 0] ^ akey; + b = raw_image[i + 1] ^ bkey; + raw_image[i + 0] = (a & t_mask) | (b & ~t_mask); + raw_image[i + 1] = (b & t_mask) | (a & ~t_mask); + } +} + +unsigned LibRaw::ph1_bithuff(int nbits, ushort *huff) +{ +#ifndef LIBRAW_NOTHREADS +#define bitbuf tls->ph1_bits.bitbuf +#define vbits tls->ph1_bits.vbits +#else + static UINT64 bitbuf = 0; + static int vbits = 0; +#endif + unsigned c; + + if (nbits == -1) + return bitbuf = vbits = 0; + if (nbits == 0) + return 0; + if (vbits < nbits) + { + bitbuf = bitbuf << 32 | get4(); + vbits += 32; + } + c = bitbuf << (64 - vbits) >> (64 - nbits); + if (huff) + { + vbits -= huff[c] >> 8; + return (uchar)huff[c]; + } + vbits -= nbits; + return c; +#ifndef LIBRAW_NOTHREADS +#undef bitbuf +#undef vbits +#endif +} + +void LibRaw::phase_one_load_raw_c() +{ + static const int length[] = {8, 7, 6, 9, 11, 10, 5, 12, 14, 13}; + int *offset, len[2], pred[2], row, col, i, j; + ushort *pixel; + short(*c_black)[2], (*r_black)[2]; + if (ph1.format == 6) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + pixel = (ushort *)calloc(raw_width * 3 + raw_height * 4, 2); + merror(pixel, "phase_one_load_raw_c()"); + offset = (int *)(pixel + raw_width); + fseek(ifp, strip_offset, SEEK_SET); + for (row = 0; row < raw_height; row++) + offset[row] = get4(); + c_black = (short(*)[2])(offset + raw_height); + fseek(ifp, ph1.black_col, SEEK_SET); + if (ph1.black_col) + read_shorts((ushort *)c_black[0], raw_height * 2); + r_black = c_black + raw_height; + fseek(ifp, ph1.black_row, SEEK_SET); + if (ph1.black_row) + read_shorts((ushort *)r_black[0], raw_width * 2); + + // Copy data to internal copy (ever if not read) + if (ph1.black_col || ph1.black_row) + { + imgdata.rawdata.ph1_cblack = + (short(*)[2])calloc(raw_height * 2, sizeof(ushort)); + merror(imgdata.rawdata.ph1_cblack, "phase_one_load_raw_c()"); + memmove(imgdata.rawdata.ph1_cblack, (ushort *)c_black[0], + raw_height * 2 * sizeof(ushort)); + imgdata.rawdata.ph1_rblack = + (short(*)[2])calloc(raw_width * 2, sizeof(ushort)); + merror(imgdata.rawdata.ph1_rblack, "phase_one_load_raw_c()"); + memmove(imgdata.rawdata.ph1_rblack, (ushort *)r_black[0], + raw_width * 2 * sizeof(ushort)); + } + + for (i = 0; i < 256; i++) + curve[i] = i * i / 3.969 + 0.5; + try + { + for (row = 0; row < raw_height; row++) + { + checkCancel(); + fseek(ifp, data_offset + offset[row], SEEK_SET); + ph1_bits(-1); + pred[0] = pred[1] = 0; + for (col = 0; col < raw_width; col++) + { + if (col >= (raw_width & -8)) + len[0] = len[1] = 14; + else if ((col & 7) == 0) + for (i = 0; i < 2; i++) + { + for (j = 0; j < 5 && !ph1_bits(1); j++) + ; + if (j--) + len[i] = length[j * 2 + ph1_bits(1)]; + } + if ((i = len[col & 1]) == 14) + pixel[col] = pred[col & 1] = ph1_bits(16); + else + pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); + if (pred[col & 1] >> 16) + derror(); + if (ph1.format == 5 && pixel[col] < 256) + pixel[col] = curve[pixel[col]]; + } + if (ph1.format == 8) + memmove(&RAW(row, 0), &pixel[0], raw_width * 2); + else + for (col = 0; col < raw_width; col++) + RAW(row, col) = pixel[col] << 2; + } + } + catch (...) + { + free(pixel); + throw; + } + free(pixel); + maximum = 0xfffc - ph1.t_black; +} + +void LibRaw::hasselblad_load_raw() +{ + struct jhead jh; + int shot, row, col, *back[5], len[2], diff[12], pred, sh, f, c; + unsigned s; + unsigned upix, urow, ucol; + ushort *ip; + + if (!ljpeg_start(&jh, 0)) + return; + order = 0x4949; + ph1_bits(-1); + try + { + back[4] = (int *)calloc(raw_width, 3 * sizeof **back); + merror(back[4], "hasselblad_load_raw()"); + FORC3 back[c] = back[4] + c * raw_width; + cblack[6] >>= sh = tiff_samples > 1; + shot = LIM(shot_select, 1, tiff_samples) - 1; + for (row = 0; row < raw_height; row++) + { + checkCancel(); + FORC4 back[(c + 3) & 3] = back[c]; + for (col = 0; col < raw_width; col += 2) + { + for (s = 0; s < tiff_samples * 2; s += 2) + { + FORC(2) len[c] = ph1_huff(jh.huff[0]); + FORC(2) + { + diff[s + c] = ph1_bits(len[c]); + if (len[c] > 0 && (diff[s + c] & (1 << (len[c] - 1))) == 0) + diff[s + c] -= (1 << len[c]) - 1; + if (diff[s + c] == 65535) + diff[s + c] = -32768; + } + } + for (s = col; s < unsigned(col + 2); s++) + { + pred = 0x8000 + load_flags; + if (col) + pred = back[2][s - 2]; + if (col && row > 1) + switch (jh.psv) + { + case 11: + pred += back[0][s] / 2 - back[0][s - 2] / 2; + break; + } + f = (row & 1) * 3 ^ ((col + s) & 1); + FORC(int(tiff_samples)) + { + pred += diff[(s & 1) * tiff_samples + c]; + upix = pred >> sh & 0xffff; + if (raw_image && c == shot) + RAW(row, s) = upix; + if (image) + { + urow = row - top_margin + (c & 1); + ucol = col - left_margin - ((c >> 1) & 1); + ip = &image[urow * width + ucol][f]; + if (urow < height && ucol < width) + *ip = c < 4 ? upix : (*ip + upix) >> 1; + } + } + back[2][s] = pred; + } + } + } + } + catch (...) + { + free(back[4]); + ljpeg_end(&jh); + throw; + } + free(back[4]); + ljpeg_end(&jh); + if (image) + mix_green = 1; +} + +void LibRaw::leaf_hdr_load_raw() +{ + ushort *pixel = 0; + unsigned tile = 0, r, c, row, col; + + if (!filters || !raw_image) + { + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + pixel = (ushort *)calloc(raw_width, sizeof *pixel); + merror(pixel, "leaf_hdr_load_raw()"); + } + try + { + FORC(tiff_samples) + for (r = 0; r < raw_height; r++) + { + checkCancel(); + if (r % tile_length == 0) + { + fseek(ifp, data_offset + 4 * tile++, SEEK_SET); + fseek(ifp, get4(), SEEK_SET); + } + if (filters && c != shot_select) + continue; + if (filters && raw_image) + pixel = raw_image + r * raw_width; + read_shorts(pixel, raw_width); + if (!filters && image && (row = r - top_margin) < height) + for (col = 0; col < width && col + left_margin < raw_width; col++) + image[row * width + col][c] = pixel[col + left_margin]; + } + } + catch (...) + { + if (!filters) + free(pixel); + throw; + } + if (!filters) + { + maximum = 0xffff; + raw_color = 1; + free(pixel); + } +} + +void LibRaw::unpacked_load_raw_FujiDBP() +/* +for Fuji DBP for GX680, aka DX-2000 + DBP_tile_width = 688; + DBP_tile_height = 3856; + DBP_n_tiles = 8; +*/ +{ + int scan_line, tile_n; + int nTiles; + + nTiles = 8; + tile_width = raw_width / nTiles; + + ushort *tile; + tile = (ushort *)calloc(raw_height, tile_width * 2); + + for (tile_n = 0; tile_n < nTiles; tile_n++) + { + read_shorts(tile, tile_width * raw_height); + for (scan_line = 0; scan_line < raw_height; scan_line++) + { + memcpy(&raw_image[scan_line * raw_width + tile_n * tile_width], + &tile[scan_line * tile_width], tile_width * 2); + } + } + free(tile); + fseek(ifp, -2, SEEK_CUR); // avoid EOF error +} + +void LibRaw::sinar_4shot_load_raw() +{ + ushort *pixel; + unsigned shot, row, col, r, c; + + if (raw_image) + { + shot = LIM(shot_select, 1, 4) - 1; + fseek(ifp, data_offset + shot * 4, SEEK_SET); + fseek(ifp, get4(), SEEK_SET); + unpacked_load_raw(); + return; + } + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + pixel = (ushort *)calloc(raw_width, sizeof *pixel); + merror(pixel, "sinar_4shot_load_raw()"); + try + { + for (shot = 0; shot < 4; shot++) + { + checkCancel(); + fseek(ifp, data_offset + shot * 4, SEEK_SET); + fseek(ifp, get4(), SEEK_SET); + for (row = 0; row < raw_height; row++) + { + read_shorts(pixel, raw_width); + if ((r = row - top_margin - (shot >> 1 & 1)) >= height) + continue; + for (col = 0; col < raw_width; col++) + { + if ((c = col - left_margin - (shot & 1)) >= width) + continue; + image[r * width + c][(row & 1) * 3 ^ (~col & 1)] = pixel[col]; + } + } + } + } + catch (...) + { + free(pixel); + throw; + } + free(pixel); + mix_green = 1; +} + +void LibRaw::imacon_full_load_raw() +{ + if (!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + int row, col; + + unsigned short *buf = + (unsigned short *)malloc(width * 3 * sizeof(unsigned short)); + merror(buf, "imacon_full_load_raw"); + + for (row = 0; row < height; row++) + { + checkCancel(); + read_shorts(buf, width * 3); + unsigned short(*rowp)[4] = &image[row * width]; + for (col = 0; col < width; col++) + { + rowp[col][0] = buf[col * 3]; + rowp[col][1] = buf[col * 3 + 1]; + rowp[col][2] = buf[col * 3 + 2]; + rowp[col][3] = 0; + } + } + free(buf); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/smal.cpp libkdcraw/libkdcraw/libraw/src/decoders/smal.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/smal.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/smal.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,181 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +#define HOLE(row) ((holes >> (((row)-raw_height) & 7)) & 1) + +/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ +void LibRaw::smal_decode_segment(unsigned seg[2][2], int holes) +{ + uchar hist[3][13] = {{7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0}, + {7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0}, + {3, 3, 0, 0, 63, 47, 31, 15, 0}}; + int low, high = 0xff, carry = 0, nbits = 8; + int s, count, bin, next, i, sym[3]; + unsigned pix; + uchar diff, pred[] = {0, 0}; + ushort data = 0, range = 0; + + fseek(ifp, seg[0][1] + 1, SEEK_SET); + getbits(-1); + if (seg[1][0] > raw_width * raw_height) + seg[1][0] = raw_width * raw_height; + for (pix = seg[0][0]; pix < seg[1][0]; pix++) + { + for (s = 0; s < 3; s++) + { + data = data << nbits | getbits(nbits); + if (carry < 0) + carry = (nbits += carry + 1) < 1 ? nbits - 1 : 0; + while (--nbits >= 0) + if ((data >> nbits & 0xff) == 0xff) + break; + if (nbits > 0) + data = + ((data & ((1 << (nbits - 1)) - 1)) << 1) | + ((data + (((data & (1 << (nbits - 1)))) << 1)) & ((~0u) << nbits)); + if (nbits >= 0) + { + data += getbits(1); + carry = nbits - 8; + } + count = ((((data - range + 1) & 0xffff) << 2) - 1) / (high >> 4); + for (bin = 0; hist[s][bin + 5] > count; bin++) + ; + low = hist[s][bin + 5] * (high >> 4) >> 2; + if (bin) + high = hist[s][bin + 4] * (high >> 4) >> 2; + high -= low; + for (nbits = 0; high << nbits < 128; nbits++) + ; + range = (range + low) << nbits; + high <<= nbits; + next = hist[s][1]; + if (++hist[s][2] > hist[s][3]) + { + next = (next + 1) & hist[s][0]; + hist[s][3] = (hist[s][next + 4] - hist[s][next + 5]) >> 2; + hist[s][2] = 1; + } + if (hist[s][hist[s][1] + 4] - hist[s][hist[s][1] + 5] > 1) + { + if (bin < hist[s][1]) + for (i = bin; i < hist[s][1]; i++) + hist[s][i + 5]--; + else if (next <= bin) + for (i = hist[s][1]; i < bin; i++) + hist[s][i + 5]++; + } + hist[s][1] = next; + sym[s] = bin; + } + diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); + if (sym[0] & 4) + diff = diff ? -diff : 0x80; + if (ftell(ifp) + 12 >= seg[1][1]) + diff = 0; + if (pix >= raw_width * raw_height) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + raw_image[pix] = pred[pix & 1] += diff; + if (!(pix & 1) && HOLE(pix / raw_width)) + pix += 2; + } + maximum = 0xff; +} + +void LibRaw::smal_v6_load_raw() +{ + unsigned seg[2][2]; + + fseek(ifp, 16, SEEK_SET); + seg[0][0] = 0; + seg[0][1] = get2(); + seg[1][0] = raw_width * raw_height; + seg[1][1] = INT_MAX; + smal_decode_segment(seg, 0); +} + +int LibRaw::median4(int *p) +{ + int min, max, sum, i; + + min = max = sum = p[0]; + for (i = 1; i < 4; i++) + { + sum += p[i]; + if (min > p[i]) + min = p[i]; + if (max < p[i]) + max = p[i]; + } + return (sum - min - max) >> 1; +} + +void LibRaw::fill_holes(int holes) +{ + int row, col, val[4]; + + for (row = 2; row < height - 2; row++) + { + if (!HOLE(row)) + continue; + for (col = 1; col < width - 1; col += 4) + { + val[0] = RAW(row - 1, col - 1); + val[1] = RAW(row - 1, col + 1); + val[2] = RAW(row + 1, col - 1); + val[3] = RAW(row + 1, col + 1); + RAW(row, col) = median4(val); + } + for (col = 2; col < width - 2; col += 4) + if (HOLE(row - 2) || HOLE(row + 2)) + RAW(row, col) = (RAW(row, col - 2) + RAW(row, col + 2)) >> 1; + else + { + val[0] = RAW(row, col - 2); + val[1] = RAW(row, col + 2); + val[2] = RAW(row - 2, col); + val[3] = RAW(row + 2, col); + RAW(row, col) = median4(val); + } + } +} + +void LibRaw::smal_v9_load_raw() +{ + unsigned seg[256][2], offset, nseg, holes, i; + + fseek(ifp, 67, SEEK_SET); + offset = get4(); + nseg = (uchar)fgetc(ifp); + fseek(ifp, offset, SEEK_SET); + for (i = 0; i < nseg * 2; i++) + ((unsigned *)seg)[i] = get4() + data_offset * (i & 1); + fseek(ifp, 78, SEEK_SET); + holes = fgetc(ifp); + fseek(ifp, 88, SEEK_SET); + seg[nseg][0] = raw_height * raw_width; + seg[nseg][1] = get4() + data_offset; + for (i = 0; i < nseg; i++) + smal_decode_segment(seg + i, holes); + if (holes) + fill_holes(holes); +} + +#undef HOLE diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/unpack.cpp libkdcraw/libkdcraw/libraw/src/decoders/unpack.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/unpack.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/unpack.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,365 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ +#include "../../internal/libraw_cameraids.h" +#include "../../internal/libraw_cxx_defs.h" + +int LibRaw::unpack(void) +{ + CHECK_ORDER_HIGH(LIBRAW_PROGRESS_LOAD_RAW); + CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); + try + { + + if (!libraw_internal_data.internal_data.input) + return LIBRAW_INPUT_CLOSED; + + RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW, 0, 2); + if (O.shot_select >= P1.raw_count) + return LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE; + + if (!load_raw) + return LIBRAW_UNSPECIFIED_ERROR; + + // already allocated ? + if (imgdata.image) + { + free(imgdata.image); + imgdata.image = 0; + } + if (imgdata.rawdata.raw_alloc) + { + free(imgdata.rawdata.raw_alloc); + imgdata.rawdata.raw_alloc = 0; + } + if (libraw_internal_data.unpacker_data.meta_length) + { + libraw_internal_data.internal_data.meta_data = + (char *)malloc(libraw_internal_data.unpacker_data.meta_length); + merror(libraw_internal_data.internal_data.meta_data, "LibRaw::unpack()"); + } + + libraw_decoder_info_t decoder_info; + get_decoder_info(&decoder_info); + + int save_iwidth = S.iwidth, save_iheight = S.iheight, + save_shrink = IO.shrink; + + int rwidth = S.raw_width, rheight = S.raw_height; + if (!IO.fuji_width) + { + // adjust non-Fuji allocation + if (rwidth < S.width + S.left_margin) + rwidth = S.width + S.left_margin; + if (rheight < S.height + S.top_margin) + rheight = S.height + S.top_margin; + } + if (rwidth > 65535 || + rheight > 65535) // No way to make image larger than 64k pix + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + imgdata.rawdata.raw_image = 0; + imgdata.rawdata.color4_image = 0; + imgdata.rawdata.color3_image = 0; + imgdata.rawdata.float_image = 0; + imgdata.rawdata.float3_image = 0; + +#ifdef USE_DNGSDK + if (imgdata.idata.dng_version && dnghost + && libraw_internal_data.unpacker_data.tiff_samples != 2 // Fuji SuperCCD; it is better to detect is more rigid way + && valid_for_dngsdk() && load_raw != &LibRaw::pentax_4shot_load_raw) + { + // Data size check + INT64 pixcount = + INT64(MAX(S.width, S.raw_width)) * INT64(MAX(S.height, S.raw_height)); + INT64 planecount = + (imgdata.idata.filters || P1.colors == 1) ? 1 : LIM(P1.colors, 3, 4); + INT64 samplesize = is_floating_point() ? 4 : 2; + INT64 bytes = pixcount * planecount * samplesize; + if (bytes > INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) + throw LIBRAW_EXCEPTION_TOOBIG; + + // find ifd to check sample + int rr = try_dngsdk(); + if (raw_was_read()) + imgdata.process_warnings |= LIBRAW_WARN_DNGSDK_PROCESSED; + } +#endif + +#ifdef USE_RAWSPEED + if (!raw_was_read()) + { + int rawspeed_enabled = 1; + + if (imgdata.idata.dng_version && (libraw_internal_data.unpacker_data.tiff_samples == 2 || imgdata.idata.raw_count > 1)) + rawspeed_enabled = 0; + + if (libraw_internal_data.unpacker_data.is_NikonTransfer) + rawspeed_enabled = 0; + + if (libraw_internal_data.unpacker_data.pana_encoding == 5) + rawspeed_enabled = 0; + + if (imgdata.idata.raw_count > 1) + rawspeed_enabled = 0; + if (!strncasecmp(imgdata.idata.software, "Magic", 5)) + rawspeed_enabled = 0; + // Disable rawspeed for double-sized Oly files + if (makeIs(LIBRAW_CAMERAMAKER_Olympus) && + ((imgdata.sizes.raw_width > 6000) || + !strncasecmp(imgdata.idata.model, "SH-", 3) || + !strncasecmp(imgdata.idata.model, "TG-", 3) )) + rawspeed_enabled = 0; + + if (makeIs(LIBRAW_CAMERAMAKER_Canon) && + (libraw_internal_data.identify_data.unique_id == CanonID_EOS_6D_Mark_II)) + rawspeed_enabled = 0; + + if (imgdata.idata.dng_version && imgdata.idata.filters == 0 && + libraw_internal_data.unpacker_data.tiff_bps == 8) // Disable for 8 bit + rawspeed_enabled = 0; + + if (load_raw == &LibRaw::packed_load_raw && + makeIs(LIBRAW_CAMERAMAKER_Nikon) && + (!strncasecmp(imgdata.idata.model, "E", 1) || + !strncasecmp(imgdata.idata.model, "COOLPIX B", 9) || + !strncasecmp(imgdata.idata.model, "COOLPIX P9", 10) || + !strncasecmp(imgdata.idata.model, "COOLPIX P1000", 13))) + rawspeed_enabled = 0; + + if (load_raw == &LibRaw::lossless_jpeg_load_raw && + imgdata.makernotes.canon.RecordMode && makeIs(LIBRAW_CAMERAMAKER_Kodak) && + /* Not normalized models here, it is intentional */ + (!strncasecmp(imgdata.idata.model, "EOS D2000", 9) || + !strncasecmp(imgdata.idata.model, "EOS D6000", 9))) + rawspeed_enabled = 0; + + if (load_raw == &LibRaw::nikon_load_raw && + makeIs(LIBRAW_CAMERAMAKER_Nikon) && + (!strncasecmp(imgdata.idata.model, "Z", 1) || !strncasecmp(imgdata.idata.model,"D780",4))) + rawspeed_enabled = 0; + + if (load_raw == &LibRaw::panasonic_load_raw && + libraw_internal_data.unpacker_data.pana_encoding > 4) + rawspeed_enabled = 0; + + // RawSpeed Supported, + if (O.use_rawspeed && rawspeed_enabled && + !(is_sraw() && (O.raw_processing_options & + (LIBRAW_PROCESSING_SRAW_NO_RGB | + LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE))) && + (decoder_info.decoder_flags & LIBRAW_DECODER_TRYRAWSPEED) && + _rawspeed_camerameta) + { + INT64 pixcount = INT64(MAX(S.width, S.raw_width)) * + INT64(MAX(S.height, S.raw_height)); + INT64 planecount = (imgdata.idata.filters || P1.colors == 1) + ? 1 + : LIM(P1.colors, 3, 4); + INT64 bytes = + pixcount * planecount * 2; // sample size is always 2 for rawspeed + if (bytes > + INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) + throw LIBRAW_EXCEPTION_TOOBIG; + + int rr = try_rawspeed(); + } + } +#endif + if (!raw_was_read()) // RawSpeed failed or not run + { + // Not allocated on RawSpeed call, try call LibRaow + int zero_rawimage = 0; + if (decoder_info.decoder_flags & LIBRAW_DECODER_OWNALLOC) + { + // x3f foveon decoder and DNG float + // Do nothing! Decoder will allocate data internally + } + if (decoder_info.decoder_flags & LIBRAW_DECODER_SINAR4SHOT) + { + if (imgdata.params.shot_select) // single image extract + { + if (INT64(rwidth) * INT64(rheight + 8) * + sizeof(imgdata.rawdata.raw_image[0]) > + INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) + throw LIBRAW_EXCEPTION_TOOBIG; + imgdata.rawdata.raw_alloc = malloc( + rwidth * (rheight + 8) * sizeof(imgdata.rawdata.raw_image[0])); + imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc; + if (!S.raw_pitch) + S.raw_pitch = S.raw_width * 2; // Bayer case, not set before + } + else // Full image extract + { + if (INT64(rwidth) * INT64(rheight + 8) * + sizeof(imgdata.rawdata.raw_image[0]) * 4 > + INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) + throw LIBRAW_EXCEPTION_TOOBIG; + S.raw_pitch = S.raw_width * 8; + imgdata.rawdata.raw_alloc = 0; + imgdata.image = (ushort(*)[4])calloc( + unsigned(MAX(S.width, S.raw_width)) * + unsigned(MAX(S.height, S.raw_height) + 8), + sizeof(*imgdata.image)); + } + } + else if (decoder_info.decoder_flags & LIBRAW_DECODER_3CHANNEL) + { + if (INT64(rwidth) * INT64(rheight + 8) * + sizeof(imgdata.rawdata.raw_image[0]) * 3 > + INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) + throw LIBRAW_EXCEPTION_TOOBIG; + + imgdata.rawdata.raw_alloc = malloc( + rwidth * (rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]) * 3); + imgdata.rawdata.color3_image = (ushort(*)[3])imgdata.rawdata.raw_alloc; + if (!S.raw_pitch) + S.raw_pitch = S.raw_width * 6; + } + else if (imgdata.idata.filters || + P1.colors == + 1) // Bayer image or single color -> decode to raw_image + { + if (INT64(rwidth) * INT64(rheight + 8) * + sizeof(imgdata.rawdata.raw_image[0]) > + INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) + throw LIBRAW_EXCEPTION_TOOBIG; + imgdata.rawdata.raw_alloc = malloc( + rwidth * (rheight + 8) * sizeof(imgdata.rawdata.raw_image[0])); + imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc; + if (!S.raw_pitch) + S.raw_pitch = S.raw_width * 2; // Bayer case, not set before + } + else // NO LEGACY FLAG if (decoder_info.decoder_flags & + // LIBRAW_DECODER_LEGACY) + { + if (decoder_info.decoder_flags & LIBRAW_DECODER_ADOBECOPYPIXEL) + { + S.raw_pitch = S.raw_width * 8; + } + else + { + S.iwidth = S.width; + S.iheight = S.height; + IO.shrink = 0; + if (!S.raw_pitch) + S.raw_pitch = (decoder_info.decoder_flags & + LIBRAW_DECODER_LEGACY_WITH_MARGINS) + ? S.raw_width * 8 + : S.width * 8; + } + // sRAW and old Foveon decoders only, so extra buffer size is just 1/4 + // allocate image as temporary buffer, size + if (INT64(MAX(S.width, S.raw_width)) * + INT64(MAX(S.height, S.raw_height) + 8) * + sizeof(*imgdata.image) > + INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) + throw LIBRAW_EXCEPTION_TOOBIG; + + imgdata.rawdata.raw_alloc = 0; + imgdata.image = + (ushort(*)[4])calloc(unsigned(MAX(S.width, S.raw_width)) * + unsigned(MAX(S.height, S.raw_height) + 8), + sizeof(*imgdata.image)); + if (!(decoder_info.decoder_flags & LIBRAW_DECODER_ADOBECOPYPIXEL)) + { + imgdata.rawdata.raw_image = (ushort *)imgdata.image; + zero_rawimage = 1; + } + } + ID.input->seek(libraw_internal_data.unpacker_data.data_offset, SEEK_SET); + + unsigned m_save = C.maximum; + if (load_raw == &LibRaw::unpacked_load_raw && + (!strcasecmp(imgdata.idata.make, "Nikon") || !strcasecmp(imgdata.idata.make, "Hasselblad")) + ) + C.maximum = 65535; + (this->*load_raw)(); + if (zero_rawimage) + imgdata.rawdata.raw_image = 0; + if (load_raw == &LibRaw::unpacked_load_raw && + (!strcasecmp(imgdata.idata.make, "Nikon") || !strcasecmp(imgdata.idata.make, "Hasselblad")) + ) + C.maximum = m_save; + if (decoder_info.decoder_flags & LIBRAW_DECODER_OWNALLOC) + { + // x3f foveon decoder only: do nothing + } + else if (decoder_info.decoder_flags & LIBRAW_DECODER_SINAR4SHOT && + imgdata.params.shot_select == 0) + { + imgdata.rawdata.raw_alloc = imgdata.image; + imgdata.rawdata.color4_image = (ushort(*)[4])imgdata.rawdata.raw_alloc; + imgdata.image = 0; + } + else if (!(imgdata.idata.filters || + P1.colors == 1)) // legacy decoder, ownalloc handled above + { + // successfully decoded legacy image, attach image to raw_alloc + imgdata.rawdata.raw_alloc = imgdata.image; + imgdata.rawdata.color4_image = (ushort(*)[4])imgdata.rawdata.raw_alloc; + imgdata.image = 0; + // Restore saved values. Note: Foveon have masked frame + // Other 4-color legacy data: no borders + if (!(libraw_internal_data.unpacker_data.load_flags & 256) && + !(decoder_info.decoder_flags & LIBRAW_DECODER_ADOBECOPYPIXEL) && + !(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY_WITH_MARGINS)) + { + S.raw_width = S.width; + S.left_margin = 0; + S.raw_height = S.height; + S.top_margin = 0; + } + } + } + + if (imgdata.rawdata.raw_image) + crop_masked_pixels(); // calculate black levels + + // recover image sizes + S.iwidth = save_iwidth; + S.iheight = save_iheight; + IO.shrink = save_shrink; + + // adjust black to possible maximum + unsigned int i = C.cblack[3]; + unsigned int c; + for (c = 0; c < 3; c++) + if (i > C.cblack[c]) + i = C.cblack[c]; + for (c = 0; c < 4; c++) + C.cblack[c] -= i; + C.black += i; + + // Save color,sizes and internal data into raw_image fields + memmove(&imgdata.rawdata.color, &imgdata.color, sizeof(imgdata.color)); + memmove(&imgdata.rawdata.sizes, &imgdata.sizes, sizeof(imgdata.sizes)); + memmove(&imgdata.rawdata.iparams, &imgdata.idata, sizeof(imgdata.idata)); + memmove(&imgdata.rawdata.ioparams, + &libraw_internal_data.internal_output_params, + sizeof(libraw_internal_data.internal_output_params)); + + SET_PROC_FLAG(LIBRAW_PROGRESS_LOAD_RAW); + RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW, 1, 2); + + return 0; + } + catch (const LibRaw_exceptions& err) + { + EXCEPTION_HANDLER(err); + } + catch (const std::exception& ee) + { + EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/decoders/unpack_thumb.cpp libkdcraw/libkdcraw/libraw/src/decoders/unpack_thumb.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/decoders/unpack_thumb.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/decoders/unpack_thumb.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,360 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#ifndef NO_JPEG +struct jpegErrorManager +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +static void jpegErrorExit(j_common_ptr cinfo) +{ + jpegErrorManager *myerr = (jpegErrorManager *)cinfo->err; + longjmp(myerr->setjmp_buffer, 1); +} +#endif + +int LibRaw::unpack_thumb(void) +{ + CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); + CHECK_ORDER_BIT(LIBRAW_PROGRESS_THUMB_LOAD); + +#define THUMB_SIZE_CHECKT(A) \ + do { \ + if (INT64(A) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) throw LIBRAW_EXCEPTION_IO_CORRUPT; \ + if (INT64(A) > 0 && INT64(A) < 64ULL) throw LIBRAW_EXCEPTION_IO_CORRUPT; \ + } while (0) + +#define THUMB_SIZE_CHECKTNZ(A) \ + do { \ + if (INT64(A) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) throw LIBRAW_EXCEPTION_IO_CORRUPT; \ + if (INT64(A) < 64ULL) throw LIBRAW_EXCEPTION_IO_CORRUPT; \ + } while (0) + + +#define THUMB_SIZE_CHECKWH(W,H) \ + do { \ + if (INT64(W)*INT64(H) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) throw LIBRAW_EXCEPTION_IO_CORRUPT; \ + if (INT64(W)*INT64(H) < 64ULL) throw LIBRAW_EXCEPTION_IO_CORRUPT; \ + } while (0) + + try + { + if (!libraw_internal_data.internal_data.input) + return LIBRAW_INPUT_CLOSED; + + int t_colors = libraw_internal_data.unpacker_data.thumb_misc >> 5 & 7; + int t_bytesps = (libraw_internal_data.unpacker_data.thumb_misc & 31) / 8; + + if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && + load_raw == &LibRaw::broadcom_load_raw) // RPi + ) + { + return LIBRAW_NO_THUMBNAIL; + } + else if (thumb_load_raw) + { + kodak_thumb_loader(); + T.tformat = LIBRAW_THUMBNAIL_BITMAP; + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } + else + { +#ifdef USE_X3FTOOLS + if (write_thumb == &LibRaw::x3f_thumb_loader) + { + INT64 tsize = x3f_thumb_size(); + if (tsize < 2048 || INT64(ID.toffset) + tsize < 1) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + if (INT64(ID.toffset) + tsize > ID.input->size() + THUMB_READ_BEYOND) + throw LIBRAW_EXCEPTION_IO_EOF; + THUMB_SIZE_CHECKT(tsize); + } +#else + if (0) {} +#endif + else + { + if (INT64(ID.toffset) + INT64(T.tlength) < 1) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + if (INT64(ID.toffset) + INT64(T.tlength) > + ID.input->size() + THUMB_READ_BEYOND) + throw LIBRAW_EXCEPTION_IO_EOF; + } + + ID.input->seek(ID.toffset, SEEK_SET); + if (write_thumb == &LibRaw::jpeg_thumb) + { + THUMB_SIZE_CHECKTNZ(T.tlength); + + if (T.thumb) + free(T.thumb); + T.thumb = (char *)malloc(T.tlength); + merror(T.thumb, "jpeg_thumb()"); + ID.input->read(T.thumb, 1, T.tlength); + unsigned char *tthumb = (unsigned char *)T.thumb; + tthumb[0] = 0xff; + tthumb[1] = 0xd8; +#ifdef NO_JPEG + T.tcolors = 3; +#else + { + jpegErrorManager jerr; + struct jpeg_decompress_struct cinfo; + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = jpegErrorExit; + if (setjmp(jerr.setjmp_buffer)) + { + err2: + // Error in original JPEG thumb, read it again because + // original bytes 0-1 was damaged above + jpeg_destroy_decompress(&cinfo); + T.tcolors = 3; + T.tformat = LIBRAW_THUMBNAIL_UNKNOWN; + ID.input->seek(ID.toffset, SEEK_SET); + ID.input->read(T.thumb, 1, T.tlength); + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } + jpeg_create_decompress(&cinfo); + jpeg_mem_src(&cinfo, (unsigned char *)T.thumb, T.tlength); + int rc = jpeg_read_header(&cinfo, TRUE); + if (rc != 1) + goto err2; + T.tcolors = (cinfo.num_components > 0 && cinfo.num_components <= 3) + ? cinfo.num_components + : 3; + jpeg_destroy_decompress(&cinfo); + } +#endif + T.tformat = LIBRAW_THUMBNAIL_JPEG; + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } + else if (write_thumb == &LibRaw::layer_thumb) + { + int colors = libraw_internal_data.unpacker_data.thumb_misc >> 5 & 7; + if (colors != 1 && colors != 3) + return LIBRAW_UNSUPPORTED_THUMBNAIL; + + THUMB_SIZE_CHECKWH(T.twidth, T.theight); + + int tlength = T.twidth * T.theight; + if (T.thumb) + free(T.thumb); + T.thumb = (char *)calloc(colors, tlength); + merror(T.thumb, "layer_thumb()"); + unsigned char *tbuf = (unsigned char *)calloc(colors, tlength); + merror(tbuf, "layer_thumb()"); + ID.input->read(tbuf, colors, T.tlength); + if (libraw_internal_data.unpacker_data.thumb_misc >> 8 && + colors == 3) // GRB order + for (int i = 0; i < tlength; i++) + { + T.thumb[i * 3] = tbuf[i + tlength]; + T.thumb[i * 3 + 1] = tbuf[i]; + T.thumb[i * 3 + 2] = tbuf[i + 2 * tlength]; + } + else if (colors == 3) // RGB or 1-channel + for (int i = 0; i < tlength; i++) + { + T.thumb[i * 3] = tbuf[i]; + T.thumb[i * 3 + 1] = tbuf[i + tlength]; + T.thumb[i * 3 + 2] = tbuf[i + 2 * tlength]; + } + else if (colors == 1) + { + free(T.thumb); + T.thumb = (char *)tbuf; + tbuf = 0; + } + if (tbuf) + free(tbuf); + T.tcolors = colors; + T.tlength = colors * tlength; + T.tformat = LIBRAW_THUMBNAIL_BITMAP; + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } + else if (write_thumb == &LibRaw::rollei_thumb) + { + int i; + THUMB_SIZE_CHECKWH(T.twidth, T.theight); + int tlength = T.twidth * T.theight; + if (T.thumb) + free(T.thumb); + T.tcolors = 3; + T.thumb = (char *)calloc(T.tcolors, tlength); + merror(T.thumb, "layer_thumb()"); + unsigned short *tbuf = (unsigned short *)calloc(2, tlength); + merror(tbuf, "layer_thumb()"); + read_shorts(tbuf, tlength); + for (i = 0; i < tlength; i++) + { + T.thumb[i * 3] = (tbuf[i] << 3) & 0xff; + T.thumb[i * 3 + 1] = (tbuf[i] >> 5 << 2) & 0xff; + T.thumb[i * 3 + 2] = (tbuf[i] >> 11 << 3) & 0xff; + } + free(tbuf); + T.tlength = T.tcolors * tlength; + T.tformat = LIBRAW_THUMBNAIL_BITMAP; + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } + else if (write_thumb == &LibRaw::ppm_thumb) + { + if (t_bytesps > 1) + throw LIBRAW_EXCEPTION_IO_CORRUPT; // 8-bit thumb, but parsed for more + // bits + THUMB_SIZE_CHECKWH(T.twidth, T.theight); + int t_length = T.twidth * T.theight * t_colors; + + if (T.tlength && + (int)T.tlength < t_length) // try to find tiff ifd with needed offset + { + int pifd = find_ifd_by_offset(libraw_internal_data.internal_data.toffset); + if (pifd >= 0 && tiff_ifd[pifd].strip_offsets_count && + tiff_ifd[pifd].strip_byte_counts_count) + { + // We found it, calculate final size + unsigned total_size = 0; + for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count; i++) + total_size += tiff_ifd[pifd].strip_byte_counts[i]; + if (total_size != (unsigned)t_length) // recalculate colors + { + if (total_size == T.twidth * T.tlength * 3) + T.tcolors = 3; + else if (total_size == T.twidth * T.tlength) + T.tcolors = 1; + } + T.tlength = total_size; + THUMB_SIZE_CHECKTNZ(T.tlength); + if (T.thumb) + free(T.thumb); + T.thumb = (char *)malloc(T.tlength); + merror(T.thumb, "ppm_thumb()"); + + char *dest = T.thumb; + INT64 pos = ID.input->tell(); + + for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count && + i < tiff_ifd[pifd].strip_offsets_count; + i++) + { + int remain = T.tlength; + int sz = tiff_ifd[pifd].strip_byte_counts[i]; + int off = tiff_ifd[pifd].strip_offsets[i]; + if (off >= 0 && off + sz <= ID.input->size() && sz <= remain) + { + ID.input->seek(off, SEEK_SET); + ID.input->read(dest, sz, 1); + remain -= sz; + dest += sz; + } + } + ID.input->seek(pos, SEEK_SET); + T.tformat = LIBRAW_THUMBNAIL_BITMAP; + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } + } + + if (!T.tlength) + T.tlength = t_length; + if (T.thumb) + free(T.thumb); + + THUMB_SIZE_CHECKTNZ(T.tlength); + + T.thumb = (char *)malloc(T.tlength); + if (!T.tcolors) + T.tcolors = t_colors; + merror(T.thumb, "ppm_thumb()"); + + ID.input->read(T.thumb, 1, T.tlength); + + T.tformat = LIBRAW_THUMBNAIL_BITMAP; + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } + else if (write_thumb == &LibRaw::ppm16_thumb) + { + if (t_bytesps > 2) + throw LIBRAW_EXCEPTION_IO_CORRUPT; // 16-bit thumb, but parsed for + // more bits + int o_bps = (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_USE_PPM16_THUMBS) + ? 2 + : 1; + int o_length = T.twidth * T.theight * t_colors * o_bps; + int i_length = T.twidth * T.theight * t_colors * 2; + if (!T.tlength) + T.tlength = o_length; + THUMB_SIZE_CHECKTNZ(o_length); + THUMB_SIZE_CHECKTNZ(i_length); + THUMB_SIZE_CHECKTNZ(T.tlength); + + ushort *t_thumb = (ushort *)calloc(i_length, 1); + ID.input->read(t_thumb, 1, i_length); + if ((libraw_internal_data.unpacker_data.order == 0x4949) == + (ntohs(0x1234) == 0x1234)) + swab((char *)t_thumb, (char *)t_thumb, i_length); + + if (T.thumb) + free(T.thumb); + if ((imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_USE_PPM16_THUMBS)) + { + T.thumb = (char *)t_thumb; + T.tformat = LIBRAW_THUMBNAIL_BITMAP16; + } + else + { + T.thumb = (char *)malloc(o_length); + merror(T.thumb, "ppm_thumb()"); + for (int i = 0; i < o_length; i++) + T.thumb[i] = t_thumb[i] >> 8; + free(t_thumb); + T.tformat = LIBRAW_THUMBNAIL_BITMAP; + } + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } +#ifdef USE_X3FTOOLS + else if (write_thumb == &LibRaw::x3f_thumb_loader) + { + x3f_thumb_loader(); + SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); + return 0; + } +#endif + else + { + return LIBRAW_UNSUPPORTED_THUMBNAIL; + } + } + // last resort + return LIBRAW_UNSUPPORTED_THUMBNAIL; + } + catch (LibRaw_exceptions err) + { + EXCEPTION_HANDLER(err); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/demosaic/aahd_demosaic.cpp libkdcraw/libkdcraw/libraw/src/demosaic/aahd_demosaic.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/demosaic/aahd_demosaic.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/demosaic/aahd_demosaic.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,787 @@ +/* -*- C++ -*- + * File: aahd_demosaic.cpp + * Copyright 2013 Anton Petrusevich + * Created: Wed May 15, 2013 + * + * This code is licensed under one of two licenses as you choose: + * + * 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + * (See file LICENSE.LGPL provided in LibRaw distribution archive for + * details). + * + * 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + * (See file LICENSE.CDDL provided in LibRaw distribution archive for + * details). + * + */ + +#include "../../internal/dmp_include.h" + +typedef ushort ushort3[3]; +typedef int int3[3]; + +#ifndef Pnw +#define Pnw (-1 - nr_width) +#define Pn (-nr_width) +#define Pne (+1 - nr_width) +#define Pe (+1) +#define Pse (+1 + nr_width) +#define Ps (+nr_width) +#define Psw (-1 + nr_width) +#define Pw (-1) +#endif + +struct AAHD +{ + int nr_height, nr_width; + static const int nr_margin = 4; + static const int Thot = 4; + static const int Tdead = 4; + static const int OverFraction = 8; + ushort3 *rgb_ahd[2]; + int3 *yuv[2]; + char *ndir, *homo[2]; + ushort channel_maximum[3], channels_max; + ushort channel_minimum[3]; + static const float yuv_coeff[3][3]; + static float gammaLUT[0x10000]; + float yuv_cam[3][3]; + LibRaw &libraw; + enum + { + HVSH = 1, + HOR = 2, + VER = 4, + HORSH = HOR | HVSH, + VERSH = VER | HVSH, + HOT = 8 + }; + + static inline float calc_dist(int c1, int c2) throw() + { + return c1 > c2 ? (float)c1 / c2 : (float)c2 / c1; + } + int inline Y(ushort3 &rgb) throw() + { + return yuv_cam[0][0] * rgb[0] + yuv_cam[0][1] * rgb[1] + + yuv_cam[0][2] * rgb[2]; + } + int inline U(ushort3 &rgb) throw() + { + return yuv_cam[1][0] * rgb[0] + yuv_cam[1][1] * rgb[1] + + yuv_cam[1][2] * rgb[2]; + } + int inline V(ushort3 &rgb) throw() + { + return yuv_cam[2][0] * rgb[0] + yuv_cam[2][1] * rgb[1] + + yuv_cam[2][2] * rgb[2]; + } + inline int nr_offset(int row, int col) throw() + { + return (row * nr_width + col); + } + ~AAHD(); + AAHD(LibRaw &_libraw); + void make_ahd_greens(); + void make_ahd_gline(int i); + void make_ahd_rb(); + void make_ahd_rb_hv(int i); + void make_ahd_rb_last(int i); + void evaluate_ahd(); + void combine_image(); + void hide_hots(); + void refine_hv_dirs(); + void refine_hv_dirs(int i, int js); + void refine_ihv_dirs(int i); + void illustrate_dirs(); + void illustrate_dline(int i); +}; + +const float AAHD::yuv_coeff[3][3] = { + // YPbPr + // { + // 0.299f, + // 0.587f, + // 0.114f }, + // { + // -0.168736, + // -0.331264f, + // 0.5f }, + // { + // 0.5f, + // -0.418688f, + // -0.081312f } + // + // Rec. 2020 + // Y'= 0,2627R' + 0,6780G' + 0,0593B' + // U = (B-Y)/1.8814 = (-0,2627R' - 0,6780G' + 0.9407B) / 1.8814 = + //-0.13963R - 0.36037G + 0.5B + // V = (R-Y)/1.4647 = (0.7373R - 0,6780G - 0,0593B) / 1.4647 = 0.5R - + //0.4629G - 0.04049B + {+0.2627f, +0.6780f, +0.0593f}, + {-0.13963f, -0.36037f, +0.5f}, + {+0.5034f, -0.4629f, -0.0405f} + +}; + +float AAHD::gammaLUT[0x10000] = {-1.f}; + +AAHD::AAHD(LibRaw &_libraw) : libraw(_libraw) +{ + nr_height = libraw.imgdata.sizes.iheight + nr_margin * 2; + nr_width = libraw.imgdata.sizes.iwidth + nr_margin * 2; + rgb_ahd[0] = (ushort3 *)calloc(nr_height * nr_width, + (sizeof(ushort3) * 2 + sizeof(int3) * 2 + 3)); + if (!rgb_ahd[0]) + throw LIBRAW_EXCEPTION_ALLOC; + + rgb_ahd[1] = rgb_ahd[0] + nr_height * nr_width; + yuv[0] = (int3 *)(rgb_ahd[1] + nr_height * nr_width); + yuv[1] = yuv[0] + nr_height * nr_width; + ndir = (char *)(yuv[1] + nr_height * nr_width); + homo[0] = ndir + nr_height * nr_width; + homo[1] = homo[0] + nr_height * nr_width; + channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0; + channel_minimum[0] = libraw.imgdata.image[0][0]; + channel_minimum[1] = libraw.imgdata.image[0][1]; + channel_minimum[2] = libraw.imgdata.image[0][2]; + int iwidth = libraw.imgdata.sizes.iwidth; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + { + yuv_cam[i][j] = 0; + for (int k = 0; k < 3; ++k) + yuv_cam[i][j] += yuv_coeff[i][k] * libraw.imgdata.color.rgb_cam[k][j]; + } + if (gammaLUT[0] < -0.1f) + { + float r; + for (int i = 0; i < 0x10000; i++) + { + r = (float)i / 0x10000; + gammaLUT[i] = + 0x10000 * (r < 0.0181 ? 4.5f * r : 1.0993f * pow(r, 0.45f) - .0993f); + } + } + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + int col_cache[48]; + for (int j = 0; j < 48; ++j) + { + int c = libraw.COLOR(i, j); + if (c == 3) + c = 1; + col_cache[j] = c; + } + int moff = nr_offset(i + nr_margin, nr_margin); + for (int j = 0; j < iwidth; ++j, ++moff) + { + int c = col_cache[j % 48]; + unsigned short d = libraw.imgdata.image[i * iwidth + j][c]; + if (d != 0) + { + if (channel_maximum[c] < d) + channel_maximum[c] = d; + if (channel_minimum[c] > d) + channel_minimum[c] = d; + rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] = d; + } + } + } + channels_max = + MAX(MAX(channel_maximum[0], channel_maximum[1]), channel_maximum[2]); +} + +void AAHD::hide_hots() +{ + int iwidth = libraw.imgdata.sizes.iwidth; + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ мимо извеÑтного зелёного + * kc -- извеÑтный цвет в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + */ + int moff = nr_offset(i + nr_margin, nr_margin + js); + for (int j = js; j < iwidth; j += 2, moff += 2) + { + ushort3 *rgb = &rgb_ahd[0][moff]; + int c = rgb[0][kc]; + if ((c > rgb[2 * Pe][kc] && c > rgb[2 * Pw][kc] && c > rgb[2 * Pn][kc] && + c > rgb[2 * Ps][kc] && c > rgb[Pe][1] && c > rgb[Pw][1] && + c > rgb[Pn][1] && c > rgb[Ps][1]) || + (c < rgb[2 * Pe][kc] && c < rgb[2 * Pw][kc] && c < rgb[2 * Pn][kc] && + c < rgb[2 * Ps][kc] && c < rgb[Pe][1] && c < rgb[Pw][1] && + c < rgb[Pn][1] && c < rgb[Ps][1])) + { + int chot = c >> Thot; + int cdead = c << Tdead; + int avg = 0; + for (int k = -2; k < 3; k += 2) + for (int m = -2; m < 3; m += 2) + if (m == 0 && k == 0) + continue; + else + avg += rgb[nr_offset(k, m)][kc]; + avg /= 8; + if (chot > avg || cdead < avg) + { + ndir[moff] |= HOT; + int dh = + ABS(rgb[2 * Pw][kc] - rgb[2 * Pe][kc]) + + ABS(rgb[Pw][1] - rgb[Pe][1]) + + ABS(rgb[Pw][1] - rgb[Pe][1] + rgb[2 * Pe][kc] - rgb[2 * Pw][kc]); + int dv = + ABS(rgb[2 * Pn][kc] - rgb[2 * Ps][kc]) + + ABS(rgb[Pn][1] - rgb[Ps][1]) + + ABS(rgb[Pn][1] - rgb[Ps][1] + rgb[2 * Ps][kc] - rgb[2 * Pn][kc]); + int d; + if (dv > dh) + d = Pw; + else + d = Pn; + rgb_ahd[1][moff][kc] = rgb[0][kc] = + (rgb[+2 * d][kc] + rgb[-2 * d][kc]) / 2; + } + } + } + js ^= 1; + moff = nr_offset(i + nr_margin, nr_margin + js); + for (int j = js; j < iwidth; j += 2, moff += 2) + { + ushort3 *rgb = &rgb_ahd[0][moff]; + int c = rgb[0][1]; + if ((c > rgb[2 * Pe][1] && c > rgb[2 * Pw][1] && c > rgb[2 * Pn][1] && + c > rgb[2 * Ps][1] && c > rgb[Pe][kc] && c > rgb[Pw][kc] && + c > rgb[Pn][kc ^ 2] && c > rgb[Ps][kc ^ 2]) || + (c < rgb[2 * Pe][1] && c < rgb[2 * Pw][1] && c < rgb[2 * Pn][1] && + c < rgb[2 * Ps][1] && c < rgb[Pe][kc] && c < rgb[Pw][kc] && + c < rgb[Pn][kc ^ 2] && c < rgb[Ps][kc ^ 2])) + { + int chot = c >> Thot; + int cdead = c << Tdead; + int avg = 0; + for (int k = -2; k < 3; k += 2) + for (int m = -2; m < 3; m += 2) + if (k == 0 && m == 0) + continue; + else + avg += rgb[nr_offset(k, m)][1]; + avg /= 8; + if (chot > avg || cdead < avg) + { + ndir[moff] |= HOT; + int dh = + ABS(rgb[2 * Pw][1] - rgb[2 * Pe][1]) + + ABS(rgb[Pw][kc] - rgb[Pe][kc]) + + ABS(rgb[Pw][kc] - rgb[Pe][kc] + rgb[2 * Pe][1] - rgb[2 * Pw][1]); + int dv = ABS(rgb[2 * Pn][1] - rgb[2 * Ps][1]) + + ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2]) + + ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2] + rgb[2 * Ps][1] - + rgb[2 * Pn][1]); + int d; + if (dv > dh) + d = Pw; + else + d = Pn; + rgb_ahd[1][moff][1] = rgb[0][1] = + (rgb[+2 * d][1] + rgb[-2 * d][1]) / 2; + } + } + } + } +} + +const static double xyz_rgb[3][3] = {{0.412453, 0.357580, 0.180423}, + {0.212671, 0.715160, 0.072169}, + {0.019334, 0.119193, 0.950227}}; + +const static float d65_white[3] = {0.950456f, 1.0f, 1.088754f}; + +void AAHD::evaluate_ahd() +{ + int hvdir[4] = {Pw, Pe, Pn, Ps}; + /* + * YUV + * + */ + for (int d = 0; d < 2; ++d) + { + for (int i = 0; i < nr_width * nr_height; ++i) + { + ushort3 rgb; + for (int c = 0; c < 3; ++c) + { + rgb[c] = gammaLUT[rgb_ahd[d][i][c]]; + } + yuv[d][i][0] = Y(rgb); + yuv[d][i][1] = U(rgb); + yuv[d][i][2] = V(rgb); + } + } + /* */ + /* + * Lab + * + float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; + for (int i = 0; i < 0x10000; i++) { + r = i / 65535.0; + cbrt[i] = r > 0.008856 ? pow((double) r, (double) (1 / 3.0)) : 7.787 * r + 16 + / 116.0; + } + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) { + xyz_cam[i][j] = 0; + for (int k = 0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * libraw.imgdata.color.rgb_cam[k][j] / + d65_white[i]; + } + for (int d = 0; d < 2; ++d) + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { + int moff = nr_offset(i + nr_margin, nr_margin); + for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) { + xyz[0] = xyz[1] = xyz[2] = 0.5; + for (int c = 0; c < 3; c++) { + xyz[0] += xyz_cam[0][c] * rgb_ahd[d][moff][c]; + xyz[1] += xyz_cam[1][c] * rgb_ahd[d][moff][c]; + xyz[2] += xyz_cam[2][c] * rgb_ahd[d][moff][c]; + } + xyz[0] = cbrt[CLIP((int) xyz[0])]; + xyz[1] = cbrt[CLIP((int) xyz[1])]; + xyz[2] = cbrt[CLIP((int) xyz[2])]; + yuv[d][moff][0] = 64 * (116 * xyz[1] - 16); + yuv[d][moff][1] = 64 * 500 * (xyz[0] - xyz[1]); + yuv[d][moff][2] = 64 * 200 * (xyz[1] - xyz[2]); + } + } + * Lab */ + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + int moff = nr_offset(i + nr_margin, nr_margin); + for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) + { + int3 *ynr; + float ydiff[2][4]; + int uvdiff[2][4]; + for (int d = 0; d < 2; ++d) + { + ynr = &yuv[d][moff]; + for (int k = 0; k < 4; k++) + { + ydiff[d][k] = ABS(ynr[0][0] - ynr[hvdir[k]][0]); + uvdiff[d][k] = SQR(ynr[0][1] - ynr[hvdir[k]][1]) + + SQR(ynr[0][2] - ynr[hvdir[k]][2]); + } + } + float yeps = + MIN(MAX(ydiff[0][0], ydiff[0][1]), MAX(ydiff[1][2], ydiff[1][3])); + int uveps = + MIN(MAX(uvdiff[0][0], uvdiff[0][1]), MAX(uvdiff[1][2], uvdiff[1][3])); + for (int d = 0; d < 2; d++) + { + ynr = &yuv[d][moff]; + for (int k = 0; k < 4; k++) + if (ydiff[d][k] <= yeps && uvdiff[d][k] <= uveps) + { + homo[d][moff + hvdir[k]]++; + if (k / 2 == d) + { + // еÑли в Ñонаправленном направлении интеполÑции Ñледующие точки + // так же гомогенны, учтём их тоже + for (int m = 2; m < 4; ++m) + { + int hvd = m * hvdir[k]; + if (ABS(ynr[0][0] - ynr[hvd][0]) < yeps && + SQR(ynr[0][1] - ynr[hvd][1]) + + SQR(ynr[0][2] - ynr[hvd][2]) < + uveps) + { + homo[d][moff + hvd]++; + } + else + break; + } + } + } + } + } + } + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + int moff = nr_offset(i + nr_margin, nr_margin); + for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) + { + char hm[2]; + for (int d = 0; d < 2; d++) + { + hm[d] = 0; + char *hh = &homo[d][moff]; + for (int hx = -1; hx < 2; hx++) + for (int hy = -1; hy < 2; hy++) + hm[d] += hh[nr_offset(hy, hx)]; + } + char d = 0; + if (hm[0] != hm[1]) + { + if (hm[1] > hm[0]) + { + d = VERSH; + } + else + { + d = HORSH; + } + } + else + { + int3 *ynr = &yuv[1][moff]; + int gv = SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]); + gv += SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) + + SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2]); + ynr = &yuv[1][moff + Pn]; + gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) + + SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) + + SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) / + 2; + ynr = &yuv[1][moff + Ps]; + gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) + + SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) + + SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) / + 2; + ynr = &yuv[0][moff]; + int gh = SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]); + gh += SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) + + SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2]); + ynr = &yuv[0][moff + Pw]; + gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) + + SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) + + SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) / + 2; + ynr = &yuv[0][moff + Pe]; + gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) + + SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) + + SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) / + 2; + if (gv > gh) + d = HOR; + else + d = VER; + } + ndir[moff] |= d; + } + } +} + +void AAHD::combine_image() +{ + for (int i = 0, i_out = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + int moff = nr_offset(i + nr_margin, nr_margin); + for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff, ++i_out) + { + if (ndir[moff] & HOT) + { + int c = libraw.COLOR(i, j); + rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] = + libraw.imgdata.image[i_out][c]; + } + if (ndir[moff] & VER) + { + libraw.imgdata.image[i_out][0] = rgb_ahd[1][moff][0]; + libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] = + rgb_ahd[1][moff][1]; + libraw.imgdata.image[i_out][2] = rgb_ahd[1][moff][2]; + } + else + { + libraw.imgdata.image[i_out][0] = rgb_ahd[0][moff][0]; + libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] = + rgb_ahd[0][moff][1]; + libraw.imgdata.image[i_out][2] = rgb_ahd[0][moff][2]; + } + } + } +} + +void AAHD::refine_hv_dirs() +{ + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + refine_hv_dirs(i, i & 1); + } + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + refine_hv_dirs(i, (i & 1) ^ 1); + } + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + refine_ihv_dirs(i); + } +} + +void AAHD::refine_ihv_dirs(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int moff = nr_offset(i + nr_margin, nr_margin); + for (int j = 0; j < iwidth; j++, ++moff) + { + if (ndir[moff] & HVSH) + continue; + int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) + + (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER); + int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) + + (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR); + nv /= VER; + nh /= HOR; + if ((ndir[moff] & VER) && nh > 3) + { + ndir[moff] &= ~VER; + ndir[moff] |= HOR; + } + if ((ndir[moff] & HOR) && nv > 3) + { + ndir[moff] &= ~HOR; + ndir[moff] |= VER; + } + } +} + +void AAHD::refine_hv_dirs(int i, int js) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int moff = nr_offset(i + nr_margin, nr_margin + js); + for (int j = js; j < iwidth; j += 2, moff += 2) + { + int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) + + (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER); + int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) + + (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR); + bool codir = (ndir[moff] & VER) + ? ((ndir[moff + Pn] & VER) || (ndir[moff + Ps] & VER)) + : ((ndir[moff + Pw] & HOR) || (ndir[moff + Pe] & HOR)); + nv /= VER; + nh /= HOR; + if ((ndir[moff] & VER) && (nh > 2 && !codir)) + { + ndir[moff] &= ~VER; + ndir[moff] |= HOR; + } + if ((ndir[moff] & HOR) && (nv > 2 && !codir)) + { + ndir[moff] &= ~HOR; + ndir[moff] |= VER; + } + } +} + +/* + * вычиÑление недоÑтающих зелёных точек. + */ +void AAHD::make_ahd_greens() +{ + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_ahd_gline(i); + } +} + +void AAHD::make_ahd_gline(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ мимо извеÑтного зелёного + * kc -- извеÑтный цвет в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + */ + int hvdir[2] = {Pe, Ps}; + for (int d = 0; d < 2; ++d) + { + int moff = nr_offset(i + nr_margin, nr_margin + js); + for (int j = js; j < iwidth; j += 2, moff += 2) + { + ushort3 *cnr; + cnr = &rgb_ahd[d][moff]; + int h1 = 2 * cnr[-hvdir[d]][1] - int(cnr[-2 * hvdir[d]][kc] + cnr[0][kc]); + int h2 = 2 * cnr[+hvdir[d]][1] - int(cnr[+2 * hvdir[d]][kc] + cnr[0][kc]); + int h0 = (h1 + h2) / 4; + int eg = cnr[0][kc] + h0; + int min = MIN(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]); + int max = MAX(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]); + min -= min / OverFraction; + max += max / OverFraction; + if (eg < min) + eg = min - sqrt(float(min - eg)); + else if (eg > max) + eg = max + sqrt(float(eg - max)); + if (eg > channel_maximum[1]) + eg = channel_maximum[1]; + else if (eg < channel_minimum[1]) + eg = channel_minimum[1]; + cnr[0][1] = eg; + } + } +} + +/* + * Ð¾Ñ‚Ð»Ð°Ð´Ð¾Ñ‡Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ + */ + +void AAHD::illustrate_dirs() +{ + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + illustrate_dline(i); + } +} + +void AAHD::illustrate_dline(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + for (int j = 0; j < iwidth; j++) + { + int x = j + nr_margin; + int y = i + nr_margin; + rgb_ahd[1][nr_offset(y, x)][0] = rgb_ahd[1][nr_offset(y, x)][1] = + rgb_ahd[1][nr_offset(y, x)][2] = rgb_ahd[0][nr_offset(y, x)][0] = + rgb_ahd[0][nr_offset(y, x)][1] = rgb_ahd[0][nr_offset(y, x)][2] = 0; + int l = ndir[nr_offset(y, x)] & HVSH; + l /= HVSH; + if (ndir[nr_offset(y, x)] & VER) + rgb_ahd[1][nr_offset(y, x)][0] = + l * channel_maximum[0] / 4 + channel_maximum[0] / 4; + else + rgb_ahd[0][nr_offset(y, x)][2] = + l * channel_maximum[2] / 4 + channel_maximum[2] / 4; + } +} + +void AAHD::make_ahd_rb_hv(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + js ^= 1; // Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð¾Ñ€Ð´Ð¸Ð½Ð°Ñ‚Ð° зелёного + int hvdir[2] = {Pe, Ps}; + // интерполÑÑ†Ð¸Ñ Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ñ‹Ñ… вертикально и горизонтальных горизонтально + for (int j = js; j < iwidth; j += 2) + { + int x = j + nr_margin; + int y = i + nr_margin; + int moff = nr_offset(y, x); + for (int d = 0; d < 2; ++d) + { + ushort3 *cnr; + cnr = &rgb_ahd[d][moff]; + int c = kc ^ (d << 1); // цвет ÑоответÑвенного направлениÑ, Ð´Ð»Ñ + // горизонтального c = kc, Ð´Ð»Ñ Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ c=kc^2 + int h1 = cnr[-hvdir[d]][c] - cnr[-hvdir[d]][1]; + int h2 = cnr[+hvdir[d]][c] - cnr[+hvdir[d]][1]; + int h0 = (h1 + h2) / 2; + int eg = cnr[0][1] + h0; + // int min = MIN(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]); + // int max = MAX(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]); + // min -= min / OverFraction; + // max += max / OverFraction; + // if (eg < min) + // eg = min - sqrt(min - eg); + // else if (eg > max) + // eg = max + sqrt(eg - max); + if (eg > channel_maximum[c]) + eg = channel_maximum[c]; + else if (eg < channel_minimum[c]) + eg = channel_minimum[c]; + cnr[0][c] = eg; + } + } +} + +void AAHD::make_ahd_rb() +{ + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_ahd_rb_hv(i); + } + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_ahd_rb_last(i); + } +} + +void AAHD::make_ahd_rb_last(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ мимо извеÑтного зелёного + * kc -- извеÑтный цвет в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + */ + int dirs[2][3] = {{Pnw, Pn, Pne}, {Pnw, Pw, Psw}}; + int moff = nr_offset(i + nr_margin, nr_margin); + for (int j = 0; j < iwidth; j++) + { + for (int d = 0; d < 2; ++d) + { + ushort3 *cnr; + cnr = &rgb_ahd[d][moff + j]; + int c = kc ^ 2; + if ((j & 1) != js) + { + // точка зелёного, Ð´Ð»Ñ Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½ÑƒÐ¶ÐµÐ½ альтернативный + // Ñтрочному цвет + c ^= d << 1; + } + int bh, bk; + int bgd = 0; + for (int k = 0; k < 3; ++k) + for (int h = 0; h < 3; ++h) + { + // градиент зелёного Ð¿Ð»ÑŽÑ Ð³Ñ€Ð°Ð´Ð¸ÐµÐ½Ñ‚ {r,b} + int gd = + ABS(2 * cnr[0][1] - (cnr[+dirs[d][k]][1] + cnr[-dirs[d][h]][1])) + + ABS(cnr[+dirs[d][k]][c] - cnr[-dirs[d][h]][c]) / 4 + + ABS(cnr[+dirs[d][k]][c] - cnr[+dirs[d][k]][1] + + cnr[-dirs[d][h]][1] - cnr[-dirs[d][h]][c]) / + 4; + if (bgd == 0 || gd < bgd) + { + bgd = gd; + bh = h; + bk = k; + } + } + int h1 = cnr[+dirs[d][bk]][c] - cnr[+dirs[d][bk]][1]; + int h2 = cnr[-dirs[d][bh]][c] - cnr[-dirs[d][bh]][1]; + int eg = cnr[0][1] + (h1 + h2) / 2; + // int min = MIN(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]); + // int max = MAX(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]); + // min -= min / OverFraction; + // max += max / OverFraction; + // if (eg < min) + // eg = min - sqrt(min - eg); + // else if (eg > max) + // eg = max + sqrt(eg - max); + if (eg > channel_maximum[c]) + eg = channel_maximum[c]; + else if (eg < channel_minimum[c]) + eg = channel_minimum[c]; + cnr[0][c] = eg; + } + } +} + +AAHD::~AAHD() { free(rgb_ahd[0]); } + +void LibRaw::aahd_interpolate() +{ + AAHD aahd(*this); + aahd.hide_hots(); + aahd.make_ahd_greens(); + aahd.make_ahd_rb(); + aahd.evaluate_ahd(); + aahd.refine_hv_dirs(); + // aahd.illustrate_dirs(); + aahd.combine_image(); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/demosaic/ahd_demosaic.cpp libkdcraw/libkdcraw/libraw/src/demosaic/ahd_demosaic.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/demosaic/ahd_demosaic.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/demosaic/ahd_demosaic.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,354 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +/* + Adaptive Homogeneity-Directed interpolation is based on + the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. + */ + +void LibRaw::cielab(ushort rgb[3], short lab[3]) +{ + int c, i, j, k; + float r, xyz[3]; +#ifdef LIBRAW_NOTHREADS + static float cbrt[0x10000], xyz_cam[3][4]; +#else +#define cbrt tls->ahd_data.cbrt +#define xyz_cam tls->ahd_data.xyz_cam +#endif + + if (!rgb) + { +#ifndef LIBRAW_NOTHREADS + if (cbrt[0] < -1.0f) +#endif + for (i = 0; i < 0x10000; i++) + { + r = i / 65535.0; + cbrt[i] = + r > 0.008856 ? pow(r, 1.f / 3.0f) : 7.787f * r + 16.f / 116.0f; + } + for (i = 0; i < 3; i++) + for (j = 0; j < colors; j++) + for (xyz_cam[i][j] = k = 0; k < 3; k++) + xyz_cam[i][j] += LibRaw_constants::xyz_rgb[i][k] * rgb_cam[k][j] / + LibRaw_constants::d65_white[i]; + return; + } + xyz[0] = xyz[1] = xyz[2] = 0.5; + FORCC + { + xyz[0] += xyz_cam[0][c] * rgb[c]; + xyz[1] += xyz_cam[1][c] * rgb[c]; + xyz[2] += xyz_cam[2][c] * rgb[c]; + } + xyz[0] = cbrt[CLIP((int)xyz[0])]; + xyz[1] = cbrt[CLIP((int)xyz[1])]; + xyz[2] = cbrt[CLIP((int)xyz[2])]; + lab[0] = 64 * (116 * xyz[1] - 16); + lab[1] = 64 * 500 * (xyz[0] - xyz[1]); + lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +#ifndef LIBRAW_NOTHREADS +#undef cbrt +#undef xyz_cam +#endif +} + +void LibRaw::ahd_interpolate_green_h_and_v( + int top, int left, ushort (*out_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3]) +{ + int row, col; + int c, val; + ushort(*pix)[4]; + const int rowlimit = MIN(top + LIBRAW_AHD_TILE, height - 2); + const int collimit = MIN(left + LIBRAW_AHD_TILE, width - 2); + + for (row = top; row < rowlimit; row++) + { + col = left + (FC(row, left) & 1); + for (c = FC(row, col); col < collimit; 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; + out_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; + out_rgb[1][row - top][col - left][1] = + ULIM(val, pix[-width][1], pix[width][1]); + } + } +} +void LibRaw::ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab( + int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][3], + short (*out_lab)[LIBRAW_AHD_TILE][3]) +{ + unsigned row, col; + int c, val; + ushort(*pix)[4]; + ushort(*rix)[3]; + short(*lix)[3]; + const unsigned num_pix_per_row = 4 * width; + const unsigned rowlimit = MIN(top + LIBRAW_AHD_TILE - 1, height - 3); + const unsigned collimit = MIN(left + LIBRAW_AHD_TILE - 1, width - 3); + ushort *pix_above; + ushort *pix_below; + int t1, t2; + + for (row = top + 1; row < rowlimit; row++) + { + pix = image + row * width + left; + rix = &inout_rgb[row - top][0]; + lix = &out_lab[row - top][0]; + + for (col = left + 1; col < collimit; col++) + { + pix++; + pix_above = &pix[0][0] - num_pix_per_row; + pix_below = &pix[0][0] + num_pix_per_row; + rix++; + lix++; + + c = 2 - FC(row, col); + + if (c == 1) + { + c = FC(row + 1, col); + t1 = 2 - c; + val = pix[0][1] + + ((pix[-1][t1] + pix[1][t1] - rix[-1][1] - rix[1][1]) >> 1); + rix[0][t1] = CLIP(val); + val = + pix[0][1] + ((pix_above[c] + pix_below[c] - + rix[-LIBRAW_AHD_TILE][1] - rix[LIBRAW_AHD_TILE][1]) >> + 1); + } + else + { + t1 = -4 + c; /* -4+c: pixel of color c to the left */ + t2 = 4 + c; /* 4+c: pixel of color c to the right */ + val = rix[0][1] + + ((pix_above[t1] + pix_above[t2] + pix_below[t1] + pix_below[t2] - + rix[-LIBRAW_AHD_TILE - 1][1] - rix[-LIBRAW_AHD_TILE + 1][1] - + rix[+LIBRAW_AHD_TILE - 1][1] - rix[+LIBRAW_AHD_TILE + 1][1] + + 1) >> + 2); + } + rix[0][c] = CLIP(val); + c = FC(row, col); + rix[0][c] = pix[0][c]; + cielab(rix[0], lix[0]); + } + } +} +void LibRaw::ahd_interpolate_r_and_b_and_convert_to_cielab( + int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], + short (*out_lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3]) +{ + int direction; + for (direction = 0; direction < 2; direction++) + { + ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab( + top, left, inout_rgb[direction], out_lab[direction]); + } +} + +void LibRaw::ahd_interpolate_build_homogeneity_map( + int top, int left, short (*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], + char (*out_homogeneity_map)[LIBRAW_AHD_TILE][2]) +{ + int row, col; + int tr; + int direction; + int i; + short(*lix)[3]; + short(*lixs[2])[3]; + short *adjacent_lix; + unsigned ldiff[2][4], abdiff[2][4], leps, abeps; + static const int dir[4] = {-1, 1, -LIBRAW_AHD_TILE, LIBRAW_AHD_TILE}; + const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 2, height - 4); + const int collimit = MIN(left + LIBRAW_AHD_TILE - 2, width - 4); + int homogeneity; + char(*homogeneity_map_p)[2]; + + memset(out_homogeneity_map, 0, 2 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE); + + for (row = top + 2; row < rowlimit; row++) + { + tr = row - top; + homogeneity_map_p = &out_homogeneity_map[tr][1]; + for (direction = 0; direction < 2; direction++) + { + lixs[direction] = &lab[direction][tr][1]; + } + + for (col = left + 2; col < collimit; col++) + { + homogeneity_map_p++; + + for (direction = 0; direction < 2; direction++) + { + lix = ++lixs[direction]; + for (i = 0; i < 4; i++) + { + adjacent_lix = lix[dir[i]]; + ldiff[direction][i] = ABS(lix[0][0] - adjacent_lix[0]); + abdiff[direction][i] = SQR(lix[0][1] - adjacent_lix[1]) + + SQR(lix[0][2] - adjacent_lix[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 (direction = 0; direction < 2; direction++) + { + homogeneity = 0; + for (i = 0; i < 4; i++) + { + if (ldiff[direction][i] <= leps && abdiff[direction][i] <= abeps) + { + homogeneity++; + } + } + homogeneity_map_p[0][direction] = homogeneity; + } + } + } +} +void LibRaw::ahd_interpolate_combine_homogeneous_pixels( + int top, int left, ushort (*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], + char (*homogeneity_map)[LIBRAW_AHD_TILE][2]) +{ + int row, col; + int tr, tc; + int i, j; + int direction; + int hm[2]; + int c; + const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 3, height - 5); + const int collimit = MIN(left + LIBRAW_AHD_TILE - 3, width - 5); + + ushort(*pix)[4]; + ushort(*rix[2])[3]; + + for (row = top + 3; row < rowlimit; row++) + { + tr = row - top; + pix = &image[row * width + left + 2]; + for (direction = 0; direction < 2; direction++) + { + rix[direction] = &rgb[direction][tr][2]; + } + + for (col = left + 3; col < collimit; col++) + { + tc = col - left; + pix++; + for (direction = 0; direction < 2; direction++) + { + rix[direction]++; + } + + for (direction = 0; direction < 2; direction++) + { + hm[direction] = 0; + for (i = tr - 1; i <= tr + 1; i++) + { + for (j = tc - 1; j <= tc + 1; j++) + { + hm[direction] += homogeneity_map[i][j][direction]; + } + } + } + if (hm[0] != hm[1]) + { + memcpy(pix[0], rix[hm[1] > hm[0]][0], 3 * sizeof(ushort)); + } + else + { + FORC3 { pix[0][c] = (rix[0][0][c] + rix[1][0][c]) >> 1; } + } + } + } +} +void LibRaw::ahd_interpolate() +{ + int top, left; + char *buffer; + ushort(*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3]; + short(*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3]; + char(*homo)[LIBRAW_AHD_TILE][2]; + int terminate_flag = 0; + + cielab(0, 0); + border_interpolate(5); + +#ifdef LIBRAW_USE_OPENMP +#pragma omp parallel private(buffer, rgb, lab, homo, top, left ) \ + shared(terminate_flag) +#endif + { +#ifdef LIBRAW_USE_OPENMP +#pragma omp critical +#endif + buffer = + (char *)malloc(26 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE); /* 1664 kB */ + merror(buffer, "ahd_interpolate()"); + rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer; + lab = (short(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])( + buffer + 12 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE); + homo = (char(*)[LIBRAW_AHD_TILE][2])(buffer + 24 * LIBRAW_AHD_TILE * + LIBRAW_AHD_TILE); + +#ifdef LIBRAW_USE_OPENMP +#pragma omp for schedule(dynamic) +#endif + for (top = 2; top < height - 5; top += LIBRAW_AHD_TILE - 6) + { +#ifdef LIBRAW_USE_OPENMP + if (0 == omp_get_thread_num()) +#endif + if (callbacks.progress_cb) + { + int rr = (*callbacks.progress_cb)(callbacks.progresscb_data, + LIBRAW_PROGRESS_INTERPOLATE, + top - 2, height - 7); + if (rr) + terminate_flag = 1; + } + for (left = 2; !terminate_flag && (left < width - 5); + left += LIBRAW_AHD_TILE - 6) + { + ahd_interpolate_green_h_and_v(top, left, rgb); + ahd_interpolate_r_and_b_and_convert_to_cielab(top, left, rgb, lab); + ahd_interpolate_build_homogeneity_map(top, left, lab, homo); + ahd_interpolate_combine_homogeneous_pixels(top, left, rgb, homo); + } + } +#ifdef LIBRAW_USE_OPENMP +#pragma omp critical +#endif + free(buffer); + } + if (terminate_flag) + throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/demosaic/dcb_demosaic.cpp libkdcraw/libkdcraw/libraw/src/demosaic/dcb_demosaic.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/demosaic/dcb_demosaic.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/demosaic/dcb_demosaic.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,901 @@ +/* + * Copyright (C) 2010, Jacek Gozdz (cuniek@kft.umcs.lublin.pl) + * + * This code is licensed under a (3-clause) BSD license as follows : + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the author nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +// DCB demosaicing by Jacek Gozdz (cuniek@kft.umcs.lublin.pl) + +// FBDD denoising by Jacek Gozdz (cuniek@kft.umcs.lublin.pl) and +// Luis Sanz RodrÃguez (luis.sanz.rodriguez@gmail.com) + +// last modification: 11.07.2010 + +#include "../../internal/dcraw_defs.h" + +// interpolates green vertically and saves it to image3 +void LibRaw::dcb_ver(float (*image3)[3]) +{ + int row, col, u = width, indx; + + for (row = 2; row < height - 2; row++) + for (col = 2 + (FC(row, 2) & 1), indx = row * width + col; col < u - 2; + col += 2, indx += 2) + { + + image3[indx][1] = CLIP((image[indx + u][1] + image[indx - u][1]) / 2.0); + } +} + +// interpolates green horizontally and saves it to image2 +void LibRaw::dcb_hor(float (*image2)[3]) +{ + int row, col, u = width, indx; + + for (row = 2; row < height - 2; row++) + for (col = 2 + (FC(row, 2) & 1), indx = row * width + col; col < u - 2; + col += 2, indx += 2) + { + + image2[indx][1] = CLIP((image[indx + 1][1] + image[indx - 1][1]) / 2.0); + } +} + +// missing colors are interpolated +void LibRaw::dcb_color() +{ + int row, col, c, d, u = width, indx; + + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 1) & 1), indx = row * width + col, + c = 2 - FC(row, col); + col < u - 1; col += 2, indx += 2) + { + + image[indx][c] = CLIP((4 * image[indx][1] - image[indx + u + 1][1] - + image[indx + u - 1][1] - image[indx - u + 1][1] - + image[indx - u - 1][1] + image[indx + u + 1][c] + + image[indx + u - 1][c] + image[indx - u + 1][c] + + image[indx - u - 1][c]) / + 4.0); + } + + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 2) & 1), indx = row * width + col, + c = FC(row, col + 1), d = 2 - c; + col < width - 1; col += 2, indx += 2) + { + + image[indx][c] = + CLIP((2 * image[indx][1] - image[indx + 1][1] - image[indx - 1][1] + + image[indx + 1][c] + image[indx - 1][c]) / + 2.0); + image[indx][d] = + CLIP((2 * image[indx][1] - image[indx + u][1] - image[indx - u][1] + + image[indx + u][d] + image[indx - u][d]) / + 2.0); + } +} + +// missing R and B are interpolated horizontally and saved in image2 +void LibRaw::dcb_color2(float (*image2)[3]) +{ + int row, col, c, d, u = width, indx; + + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 1) & 1), indx = row * width + col, + c = 2 - FC(row, col); + col < u - 1; col += 2, indx += 2) + { + + image2[indx][c] = + CLIP((4 * image2[indx][1] - image2[indx + u + 1][1] - + image2[indx + u - 1][1] - image2[indx - u + 1][1] - + image2[indx - u - 1][1] + image[indx + u + 1][c] + + image[indx + u - 1][c] + image[indx - u + 1][c] + + image[indx - u - 1][c]) / + 4.0); + } + + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 2) & 1), indx = row * width + col, + c = FC(row, col + 1), d = 2 - c; + col < width - 1; col += 2, indx += 2) + { + + image2[indx][c] = CLIP((image[indx + 1][c] + image[indx - 1][c]) / 2.0); + image2[indx][d] = + CLIP((2 * image2[indx][1] - image2[indx + u][1] - + image2[indx - u][1] + image[indx + u][d] + image[indx - u][d]) / + 2.0); + } +} + +// missing R and B are interpolated vertically and saved in image3 +void LibRaw::dcb_color3(float (*image3)[3]) +{ + int row, col, c, d, u = width, indx; + + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 1) & 1), indx = row * width + col, + c = 2 - FC(row, col); + col < u - 1; col += 2, indx += 2) + { + + image3[indx][c] = + CLIP((4 * image3[indx][1] - image3[indx + u + 1][1] - + image3[indx + u - 1][1] - image3[indx - u + 1][1] - + image3[indx - u - 1][1] + image[indx + u + 1][c] + + image[indx + u - 1][c] + image[indx - u + 1][c] + + image[indx - u - 1][c]) / + 4.0); + } + + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 2) & 1), indx = row * width + col, + c = FC(row, col + 1), d = 2 - c; + col < width - 1; col += 2, indx += 2) + { + + image3[indx][c] = + CLIP((2 * image3[indx][1] - image3[indx + 1][1] - + image3[indx - 1][1] + image[indx + 1][c] + image[indx - 1][c]) / + 2.0); + image3[indx][d] = CLIP((image[indx + u][d] + image[indx - u][d]) / 2.0); + } +} + +// decides the primary green interpolation direction +void LibRaw::dcb_decide(float (*image2)[3], float (*image3)[3]) +{ + int row, col, c, d, u = width, v = 2 * u, indx; + float current, current2, current3; + + for (row = 2; row < height - 2; row++) + for (col = 2 + (FC(row, 2) & 1), indx = row * width + col, c = FC(row, col); + col < u - 2; col += 2, indx += 2) + { + + d = ABS(c - 2); + + current = MAX(image[indx + v][c], + MAX(image[indx - v][c], + MAX(image[indx - 2][c], image[indx + 2][c]))) - + MIN(image[indx + v][c], + MIN(image[indx - v][c], + MIN(image[indx - 2][c], image[indx + 2][c]))) + + MAX(image[indx + 1 + u][d], + MAX(image[indx + 1 - u][d], + MAX(image[indx - 1 + u][d], image[indx - 1 - u][d]))) - + MIN(image[indx + 1 + u][d], + MIN(image[indx + 1 - u][d], + MIN(image[indx - 1 + u][d], image[indx - 1 - u][d]))); + + current2 = + MAX(image2[indx + v][d], + MAX(image2[indx - v][d], + MAX(image2[indx - 2][d], image2[indx + 2][d]))) - + MIN(image2[indx + v][d], + MIN(image2[indx - v][d], + MIN(image2[indx - 2][d], image2[indx + 2][d]))) + + MAX(image2[indx + 1 + u][c], + MAX(image2[indx + 1 - u][c], + MAX(image2[indx - 1 + u][c], image2[indx - 1 - u][c]))) - + MIN(image2[indx + 1 + u][c], + MIN(image2[indx + 1 - u][c], + MIN(image2[indx - 1 + u][c], image2[indx - 1 - u][c]))); + + current3 = + MAX(image3[indx + v][d], + MAX(image3[indx - v][d], + MAX(image3[indx - 2][d], image3[indx + 2][d]))) - + MIN(image3[indx + v][d], + MIN(image3[indx - v][d], + MIN(image3[indx - 2][d], image3[indx + 2][d]))) + + MAX(image3[indx + 1 + u][c], + MAX(image3[indx + 1 - u][c], + MAX(image3[indx - 1 + u][c], image3[indx - 1 - u][c]))) - + MIN(image3[indx + 1 + u][c], + MIN(image3[indx + 1 - u][c], + MIN(image3[indx - 1 + u][c], image3[indx - 1 - u][c]))); + + if (ABS(current - current2) < ABS(current - current3)) + image[indx][1] = image2[indx][1]; + else + image[indx][1] = image3[indx][1]; + } +} + +// saves red and blue in image2 +void LibRaw::dcb_copy_to_buffer(float (*image2)[3]) +{ + int indx; + + for (indx = 0; indx < height * width; indx++) + { + image2[indx][0] = image[indx][0]; // R + image2[indx][2] = image[indx][2]; // B + } +} + +// restores red and blue from image2 +void LibRaw::dcb_restore_from_buffer(float (*image2)[3]) +{ + int indx; + + for (indx = 0; indx < height * width; indx++) + { + image[indx][0] = image2[indx][0]; // R + image[indx][2] = image2[indx][2]; // B + } +} + +// R and B smoothing using green contrast, all pixels except 2 pixel wide border +void LibRaw::dcb_pp() +{ + int g1, r1, b1, u = width, indx, row, col; + + for (row = 2; row < height - 2; row++) + for (col = 2, indx = row * u + col; col < width - 2; col++, indx++) + { + + r1 = (image[indx - 1][0] + image[indx + 1][0] + image[indx - u][0] + + image[indx + u][0] + image[indx - u - 1][0] + + image[indx + u + 1][0] + image[indx - u + 1][0] + + image[indx + u - 1][0]) / + 8.0; + g1 = (image[indx - 1][1] + image[indx + 1][1] + image[indx - u][1] + + image[indx + u][1] + image[indx - u - 1][1] + + image[indx + u + 1][1] + image[indx - u + 1][1] + + image[indx + u - 1][1]) / + 8.0; + b1 = (image[indx - 1][2] + image[indx + 1][2] + image[indx - u][2] + + image[indx + u][2] + image[indx - u - 1][2] + + image[indx + u + 1][2] + image[indx - u + 1][2] + + image[indx + u - 1][2]) / + 8.0; + + image[indx][0] = CLIP(r1 + (image[indx][1] - g1)); + image[indx][2] = CLIP(b1 + (image[indx][1] - g1)); + } +} + +// green blurring correction, helps to get the nyquist right +void LibRaw::dcb_nyquist() +{ + int row, col, c, u = width, v = 2 * u, indx; + + for (row = 2; row < height - 2; row++) + for (col = 2 + (FC(row, 2) & 1), indx = row * width + col, c = FC(row, col); + col < u - 2; col += 2, indx += 2) + { + + image[indx][1] = CLIP((image[indx + v][1] + image[indx - v][1] + + image[indx - 2][1] + image[indx + 2][1]) / + 4.0 + + image[indx][c] - + (image[indx + v][c] + image[indx - v][c] + + image[indx - 2][c] + image[indx + 2][c]) / + 4.0); + } +} + +// missing colors are interpolated using high quality algorithm by Luis Sanz +// RodrÃguez +void LibRaw::dcb_color_full() +{ + int row, col, c, d, u = width, w = 3 * u, indx, g1, g2; + float f[4], g[4], (*chroma)[2]; + + chroma = (float(*)[2])calloc(width * height, sizeof *chroma); + merror(chroma, "dcb_color_full()"); + + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 1) & 1), indx = row * width + col, c = FC(row, col), + d = c / 2; + col < u - 1; col += 2, indx += 2) + chroma[indx][d] = image[indx][c] - image[indx][1]; + + for (row = 3; row < height - 3; row++) + for (col = 3 + (FC(row, 1) & 1), indx = row * width + col, + c = 1 - FC(row, col) / 2, d = 1 - c; + col < u - 3; col += 2, indx += 2) + { + f[0] = 1.0 / + (float)(1.0 + + fabs(chroma[indx - u - 1][c] - chroma[indx + u + 1][c]) + + fabs(chroma[indx - u - 1][c] - chroma[indx - w - 3][c]) + + fabs(chroma[indx + u + 1][c] - chroma[indx - w - 3][c])); + f[1] = 1.0 / + (float)(1.0 + + fabs(chroma[indx - u + 1][c] - chroma[indx + u - 1][c]) + + fabs(chroma[indx - u + 1][c] - chroma[indx - w + 3][c]) + + fabs(chroma[indx + u - 1][c] - chroma[indx - w + 3][c])); + f[2] = 1.0 / + (float)(1.0 + + fabs(chroma[indx + u - 1][c] - chroma[indx - u + 1][c]) + + fabs(chroma[indx + u - 1][c] - chroma[indx + w + 3][c]) + + fabs(chroma[indx - u + 1][c] - chroma[indx + w - 3][c])); + f[3] = 1.0 / + (float)(1.0 + + fabs(chroma[indx + u + 1][c] - chroma[indx - u - 1][c]) + + fabs(chroma[indx + u + 1][c] - chroma[indx + w - 3][c]) + + fabs(chroma[indx - u - 1][c] - chroma[indx + w + 3][c])); + g[0] = 1.325 * chroma[indx - u - 1][c] - 0.175 * chroma[indx - w - 3][c] - + 0.075 * chroma[indx - w - 1][c] - 0.075 * chroma[indx - u - 3][c]; + g[1] = 1.325 * chroma[indx - u + 1][c] - 0.175 * chroma[indx - w + 3][c] - + 0.075 * chroma[indx - w + 1][c] - 0.075 * chroma[indx - u + 3][c]; + g[2] = 1.325 * chroma[indx + u - 1][c] - 0.175 * chroma[indx + w - 3][c] - + 0.075 * chroma[indx + w - 1][c] - 0.075 * chroma[indx + u - 3][c]; + g[3] = 1.325 * chroma[indx + u + 1][c] - 0.175 * chroma[indx + w + 3][c] - + 0.075 * chroma[indx + w + 1][c] - 0.075 * chroma[indx + u + 3][c]; + chroma[indx][c] = + (f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / + (f[0] + f[1] + f[2] + f[3]); + } + for (row = 3; row < height - 3; row++) + for (col = 3 + (FC(row, 2) & 1), indx = row * width + col, + c = FC(row, col + 1) / 2; + col < u - 3; col += 2, indx += 2) + for (d = 0; d <= 1; c = 1 - c, d++) + { + f[0] = 1.0 / + (float)(1.0 + fabs(chroma[indx - u][c] - chroma[indx + u][c]) + + fabs(chroma[indx - u][c] - chroma[indx - w][c]) + + fabs(chroma[indx + u][c] - chroma[indx - w][c])); + f[1] = 1.0 / + (float)(1.0 + fabs(chroma[indx + 1][c] - chroma[indx - 1][c]) + + fabs(chroma[indx + 1][c] - chroma[indx + 3][c]) + + fabs(chroma[indx - 1][c] - chroma[indx + 3][c])); + f[2] = 1.0 / + (float)(1.0 + fabs(chroma[indx - 1][c] - chroma[indx + 1][c]) + + fabs(chroma[indx - 1][c] - chroma[indx - 3][c]) + + fabs(chroma[indx + 1][c] - chroma[indx - 3][c])); + f[3] = 1.0 / + (float)(1.0 + fabs(chroma[indx + u][c] - chroma[indx - u][c]) + + fabs(chroma[indx + u][c] - chroma[indx + w][c]) + + fabs(chroma[indx - u][c] - chroma[indx + w][c])); + + g[0] = 0.875 * chroma[indx - u][c] + 0.125 * chroma[indx - w][c]; + g[1] = 0.875 * chroma[indx + 1][c] + 0.125 * chroma[indx + 3][c]; + g[2] = 0.875 * chroma[indx - 1][c] + 0.125 * chroma[indx - 3][c]; + g[3] = 0.875 * chroma[indx + u][c] + 0.125 * chroma[indx + w][c]; + + chroma[indx][c] = + (f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / + (f[0] + f[1] + f[2] + f[3]); + } + + for (row = 6; row < height - 6; row++) + for (col = 6, indx = row * width + col; col < width - 6; col++, indx++) + { + image[indx][0] = CLIP(chroma[indx][0] + image[indx][1]); + image[indx][2] = CLIP(chroma[indx][1] + image[indx][1]); + + g1 = MIN( + image[indx + 1 + u][0], + MIN(image[indx + 1 - u][0], + MIN(image[indx - 1 + u][0], + MIN(image[indx - 1 - u][0], + MIN(image[indx - 1][0], + MIN(image[indx + 1][0], + MIN(image[indx - u][0], image[indx + u][0]))))))); + + g2 = MAX( + image[indx + 1 + u][0], + MAX(image[indx + 1 - u][0], + MAX(image[indx - 1 + u][0], + MAX(image[indx - 1 - u][0], + MAX(image[indx - 1][0], + MAX(image[indx + 1][0], + MAX(image[indx - u][0], image[indx + u][0]))))))); + + image[indx][0] = ULIM(image[indx][0], g2, g1); + + g1 = MIN( + image[indx + 1 + u][2], + MIN(image[indx + 1 - u][2], + MIN(image[indx - 1 + u][2], + MIN(image[indx - 1 - u][2], + MIN(image[indx - 1][2], + MIN(image[indx + 1][2], + MIN(image[indx - u][2], image[indx + u][2]))))))); + + g2 = MAX( + image[indx + 1 + u][2], + MAX(image[indx + 1 - u][2], + MAX(image[indx - 1 + u][2], + MAX(image[indx - 1 - u][2], + MAX(image[indx - 1][2], + MAX(image[indx + 1][2], + MAX(image[indx - u][2], image[indx + u][2]))))))); + + image[indx][2] = ULIM(image[indx][2], g2, g1); + } + + free(chroma); +} + +// green is used to create an interpolation direction map saved in image[][3] +// 1 = vertical +// 0 = horizontal +void LibRaw::dcb_map() +{ + int row, col, u = width, indx; + + for (row = 1; row < height - 1; row++) + { + for (col = 1, indx = row * width + col; col < width - 1; col++, indx++) + { + + if (image[indx][1] > (image[indx - 1][1] + image[indx + 1][1] + + image[indx - u][1] + image[indx + u][1]) / + 4.0) + image[indx][3] = ((MIN(image[indx - 1][1], image[indx + 1][1]) + + image[indx - 1][1] + image[indx + 1][1]) < + (MIN(image[indx - u][1], image[indx + u][1]) + + image[indx - u][1] + image[indx + u][1])); + else + image[indx][3] = ((MAX(image[indx - 1][1], image[indx + 1][1]) + + image[indx - 1][1] + image[indx + 1][1]) > + (MAX(image[indx - u][1], image[indx + u][1]) + + image[indx - u][1] + image[indx + u][1])); + } + } +} + +// interpolated green pixels are corrected using the map +void LibRaw::dcb_correction() +{ + int current, row, col, u = width, v = 2 * u, indx; + + for (row = 2; row < height - 2; row++) + for (col = 2 + (FC(row, 2) & 1), indx = row * width + col; col < u - 2; + col += 2, indx += 2) + { + + current = 4 * image[indx][3] + + 2 * (image[indx + u][3] + image[indx - u][3] + + image[indx + 1][3] + image[indx - 1][3]) + + image[indx + v][3] + image[indx - v][3] + image[indx + 2][3] + + image[indx - 2][3]; + + image[indx][1] = + ((16 - current) * (image[indx - 1][1] + image[indx + 1][1]) / 2.0 + + current * (image[indx - u][1] + image[indx + u][1]) / 2.0) / + 16.0; + } +} + +// interpolated green pixels are corrected using the map +// with contrast correction +void LibRaw::dcb_correction2() +{ + int current, row, col, c, u = width, v = 2 * u, indx; + + for (row = 4; row < height - 4; row++) + for (col = 4 + (FC(row, 2) & 1), indx = row * width + col, c = FC(row, col); + col < u - 4; col += 2, indx += 2) + { + + current = 4 * image[indx][3] + + 2 * (image[indx + u][3] + image[indx - u][3] + + image[indx + 1][3] + image[indx - 1][3]) + + image[indx + v][3] + image[indx - v][3] + image[indx + 2][3] + + image[indx - 2][3]; + + image[indx][1] = CLIP( + ((16 - current) * ((image[indx - 1][1] + image[indx + 1][1]) / 2.0 + + image[indx][c] - + (image[indx + 2][c] + image[indx - 2][c]) / 2.0) + + current * ((image[indx - u][1] + image[indx + u][1]) / 2.0 + + image[indx][c] - + (image[indx + v][c] + image[indx - v][c]) / 2.0)) / + 16.0); + } +} + +void LibRaw::dcb_refinement() +{ + int row, col, c, u = width, v = 2 * u, w = 3 * u, indx, current; + float f[5], g1, g2; + + for (row = 4; row < height - 4; row++) + for (col = 4 + (FC(row, 2) & 1), indx = row * width + col, c = FC(row, col); + col < u - 4; col += 2, indx += 2) + { + + current = 4 * image[indx][3] + + 2 * (image[indx + u][3] + image[indx - u][3] + + image[indx + 1][3] + image[indx - 1][3]) + + image[indx + v][3] + image[indx - v][3] + image[indx - 2][3] + + image[indx + 2][3]; + + if (image[indx][c] > 1) + { + + f[0] = (float)(image[indx - u][1] + image[indx + u][1]) / + (2 * image[indx][c]); + + if (image[indx - v][c] > 0) + f[1] = 2 * (float)image[indx - u][1] / + (image[indx - v][c] + image[indx][c]); + else + f[1] = f[0]; + + if (image[indx - v][c] > 0) + f[2] = (float)(image[indx - u][1] + image[indx - w][1]) / + (2 * image[indx - v][c]); + else + f[2] = f[0]; + + if (image[indx + v][c] > 0) + f[3] = 2 * (float)image[indx + u][1] / + (image[indx + v][c] + image[indx][c]); + else + f[3] = f[0]; + + if (image[indx + v][c] > 0) + f[4] = (float)(image[indx + u][1] + image[indx + w][1]) / + (2 * image[indx + v][c]); + else + f[4] = f[0]; + + g1 = (5 * f[0] + 3 * f[1] + f[2] + 3 * f[3] + f[4]) / 13.0; + + f[0] = (float)(image[indx - 1][1] + image[indx + 1][1]) / + (2 * image[indx][c]); + + if (image[indx - 2][c] > 0) + f[1] = 2 * (float)image[indx - 1][1] / + (image[indx - 2][c] + image[indx][c]); + else + f[1] = f[0]; + + if (image[indx - 2][c] > 0) + f[2] = (float)(image[indx - 1][1] + image[indx - 3][1]) / + (2 * image[indx - 2][c]); + else + f[2] = f[0]; + + if (image[indx + 2][c] > 0) + f[3] = 2 * (float)image[indx + 1][1] / + (image[indx + 2][c] + image[indx][c]); + else + f[3] = f[0]; + + if (image[indx + 2][c] > 0) + f[4] = (float)(image[indx + 1][1] + image[indx + 3][1]) / + (2 * image[indx + 2][c]); + else + f[4] = f[0]; + + g2 = (5 * f[0] + 3 * f[1] + f[2] + 3 * f[3] + f[4]) / 13.0; + + image[indx][1] = CLIP((image[indx][c]) * + (current * g1 + (16 - current) * g2) / 16.0); + } + else + image[indx][1] = image[indx][c]; + + // get rid of overshooted pixels + + g1 = MIN( + image[indx + 1 + u][1], + MIN(image[indx + 1 - u][1], + MIN(image[indx - 1 + u][1], + MIN(image[indx - 1 - u][1], + MIN(image[indx - 1][1], + MIN(image[indx + 1][1], + MIN(image[indx - u][1], image[indx + u][1]))))))); + + g2 = MAX( + image[indx + 1 + u][1], + MAX(image[indx + 1 - u][1], + MAX(image[indx - 1 + u][1], + MAX(image[indx - 1 - u][1], + MAX(image[indx - 1][1], + MAX(image[indx + 1][1], + MAX(image[indx - u][1], image[indx + u][1]))))))); + + image[indx][1] = ULIM(image[indx][1], g2, g1); + } +} + +// converts RGB to LCH colorspace and saves it to image3 +void LibRaw::rgb_to_lch(double (*image2)[3]) +{ + int indx; + for (indx = 0; indx < height * width; indx++) + { + + image2[indx][0] = image[indx][0] + image[indx][1] + image[indx][2]; // L + image2[indx][1] = 1.732050808 * (image[indx][0] - image[indx][1]); // C + image2[indx][2] = + 2.0 * image[indx][2] - image[indx][0] - image[indx][1]; // H + } +} + +// converts LCH to RGB colorspace and saves it back to image +void LibRaw::lch_to_rgb(double (*image2)[3]) +{ + int indx; + for (indx = 0; indx < height * width; indx++) + { + + image[indx][0] = CLIP(image2[indx][0] / 3.0 - image2[indx][2] / 6.0 + + image2[indx][1] / 3.464101615); + image[indx][1] = CLIP(image2[indx][0] / 3.0 - image2[indx][2] / 6.0 - + image2[indx][1] / 3.464101615); + image[indx][2] = CLIP(image2[indx][0] / 3.0 + image2[indx][2] / 3.0); + } +} + +// denoising using interpolated neighbours +void LibRaw::fbdd_correction() +{ + int row, col, c, u = width, indx; + + for (row = 2; row < height - 2; row++) + { + for (col = 2, indx = row * width + col; col < width - 2; col++, indx++) + { + + c = fcol(row, col); + + image[indx][c] = + ULIM(image[indx][c], + MAX(image[indx - 1][c], + MAX(image[indx + 1][c], + MAX(image[indx - u][c], image[indx + u][c]))), + MIN(image[indx - 1][c], + MIN(image[indx + 1][c], + MIN(image[indx - u][c], image[indx + u][c])))); + } + } +} + +// corrects chroma noise +void LibRaw::fbdd_correction2(double (*image2)[3]) +{ + int indx, v = 2 * width; + int col, row; + double Co, Ho, ratio; + + for (row = 6; row < height - 6; row++) + { + for (col = 6; col < width - 6; col++) + { + indx = row * width + col; + + if (image2[indx][1] * image2[indx][2] != 0) + { + Co = (image2[indx + v][1] + image2[indx - v][1] + image2[indx - 2][1] + + image2[indx + 2][1] - + MAX(image2[indx - 2][1], + MAX(image2[indx + 2][1], + MAX(image2[indx - v][1], image2[indx + v][1]))) - + MIN(image2[indx - 2][1], + MIN(image2[indx + 2][1], + MIN(image2[indx - v][1], image2[indx + v][1])))) / + 2.0; + Ho = (image2[indx + v][2] + image2[indx - v][2] + image2[indx - 2][2] + + image2[indx + 2][2] - + MAX(image2[indx - 2][2], + MAX(image2[indx + 2][2], + MAX(image2[indx - v][2], image2[indx + v][2]))) - + MIN(image2[indx - 2][2], + MIN(image2[indx + 2][2], + MIN(image2[indx - v][2], image2[indx + v][2])))) / + 2.0; + ratio = sqrt((Co * Co + Ho * Ho) / (image2[indx][1] * image2[indx][1] + + image2[indx][2] * image2[indx][2])); + + if (ratio < 0.85) + { + image2[indx][0] = + -(image2[indx][1] + image2[indx][2] - Co - Ho) + image2[indx][0]; + image2[indx][1] = Co; + image2[indx][2] = Ho; + } + } + } + } +} + +// Cubic Spline Interpolation by Li and Randhawa, modified by Jacek Gozdz and +// Luis Sanz RodrÃguez +void LibRaw::fbdd_green() +{ + int row, col, c, u = width, v = 2 * u, w = 3 * u, x = 4 * u, y = 5 * u, indx, + min, max; + float f[4], g[4]; + + for (row = 5; row < height - 5; row++) + for (col = 5 + (FC(row, 1) & 1), indx = row * width + col, c = FC(row, col); + col < u - 5; col += 2, indx += 2) + { + + f[0] = 1.0 / (1.0 + abs(image[indx - u][1] - image[indx - w][1]) + + abs(image[indx - w][1] - image[indx + y][1])); + f[1] = 1.0 / (1.0 + abs(image[indx + 1][1] - image[indx + 3][1]) + + abs(image[indx + 3][1] - image[indx - 5][1])); + f[2] = 1.0 / (1.0 + abs(image[indx - 1][1] - image[indx - 3][1]) + + abs(image[indx - 3][1] - image[indx + 5][1])); + f[3] = 1.0 / (1.0 + abs(image[indx + u][1] - image[indx + w][1]) + + abs(image[indx + w][1] - image[indx - y][1])); + + g[0] = CLIP((23 * image[indx - u][1] + 23 * image[indx - w][1] + + 2 * image[indx - y][1] + + 8 * (image[indx - v][c] - image[indx - x][c]) + + 40 * (image[indx][c] - image[indx - v][c])) / + 48.0); + g[1] = CLIP((23 * image[indx + 1][1] + 23 * image[indx + 3][1] + + 2 * image[indx + 5][1] + + 8 * (image[indx + 2][c] - image[indx + 4][c]) + + 40 * (image[indx][c] - image[indx + 2][c])) / + 48.0); + g[2] = CLIP((23 * image[indx - 1][1] + 23 * image[indx - 3][1] + + 2 * image[indx - 5][1] + + 8 * (image[indx - 2][c] - image[indx - 4][c]) + + 40 * (image[indx][c] - image[indx - 2][c])) / + 48.0); + g[3] = CLIP((23 * image[indx + u][1] + 23 * image[indx + w][1] + + 2 * image[indx + y][1] + + 8 * (image[indx + v][c] - image[indx + x][c]) + + 40 * (image[indx][c] - image[indx + v][c])) / + 48.0); + + image[indx][1] = + CLIP((f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / + (f[0] + f[1] + f[2] + f[3])); + + min = MIN( + image[indx + 1 + u][1], + MIN(image[indx + 1 - u][1], + MIN(image[indx - 1 + u][1], + MIN(image[indx - 1 - u][1], + MIN(image[indx - 1][1], + MIN(image[indx + 1][1], + MIN(image[indx - u][1], image[indx + u][1]))))))); + + max = MAX( + image[indx + 1 + u][1], + MAX(image[indx + 1 - u][1], + MAX(image[indx - 1 + u][1], + MAX(image[indx - 1 - u][1], + MAX(image[indx - 1][1], + MAX(image[indx + 1][1], + MAX(image[indx - u][1], image[indx + u][1]))))))); + + image[indx][1] = ULIM(image[indx][1], max, min); + } +} + +// FBDD (Fake Before Demosaicing Denoising) +void LibRaw::fbdd(int noiserd) +{ + double(*image2)[3]; + // safety net: disable for 4-color bayer or full-color images + if (colors != 3 || !filters) + return; + image2 = (double(*)[3])calloc(width * height, sizeof *image2); + + border_interpolate(4); + + if (noiserd > 1) + { + fbdd_green(); + // dcb_color_full(image2); + dcb_color_full(); + fbdd_correction(); + + dcb_color(); + rgb_to_lch(image2); + fbdd_correction2(image2); + fbdd_correction2(image2); + lch_to_rgb(image2); + } + else + { + fbdd_green(); + // dcb_color_full(image2); + dcb_color_full(); + fbdd_correction(); + } + + free(image2); +} + +// DCB demosaicing main routine +void LibRaw::dcb(int iterations, int dcb_enhance) +{ + + int i = 1; + + float(*image2)[3]; + image2 = (float(*)[3])calloc(width * height, sizeof *image2); + + float(*image3)[3]; + image3 = (float(*)[3])calloc(width * height, sizeof *image3); + + border_interpolate(6); + + dcb_hor(image2); + dcb_color2(image2); + + dcb_ver(image3); + dcb_color3(image3); + + dcb_decide(image2, image3); + + free(image3); + + dcb_copy_to_buffer(image2); + + while (i <= iterations) + { + dcb_nyquist(); + dcb_nyquist(); + dcb_nyquist(); + dcb_map(); + dcb_correction(); + i++; + } + + dcb_color(); + dcb_pp(); + + dcb_map(); + dcb_correction2(); + + dcb_map(); + dcb_correction(); + + dcb_map(); + dcb_correction(); + + dcb_map(); + dcb_correction(); + + dcb_map(); + dcb_restore_from_buffer(image2); + dcb_color(); + + if (dcb_enhance) + { + dcb_refinement(); + // dcb_color_full(image2); + dcb_color_full(); + } + + free(image2); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/demosaic/dht_demosaic.cpp libkdcraw/libkdcraw/libraw/src/demosaic/dht_demosaic.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/demosaic/dht_demosaic.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/demosaic/dht_demosaic.cpp 2022-11-07 07:46:31.730795008 +0300 @@ -0,0 +1,1024 @@ +/* -*- C++ -*- + * File: dht_demosaic.cpp + * Copyright 2013 Anton Petrusevich + * Created: Tue Apr 9, 2013 + * + * This code is licensed under one of two licenses as you choose: + * + * 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + * (See file LICENSE.LGPL provided in LibRaw distribution archive for + * details). + * + * 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + * (See file LICENSE.CDDL provided in LibRaw distribution archive for + * details). + * + */ + +/* + * Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñ‹Ñ‡Ð¸ÑлÑет ÑркоÑтную диÑтанцию. + * еÑли две ÑркоÑти отличаютÑÑ Ð² два раза, например 10 и 20, то они имеют такой + * же Ð²ÐµÑ Ð¿Ñ€Ð¸ принÑтии Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¾Ð± интерполировании, как и 100 и 200 -- + * фотографичеÑÐºÐ°Ñ ÑркоÑÑ‚ÑŒ между ними 1 Ñтоп. диÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð²Ñегда >=1 + */ + +#include "../../internal/dmp_include.h" + +static inline float calc_dist(float c1, float c2) +{ + return c1 > c2 ? c1 / c2 : c2 / c1; +} + +struct DHT +{ + int nr_height, nr_width; + static const int nr_topmargin = 4, nr_leftmargin = 4; + float (*nraw)[3]; + ushort channel_maximum[3]; + float channel_minimum[3]; + LibRaw &libraw; + enum + { + HVSH = 1, + HOR = 2, + VER = 4, + HORSH = HOR | HVSH, + VERSH = VER | HVSH, + DIASH = 8, + LURD = 16, + RULD = 32, + LURDSH = LURD | DIASH, + RULDSH = RULD | DIASH, + HOT = 64 + }; + static inline float Thot(void) throw() { return 64.0f; } + static inline float Tg(void) throw() { return 256.0f; } + static inline float T(void) throw() { return 1.4f; } + char *ndir; + inline int nr_offset(int row, int col) throw() + { + return (row * nr_width + col); + } + int get_hv_grb(int x, int y, int kc) + { + float hv1 = 2 * nraw[nr_offset(y - 1, x)][1] / + (nraw[nr_offset(y - 2, x)][kc] + nraw[nr_offset(y, x)][kc]); + float hv2 = 2 * nraw[nr_offset(y + 1, x)][1] / + (nraw[nr_offset(y + 2, x)][kc] + nraw[nr_offset(y, x)][kc]); + float kv = calc_dist(hv1, hv2) * + calc_dist(nraw[nr_offset(y, x)][kc] * nraw[nr_offset(y, x)][kc], + (nraw[nr_offset(y - 2, x)][kc] * + nraw[nr_offset(y + 2, x)][kc])); + kv *= kv; + kv *= kv; + kv *= kv; + float dv = + kv * + calc_dist(nraw[nr_offset(y - 3, x)][1] * nraw[nr_offset(y + 3, x)][1], + nraw[nr_offset(y - 1, x)][1] * nraw[nr_offset(y + 1, x)][1]); + float hh1 = 2 * nraw[nr_offset(y, x - 1)][1] / + (nraw[nr_offset(y, x - 2)][kc] + nraw[nr_offset(y, x)][kc]); + float hh2 = 2 * nraw[nr_offset(y, x + 1)][1] / + (nraw[nr_offset(y, x + 2)][kc] + nraw[nr_offset(y, x)][kc]); + float kh = calc_dist(hh1, hh2) * + calc_dist(nraw[nr_offset(y, x)][kc] * nraw[nr_offset(y, x)][kc], + (nraw[nr_offset(y, x - 2)][kc] * + nraw[nr_offset(y, x + 2)][kc])); + kh *= kh; + kh *= kh; + kh *= kh; + float dh = + kh * + calc_dist(nraw[nr_offset(y, x - 3)][1] * nraw[nr_offset(y, x + 3)][1], + nraw[nr_offset(y, x - 1)][1] * nraw[nr_offset(y, x + 1)][1]); + float e = calc_dist(dh, dv); + char d = dh < dv ? (e > Tg() ? HORSH : HOR) : (e > Tg() ? VERSH : VER); + return d; + } + int get_hv_rbg(int x, int y, int hc) + { + float hv1 = 2 * nraw[nr_offset(y - 1, x)][hc ^ 2] / + (nraw[nr_offset(y - 2, x)][1] + nraw[nr_offset(y, x)][1]); + float hv2 = 2 * nraw[nr_offset(y + 1, x)][hc ^ 2] / + (nraw[nr_offset(y + 2, x)][1] + nraw[nr_offset(y, x)][1]); + float kv = calc_dist(hv1, hv2) * + calc_dist(nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1], + (nraw[nr_offset(y - 2, x)][1] * + nraw[nr_offset(y + 2, x)][1])); + kv *= kv; + kv *= kv; + kv *= kv; + float dv = kv * calc_dist(nraw[nr_offset(y - 3, x)][hc ^ 2] * + nraw[nr_offset(y + 3, x)][hc ^ 2], + nraw[nr_offset(y - 1, x)][hc ^ 2] * + nraw[nr_offset(y + 1, x)][hc ^ 2]); + float hh1 = 2 * nraw[nr_offset(y, x - 1)][hc] / + (nraw[nr_offset(y, x - 2)][1] + nraw[nr_offset(y, x)][1]); + float hh2 = 2 * nraw[nr_offset(y, x + 1)][hc] / + (nraw[nr_offset(y, x + 2)][1] + nraw[nr_offset(y, x)][1]); + float kh = calc_dist(hh1, hh2) * + calc_dist(nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1], + (nraw[nr_offset(y, x - 2)][1] * + nraw[nr_offset(y, x + 2)][1])); + kh *= kh; + kh *= kh; + kh *= kh; + float dh = + kh * calc_dist( + nraw[nr_offset(y, x - 3)][hc] * nraw[nr_offset(y, x + 3)][hc], + nraw[nr_offset(y, x - 1)][hc] * nraw[nr_offset(y, x + 1)][hc]); + float e = calc_dist(dh, dv); + char d = dh < dv ? (e > Tg() ? HORSH : HOR) : (e > Tg() ? VERSH : VER); + return d; + } + int get_diag_grb(int x, int y, int kc) + { + float hlu = + nraw[nr_offset(y - 1, x - 1)][1] / nraw[nr_offset(y - 1, x - 1)][kc]; + float hrd = + nraw[nr_offset(y + 1, x + 1)][1] / nraw[nr_offset(y + 1, x + 1)][kc]; + float dlurd = + calc_dist(hlu, hrd) * + calc_dist(nraw[nr_offset(y - 1, x - 1)][1] * + nraw[nr_offset(y + 1, x + 1)][1], + nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); + float druld = + calc_dist(hlu, hrd) * + calc_dist(nraw[nr_offset(y - 1, x + 1)][1] * + nraw[nr_offset(y + 1, x - 1)][1], + nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); + float e = calc_dist(dlurd, druld); + char d = + druld < dlurd ? (e > T() ? RULDSH : RULD) : (e > T() ? LURDSH : LURD); + return d; + } + int get_diag_rbg(int x, int y, int hc) + { + float dlurd = calc_dist( + nraw[nr_offset(y - 1, x - 1)][1] * nraw[nr_offset(y + 1, x + 1)][1], + nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); + float druld = calc_dist( + nraw[nr_offset(y - 1, x + 1)][1] * nraw[nr_offset(y + 1, x - 1)][1], + nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); + float e = calc_dist(dlurd, druld); + char d = + druld < dlurd ? (e > T() ? RULDSH : RULD) : (e > T() ? LURDSH : LURD); + return d; + } + static inline float scale_over(float ec, float base) + { + float s = base * .4; + float o = ec - base; + return base + sqrt(s * (o + s)) - s; + } + static inline float scale_under(float ec, float base) + { + float s = base * .6; + float o = base - ec; + return base - sqrt(s * (o + s)) + s; + } + ~DHT(); + DHT(LibRaw &_libraw); + void copy_to_image(); + void make_greens(); + void make_diag_dirs(); + void make_hv_dirs(); + void refine_hv_dirs(int i, int js); + void refine_diag_dirs(int i, int js); + void refine_ihv_dirs(int i); + void refine_idiag_dirs(int i); + void illustrate_dirs(); + void illustrate_dline(int i); + void make_hv_dline(int i); + void make_diag_dline(int i); + void make_gline(int i); + void make_rbdiag(int i); + void make_rbhv(int i); + void make_rb(); + void hide_hots(); + void restore_hots(); +}; + +typedef float float3[3]; + +/* + * Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ цветах копируетÑÑ Ð²Ð¾ float в общем то Ñ Ð¾Ð´Ð½Ð¾Ð¹ целью -- чтобы + * вмеÑто 0 можно было пиÑать 0.5, что больше подходит Ð´Ð»Ñ Ð²Ñ‹Ñ‡Ð¸ÑÐ»ÐµÐ½Ð¸Ñ ÑркоÑтной + * разницы. причина: в целых чиÑлах разница в 1 Ñтоп ÑоÑтавлÑет Ñ€Ñд 8,4,2,1,0 -- + * поÑледнее чиÑло должно быть 0.5, которое непредÑтвамио в целых чиÑлах. так же + * Ñто изменение позволÑет не думать о Ñпециальных ÑлучаÑÑ… Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð½Ð° ноль. + * + * альтернативное решение: умножить вÑе данные на 2 и в младший бит внеÑти 1. + * правда, вÑÑ‘ равно придётÑÑ Ñледить, чтобы при интерпретации зелёного цвета не + * получилÑÑ 0 при округлении, иначе проблема при интерпретации Ñиних и краÑных. + * + */ +DHT::DHT(LibRaw &_libraw) : libraw(_libraw) +{ + nr_height = libraw.imgdata.sizes.iheight + nr_topmargin * 2; + nr_width = libraw.imgdata.sizes.iwidth + nr_leftmargin * 2; + nraw = (float3 *)malloc(nr_height * nr_width * sizeof(float3)); + int iwidth = libraw.imgdata.sizes.iwidth; + ndir = (char *)calloc(nr_height * nr_width, 1); + channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0; + channel_minimum[0] = libraw.imgdata.image[0][0]; + channel_minimum[1] = libraw.imgdata.image[0][1]; + channel_minimum[2] = libraw.imgdata.image[0][2]; + for (int i = 0; i < nr_height * nr_width; ++i) + nraw[i][0] = nraw[i][1] = nraw[i][2] = 0.5; + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + int col_cache[48]; + for (int j = 0; j < 48; ++j) + { + int l = libraw.COLOR(i, j); + if (l == 3) + l = 1; + col_cache[j] = l; + } + for (int j = 0; j < iwidth; ++j) + { + int l = col_cache[j % 48]; + unsigned short c = libraw.imgdata.image[i * iwidth + j][l]; + if (c != 0) + { + if (channel_maximum[l] < c) + channel_maximum[l] = c; + if (channel_minimum[l] > c) + channel_minimum[l] = c; + nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)][l] = (float)c; + } + } + } + channel_minimum[0] += .5; + channel_minimum[1] += .5; + channel_minimum[2] += .5; +} + +void DHT::hide_hots() +{ + int iwidth = libraw.imgdata.sizes.iwidth; +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) firstprivate(iwidth) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ мимо извеÑтного зелёного + * kc -- извеÑтный цвет в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + */ + for (int j = js; j < iwidth; j += 2) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + float c = nraw[nr_offset(y, x)][kc]; + if ((c > nraw[nr_offset(y, x + 2)][kc] && + c > nraw[nr_offset(y, x - 2)][kc] && + c > nraw[nr_offset(y - 2, x)][kc] && + c > nraw[nr_offset(y + 2, x)][kc] && + c > nraw[nr_offset(y, x + 1)][1] && + c > nraw[nr_offset(y, x - 1)][1] && + c > nraw[nr_offset(y - 1, x)][1] && + c > nraw[nr_offset(y + 1, x)][1]) || + (c < nraw[nr_offset(y, x + 2)][kc] && + c < nraw[nr_offset(y, x - 2)][kc] && + c < nraw[nr_offset(y - 2, x)][kc] && + c < nraw[nr_offset(y + 2, x)][kc] && + c < nraw[nr_offset(y, x + 1)][1] && + c < nraw[nr_offset(y, x - 1)][1] && + c < nraw[nr_offset(y - 1, x)][1] && + c < nraw[nr_offset(y + 1, x)][1])) + { + float avg = 0; + for (int k = -2; k < 3; k += 2) + for (int m = -2; m < 3; m += 2) + if (m == 0 && k == 0) + continue; + else + avg += nraw[nr_offset(y + k, x + m)][kc]; + avg /= 8; + // float dev = 0; + // for (int k = -2; k < 3; k += 2) + // for (int l = -2; l < 3; l += 2) + // if (k == 0 && l == 0) + // continue; + // else { + // float t = nraw[nr_offset(y + k, x + l)][kc] - + //avg; dev += t * t; + // } + // dev /= 8; + // dev = sqrt(dev); + if (calc_dist(c, avg) > Thot()) + { + ndir[nr_offset(y, x)] |= HOT; + float dv = calc_dist( + nraw[nr_offset(y - 2, x)][kc] * nraw[nr_offset(y - 1, x)][1], + nraw[nr_offset(y + 2, x)][kc] * nraw[nr_offset(y + 1, x)][1]); + float dh = calc_dist( + nraw[nr_offset(y, x - 2)][kc] * nraw[nr_offset(y, x - 1)][1], + nraw[nr_offset(y, x + 2)][kc] * nraw[nr_offset(y, x + 1)][1]); + if (dv > dh) + nraw[nr_offset(y, x)][kc] = (nraw[nr_offset(y, x + 2)][kc] + + nraw[nr_offset(y, x - 2)][kc]) / + 2; + else + nraw[nr_offset(y, x)][kc] = (nraw[nr_offset(y - 2, x)][kc] + + nraw[nr_offset(y + 2, x)][kc]) / + 2; + } + } + } + for (int j = js ^ 1; j < iwidth; j += 2) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + float c = nraw[nr_offset(y, x)][1]; + if ((c > nraw[nr_offset(y, x + 2)][1] && + c > nraw[nr_offset(y, x - 2)][1] && + c > nraw[nr_offset(y - 2, x)][1] && + c > nraw[nr_offset(y + 2, x)][1] && + c > nraw[nr_offset(y, x + 1)][kc] && + c > nraw[nr_offset(y, x - 1)][kc] && + c > nraw[nr_offset(y - 1, x)][kc ^ 2] && + c > nraw[nr_offset(y + 1, x)][kc ^ 2]) || + (c < nraw[nr_offset(y, x + 2)][1] && + c < nraw[nr_offset(y, x - 2)][1] && + c < nraw[nr_offset(y - 2, x)][1] && + c < nraw[nr_offset(y + 2, x)][1] && + c < nraw[nr_offset(y, x + 1)][kc] && + c < nraw[nr_offset(y, x - 1)][kc] && + c < nraw[nr_offset(y - 1, x)][kc ^ 2] && + c < nraw[nr_offset(y + 1, x)][kc ^ 2])) + { + float avg = 0; + for (int k = -2; k < 3; k += 2) + for (int m = -2; m < 3; m += 2) + if (k == 0 && m == 0) + continue; + else + avg += nraw[nr_offset(y + k, x + m)][1]; + avg /= 8; + // float dev = 0; + // for (int k = -2; k < 3; k += 2) + // for (int l = -2; l < 3; l += 2) + // if (k == 0 && l == 0) + // continue; + // else { + // float t = nraw[nr_offset(y + k, x + l)][1] - + //avg; dev += t * t; + // } + // dev /= 8; + // dev = sqrt(dev); + if (calc_dist(c, avg) > Thot()) + { + ndir[nr_offset(y, x)] |= HOT; + float dv = calc_dist( + nraw[nr_offset(y - 2, x)][1] * nraw[nr_offset(y - 1, x)][kc ^ 2], + nraw[nr_offset(y + 2, x)][1] * nraw[nr_offset(y + 1, x)][kc ^ 2]); + float dh = calc_dist( + nraw[nr_offset(y, x - 2)][1] * nraw[nr_offset(y, x - 1)][kc], + nraw[nr_offset(y, x + 2)][1] * nraw[nr_offset(y, x + 1)][kc]); + if (dv > dh) + nraw[nr_offset(y, x)][1] = + (nraw[nr_offset(y, x + 2)][1] + nraw[nr_offset(y, x - 2)][1]) / + 2; + else + nraw[nr_offset(y, x)][1] = + (nraw[nr_offset(y - 2, x)][1] + nraw[nr_offset(y + 2, x)][1]) / + 2; + } + } + } + } +} + +void DHT::restore_hots() +{ + int iwidth = libraw.imgdata.sizes.iwidth; +#if defined(LIBRAW_USE_OPENMP) +#ifdef _MSC_VER +#pragma omp parallel for firstprivate(iwidth) +#else +#pragma omp parallel for schedule(guided) firstprivate(iwidth) collapse(2) +#endif +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + for (int j = 0; j < iwidth; ++j) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + if (ndir[nr_offset(y, x)] & HOT) + { + int l = libraw.COLOR(i, j); + nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)][l] = + libraw.imgdata.image[i * iwidth + j][l]; + } + } + } +} + +void DHT::make_diag_dirs() +{ +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_diag_dline(i); + } +//#if defined(LIBRAW_USE_OPENMP) +//#pragma omp parallel for schedule(guided) +//#endif +// for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { +// refine_diag_dirs(i, i & 1); +// } +//#if defined(LIBRAW_USE_OPENMP) +//#pragma omp parallel for schedule(guided) +//#endif +// for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { +// refine_diag_dirs(i, (i & 1) ^ 1); +// } +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + refine_idiag_dirs(i); + } +} + +void DHT::make_hv_dirs() +{ +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_hv_dline(i); + } +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + refine_hv_dirs(i, i & 1); + } +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + refine_hv_dirs(i, (i & 1) ^ 1); + } +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + refine_ihv_dirs(i); + } +} + +void DHT::refine_hv_dirs(int i, int js) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + for (int j = js; j < iwidth; j += 2) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + if (ndir[nr_offset(y, x)] & HVSH) + continue; + int nv = + (ndir[nr_offset(y - 1, x)] & VER) + (ndir[nr_offset(y + 1, x)] & VER) + + (ndir[nr_offset(y, x - 1)] & VER) + (ndir[nr_offset(y, x + 1)] & VER); + int nh = + (ndir[nr_offset(y - 1, x)] & HOR) + (ndir[nr_offset(y + 1, x)] & HOR) + + (ndir[nr_offset(y, x - 1)] & HOR) + (ndir[nr_offset(y, x + 1)] & HOR); + bool codir = (ndir[nr_offset(y, x)] & VER) + ? ((ndir[nr_offset(y - 1, x)] & VER) || + (ndir[nr_offset(y + 1, x)] & VER)) + : ((ndir[nr_offset(y, x - 1)] & HOR) || + (ndir[nr_offset(y, x + 1)] & HOR)); + nv /= VER; + nh /= HOR; + if ((ndir[nr_offset(y, x)] & VER) && (nh > 2 && !codir)) + { + ndir[nr_offset(y, x)] &= ~VER; + ndir[nr_offset(y, x)] |= HOR; + } + if ((ndir[nr_offset(y, x)] & HOR) && (nv > 2 && !codir)) + { + ndir[nr_offset(y, x)] &= ~HOR; + ndir[nr_offset(y, x)] |= VER; + } + } +} + +void DHT::refine_ihv_dirs(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + for (int j = 0; j < iwidth; j++) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + if (ndir[nr_offset(y, x)] & HVSH) + continue; + int nv = + (ndir[nr_offset(y - 1, x)] & VER) + (ndir[nr_offset(y + 1, x)] & VER) + + (ndir[nr_offset(y, x - 1)] & VER) + (ndir[nr_offset(y, x + 1)] & VER); + int nh = + (ndir[nr_offset(y - 1, x)] & HOR) + (ndir[nr_offset(y + 1, x)] & HOR) + + (ndir[nr_offset(y, x - 1)] & HOR) + (ndir[nr_offset(y, x + 1)] & HOR); + nv /= VER; + nh /= HOR; + if ((ndir[nr_offset(y, x)] & VER) && nh > 3) + { + ndir[nr_offset(y, x)] &= ~VER; + ndir[nr_offset(y, x)] |= HOR; + } + if ((ndir[nr_offset(y, x)] & HOR) && nv > 3) + { + ndir[nr_offset(y, x)] &= ~HOR; + ndir[nr_offset(y, x)] |= VER; + } + } +} +void DHT::make_hv_dline(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ мимо извеÑтного зелёного + * kc -- извеÑтный цвет в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + */ + for (int j = 0; j < iwidth; j++) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + char d = 0; + if ((j & 1) == js) + { + d = get_hv_grb(x, y, kc); + } + else + { + d = get_hv_rbg(x, y, kc); + } + ndir[nr_offset(y, x)] |= d; + } +} + +void DHT::make_diag_dline(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ мимо извеÑтного зелёного + * kc -- извеÑтный цвет в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + */ + for (int j = 0; j < iwidth; j++) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + char d = 0; + if ((j & 1) == js) + { + d = get_diag_grb(x, y, kc); + } + else + { + d = get_diag_rbg(x, y, kc); + } + ndir[nr_offset(y, x)] |= d; + } +} + +void DHT::refine_diag_dirs(int i, int js) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + for (int j = js; j < iwidth; j += 2) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + if (ndir[nr_offset(y, x)] & DIASH) + continue; + int nv = (ndir[nr_offset(y - 1, x)] & LURD) + + (ndir[nr_offset(y + 1, x)] & LURD) + + (ndir[nr_offset(y, x - 1)] & LURD) + + (ndir[nr_offset(y, x + 1)] & LURD) + + (ndir[nr_offset(y - 1, x - 1)] & LURD) + + (ndir[nr_offset(y - 1, x + 1)] & LURD) + + (ndir[nr_offset(y + 1, x - 1)] & LURD) + + (ndir[nr_offset(y + 1, x + 1)] & LURD); + int nh = (ndir[nr_offset(y - 1, x)] & RULD) + + (ndir[nr_offset(y + 1, x)] & RULD) + + (ndir[nr_offset(y, x - 1)] & RULD) + + (ndir[nr_offset(y, x + 1)] & RULD) + + (ndir[nr_offset(y - 1, x - 1)] & RULD) + + (ndir[nr_offset(y - 1, x + 1)] & RULD) + + (ndir[nr_offset(y + 1, x - 1)] & RULD) + + (ndir[nr_offset(y + 1, x + 1)] & RULD); + bool codir = (ndir[nr_offset(y, x)] & LURD) + ? ((ndir[nr_offset(y - 1, x - 1)] & LURD) || + (ndir[nr_offset(y + 1, x + 1)] & LURD)) + : ((ndir[nr_offset(y - 1, x + 1)] & RULD) || + (ndir[nr_offset(y + 1, x - 1)] & RULD)); + nv /= LURD; + nh /= RULD; + if ((ndir[nr_offset(y, x)] & LURD) && (nh > 4 && !codir)) + { + ndir[nr_offset(y, x)] &= ~LURD; + ndir[nr_offset(y, x)] |= RULD; + } + if ((ndir[nr_offset(y, x)] & RULD) && (nv > 4 && !codir)) + { + ndir[nr_offset(y, x)] &= ~RULD; + ndir[nr_offset(y, x)] |= LURD; + } + } +} + +void DHT::refine_idiag_dirs(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + for (int j = 0; j < iwidth; j++) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + if (ndir[nr_offset(y, x)] & DIASH) + continue; + int nv = (ndir[nr_offset(y - 1, x)] & LURD) + + (ndir[nr_offset(y + 1, x)] & LURD) + + (ndir[nr_offset(y, x - 1)] & LURD) + + (ndir[nr_offset(y, x + 1)] & LURD) + + (ndir[nr_offset(y - 1, x - 1)] & LURD) + + (ndir[nr_offset(y - 1, x + 1)] & LURD) + + (ndir[nr_offset(y + 1, x - 1)] & LURD) + + (ndir[nr_offset(y + 1, x + 1)] & LURD); + int nh = (ndir[nr_offset(y - 1, x)] & RULD) + + (ndir[nr_offset(y + 1, x)] & RULD) + + (ndir[nr_offset(y, x - 1)] & RULD) + + (ndir[nr_offset(y, x + 1)] & RULD) + + (ndir[nr_offset(y - 1, x - 1)] & RULD) + + (ndir[nr_offset(y - 1, x + 1)] & RULD) + + (ndir[nr_offset(y + 1, x - 1)] & RULD) + + (ndir[nr_offset(y + 1, x + 1)] & RULD); + nv /= LURD; + nh /= RULD; + if ((ndir[nr_offset(y, x)] & LURD) && nh > 7) + { + ndir[nr_offset(y, x)] &= ~LURD; + ndir[nr_offset(y, x)] |= RULD; + } + if ((ndir[nr_offset(y, x)] & RULD) && nv > 7) + { + ndir[nr_offset(y, x)] &= ~RULD; + ndir[nr_offset(y, x)] |= LURD; + } + } +} + +/* + * вычиÑление недоÑтающих зелёных точек. + */ +void DHT::make_greens() +{ +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_gline(i); + } +} + +void DHT::make_gline(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = libraw.COLOR(i, 0) & 1; + int kc = libraw.COLOR(i, js); + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ мимо извеÑтного зелёного + * kc -- извеÑтный цвет в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + */ + for (int j = js; j < iwidth; j += 2) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + int dx, dy, dx2, dy2; + float h1, h2; + if (ndir[nr_offset(y, x)] & VER) + { + dx = dx2 = 0; + dy = -1; + dy2 = 1; + h1 = 2 * nraw[nr_offset(y - 1, x)][1] / + (nraw[nr_offset(y - 2, x)][kc] + nraw[nr_offset(y, x)][kc]); + h2 = 2 * nraw[nr_offset(y + 1, x)][1] / + (nraw[nr_offset(y + 2, x)][kc] + nraw[nr_offset(y, x)][kc]); + } + else + { + dy = dy2 = 0; + dx = 1; + dx2 = -1; + h1 = 2 * nraw[nr_offset(y, x + 1)][1] / + (nraw[nr_offset(y, x + 2)][kc] + nraw[nr_offset(y, x)][kc]); + h2 = 2 * nraw[nr_offset(y, x - 1)][1] / + (nraw[nr_offset(y, x - 2)][kc] + nraw[nr_offset(y, x)][kc]); + } + float b1 = 1 / calc_dist(nraw[nr_offset(y, x)][kc], + nraw[nr_offset(y + dy * 2, x + dx * 2)][kc]); + float b2 = 1 / calc_dist(nraw[nr_offset(y, x)][kc], + nraw[nr_offset(y + dy2 * 2, x + dx2 * 2)][kc]); + b1 *= b1; + b2 *= b2; + float eg = nraw[nr_offset(y, x)][kc] * (b1 * h1 + b2 * h2) / (b1 + b2); + float min, max; + min = MIN(nraw[nr_offset(y + dy, x + dx)][1], + nraw[nr_offset(y + dy2, x + dx2)][1]); + max = MAX(nraw[nr_offset(y + dy, x + dx)][1], + nraw[nr_offset(y + dy2, x + dx2)][1]); + min /= 1.2; + max *= 1.2; + if (eg < min) + eg = scale_under(eg, min); + else if (eg > max) + eg = scale_over(eg, max); + if (eg > channel_maximum[1]) + eg = channel_maximum[1]; + else if (eg < channel_minimum[1]) + eg = channel_minimum[1]; + nraw[nr_offset(y, x)][1] = eg; + } +} + +/* + * Ð¾Ñ‚Ð»Ð°Ð´Ð¾Ñ‡Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ + */ + +void DHT::illustrate_dirs() +{ +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + illustrate_dline(i); + } +} + +void DHT::illustrate_dline(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + for (int j = 0; j < iwidth; j++) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + nraw[nr_offset(y, x)][0] = nraw[nr_offset(y, x)][1] = + nraw[nr_offset(y, x)][2] = 0.5; + int l = ndir[nr_offset(y, x)] & 8; + // l >>= 3; // WTF? + l = 1; + if (ndir[nr_offset(y, x)] & HOT) + nraw[nr_offset(y, x)][0] = + l * channel_maximum[0] / 4 + channel_maximum[0] / 4; + else + nraw[nr_offset(y, x)][2] = + l * channel_maximum[2] / 4 + channel_maximum[2] / 4; + } +} + +/* + * интерполÑÑ†Ð¸Ñ ÐºÑ€Ð°Ñных и Ñиних. + * + * Ñначала интерполируютÑÑ Ð½ÐµÐ´Ð¾Ñтающие цвета, по диагональным направлениÑм от + * которых находÑÑ‚ÑÑ Ð¸Ð·Ð²ÐµÑтные, затем ÑÐ¸Ñ‚ÑƒÐ°Ñ†Ð¸Ñ ÑводитÑÑ Ðº тому как + * интерполировалиÑÑŒ зелёные. + */ + +void DHT::make_rbdiag(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = libraw.COLOR(i, 0) & 1; + int uc = libraw.COLOR(i, js); + int cl = uc ^ 2; + /* + * js -- Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ…-координата, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ‚ на уже интерполированный + * зелёный al -- извеÑтный цвет (кроме зелёного) в точке Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ cl + * -- неизвеÑтный цвет + */ + for (int j = js; j < iwidth; j += 2) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + int dx, dy, dx2, dy2; + if (ndir[nr_offset(y, x)] & LURD) + { + dx = -1; + dx2 = 1; + dy = -1; + dy2 = 1; + } + else + { + dx = -1; + dx2 = 1; + dy = 1; + dy2 = -1; + } + float g1 = 1 / calc_dist(nraw[nr_offset(y, x)][1], + nraw[nr_offset(y + dy, x + dx)][1]); + float g2 = 1 / calc_dist(nraw[nr_offset(y, x)][1], + nraw[nr_offset(y + dy2, x + dx2)][1]); + g1 *= g1 * g1; + g2 *= g2 * g2; + + float eg; + eg = nraw[nr_offset(y, x)][1] * + (g1 * nraw[nr_offset(y + dy, x + dx)][cl] / + nraw[nr_offset(y + dy, x + dx)][1] + + g2 * nraw[nr_offset(y + dy2, x + dx2)][cl] / + nraw[nr_offset(y + dy2, x + dx2)][1]) / + (g1 + g2); + float min, max; + min = MIN(nraw[nr_offset(y + dy, x + dx)][cl], + nraw[nr_offset(y + dy2, x + dx2)][cl]); + max = MAX(nraw[nr_offset(y + dy, x + dx)][cl], + nraw[nr_offset(y + dy2, x + dx2)][cl]); + min /= 1.2; + max *= 1.2; + if (eg < min) + eg = scale_under(eg, min); + else if (eg > max) + eg = scale_over(eg, max); + if (eg > channel_maximum[cl]) + eg = channel_maximum[cl]; + else if (eg < channel_minimum[cl]) + eg = channel_minimum[cl]; + nraw[nr_offset(y, x)][cl] = eg; + } +} + +/* + * интерполÑÑ†Ð¸Ñ ÐºÑ€Ð°Ñных и Ñиних в точках где был извеÑтен только зелёный, + * Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð³Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒÐ½Ñ‹Ðµ или вертикальные + */ + +void DHT::make_rbhv(int i) +{ + int iwidth = libraw.imgdata.sizes.iwidth; + int js = (libraw.COLOR(i, 0) & 1) ^ 1; + for (int j = js; j < iwidth; j += 2) + { + int x = j + nr_leftmargin; + int y = i + nr_topmargin; + /* + * поÑкольку Ñверху-Ñнизу и Ñправа-Ñлева уже еÑÑ‚ÑŒ вÑе необходимые краÑные и + * Ñиние, то можно выбрать наилучшее направление иÑÑ…Ð¾Ð´Ñ Ð¸Ð· информации по + * обоим цветам. + */ + int dx, dy, dx2, dy2; + if (ndir[nr_offset(y, x)] & VER) + { + dx = dx2 = 0; + dy = -1; + dy2 = 1; + } + else + { + dy = dy2 = 0; + dx = 1; + dx2 = -1; + } + float g1 = 1 / calc_dist(nraw[nr_offset(y, x)][1], + nraw[nr_offset(y + dy, x + dx)][1]); + float g2 = 1 / calc_dist(nraw[nr_offset(y, x)][1], + nraw[nr_offset(y + dy2, x + dx2)][1]); + g1 *= g1; + g2 *= g2; + float eg_r, eg_b; + eg_r = nraw[nr_offset(y, x)][1] * + (g1 * nraw[nr_offset(y + dy, x + dx)][0] / + nraw[nr_offset(y + dy, x + dx)][1] + + g2 * nraw[nr_offset(y + dy2, x + dx2)][0] / + nraw[nr_offset(y + dy2, x + dx2)][1]) / + (g1 + g2); + eg_b = nraw[nr_offset(y, x)][1] * + (g1 * nraw[nr_offset(y + dy, x + dx)][2] / + nraw[nr_offset(y + dy, x + dx)][1] + + g2 * nraw[nr_offset(y + dy2, x + dx2)][2] / + nraw[nr_offset(y + dy2, x + dx2)][1]) / + (g1 + g2); + float min_r, max_r; + min_r = MIN(nraw[nr_offset(y + dy, x + dx)][0], + nraw[nr_offset(y + dy2, x + dx2)][0]); + max_r = MAX(nraw[nr_offset(y + dy, x + dx)][0], + nraw[nr_offset(y + dy2, x + dx2)][0]); + float min_b, max_b; + min_b = MIN(nraw[nr_offset(y + dy, x + dx)][2], + nraw[nr_offset(y + dy2, x + dx2)][2]); + max_b = MAX(nraw[nr_offset(y + dy, x + dx)][2], + nraw[nr_offset(y + dy2, x + dx2)][2]); + min_r /= 1.2; + max_r *= 1.2; + min_b /= 1.2; + max_b *= 1.2; + + if (eg_r < min_r) + eg_r = scale_under(eg_r, min_r); + else if (eg_r > max_r) + eg_r = scale_over(eg_r, max_r); + if (eg_b < min_b) + eg_b = scale_under(eg_b, min_b); + else if (eg_b > max_b) + eg_b = scale_over(eg_b, max_b); + + if (eg_r > channel_maximum[0]) + eg_r = channel_maximum[0]; + else if (eg_r < channel_minimum[0]) + eg_r = channel_minimum[0]; + if (eg_b > channel_maximum[2]) + eg_b = channel_maximum[2]; + else if (eg_b < channel_minimum[2]) + eg_b = channel_minimum[2]; + nraw[nr_offset(y, x)][0] = eg_r; + nraw[nr_offset(y, x)][2] = eg_b; + } +} + +void DHT::make_rb() +{ +#if defined(LIBRAW_USE_OPENMP) +#pragma omp barrier +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_rbdiag(i); + } +#if defined(LIBRAW_USE_OPENMP) +#pragma omp barrier +#pragma omp parallel for schedule(guided) +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + make_rbhv(i); + } +} + +/* + * Ð¿ÐµÑ€ÐµÐ½Ð¾Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² выходной маÑÑив + */ +void DHT::copy_to_image() +{ + int iwidth = libraw.imgdata.sizes.iwidth; +#if defined(LIBRAW_USE_OPENMP) +#ifdef _MSC_VER +#pragma omp parallel for +#else +#pragma omp parallel for schedule(guided) collapse(2) +#endif +#endif + for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) + { + for (int j = 0; j < iwidth; ++j) + { + libraw.imgdata.image[i * iwidth + j][0] = + (unsigned short)(nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)] + [0]); + libraw.imgdata.image[i * iwidth + j][2] = + (unsigned short)(nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)] + [2]); + libraw.imgdata.image[i * iwidth + j][1] = + libraw.imgdata.image[i * iwidth + j][3] = + (unsigned short)(nraw[nr_offset(i + nr_topmargin, + j + nr_leftmargin)][1]); + } + } +} + +DHT::~DHT() +{ + free(nraw); + free(ndir); +} + +void LibRaw::dht_interpolate() +{ + DHT dht(*this); + dht.hide_hots(); + dht.make_hv_dirs(); + // dht.illustrate_dirs(); + dht.make_greens(); + dht.make_diag_dirs(); + // dht.illustrate_dirs(); + dht.make_rb(); + dht.restore_hots(); + dht.copy_to_image(); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/demosaic/misc_demosaic.cpp libkdcraw/libkdcraw/libraw/src/demosaic/misc_demosaic.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/demosaic/misc_demosaic.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/demosaic/misc_demosaic.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,423 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::pre_interpolate() +{ + ushort(*img)[4]; + int row, col, c; + RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 0, 2); + if (shrink) + { + if (half_size) + { + height = iheight; + width = iwidth; + if (filters == 9) + { + for (row = 0; row < 3; row++) + for (col = 1; col < 4; col++) + if (!(image[row * width + col][0] | image[row * width + col][2])) + goto break2; + break2: + for (; row < height; row += 3) + for (col = (col - 1) % 3 + 1; col < width - 1; col += 3) + { + img = image + row * width + col; + for (c = 0; c < 3; c += 2) + img[0][c] = (img[-1][c] + img[1][c]) >> 1; + } + } + } + else + { + img = (ushort(*)[4])calloc(height, width * sizeof *img); + merror(img, "pre_interpolate()"); + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) + { + c = fcol(row, col); + img[row * width + col][c] = + image[(row >> 1) * iwidth + (col >> 1)][c]; + } + free(image); + image = img; + shrink = 0; + } + } + if (filters > 1000 && colors == 3) + { + mix_green = four_color_rgb ^ half_size; + if (four_color_rgb | half_size) + colors++; + else + { + for (row = FC(1, 0) >> 1; row < height; row += 2) + for (col = FC(row, 1) & 1; col < width; col += 2) + image[row * width + col][1] = image[row * width + col][3]; + filters &= ~((filters & 0x55555555U) << 1); + } + } + if (half_size) + filters = 0; + RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 1, 2); +} + +void LibRaw::border_interpolate(int border) +{ + unsigned row, col, y, x, f, c, sum[8]; + + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) + { + if (col == (unsigned)border && row >= (unsigned)border && row < (unsigned)(height - border)) + col = width - border; + memset(sum, 0, sizeof sum); + for (y = row - 1; y != row + 2; y++) + for (x = col - 1; x != col + 2; x++) + if (y < height && x < width) + { + f = fcol(y, x); + sum[f] += image[y * width + x][f]; + sum[f + 4]++; + } + f = fcol(row, col); + FORC(unsigned(colors)) if (c != f && sum[c + 4]) image[row * width + col][c] = + sum[c] / sum[c + 4]; + } +} + +void LibRaw::lin_interpolate_loop(int *code, int size) +{ + int row; + for (row = 1; row < height - 1; row++) + { + int col, *ip; + ushort *pix; + for (col = 1; col < width - 1; col++) + { + int i; + int sum[4]; + pix = image[row * width + col]; + ip = code + ((((row % size) * 16) + (col % size)) * 32); + 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; + } + } +} + +void LibRaw::lin_interpolate() +{ + std::vector<int> code_buffer(16 * 16 * 32); + int* code = &code_buffer[0], size = 16, *ip, sum[4]; + int f, c, x, y, row, col, shift, color; + + RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3); + + if (filters == 9) + size = 6; + border_interpolate(1); + for (row = 0; row < size; row++) + for (col = 0; col < size; col++) + { + ip = code + (((row * 16) + col) * 32) + 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 + 48, col + x + 48); + if (color == f) + continue; + *ip++ = (width * y + x) * 4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + code[(row * 16 + col) * 32] = (ip - (code + ((row * 16) + col) * 32)) / 3; + FORCC + if (c != f) + { + *ip++ = c; + *ip++ = sum[c] > 0 ? 256 / sum[c] : 0; + } + } + RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3); + lin_interpolate_loop(code, size); + RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3); +} + +/* + 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 LibRaw::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, -128, -1, -2, +0, -1, 0, 0x01, -1, -2, +1, + -1, 0, 0x01, -1, -2, +1, +0, 1, 0x01, -1, -1, -1, +1, 0, -120, + -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, -128, + +0, -1, +0, +1, 1, -120, +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, -128, + +1, -1, +1, +1, 0, -120, +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 (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 + 144, col + x1 + 144); + if (fcol(row + y2 + 144, col + x2 + 144) != 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 + 144, col + x + 144) != color && + fcol(row + y * 2 + 144, col + x * 2 + 144) == 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 */ + if (!((row - 2) % 256)) + RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, (row - 2) / 256 + 1, + ((height - 3) / 256) + 1); + 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 LibRaw::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); + + /* Fill in the green layer with gradients and pattern recognition: */ + RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3); +#ifdef LIBRAW_USE_OPENMP +#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, \ + i, pix) schedule(static) +#endif + for (row = 3; row < height - 3; row++) + for (col = 3 + (FC(row, 3) & 1), c = FC(row, col); col < width - 3; + col += 2) + { + pix = image + row * width + col; + for (i = 0; i < 2; i++) + { + d = dir[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: */ + RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3); +#ifdef LIBRAW_USE_OPENMP +#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, \ + i, pix) schedule(static) +#endif + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 2) & 1), c = FC(row, col + 1); col < width - 1; + col += 2) + { + pix = image + row * width + col; + for (i = 0; i < 2; c = 2 - c, i++) + { + d = dir[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: */ + RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3); +#ifdef LIBRAW_USE_OPENMP +#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, \ + i, pix) schedule(static) +#endif + for (row = 1; row < height - 1; row++) + for (col = 1 + (FC(row, 1) & 1), c = 2 - FC(row, col); col < width - 1; + col += 2) + { + pix = image + row * width + col; + for (i = 0; i < 2; i++) + { + d = dir[i] + dir[i+1]; + 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); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/demosaic/xtrans_demosaic.cpp libkdcraw/libkdcraw/libraw/src/demosaic/xtrans_demosaic.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/demosaic/xtrans_demosaic.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/demosaic/xtrans_demosaic.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,381 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +#define fcol(row, col) xtrans[(row + 6) % 6][(col + 6) % 6] +/* + Frank Markesteijn's algorithm for Fuji X-Trans sensors + */ +void LibRaw::xtrans_interpolate(int passes) +{ + int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; + + int cstat[4] = {0, 0, 0, 0}; + + int val, ndir, pass, hm[8], avg[4], color[3][8]; + static const short orth[12] = {1, 0, 0, 1, -1, 0, 0, -1, 1, 0, 0, 1}, + patt[2][16] = {{0, 1, 0, -1, 2, 0, -1, 0, 1, 1, 1, -1, 0, + 0, 0, 0}, + {0, 1, 0, -2, 1, 0, -2, 0, 1, 1, -2, -2, 1, + -1, -1, 1}}, + dir[4] = {1, LIBRAW_AHD_TILE, LIBRAW_AHD_TILE + 1, + LIBRAW_AHD_TILE - 1}; + short allhex[3][3][2][8], *hex; + ushort min, max, sgrow, sgcol; + ushort(*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], (*rix)[3], (*pix)[4]; + short(*lab)[LIBRAW_AHD_TILE][3], (*lix)[3]; + float(*drv)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE], diff[6], tr; + char(*homo)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE], *buffer; + + if (width < LIBRAW_AHD_TILE || height < LIBRAW_AHD_TILE) + throw LIBRAW_EXCEPTION_IO_CORRUPT; // too small image + /* Check against right pattern */ + for (row = 0; row < 6; row++) + for (col = 0; col < 6; col++) + cstat[(unsigned)fcol(row, col)]++; + + if (cstat[0] < 6 || cstat[0] > 10 || cstat[1] < 16 || cstat[1] > 24 || + cstat[2] < 6 || cstat[2] > 10 || cstat[3]) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + // Init allhex table to unreasonable values + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + for (int l = 0; l < 8; l++) + allhex[i][j][k][l] = 32700; + + cielab(0, 0); + ndir = 4 << (passes > 1); + buffer = (char *)malloc(LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 11 + 6)); + merror(buffer, "xtrans_interpolate()"); + rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer; + lab = (short(*)[LIBRAW_AHD_TILE][3])( + buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 6)); + drv = (float(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE])( + buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 6 + 6)); + homo = (char(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE])( + buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 10 + 6)); + + int minv = 0, maxv = 0, minh = 0, maxh = 0; + /* Map a green hexagon around each non-green pixel and vice versa: */ + for (row = 0; row < 3; row++) + for (col = 0; col < 3; col++) + for (ng = d = 0; d < 10; d += 2) + { + g = fcol(row, col) == 1; + if (fcol(row + orth[d], col + orth[d + 2]) == 1) + ng = 0; + else + ng++; + if (ng == 4) + { + sgrow = row; + sgcol = col; + } + if (ng == g + 1) + FORC(8) + { + v = orth[d] * patt[g][c * 2] + orth[d + 1] * patt[g][c * 2 + 1]; + h = orth[d + 2] * patt[g][c * 2] + orth[d + 3] * patt[g][c * 2 + 1]; + minv = MIN(v, minv); + maxv = MAX(v, maxv); + minh = MIN(v, minh); + maxh = MAX(v, maxh); + allhex[row][col][0][c ^ (g * 2 & d)] = h + v * width; + allhex[row][col][1][c ^ (g * 2 & d)] = h + v * LIBRAW_AHD_TILE; + } + } + + // Check allhex table initialization + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + for (int l = 0; l < 8; l++) + if (allhex[i][j][k][l] > maxh + maxv * width + 1 || + allhex[i][j][k][l] < minh + minv * width - 1) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + int retrycount = 0; + + /* Set green1 and green3 to the minimum and maximum allowed values: */ + for (row = 2; row < height - 2; row++) + for (min = ~(max = 0), col = 2; col < width - 2; col++) + { + if (fcol(row, col) == 1 && (min = ~(max = 0))) + continue; + pix = image + row * width + col; + hex = allhex[row % 3][col % 3][0]; + if (!max) + FORC(6) + { + val = pix[hex[c]][1]; + if (min > val) + min = val; + if (max < val) + max = val; + } + pix[0][1] = min; + pix[0][3] = max; + switch ((row - sgrow) % 3) + { + case 1: + if (row < height - 3) + { + row++; + col--; + } + break; + case 2: + if ((min = ~(max = 0)) && (col += 2) < width - 3 && row > 2) + { + row--; + if (retrycount++ > width * height) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + } + } + + for (row = 3; row < 9 && row < height - 3; row++) + for (col = 3; col < 9 && col < width - 3; col++) + { + if ((f = fcol(row, col)) == 1) + continue; + hex = allhex[row % 3][col % 3][0]; + FORC(2) + { + int idx3 = 3 * hex[4 + c] + row * width + col; + int idx4 = -3 * hex[4 + c] + row * width + col; + int maxidx = width * height; + if (idx3 < 0 || idx3 >= maxidx) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if (idx4 < 0 || idx4 >= maxidx) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + } + + for (top = 3; top < height - 19; top += LIBRAW_AHD_TILE - 16) + for (left = 3; left < width - 19; left += LIBRAW_AHD_TILE - 16) + { + mrow = MIN(top + LIBRAW_AHD_TILE, height - 3); + mcol = MIN(left + LIBRAW_AHD_TILE, width - 3); + for (row = top; row < mrow; row++) + for (col = left; col < mcol; col++) + memcpy(rgb[0][row - top][col - left], image[row * width + col], 6); + FORC3 memcpy(rgb[c + 1], rgb[0], sizeof *rgb); + + /* Interpolate green horizontally, vertically, and along both diagonals: + */ + for (row = top; row < mrow; row++) + for (col = left; col < mcol; col++) + { + if ((f = fcol(row, col)) == 1) + continue; + pix = image + row * width + col; + hex = allhex[row % 3][col % 3][0]; + color[1][0] = 174 * (pix[hex[1]][1] + pix[hex[0]][1]) - + 46 * (pix[2 * hex[1]][1] + pix[2 * hex[0]][1]); + color[1][1] = 223 * pix[hex[3]][1] + pix[hex[2]][1] * 33 + + 92 * (pix[0][f] - pix[-hex[2]][f]); + FORC(2) + color[1][2 + c] = 164 * pix[hex[4 + c]][1] + + 92 * pix[-2 * hex[4 + c]][1] + + 33 * (2 * pix[0][f] - pix[3 * hex[4 + c]][f] - + pix[-3 * hex[4 + c]][f]); + FORC4 rgb[c ^ !((row - sgrow) % 3)][row - top][col - left][1] = + LIM(color[1][c] >> 8, pix[0][1], pix[0][3]); + } + + for (pass = 0; pass < passes; pass++) + { + if (pass == 1) + memcpy(rgb += 4, buffer, 4 * sizeof *rgb); + + /* Recalculate green from interpolated values of closer pixels: */ + if (pass) + { + for (row = top + 2; row < mrow - 2; row++) + for (col = left + 2; col < mcol - 2; col++) + { + if ((f = fcol(row, col)) == 1) + continue; + pix = image + row * width + col; + hex = allhex[row % 3][col % 3][1]; + for (d = 3; d < 6; d++) + { + rix = + &rgb[(d - 2) ^ !((row - sgrow) % 3)][row - top][col - left]; + val = rix[-2 * hex[d]][1] + 2 * rix[hex[d]][1] - + rix[-2 * hex[d]][f] - 2 * rix[hex[d]][f] + 3 * rix[0][f]; + rix[0][1] = LIM(val / 3, pix[0][1], pix[0][3]); + } + } + } + + /* Interpolate red and blue values for solitary green pixels: */ + for (row = (top - sgrow + 4) / 3 * 3 + sgrow; row < mrow - 2; row += 3) + for (col = (left - sgcol + 4) / 3 * 3 + sgcol; col < mcol - 2; + col += 3) + { + rix = &rgb[0][row - top][col - left]; + h = fcol(row, col + 1); + memset(diff, 0, sizeof diff); + for (i = 1, d = 0; d < 6; d++, i ^= LIBRAW_AHD_TILE ^ 1, h ^= 2) + { + for (c = 0; c < 2; c++, h ^= 2) + { + g = 2 * rix[0][1] - rix[i << c][1] - rix[-i << c][1]; + color[h][d] = g + rix[i << c][h] + rix[-i << c][h]; + if (d > 1) + diff[d] += SQR((float)rix[i << c][1] - (float)rix[-i << c][1] - + (float)rix[i << c][h] + (float)rix[-i << c][h]) + SQR((float)g); + } + if (d > 1 && (d & 1)) + if (diff[d - 1] < diff[d]) + FORC(2) color[c * 2][d] = color[c * 2][d - 1]; + if (d < 2 || (d & 1)) + { + FORC(2) rix[0][c * 2] = CLIP(color[c * 2][d] / 2); + rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE; + } + } + } + + /* Interpolate red for blue pixels and vice versa: */ + for (row = top + 3; row < mrow - 3; row++) + for (col = left + 3; col < mcol - 3; col++) + { + if ((f = 2 - fcol(row, col)) == 1) + continue; + rix = &rgb[0][row - top][col - left]; + c = (row - sgrow) % 3 ? LIBRAW_AHD_TILE : 1; + h = 3 * (c ^ LIBRAW_AHD_TILE ^ 1); + for (d = 0; d < 4; d++, rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE) + { + i = d > 1 || ((d ^ c) & 1) || + ((ABS(rix[0][1] - rix[c][1]) + + ABS(rix[0][1] - rix[-c][1])) < + 2 * (ABS(rix[0][1] - rix[h][1]) + + ABS(rix[0][1] - rix[-h][1]))) + ? c + : h; + rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + 2 * rix[0][1] - + rix[i][1] - rix[-i][1]) / + 2); + } + } + + /* Fill in red and blue for 2x2 blocks of green: */ + for (row = top + 2; row < mrow - 2; row++) + if ((row - sgrow) % 3) + for (col = left + 2; col < mcol - 2; col++) + if ((col - sgcol) % 3) + { + rix = &rgb[0][row - top][col - left]; + hex = allhex[row % 3][col % 3][1]; + for (d = 0; d < ndir; + d += 2, rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE) + if (hex[d] + hex[d + 1]) + { + g = 3 * rix[0][1] - 2 * rix[hex[d]][1] - rix[hex[d + 1]][1]; + for (c = 0; c < 4; c += 2) + rix[0][c] = CLIP( + (g + 2 * rix[hex[d]][c] + rix[hex[d + 1]][c]) / 3); + } + else + { + g = 2 * rix[0][1] - rix[hex[d]][1] - rix[hex[d + 1]][1]; + for (c = 0; c < 4; c += 2) + rix[0][c] = + CLIP((g + rix[hex[d]][c] + rix[hex[d + 1]][c]) / 2); + } + } + } + rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer; + mrow -= top; + mcol -= left; + + /* Convert to CIELab and differentiate in all directions: */ + for (d = 0; d < ndir; d++) + { + for (row = 2; row < mrow - 2; row++) + for (col = 2; col < mcol - 2; col++) + cielab(rgb[d][row][col], lab[row][col]); + for (f = dir[d & 3], row = 3; row < mrow - 3; row++) + for (col = 3; col < mcol - 3; col++) + { + lix = &lab[row][col]; + g = 2 * lix[0][0] - lix[f][0] - lix[-f][0]; + drv[d][row][col] = + SQR(g) + + SQR((2 * lix[0][1] - lix[f][1] - lix[-f][1] + g * 500 / 232)) + + SQR((2 * lix[0][2] - lix[f][2] - lix[-f][2] - g * 500 / 580)); + } + } + + /* Build homogeneity maps from the derivatives: */ + memset(homo, 0, ndir * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE); + for (row = 4; row < mrow - 4; row++) + for (col = 4; col < mcol - 4; col++) + { + for (tr = FLT_MAX, d = 0; d < ndir; d++) + if (tr > drv[d][row][col]) + tr = drv[d][row][col]; + tr *= 8; + for (d = 0; d < ndir; d++) + for (v = -1; v <= 1; v++) + for (h = -1; h <= 1; h++) + if (drv[d][row + v][col + h] <= tr) + homo[d][row][col]++; + } + + /* Average the most homogenous pixels for the final result: */ + if (height - top < LIBRAW_AHD_TILE + 4) + mrow = height - top + 2; + if (width - left < LIBRAW_AHD_TILE + 4) + mcol = width - left + 2; + for (row = MIN(top, 8); row < mrow - 8; row++) + for (col = MIN(left, 8); col < mcol - 8; col++) + { + for (d = 0; d < ndir; d++) + for (hm[d] = 0, v = -2; v <= 2; v++) + for (h = -2; h <= 2; h++) + hm[d] += homo[d][row + v][col + h]; + for (d = 0; d < ndir - 4; d++) + if (hm[d] < hm[d + 4]) + hm[d] = 0; + else if (hm[d] > hm[d + 4]) + hm[d + 4] = 0; + for (max = hm[0], d = 1; d < ndir; d++) + if (max < hm[d]) + max = hm[d]; + max -= max >> 3; + memset(avg, 0, sizeof avg); + for (d = 0; d < ndir; d++) + if (hm[d] >= max) + { + FORC3 avg[c] += rgb[d][row][col][c]; + avg[3]++; + } + FORC3 image[(row + top) * width + col + left][c] = avg[c] / avg[3]; + } + } + free(buffer); + border_interpolate(8); +} +#undef fcol diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/integration/dngsdk_glue.cpp libkdcraw/libkdcraw/libraw/src/integration/dngsdk_glue.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/integration/dngsdk_glue.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/integration/dngsdk_glue.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,389 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#if defined (USE_GPRSDK) && !defined(USE_DNGSDK) +#error GPR (GoPro) SDK should be used with Adobe DNG SDK +#endif +#ifdef USE_DNGSDK +#include "dng_read_image.h" +#endif +#ifdef USE_GPRSDK +#include "gpr_read_image.h" +#endif + +#ifdef USE_DNGSDK +static dng_ifd* search_single_ifd(const std::vector <dng_ifd *>& v, uint64 offset, int& idx, dng_stream& stream) +{ + idx = -1; + for (int i = 0; i < v.size(); i++) + { + if (!v[i]) continue; + if (v[i]->fTileOffsetsOffset == offset) + { + idx = i; + return v[i]; + } + else if (v[i]->fTileOffsetsCount == 1 && v[i]->fTileOffset[0] == offset) + { + idx = i; + return v[i]; + } + else if (v[i]->fTileOffsetsCount > dng_ifd::kMaxTileInfo) + { + uint64 p = stream.Position(); + stream.SetReadPosition(v[i]->fTileOffsetsOffset); + int32 oo = stream.TagValue_uint32(v[i]->fTileOffsetsType); + stream.SetReadPosition(p); + if (oo == offset) + { + idx = i; + return v[i]; + } + } + } + return NULL; +} + +static dng_ifd* search_for_ifd(const dng_info& info, uint64 offset, ushort w, ushort h, int& ifdIndex, dng_stream& stream) +{ + dng_ifd *ret = 0; + ret = search_single_ifd(info.fIFD, offset, ifdIndex, stream); + int dummy; + if (!ret) ret = search_single_ifd(info.fChainedIFD, offset, dummy, stream); + if (!ret) + { + for (int c = 0; !ret && c < info.fChainedSubIFD.size(); c++) + ret = search_single_ifd(info.fChainedSubIFD[c], offset, dummy, stream); + } + if (ret && (ret->fImageLength == h) && ret->fImageWidth == w) + return ret; + ifdIndex = -1; + return 0; +} +#endif + +int LibRaw::valid_for_dngsdk() +{ +#ifndef USE_DNGSDK + return 0; +#else + if (!imgdata.idata.dng_version) + return 0; + if (libraw_internal_data.unpacker_data.tiff_compress == 34892 + && libraw_internal_data.unpacker_data.tiff_bps == 8 + && libraw_internal_data.unpacker_data.tiff_samples == 3 + && load_raw == &LibRaw::lossy_dng_load_raw + ) + { + if (!dnghost) + return 0; + dng_host *host = static_cast<dng_host *>(dnghost); + libraw_dng_stream stream(libraw_internal_data.internal_data.input); + AutoPtr<dng_negative> negative; + negative.Reset(host->Make_dng_negative()); + dng_info info; + info.Parse(*host, stream); + info.PostParse(*host); + if (!info.IsValidDNG()) + return 0; + negative->Parse(*host, stream, info); + negative->PostParse(*host, stream, info); + int ifdindex = -1; + dng_ifd *rawIFD = search_for_ifd(info, libraw_internal_data.unpacker_data.data_offset, imgdata.sizes.raw_width, imgdata.sizes.raw_height, ifdindex,stream); + if (rawIFD && ifdindex >= 0 && ifdindex == info.fMainIndex) + return 1; + return 0; + } + +#ifdef USE_GPRSDK + if (load_raw == &LibRaw::vc5_dng_load_raw_placeholder) // regardless of flags or use_dngsdk value! + return 1; +#endif + if (!imgdata.params.use_dngsdk) + return 0; + if (load_raw == &LibRaw::lossy_dng_load_raw) // WHY?? + return 0; + if (load_raw == + &LibRaw::float_dng_load_raw_placeholder) // regardless of flags! + return 1; + if (is_floating_point() && (imgdata.params.use_dngsdk & LIBRAW_DNG_FLOAT)) + return 1; + if (!imgdata.idata.filters && (imgdata.params.use_dngsdk & LIBRAW_DNG_LINEAR)) + return 1; + if (libraw_internal_data.unpacker_data.tiff_bps == 8 && + (imgdata.params.use_dngsdk & LIBRAW_DNG_8BIT)) + return 1; + if (libraw_internal_data.unpacker_data.tiff_compress == 8 && + (imgdata.params.use_dngsdk & LIBRAW_DNG_DEFLATE)) + return 1; + if (libraw_internal_data.unpacker_data.tiff_samples == 2) + return 0; // Always deny 2-samples (old fuji superccd) + if (imgdata.idata.filters == 9 && + (imgdata.params.use_dngsdk & LIBRAW_DNG_XTRANS)) + return 1; + if (is_fuji_rotated()) + return 0; // refuse + if (imgdata.params.use_dngsdk & LIBRAW_DNG_OTHER) + return 1; + return 0; +#endif +} + + + + +int LibRaw::try_dngsdk() +{ +#ifdef USE_DNGSDK + if (!dnghost) + return LIBRAW_UNSPECIFIED_ERROR; + + dng_host *host = static_cast<dng_host *>(dnghost); + + try + { + libraw_dng_stream stream(libraw_internal_data.internal_data.input); + + AutoPtr<dng_negative> negative; + negative.Reset(host->Make_dng_negative()); + + dng_info info; + info.Parse(*host, stream); + info.PostParse(*host); + + if (!info.IsValidDNG()) + { + return LIBRAW_DATA_ERROR; + } + negative->Parse(*host, stream, info); + negative->PostParse(*host, stream, info); + int ifdindex; + dng_ifd *rawIFD = search_for_ifd(info,libraw_internal_data.unpacker_data.data_offset,imgdata.sizes.raw_width,imgdata.sizes.raw_height,ifdindex,stream); + if(!rawIFD) + return LIBRAW_DATA_ERROR; + + AutoPtr<dng_simple_image> stage2; + bool stage23used = false; + bool zerocopy = false; + + //(new dng_simple_image(rawIFD->Bounds(), rawIFD->fSamplesPerPixel, rawIFD->PixelType(), host->Allocator())); + + if (((libraw_internal_data.unpacker_data.tiff_compress == 34892 + && libraw_internal_data.unpacker_data.tiff_bps == 8 + && libraw_internal_data.unpacker_data.tiff_samples == 3 + && load_raw == &LibRaw::lossy_dng_load_raw) || + (imgdata.params.raw_processing_options & (LIBRAW_PROCESSING_DNG_STAGE2| LIBRAW_PROCESSING_DNG_STAGE3))) + && ifdindex >= 0) + { + if (info.fMainIndex != ifdindex) + info.fMainIndex = ifdindex; + + negative->ReadStage1Image(*host, stream, info); + negative->BuildStage2Image(*host); + imgdata.process_warnings |= LIBRAW_WARN_DNG_STAGE2_APPLIED; + if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNG_STAGE3) + { + negative->BuildStage3Image(*host); + stage2.Reset((dng_simple_image*)negative->Stage3Image()); + imgdata.process_warnings |= LIBRAW_WARN_DNG_STAGE3_APPLIED; + } + else + stage2.Reset((dng_simple_image*)negative->Stage2Image()); + stage23used = true; + } + else + { + stage2.Reset(new dng_simple_image(rawIFD->Bounds(), rawIFD->fSamplesPerPixel, rawIFD->PixelType(), host->Allocator())); +#ifdef USE_GPRSDK + if (libraw_internal_data.unpacker_data.tiff_compress == 9) + { + gpr_allocator allocator; + allocator.Alloc = ::malloc; + allocator.Free = ::free; + gpr_buffer_auto vc5_image_obj(allocator.Alloc, allocator.Free); + + gpr_read_image reader(&vc5_image_obj); + reader.Read(*host, *rawIFD, stream, *stage2.Get(), NULL, NULL); + } + else +#endif + { + dng_read_image reader; + reader.Read(*host, *rawIFD, stream, *stage2.Get(), NULL, NULL); + } + } + + if (stage2->Bounds().W() != S.raw_width || + stage2->Bounds().H() != S.raw_height) + { + if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNG_ALLOWSIZECHANGE) + { + S.raw_width = S.width = stage2->Bounds().W(); + S.left_margin = 0; + S.raw_height = S.height = stage2->Bounds().H(); + S.top_margin = 0; + } + else + { + stage2.Release(); // It holds copy to internal dngnegative + return LIBRAW_DATA_ERROR; + } + } + if (stage23used) + { + if (stage2->Planes() > 1) + { + imgdata.idata.filters = 0; + imgdata.idata.colors = stage2->Planes(); + } + // reset BL and whitepoint + imgdata.color.black = 0; + memset(imgdata.color.cblack, 0, sizeof(imgdata.color.cblack)); + imgdata.color.maximum = 0xffff; + } + + int pplanes = stage2->Planes(); + int ptype = stage2->PixelType(); + + dng_pixel_buffer buffer; + stage2->GetPixelBuffer(buffer); + + int pixels = stage2->Bounds().H() * stage2->Bounds().W() * pplanes; + + if (ptype == ttShort && !stage23used && !is_curve_linear()) + { + imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ptype)); + ushort *src = (ushort *)buffer.fData; + ushort *dst = (ushort *)imgdata.rawdata.raw_alloc; + for (int i = 0; i < pixels; i++) + dst[i] = imgdata.color.curve[src[i]]; + S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ptype); + + } + else if (ptype == ttByte) + { + imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ttShort)); + unsigned char *src = (unsigned char *)buffer.fData; + ushort *dst = (ushort *)imgdata.rawdata.raw_alloc; + if (is_curve_linear()) + { + for (int i = 0; i < pixels; i++) + dst[i] = src[i]; + } + else + { + for (int i = 0; i < pixels; i++) + dst[i] = imgdata.color.curve[src[i]]; + } + S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ttShort); + } + else + { + // Alloc + if ((imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNGSDK_ZEROCOPY) && !stage23used) + { + zerocopy = true; + } + else + { + imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ptype)); + memmove(imgdata.rawdata.raw_alloc, buffer.fData, + pixels * TagTypeSize(ptype)); + } + S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ptype); + } + + if (stage23used) + stage2.Release(); + + if (zerocopy) + { + switch (ptype) + { + case ttFloat: + if (pplanes == 1) + imgdata.rawdata.float_image = (float *)buffer.fData; + else if (pplanes == 3) + imgdata.rawdata.float3_image = (float(*)[3])buffer.fData; + else if (pplanes == 4) + imgdata.rawdata.float4_image = (float(*)[4])buffer.fData; + break; + + case ttShort: + if (pplanes == 1) + imgdata.rawdata.raw_image = (ushort *)buffer.fData; + else if (pplanes == 3) + imgdata.rawdata.color3_image = (ushort(*)[3])buffer.fData; + else if (pplanes == 4) + imgdata.rawdata.color4_image = (ushort(*)[4])buffer.fData; + break; + default: + /* do nothing */ + break; + } + } + else + { + switch (ptype) + { + case ttFloat: + if (pplanes == 1) + imgdata.rawdata.float_image = (float *)imgdata.rawdata.raw_alloc; + else if (pplanes == 3) + imgdata.rawdata.float3_image = (float(*)[3])imgdata.rawdata.raw_alloc; + else if (pplanes == 4) + imgdata.rawdata.float4_image = (float(*)[4])imgdata.rawdata.raw_alloc; + break; + + case ttByte: + case ttShort: + if (pplanes == 1) + imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc; + else if (pplanes == 3) + imgdata.rawdata.color3_image = + (ushort(*)[3])imgdata.rawdata.raw_alloc; + else if (pplanes == 4) + imgdata.rawdata.color4_image = + (ushort(*)[4])imgdata.rawdata.raw_alloc; + break; + default: + /* do nothing */ + break; + } + } + if (zerocopy) + { + dng_negative *stolen = negative.Release(); + dngnegative = stolen; + dng_simple_image *simage = stage2.Release(); + dngimage = simage; + } + } + catch (...) + { + return LIBRAW_UNSPECIFIED_ERROR; + } + return imgdata.rawdata.raw_alloc ? LIBRAW_SUCCESS : LIBRAW_UNSPECIFIED_ERROR; +#else + return LIBRAW_UNSPECIFIED_ERROR; +#endif +} +void LibRaw::set_dng_host(void *p) +{ +#ifdef USE_DNGSDK + dnghost = p; +#endif +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/integration/rawspeed_glue.cpp libkdcraw/libkdcraw/libraw/src/integration/rawspeed_glue.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/integration/rawspeed_glue.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/integration/rawspeed_glue.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,273 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#ifdef USE_RAWSPEED +using namespace RawSpeed; + +CameraMetaDataLR::CameraMetaDataLR(char *data, int sz) : CameraMetaData() +{ + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + { + ThrowCME("CameraMetaData:Could not initialize context."); + } + + xmlResetLastError(); + doc = xmlCtxtReadMemory(ctxt, data, sz, "", NULL, XML_PARSE_DTDVALID); + + if (doc == NULL) + { + ThrowCME("CameraMetaData: XML Document could not be parsed successfully. " + "Error was: %s", + ctxt->lastError.message); + } + + if (ctxt->valid == 0) + { + if (ctxt->lastError.code == 0x5e) + { + // ignore this error code + } + else + { + ThrowCME("CameraMetaData: XML file does not validate. DTD Error was: %s", + ctxt->lastError.message); + } + } + + xmlNodePtr cur; + cur = xmlDocGetRootElement(doc); + if (xmlStrcmp(cur->name, (const xmlChar *)"Cameras")) + { + ThrowCME("CameraMetaData: XML document of the wrong type, root node is not " + "cameras."); + return; + } + + cur = cur->xmlChildrenNode; + while (cur != NULL) + { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"Camera"))) + { + Camera *camera = new Camera(doc, cur); + addCamera(camera); + + // Create cameras for aliases. + for (unsigned int i = 0; i < camera->aliases.size(); i++) + { + addCamera(new Camera(camera, i)); + } + } + cur = cur->next; + } + if (doc) + xmlFreeDoc(doc); + doc = 0; + if (ctxt) + xmlFreeParserCtxt(ctxt); + ctxt = 0; +} + +CameraMetaDataLR *make_camera_metadata() +{ + int len = 0, i; + for (i = 0; i < RAWSPEED_DATA_COUNT; i++) + if (_rawspeed_data_xml[i]) + { + len += strlen(_rawspeed_data_xml[i]); + } + char *rawspeed_xml = + (char *)calloc(len + 1, sizeof(_rawspeed_data_xml[0][0])); + if (!rawspeed_xml) + return NULL; + int offt = 0; + for (i = 0; i < RAWSPEED_DATA_COUNT; i++) + if (_rawspeed_data_xml[i]) + { + int ll = strlen(_rawspeed_data_xml[i]); + if (offt + ll > len) + break; + memmove(rawspeed_xml + offt, _rawspeed_data_xml[i], ll); + offt += ll; + } + rawspeed_xml[offt] = 0; + CameraMetaDataLR *ret = NULL; + try + { + ret = new CameraMetaDataLR(rawspeed_xml, offt); + } + catch (...) + { + // Mask all exceptions + } + free(rawspeed_xml); + return ret; +} + +#endif + +int LibRaw::set_rawspeed_camerafile(char *filename) +{ +#ifdef USE_RAWSPEED + try + { + CameraMetaDataLR *camerameta = new CameraMetaDataLR(filename); + if (_rawspeed_camerameta) + { + CameraMetaDataLR *d = + static_cast<CameraMetaDataLR *>(_rawspeed_camerameta); + delete d; + } + _rawspeed_camerameta = static_cast<void *>(camerameta); + } + catch (...) + { + // just return error code + return -1; + } +#endif + return 0; +} +#ifdef USE_RAWSPEED +void LibRaw::fix_after_rawspeed(int bl) +{ + if (load_raw == &LibRaw::lossy_dng_load_raw) + C.maximum = 0xffff; + else if (load_raw == &LibRaw::sony_load_raw) + C.maximum = 0x3ff0; +} +#else +void LibRaw::fix_after_rawspeed(int) {} +#endif + +int LibRaw::try_rawspeed() +{ +#ifdef USE_RAWSPEED + int ret = LIBRAW_SUCCESS; + + int rawspeed_ignore_errors = 0; + if (imgdata.idata.dng_version && imgdata.idata.colors == 3 && + !strcasecmp(imgdata.idata.software, + "Adobe Photoshop Lightroom 6.1.1 (Windows)")) + rawspeed_ignore_errors = 1; + + // RawSpeed Supported, + INT64 spos = ID.input->tell(); + void *_rawspeed_buffer = 0; + try + { + ID.input->seek(0, SEEK_SET); + INT64 _rawspeed_buffer_sz = ID.input->size() + 32; + _rawspeed_buffer = malloc(_rawspeed_buffer_sz); + if (!_rawspeed_buffer) + throw LIBRAW_EXCEPTION_ALLOC; + ID.input->read(_rawspeed_buffer, _rawspeed_buffer_sz, 1); + FileMap map((uchar8 *)_rawspeed_buffer, _rawspeed_buffer_sz); + RawParser t(&map); + RawDecoder *d = 0; + CameraMetaDataLR *meta = + static_cast<CameraMetaDataLR *>(_rawspeed_camerameta); + d = t.getDecoder(); + if (!d) + throw "Unable to find decoder"; + try + { + d->checkSupport(meta); + } + catch (const RawDecoderException &e) + { + imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_UNSUPPORTED; + throw e; + } + d->interpolateBadPixels = FALSE; + d->applyStage1DngOpcodes = FALSE; + _rawspeed_decoder = static_cast<void *>(d); + d->decodeRaw(); + d->decodeMetaData(meta); + RawImage r = d->mRaw; + if (r->errors.size() > 0 && !rawspeed_ignore_errors) + { + delete d; + _rawspeed_decoder = 0; + throw 1; + } + if (r->isCFA) + { + imgdata.rawdata.raw_image = (ushort *)r->getDataUncropped(0, 0); + } + else if (r->getCpp() == 4) + { + imgdata.rawdata.color4_image = (ushort(*)[4])r->getDataUncropped(0, 0); + if (r->whitePoint > 0 && r->whitePoint < 65536) + C.maximum = r->whitePoint; + } + else if (r->getCpp() == 3) + { + imgdata.rawdata.color3_image = (ushort(*)[3])r->getDataUncropped(0, 0); + if (r->whitePoint > 0 && r->whitePoint < 65536) + C.maximum = r->whitePoint; + } + else + { + delete d; + _rawspeed_decoder = 0; + ret = LIBRAW_UNSPECIFIED_ERROR; + } + if (_rawspeed_decoder) + { + // set sizes + iPoint2D rsdim = r->getUncroppedDim(); + S.raw_pitch = r->pitch; + S.raw_width = rsdim.x; + S.raw_height = rsdim.y; + // C.maximum = r->whitePoint; + fix_after_rawspeed(r->blackLevel); + } + free(_rawspeed_buffer); + _rawspeed_buffer = 0; + imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROCESSED; + } + catch (const RawDecoderException &RDE) + { + imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROBLEM; + if (_rawspeed_buffer) + { + free(_rawspeed_buffer); + _rawspeed_buffer = 0; + } + const char *p = RDE.what(); + if (!strncmp(RDE.what(), "Decoder canceled", strlen("Decoder canceled"))) + throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; + ret = LIBRAW_UNSPECIFIED_ERROR; + } + catch (...) + { + // We may get here due to cancellation flag + imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROBLEM; + if (_rawspeed_buffer) + { + free(_rawspeed_buffer); + _rawspeed_buffer = 0; + } + ret = LIBRAW_UNSPECIFIED_ERROR; + } + ID.input->seek(spos, SEEK_SET); + + return ret; +#else + return LIBRAW_NOT_IMPLEMENTED; +#endif +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/libraw_c_api.cpp libkdcraw/libkdcraw/libraw/src/libraw_c_api.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/libraw_c_api.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/src/libraw_c_api.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -1,142 +1,430 @@ -/* +/* -*- C++ -*- * File: libraw_c_api.cpp - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * - * LibRaw C++ interface (implementation) - */ -#include <errno.h> -#include "libraw/libraw.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - - libraw_data_t *libraw_init(unsigned int flags) - { - LibRaw *ret = new LibRaw(flags); - return &(ret->imgdata); - } - - const char* libraw_version() { return LibRaw::version();} - const char* libraw_strprogress(enum LibRaw_progress p) { return LibRaw::strprogress(p);} - int libraw_versionNumber() { return LibRaw::versionNumber();} - const char** libraw_cameraList() { return LibRaw::cameraList();} - int libraw_cameraCount() { return LibRaw::cameraCount(); } - const char* libraw_unpack_function_name(libraw_data_t* lr) - { - if(!lr) return "NULL parameter passed"; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->unpack_function_name(); - } - int libraw_rotate_fuji_raw(libraw_data_t* lr) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->rotate_fuji_raw(); - } - - int libraw_add_masked_borders_to_bitmap(libraw_data_t* lr) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->add_masked_borders_to_bitmap(); - } - - int libraw_open_file(libraw_data_t* lr, const char *file) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->open_file(file); - } - int libraw_open_buffer(libraw_data_t* lr, void *buffer, size_t size) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->open_buffer(buffer,size); - } - int libraw_unpack(libraw_data_t* lr) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->unpack(); - } - int libraw_unpack_thumb(libraw_data_t* lr) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->unpack_thumb(); - } - void libraw_recycle(libraw_data_t* lr) - { - if(!lr) return; - LibRaw *ip = (LibRaw*) lr->parent_class; - ip->recycle(); - } - void libraw_close(libraw_data_t* lr) - { - if(!lr) return; - LibRaw *ip = (LibRaw*) lr->parent_class; - delete ip; - } + * LibRaw C interface - void libraw_set_memerror_handler(libraw_data_t* lr, memory_callback cb,void *data) - { - if(!lr) return; - LibRaw *ip = (LibRaw*) lr->parent_class; - ip->set_memerror_handler(cb,data); - } - void libraw_set_dataerror_handler(libraw_data_t* lr,data_callback func,void *data) - { - if(!lr) return; - LibRaw *ip = (LibRaw*) lr->parent_class; - ip->set_dataerror_handler(func,data); +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: - } - void libraw_set_progress_handler(libraw_data_t* lr, progress_callback cb,void *data) - { - if(!lr) return; - LibRaw *ip = (LibRaw*) lr->parent_class; - ip->set_progress_handler(cb,data); +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). - } +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). - // DCRAW - int libraw_adjust_sizes_info_only(libraw_data_t* lr) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->adjust_sizes_info_only(); - } + */ - int libraw_dcraw_document_mode_processing(libraw_data_t* lr) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->dcraw_document_mode_processing(); +#include <math.h> +#include <errno.h> +#include "libraw/libraw.h" - } - int libraw_dcraw_ppm_tiff_writer(libraw_data_t* lr,const char *filename) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->dcraw_ppm_tiff_writer(filename); - } - int libraw_dcraw_thumb_writer(libraw_data_t* lr,const char *fname) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->dcraw_thumb_writer(fname); +#ifdef __cplusplus +#include <new> +extern "C" +{ +#endif - } - int libraw_dcraw_process(libraw_data_t* lr) - { - if(!lr) return EINVAL; - LibRaw *ip = (LibRaw*) lr->parent_class; - return ip->dcraw_process(); - } + libraw_data_t *libraw_init(unsigned int flags) + { + LibRaw *ret; + try + { + ret = new LibRaw(flags); + } + catch (const std::bad_alloc& ) + { + return NULL; + } + return &(ret->imgdata); + } + + unsigned libraw_capabilities() { return LibRaw::capabilities(); } + const char *libraw_version() { return LibRaw::version(); } + const char *libraw_strprogress(enum LibRaw_progress p) + { + return LibRaw::strprogress(p); + } + int libraw_versionNumber() { return LibRaw::versionNumber(); } + const char **libraw_cameraList() { return LibRaw::cameraList(); } + int libraw_cameraCount() { return LibRaw::cameraCount(); } + const char *libraw_unpack_function_name(libraw_data_t *lr) + { + if (!lr) + return "NULL parameter passed"; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->unpack_function_name(); + } + + void libraw_subtract_black(libraw_data_t *lr) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->subtract_black(); + } + + int libraw_open_file(libraw_data_t *lr, const char *file) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->open_file(file); + } + + libraw_iparams_t *libraw_get_iparams(libraw_data_t *lr) + { + if (!lr) + return NULL; + return &(lr->idata); + } + + libraw_lensinfo_t *libraw_get_lensinfo(libraw_data_t *lr) + { + if (!lr) + return NULL; + return &(lr->lens); + } + + libraw_imgother_t *libraw_get_imgother(libraw_data_t *lr) + { + if (!lr) + return NULL; + return &(lr->other); + } + + int libraw_open_file_ex(libraw_data_t *lr, const char *file, INT64 sz) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->open_file(file, sz); + } +#if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && \ + (_MSC_VER > 1310) + int libraw_open_wfile(libraw_data_t *lr, const wchar_t *file) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->open_file(file); + } + + int libraw_open_wfile_ex(libraw_data_t *lr, const wchar_t *file, INT64 sz) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->open_file(file, sz); + } +#endif + int libraw_open_buffer(libraw_data_t *lr, void *buffer, size_t size) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->open_buffer(buffer, size); + } + int libraw_unpack(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->unpack(); + } + int libraw_unpack_thumb(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->unpack_thumb(); + } + void libraw_recycle_datastream(libraw_data_t *lr) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->recycle_datastream(); + } + void libraw_recycle(libraw_data_t *lr) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->recycle(); + } + void libraw_close(libraw_data_t *lr) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + delete ip; + } + + void libraw_set_exifparser_handler(libraw_data_t *lr, exif_parser_callback cb, + void *data) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->set_exifparser_handler(cb, data); + } + + void libraw_set_memerror_handler(libraw_data_t *lr, memory_callback cb, + void *data) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->set_memerror_handler(cb, data); + } + void libraw_set_dataerror_handler(libraw_data_t *lr, data_callback func, + void *data) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->set_dataerror_handler(func, data); + } + void libraw_set_progress_handler(libraw_data_t *lr, progress_callback cb, + void *data) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->set_progress_handler(cb, data); + } + + // DCRAW + int libraw_adjust_sizes_info_only(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->adjust_sizes_info_only(); + } + int libraw_dcraw_ppm_tiff_writer(libraw_data_t *lr, const char *filename) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->dcraw_ppm_tiff_writer(filename); + } + int libraw_dcraw_thumb_writer(libraw_data_t *lr, const char *fname) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->dcraw_thumb_writer(fname); + } + int libraw_dcraw_process(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->dcraw_process(); + } + libraw_processed_image_t *libraw_dcraw_make_mem_image(libraw_data_t *lr, + int *errc) + { + if (!lr) + { + if (errc) + *errc = EINVAL; + return NULL; + } + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->dcraw_make_mem_image(errc); + } + libraw_processed_image_t *libraw_dcraw_make_mem_thumb(libraw_data_t *lr, + int *errc) + { + if (!lr) + { + if (errc) + *errc = EINVAL; + return NULL; + } + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->dcraw_make_mem_thumb(errc); + } + + void libraw_dcraw_clear_mem(libraw_processed_image_t *p) + { + LibRaw::dcraw_clear_mem(p); + } + + int libraw_raw2image(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->raw2image(); + } + void libraw_free_image(libraw_data_t *lr) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->free_image(); + } + int libraw_get_decoder_info(libraw_data_t *lr, libraw_decoder_info_t *d) + { + if (!lr || !d) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->get_decoder_info(d); + } + int libraw_COLOR(libraw_data_t *lr, int row, int col) + { + if (!lr) + return EINVAL; + LibRaw *ip = (LibRaw *)lr->parent_class; + return ip->COLOR(row, col); + } + + /* getters/setters used by 3DLut Creator */ + DllDef void libraw_set_demosaic(libraw_data_t *lr, int value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.user_qual = value; + } + + DllDef void libraw_set_output_color(libraw_data_t *lr, int value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.output_color = value; + } + + DllDef void libraw_set_output_bps(libraw_data_t *lr, int value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.output_bps = value; + } + + DllDef void libraw_set_output_tif(libraw_data_t *lr, int value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.output_tiff = value; + } + +#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)) + + DllDef void libraw_set_user_mul(libraw_data_t *lr, int index, float val) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.user_mul[LIM(index, 0, 3)] = val; + } + + DllDef void libraw_set_gamma(libraw_data_t *lr, int index, float value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.gamm[LIM(index, 0, 5)] = value; + } + + DllDef void libraw_set_no_auto_bright(libraw_data_t *lr, int value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.no_auto_bright = value; + } + + DllDef void libraw_set_bright(libraw_data_t *lr, float value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.bright = value; + } + + DllDef void libraw_set_highlight(libraw_data_t *lr, int value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.highlight = value; + } + + DllDef void libraw_set_fbdd_noiserd(libraw_data_t *lr, int value) + { + if (!lr) + return; + LibRaw *ip = (LibRaw *)lr->parent_class; + ip->imgdata.params.fbdd_noiserd = value; + } + + DllDef int libraw_get_raw_height(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + return lr->sizes.raw_height; + } + + DllDef int libraw_get_raw_width(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + return lr->sizes.raw_width; + } + + DllDef int libraw_get_iheight(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + return lr->sizes.iheight; + } + + DllDef int libraw_get_iwidth(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + return lr->sizes.iwidth; + } + + DllDef float libraw_get_cam_mul(libraw_data_t *lr, int index) + { + if (!lr) + return EINVAL; + return lr->color.cam_mul[LIM(index, 0, 3)]; + } + + DllDef float libraw_get_pre_mul(libraw_data_t *lr, int index) + { + if (!lr) + return EINVAL; + return lr->color.pre_mul[LIM(index, 0, 3)]; + } + + DllDef float libraw_get_rgb_cam(libraw_data_t *lr, int index1, int index2) + { + if (!lr) + return EINVAL; + return lr->color.rgb_cam[LIM(index1, 0, 2)][LIM(index2, 0, 3)]; + } + + DllDef int libraw_get_color_maximum(libraw_data_t *lr) + { + if (!lr) + return EINVAL; + return lr->color.maximum; + } #ifdef __cplusplus } diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/libraw_cxx.cpp libkdcraw/libkdcraw/libraw/src/libraw_cxx.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/libraw_cxx.cpp 2022-11-07 08:15:53.614821808 +0300 +++ libkdcraw/libkdcraw/libraw/src/libraw_cxx.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -1,1940 +1,55 @@ -/* +/* -*- C++ -*- * File: libraw_cxx.cpp - * Copyright 2008-2009 Alex Tutubalin <lexa@lexa.ru> + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * - * LibRaw C++ interface (implementation) - */ - -#include <errno.h> -#include <float.h> -#include <math.h> -#ifndef WIN32 -#include <netinet/in.h> -#else -#include <winsock2.h> -#endif -#define LIBRAW_LIBRARY_BUILD -#include "libraw/libraw.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - void default_memory_callback(void *,const char *file,const char *where) - { - fprintf (stderr,"%s: Out of memory in %s\n", file?file:"unknown file", where); - } - - void default_data_callback(void*,const char *file, const int offset) - { - if(offset < 0) - fprintf (stderr,"%s: Unexpected end of file\n", file?file:"unknown file"); - else - fprintf (stderr,"%s: data corrupted at %d\n",file?file:"unknown file",offset); - } - const char *libraw_strerror(int e) - { - enum LibRaw_errors errorcode = (LibRaw_errors)e; - switch(errorcode) - { - case LIBRAW_SUCCESS: - return "No error"; - case LIBRAW_UNSPECIFIED_ERROR: - return "Unspecified error"; - case LIBRAW_FILE_UNSUPPORTED: - return "Unsupported file format or not RAW file"; - case LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE: - return "Request for nonexisting image number"; - case LIBRAW_OUT_OF_ORDER_CALL: - return "Out of order call of libraw function"; - case LIBRAW_NO_THUMBNAIL: - return "No thumbnail in file"; - case LIBRAW_UNSUPPORTED_THUMBNAIL: - return "Unsupported thumbnail format"; - case LIBRAW_CANNOT_ADDMASK: - return "Cannot add masked pixels to resized image"; - case LIBRAW_UNSUFFICIENT_MEMORY: - return "Unsufficient memory"; - case LIBRAW_DATA_ERROR: - return "Corrupted data or unexpected EOF"; - case LIBRAW_IO_ERROR: - return "Input/output error"; - case LIBRAW_CANCELLED_BY_CALLBACK: - return "Cancelled by user callback"; - default: - return "Unknown error code"; - } - } - -#ifdef __cplusplus -} -#endif - - -const double LibRaw_constants::xyz_rgb[3][3] = -{ - { 0.412453, 0.357580, 0.180423 }, - { 0.212671, 0.715160, 0.072169 }, - { 0.019334, 0.119193, 0.950227 } -}; - -const float LibRaw_constants::d65_white[3] = { 0.950456, 1, 1.088754 }; - -#define P1 imgdata.idata -#define S imgdata.sizes -#define O imgdata.params -#define C imgdata.color -#define M imgdata.masked_pixels -#define T imgdata.thumbnail -#define IO libraw_internal_data.internal_output_params -#define ID libraw_internal_data.internal_data - -#define EXCEPTION_HANDLER(e) do{ \ - fprintf(stderr,"Exception %d caught\n",e); \ - switch(e) \ - { \ - case LIBRAW_EXCEPTION_ALLOC: \ - recycle(); \ - return LIBRAW_UNSUFFICIENT_MEMORY; \ - case LIBRAW_EXCEPTION_DECODE_RAW: \ - case LIBRAW_EXCEPTION_DECODE_JPEG: \ - recycle(); \ - return LIBRAW_DATA_ERROR; \ - case LIBRAW_EXCEPTION_IO_EOF: \ - case LIBRAW_EXCEPTION_IO_CORRUPT: \ - recycle(); \ - return LIBRAW_IO_ERROR; \ - case LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK:\ - recycle(); \ - return LIBRAW_CANCELLED_BY_CALLBACK; \ - default: \ - return LIBRAW_UNSPECIFIED_ERROR; \ - } \ - }while(0) - -void LibRaw::derror() -{ - if (!libraw_internal_data.unpacker_data.data_error && libraw_internal_data.internal_data.input) - { - if (libraw_internal_data.internal_data.input->eof()) - { - if(callbacks.data_cb)(*callbacks.data_cb)(callbacks.datacb_data, - libraw_internal_data.internal_data.input->fname(),-1); - throw LIBRAW_EXCEPTION_IO_EOF; - } - else - { - if(callbacks.data_cb)(*callbacks.data_cb)(callbacks.datacb_data, - libraw_internal_data.internal_data.input->fname(), - libraw_internal_data.internal_data.input->tell()); - throw LIBRAW_EXCEPTION_IO_CORRUPT; - } - } - libraw_internal_data.unpacker_data.data_error = 1; -} -LibRaw:: LibRaw(unsigned int flags) -{ - double aber[4] = {1,1,1,1}; - double gamm[5] = { 0.45,4.5,0,0,0 }; - unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX }; -#ifdef DCRAW_VERBOSE - verbose = 1; -#else - verbose = 0; -#endif - bzero(&imgdata,sizeof(imgdata)); - bzero(&libraw_internal_data,sizeof(libraw_internal_data)); - bzero(&callbacks,sizeof(callbacks)); - callbacks.mem_cb = (flags & LIBRAW_OPIONS_NO_MEMERR_CALLBACK) ? NULL: &default_memory_callback; - callbacks.data_cb = (flags & LIBRAW_OPIONS_NO_DATAERR_CALLBACK)? NULL : &default_data_callback; - memmove(&imgdata.params.aber,&aber,sizeof(aber)); - memmove(&imgdata.params.gamm,&gamm,sizeof(gamm)); - memmove(&imgdata.params.greybox,&greybox,sizeof(greybox)); - - imgdata.params.bright=1; - imgdata.params.use_camera_matrix=-1; - imgdata.params.user_flip=-1; - imgdata.params.user_black=-1; - imgdata.params.user_sat=-1; - imgdata.params.user_qual=-1; - imgdata.params.output_color=1; - imgdata.params.output_bps=8; - imgdata.params.use_fuji_rotate=1; - imgdata.params.auto_bright_thr = 0.01; - imgdata.parent_class = this; - imgdata.progress_flags = 0; - tls = new LibRaw_TLS; - tls->init(); -} - - -void* LibRaw:: malloc(size_t t) -{ - void *p = memmgr.malloc(t); - return p; -} -void* LibRaw:: calloc(size_t n,size_t t) -{ - void *p = memmgr.calloc(n,t); - return p; -} -void LibRaw:: free(void *p) -{ - memmgr.free(p); -} - - -int LibRaw:: fc (int row, int col) -{ - static const char filter[16][16] = - { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, - { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, - { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, - { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, - { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, - { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, - { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, - { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, - { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, - { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, - { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, - { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, - { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, - { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, - { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, - { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; - - if (imgdata.idata.filters != 1) return FC(row,col); - return filter[(row+imgdata.sizes.top_margin) & 15][(col+imgdata.sizes.left_margin) & 15]; -} - -void LibRaw:: recycle() -{ - if(libraw_internal_data.internal_data.input && libraw_internal_data.internal_data.input_internal) - { - delete libraw_internal_data.internal_data.input; - libraw_internal_data.internal_data.input = NULL; - } - libraw_internal_data.internal_data.input_internal = 0; -#define FREE(a) do { if(a) { free(a); a = NULL;} }while(0) - - FREE(imgdata.image); - FREE(imgdata.thumbnail.thumb); - FREE(libraw_internal_data.internal_data.meta_data); - FREE(libraw_internal_data.output_data.histogram); - FREE(libraw_internal_data.output_data.oprof); - FREE(imgdata.color.profile); - FREE(imgdata.masked_pixels.buffer); - FREE(imgdata.masked_pixels.ph1_black); -#undef FREE -#define ZERO(a) bzero(&a,sizeof(a)) - ZERO(imgdata.masked_pixels); - ZERO(imgdata.sizes); - ZERO(libraw_internal_data.internal_output_params); -#undef ZERO - memmgr.cleanup(); - imgdata.thumbnail.tformat = LIBRAW_THUMBNAIL_UNKNOWN; - imgdata.progress_flags = 0; - - tls->init(); -} - -const char * LibRaw::unpack_function_name() -{ - if(!load_raw) return "Function not set"; - - // sorted names order - if (load_raw == &LibRaw::adobe_dng_load_raw_lj) return "adobe_dng_load_raw_lj()"; - if (load_raw == &LibRaw::adobe_dng_load_raw_nc) return "adobe_dng_load_raw_nc()"; - if (load_raw == &LibRaw::canon_600_load_raw) return "canon_600_load_raw()"; - - if (load_raw == &LibRaw::canon_a5_load_raw) return "canon_a5_load_raw()"; - if (load_raw == &LibRaw::canon_compressed_load_raw) return "canon_compressed_load_raw()"; - if (load_raw == &LibRaw::canon_sraw_load_raw) return "canon_sraw_load_raw()"; - - if (load_raw == &LibRaw::casio_qv5700_load_raw ) return "casio_qv5700_load_raw()"; - if (load_raw == &LibRaw::eight_bit_load_raw ) return "eight_bit_load_raw()"; - if (load_raw == &LibRaw::foveon_load_raw ) return "foveon_load_raw()"; - if (load_raw == &LibRaw::fuji_load_raw ) return "fuji_load_raw()"; - // 10 - if (load_raw == &LibRaw::hasselblad_load_raw ) return "hasselblad_load_raw()"; - if (load_raw == &LibRaw::imacon_full_load_raw ) return "imacon_full_load_raw()"; - if (load_raw == &LibRaw::kodak_262_load_raw ) return "kodak_262_load_raw()"; - - if (load_raw == &LibRaw::kodak_65000_load_raw ) return "kodak_65000_load_raw()"; - if (load_raw == &LibRaw::kodak_dc120_load_raw ) return "kodak_dc120_load_raw()"; - if (load_raw == &LibRaw::kodak_jpeg_load_raw ) return "kodak_jpeg_load_raw()"; - - if (load_raw == &LibRaw::kodak_radc_load_raw ) return "kodak_radc_load_raw()"; - if (load_raw == &LibRaw::kodak_rgb_load_raw ) return "kodak_rgb_load_raw()"; - if (load_raw == &LibRaw::kodak_yrgb_load_raw ) return "kodak_yrgb_load_raw()"; - if (load_raw == &LibRaw::kodak_ycbcr_load_raw ) return "kodak_ycbcr_load_raw()"; - // 20 - if (load_raw == &LibRaw::leaf_hdr_load_raw ) return "leaf_hdr_load_raw()"; - if (load_raw == &LibRaw::lossless_jpeg_load_raw) return "lossless_jpeg_load_raw()"; - if (load_raw == &LibRaw::minolta_rd175_load_raw ) return "minolta_rd175_load_raw()"; - - if (load_raw == &LibRaw::nikon_compressed_load_raw) return "nikon_compressed_load_raw()"; - if (load_raw == &LibRaw::nikon_e900_load_raw ) return "nikon_e900_load_raw()"; - if (load_raw == &LibRaw::nokia_load_raw ) return "nokia_load_raw()"; - - if (load_raw == &LibRaw::olympus_e300_load_raw ) return "olympus_e300_load_raw()"; - if (load_raw == &LibRaw::olympus_e410_load_raw ) return "olympus_e410_load_raw()"; - if (load_raw == &LibRaw::packed_12_load_raw ) return "packed_12_load_raw()"; - if (load_raw == &LibRaw::panasonic_load_raw ) return "panasonic_load_raw()"; - // 30 - if (load_raw == &LibRaw::pentax_k10_load_raw ) return "pentax_k10_load_raw()"; - if (load_raw == &LibRaw::phase_one_load_raw ) return "phase_one_load_raw()"; - if (load_raw == &LibRaw::phase_one_load_raw_c ) return "phase_one_load_raw_c()"; - - if (load_raw == &LibRaw::quicktake_100_load_raw ) return "quicktake_100_load_raw()"; - if (load_raw == &LibRaw::rollei_load_raw ) return "rollei_load_raw()"; - if (load_raw == &LibRaw::sinar_4shot_load_raw ) return "sinar_4shot_load_raw()"; - - if (load_raw == &LibRaw::smal_v6_load_raw ) return "smal_v6_load_raw()"; - if (load_raw == &LibRaw::smal_v9_load_raw ) return "smal_v9_load_raw()"; - if (load_raw == &LibRaw::sony_load_raw ) return "sony_load_raw()"; - if (load_raw == &LibRaw::sony_arw_load_raw ) return "sony_arw_load_raw()"; - // 40 - if (load_raw == &LibRaw::sony_arw2_load_raw ) return "sony_arw2_load_raw()"; - if (load_raw == &LibRaw::unpacked_load_raw ) return "unpacked_load_raw()"; - // 42 total - - return "Unknown unpack function"; -} - - -void LibRaw:: merror (void *ptr, const char *where) -{ - if (ptr) return; - if(callbacks.mem_cb)(*callbacks.mem_cb)(callbacks.memcb_data, - libraw_internal_data.internal_data.input - ?libraw_internal_data.internal_data.input->fname() - :NULL, - where); - throw LIBRAW_EXCEPTION_ALLOC; -} - -ushort * LibRaw::get_masked_pointer(int row, int col) -{ - if(row<0 || col < 0) return NULL; - if(!M.buffer) return NULL; - if(row < S.top_margin) - { - // top band - if(col < S.left_margin) - { - return &(M.tl[row*S.left_margin+col]); - } - else if (col < S.left_margin + S.width) - { - int icol = col - S.left_margin; - return &(M.top[row*S.width+icol]); - } - else if (col < S.raw_width) - { - int icol = col - S.left_margin - S.width; - return &(M.tr[row*S.right_margin+icol]); - } - else - return NULL; // out of bounds - } - else if (row < S.top_margin + S.height) - { - //normal image height - int irow = row - S.top_margin; - if(col < S.left_margin) - { - return &M.left[irow*S.left_margin + col]; - } - else if (col < S.left_margin + S.width) - { - // central image - return NULL; - } - else if (col < S.raw_width) - { - int icol = col - S.left_margin - S.width; - return &M.right[irow*S.right_margin+icol]; - } - else - return NULL; // out of bounds - } - else if (row < S.raw_height) - { - int irow = row - S.top_margin - S.height; - // bottom band - if(col < S.left_margin) - { - return &M.bl[irow*S.left_margin+col]; - } - else if (col < S.left_margin + S.width) - { - int icol = col - S.left_margin; - return &M.bottom[irow*S.width + icol]; - } - else if (col < S.raw_width) - { - int icol = col - S.left_margin - S.width; - return &M.br[irow*S.right_margin + icol]; - } - else - return NULL; // out of bounds - } - else - { - // out of bounds - return NULL; - } - // fallback - return NULL; -} - -void LibRaw:: init_masked_ptrs() -{ - if(!M.buffer) return; - - // top band - M.tl = M.buffer; - M.top = M.tl +(S.top_margin*S.left_margin); - M.tr = M.top + (S.top_margin*S.width); - - // left-right - M.left = M.tr + (S.top_margin * S.right_margin); - M.right = M.left + (S.left_margin * S.height); - - // bottom band - M.bl = M.right + (S.right_margin * S.height); - M.bottom = M.bl + (S.left_margin * S.bottom_margin); - M.br = M.bottom + (S.width * S.bottom_margin); - -} - -int LibRaw::add_masked_borders_to_bitmap() -{ - CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE); - CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); - - if(S.width != S.iwidth || S.height!=S.iheight) - return LIBRAW_CANNOT_ADDMASK; - - if(P1.is_foveon || !P1.filters) - return LIBRAW_CANNOT_ADDMASK; - - if(!imgdata.image) - return LIBRAW_OUT_OF_ORDER_CALL; - - if(S.raw_width < S.width || S.raw_height < S.height) - return LIBRAW_SUCCESS; // nothing to do or already called - - if(S.width == S.raw_width && S.height == S.raw_height) - return LIBRAW_SUCCESS; // nothing to do or already called - - ushort (*newimage)[4]; - - newimage = (ushort (*)[4]) calloc (S.raw_height*S.raw_width, sizeof (*newimage)); - merror (newimage, "add_masked_borders_to_bitmap()"); - - int r,c; - // top rows - for (r=0; r<S.top_margin;r++) - for(c=0;c<S.raw_width;c++) - { - ushort *p = get_masked_pointer(r,c); - if(p) - newimage[r*S.raw_width+c][FC(r,c)] = *p; - } - // middle rows - for (r=S.top_margin; r<S.top_margin+S.height;r++) - { - int row = r-S.top_margin; - for(c=0;c<S.left_margin;c++) - { - ushort *p = get_masked_pointer(r,c); - if(p) - newimage[r*S.raw_width+c][FC(r,c)] = *p; - } - for(c=S.left_margin; c<S.left_margin+S.iwidth;c++) - { - int col = c - S.left_margin; - newimage[r*S.raw_width+c][FC(r,c)] = imgdata.image[row*S.iwidth+col][FC(row,col)]; - } - for(c=S.left_margin+S.iwidth;c<S.raw_width;c++) - { - ushort *p = get_masked_pointer(r,c); - if(p) - newimage[r*S.raw_width+c][FC(r,c)] = *p; - } - } - // bottom rows - for (r=S.top_margin+S.height; r<S.raw_height;r++) - for(c=0;c<S.raw_width;c++) - { - ushort *p = get_masked_pointer(r,c); - if(p) - newimage[r*S.raw_width+c][FC(r,c)] = *p; - } - free(imgdata.image); - imgdata.image=newimage; - S.iwidth = S.width = S.raw_width; - S.iheight = S.height = S.raw_height; - return LIBRAW_SUCCESS; -} - -int LibRaw::open_file(const char *fname) -{ - // this stream will close on recycle() - LibRaw_file_datastream *stream = new LibRaw_file_datastream(fname); - if(!stream->valid()) - { - delete stream; - return LIBRAW_IO_ERROR; - } - ID.input_internal = 0; // preserve from deletion on error - int ret = open_datastream(stream); - if (ret == LIBRAW_SUCCESS) - { - ID.input_internal =1 ; // flag to delete datastream on recycle - } - else - { - delete stream; - ID.input_internal = 0; - } - return ret; -} - -int LibRaw::open_buffer(void *buffer, size_t size) -{ - // this stream will close on recycle() - if(!buffer || buffer==(void*)-1) - return LIBRAW_IO_ERROR; - - LibRaw_buffer_datastream *stream = new LibRaw_buffer_datastream(buffer,size); - if(!stream->valid()) - { - delete stream; - return LIBRAW_IO_ERROR; - } - ID.input_internal = 0; // preserve from deletion on error - int ret = open_datastream(stream); - if (ret == LIBRAW_SUCCESS) - { - ID.input_internal =1 ; // flag to delete datastream on recycle - } - else - { - delete stream; - ID.input_internal = 0; - } - return ret; -} - - -int LibRaw::open_datastream(LibRaw_abstract_datastream *stream) -{ - - if(!stream) - return ENOENT; - if(!stream->valid()) - return LIBRAW_IO_ERROR; - recycle(); - - try { - ID.input = stream; - SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN); - - if (O.use_camera_matrix < 0) - O.use_camera_matrix = O.use_camera_wb; - - identify(); - - if(IO.fuji_width) - { - IO.fwidth = S.width; - IO.fheight = S.height; - S.iwidth = S.width = IO.fuji_width << !libraw_internal_data.unpacker_data.fuji_layout; - S.iheight = S.height = S.raw_height; - S.raw_height += 2*S.top_margin; - } - - int saved_raw_width = S.raw_width; - int saved_width = S.width; - // from packed_12_load_raw - if ((load_raw == &LibRaw:: packed_12_load_raw) && (S.raw_width * 2 >= S.width * 3)) - { - // raw_width is in bytes! - S.raw_width = S.raw_width * 2 / 3; - } - else if (S.pixel_aspect < 0.95 || S.pixel_aspect > 1.05) - { - S.width*=S.pixel_aspect; - } - - if(S.raw_width>S.width + S.left_margin) - S.right_margin = S.raw_width - S.width - S.left_margin; - - if(S.raw_height > S.height + S.top_margin) - S.bottom_margin = S.raw_height - S.height - S.top_margin; - - S.raw_width = saved_raw_width; - S.width = saved_width; - - if(C.profile_length) - { - if(C.profile) free(C.profile); - C.profile = malloc(C.profile_length); - merror(C.profile,"LibRaw::open_file()"); - ID.input->seek(ID.profile_offset,SEEK_SET); - ID.input->read(C.profile,C.profile_length,1); - } - - SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY); - } - catch ( LibRaw_exceptions err) { - EXCEPTION_HANDLER(err); - } - - if(P1.raw_count < 1) - return LIBRAW_FILE_UNSUPPORTED; - - if (O.user_flip >= 0) - S.flip = O.user_flip; - - switch ((S.flip+3600) % 360) - { - case 270: S.flip = 5; break; - case 180: S.flip = 3; break; - case 90: S.flip = 6; break; - } - - write_fun = &LibRaw::write_ppm_tiff; - - if (load_raw == &LibRaw::kodak_ycbcr_load_raw) - { - S.height += S.height & 1; - S.width += S.width & 1; - } - - IO.shrink = P1.filters && (O.half_size || O.threshold || O.aber[0] != 1 || O.aber[2] != 1); - S.iheight = (S.height + IO.shrink) >> IO.shrink; - S.iwidth = (S.width + IO.shrink) >> IO.shrink; - - SET_PROC_FLAG(LIBRAW_PROGRESS_SIZE_ADJUST); - - - return LIBRAW_SUCCESS; -} - -int LibRaw::unpack(void) -{ - CHECK_ORDER_HIGH(LIBRAW_PROGRESS_LOAD_RAW); - CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); - try { - - RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,0,2); - if (O.shot_select >= P1.raw_count) - return LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE; - - if(!load_raw) - return LIBRAW_UNSPECIFIED_ERROR; - - if (O.use_camera_matrix && C.cmatrix[0][0] > 0.25) - { - memcpy (C.rgb_cam, C.cmatrix, sizeof (C.cmatrix)); - IO.raw_color = 0; - } - // already allocated ? - if(imgdata.image) free(imgdata.image); - - imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image)); - merror (imgdata.image, "unpack()"); - - - if(S.top_margin || S.left_margin || S.right_margin || S.bottom_margin) - { - unsigned sz = S.raw_height*(S.left_margin+S.right_margin) - + S.width*(S.top_margin+S.bottom_margin); - imgdata.masked_pixels.buffer = (ushort*) calloc(sz, sizeof(ushort)); - merror (imgdata.masked_pixels.buffer, "unpack()"); - init_masked_ptrs(); - } - if (libraw_internal_data.unpacker_data.meta_length) - { - libraw_internal_data.internal_data.meta_data = - (char *) malloc (libraw_internal_data.unpacker_data.meta_length); - merror (libraw_internal_data.internal_data.meta_data, "LibRaw::unpack()"); - } - ID.input->seek(libraw_internal_data.unpacker_data.data_offset, SEEK_SET); - // foveon_load_raw produces different data for document_mode, we'll - // deal with it in dcraw_document_mode_processing - int save_document_mode = O.document_mode; - O.document_mode = 0; - - if(!own_filtering_supported() && (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT)) - O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC_BIT; // turn on black and zeroes filtering - - (this->*load_raw)(); - - O.document_mode = save_document_mode; - - if (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT) - O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; // restore automated mode - - SET_PROC_FLAG(LIBRAW_PROGRESS_LOAD_RAW); - RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,1,2); - - return 0; - } - catch ( LibRaw_exceptions err) { - EXCEPTION_HANDLER(err); - } -} - -int LibRaw::dcraw_document_mode_processing(void) -{ - CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE); - CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); - - try { - - if(IO.fwidth) - rotate_fuji_raw(); - - if(!own_filtering_supported() && (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT)) - O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC_BIT; // turn on black and zeroes filtering - - O.document_mode = 2; - if(P1.is_foveon) - { - // filter image data for foveon document mode - short *iptr = (short *)imgdata.image; - for (int i=0; i < S.height*S.width*4; i++) - { - if ((short) iptr[i] < 0) - iptr[i] = 0; - } - SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE); - } - - O.use_fuji_rotate = 0; - if (!(O.filtering_mode & LIBRAW_FILTERING_NOZEROES) && IO.zero_is_bad) - { - remove_zeroes(); - SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES); - } - if(O.bad_pixels) - { - bad_pixels(O.bad_pixels); - SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS); - } - if (O.dark_frame) - { - subtract (O.dark_frame); - SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME); - } - if(O.filtering_mode & LIBRAW_FILTERING_NOBLACKS) - C.black=0; - - if (O.user_black >= 0) - C.black = O.user_black; - - if (O.user_sat > 0) - C.maximum = O.user_sat; - - pre_interpolate(); - SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE); - - if (libraw_internal_data.internal_output_params.mix_green) - { - int i; - for (P1.colors=3, i=0; i < S.height*S.width; i++) - imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1; - } - SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN); - - if (!P1.is_foveon && P1.colors == 3) - median_filter(); - SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER); - - if (!P1.is_foveon && O.highlight == 2) - blend_highlights(); - - if (!P1.is_foveon && O.highlight > 2) - recover_highlights(); - SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); - - if (O.use_fuji_rotate) - fuji_rotate(); - SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); -#ifndef NO_LCMS - if(O.camera_profile) - { - apply_profile(O.camera_profile,O.output_profile); - SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE); - } -#endif - if(!libraw_internal_data.output_data.histogram) - { - libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4); - merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_document_mode_processing()"); - } - convert_to_rgb(); - SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB); - - if (O.use_fuji_rotate) - stretch(); - SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH); - - if (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT) - O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; // restore automated mode - - return 0; - } - catch ( LibRaw_exceptions err) { - EXCEPTION_HANDLER(err); - } - -} - -#if 1 -#define FORC(cnt) for (c=0; c < cnt; c++) -#define FORCC FORC(ret->colors) -#define SWAP(a,b) { a ^= b; a ^= (b ^= a); } - -libraw_processed_image_t * LibRaw::dcraw_make_mem_thumb(int *errcode) -{ - if(!T.thumb) - { - if ( !ID.toffset) - { - if(errcode) *errcode= LIBRAW_NO_THUMBNAIL; - } - else - { - if(errcode) *errcode= LIBRAW_OUT_OF_ORDER_CALL; - } - return NULL; - } - - if (T.tformat == LIBRAW_THUMBNAIL_BITMAP) - { - libraw_processed_image_t * ret = - (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t)+T.tlength); + * This file is provided for compatibility w/ old build scripts/tools: + * It includes multiple separate files that should be built separately + * if new build tools are used - if(!ret) - { - if(errcode) *errcode= ENOMEM; - return NULL; - } +LibRaw is free software; you can redistribute it and/or modify +it under the terms of the one of two licenses as you choose: - bzero(ret,sizeof(libraw_processed_image_t)); - ret->type = LIBRAW_IMAGE_BITMAP; - ret->height = T.theight; - ret->width = T.twidth; - ret->colors = 3; - ret->bits = 8; - ret->gamma_corrected = 1; - ret->data_size = T.tlength; - memmove(ret->data,T.thumb,T.tlength); - if(errcode) *errcode= 0; - return ret; - } - else if (T.tformat == LIBRAW_THUMBNAIL_JPEG) - { - ushort exif[5]; - int mk_exif = 0; - if(strcmp(T.thumb+6,"Exif")) mk_exif = 1; - - int dsize = T.tlength + mk_exif * (sizeof(exif)+sizeof(tiff_hdr)); +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). - libraw_processed_image_t * ret = - (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t)+dsize); +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). - if(!ret) - { - if(errcode) *errcode= ENOMEM; - return NULL; - } - - bzero(ret,sizeof(libraw_processed_image_t)); - - ret->type = LIBRAW_IMAGE_JPEG; - ret->data_size = dsize; - - ret->data[0] = 0xff; - ret->data[1] = 0xd8; - if(mk_exif) - { - struct tiff_hdr th; - memcpy (exif, "\xff\xe1 Exif\0\0", 10); - exif[1] = htons (8 + sizeof th); - memmove(ret->data+2,exif,sizeof(exif)); - tiff_head (&th, 0); - memmove(ret->data+(2+sizeof(exif)),&th,sizeof(th)); - memmove(ret->data+(2+sizeof(exif)+sizeof(th)),T.thumb+2,T.tlength-2); - } - else - { - memmove(ret->data+2,T.thumb+2,T.tlength-2); - } - if(errcode) *errcode= 0; - return ret; - - } - else - { - if(errcode) *errcode= LIBRAW_UNSUPPORTED_THUMBNAIL; - return NULL; - - } -} - - - -libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode) -{ - if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) < LIBRAW_PROGRESS_PRE_INTERPOLATE) - { - if(errcode) *errcode= LIBRAW_OUT_OF_ORDER_CALL; - return NULL; - } - - if(!libraw_internal_data.output_data.histogram) - { - libraw_internal_data.output_data.histogram = - (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4); - merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_make_mem_image()"); - } - - unsigned ds = S.height * S.width * (O.output_bps/8) * P1.colors; - libraw_processed_image_t *ret = (libraw_processed_image_t*)::malloc(sizeof(libraw_processed_image_t)+ds); - if(!ret) - { - if(errcode) *errcode= ENOMEM; - return NULL; - } - bzero(ret,sizeof(libraw_processed_image_t)); - // metadata init - - int s_iheight = S.iheight; - int s_iwidth = S.iwidth; - int s_width = S.width; - int s_hwight = S.height; - - S.iheight = S.height; - S.iwidth = S.width; - - - if (S.flip & 4) SWAP(S.height,S.width); - - - ret->type = LIBRAW_IMAGE_BITMAP; - ret->height = S.height; - ret->width = S.width; - ret->colors = P1.colors; - ret->bits = O.output_bps; - ret->gamma_corrected = (O.output_bps == 8)?1:O.gamma_16bit; - - ret->data_size = ds; - - // Cut'n'paste from write_tiff_ppm, should be generalized later - uchar *bufp = ret->data; - uchar *ppm; - ushort *ppm2,lut16[0x10000]; - int c, row, col, soff, rstep, cstep; - - - if (ret->bits == 8 || ret->gamma_corrected ) gamma_lut (lut16); - soff = flip_index (0, 0); - cstep = flip_index (0, 1) - soff; - rstep = flip_index (1, 0) - flip_index (0, S.width); - - - for (row=0; row < ret->height; row++, soff += rstep) - { - ppm2 = (ushort*) (ppm = bufp); - for (col=0; col < ret->width; col++, soff += cstep) - if (ret->bits == 8) - FORCC ppm [col*ret->colors+c] = lut16[imgdata.image[soff][c]]/256; - else if(ret->gamma_corrected) - FORCC ppm2[col*ret->colors+c] = lut16[imgdata.image[soff][c]]; - else - FORCC ppm2[col*ret->colors+c] = imgdata.image[soff][c]; - bufp+=ret->colors*(ret->bits/8)*ret->width; - } - if(errcode) *errcode= 0; - - S.iheight = s_iheight; - S.iwidth = s_iwidth; - S.width = s_width; - S.height = s_hwight; - - return ret; -} - -#undef FORC -#undef FORCC -#undef SWAP -#endif - - -int LibRaw::dcraw_ppm_tiff_writer(const char *filename) -{ - CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); - - if(!imgdata.image) - return LIBRAW_OUT_OF_ORDER_CALL; - - if(!filename) - return ENOENT; - FILE *f = fopen(filename,"wb"); - - if(!f) - return errno; - - try { - if(!libraw_internal_data.output_data.histogram) - { - libraw_internal_data.output_data.histogram = - (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4); - merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_ppm_tiff_writer()"); - } - write_ppm_tiff(f); - SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP); - fclose(f); - return 0; - } - catch ( LibRaw_exceptions err) { - fclose(f); - EXCEPTION_HANDLER(err); - } -} - -void LibRaw::kodak_thumb_loader() -{ - // some kodak cameras - ushort s_height = S.height, s_width = S.width,s_iwidth = S.iwidth,s_iheight=S.iheight; - int s_colors = P1.colors; - unsigned s_filters = P1.filters; - ushort (*s_image)[4] = imgdata.image; - - - S.height = T.theight; - S.width = T.twidth; - P1.filters = 0; - - if (thumb_load_raw == &CLASS kodak_ycbcr_load_raw) - { - S.height += S.height & 1; - S.width += S.width & 1; - } - - imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image)); - merror (imgdata.image, "LibRaw::kodak_thumb_loader()"); - - ID.input->seek(ID.toffset, SEEK_SET); - // read kodak thumbnail into T.image[] - (this->*thumb_load_raw)(); - - // copy-n-paste from image pipe -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define LIM(x,min,max) MAX(min,MIN(x,max)) -#define CLIP(x) LIM(x,0,65535) -#define SWAP(a,b) { a ^= b; a ^= (b ^= a); } - - // from scale_colors - { - double dmax; - float scale_mul[4]; - int c,val; - for (dmax=DBL_MAX, c=0; c < 3; c++) - if (dmax > C.pre_mul[c]) - dmax = C.pre_mul[c]; - - for( c=0; c< 3; c++) - scale_mul[c] = (C.pre_mul[c] / dmax) * 65535.0 / C.maximum; - scale_mul[3] = scale_mul[1]; - - size_t size = S.height * S.width; - for (int i=0; i < size*4 ; i++) - { - val = imgdata.image[0][i]; - if(!val) continue; - val *= scale_mul[i & 3]; - imgdata.image[0][i] = CLIP(val); - } - } - - // from convert_to_rgb - ushort *img; - int row,col; - - int (*t_hist)[LIBRAW_HISTOGRAM_SIZE] = (int (*)[LIBRAW_HISTOGRAM_SIZE]) calloc(sizeof(*t_hist),4); - merror (t_hist, "LibRaw::kodak_thumb_loader()"); - - float out[3], - out_cam[3][4] = - { - {2.81761312, -1.98369181, 0.166078627, 0}, - {-0.111855984, 1.73688626, -0.625030339, 0}, - {-0.0379119813, -0.891268849, 1.92918086, 0} - }; - - for (img=imgdata.image[0], row=0; row < S.height; row++) - for (col=0; col < S.width; col++, img+=4) - { - out[0] = out[1] = out[2] = 0; - for(int c=0;c<3;c++) - { - out[0] += out_cam[0][c] * img[c]; - out[1] += out_cam[1][c] * img[c]; - out[2] += out_cam[2][c] * img[c]; - } - for(int c=0; c<3; c++) - img[c] = CLIP((int) out[c]); - for(int c=0; c<P1.colors;c++) - t_hist[c][img[c] >> 3]++; - - } - - // from gamma_lut - int (*save_hist)[LIBRAW_HISTOGRAM_SIZE] = libraw_internal_data.output_data.histogram; - libraw_internal_data.output_data.histogram = t_hist; - - ushort *lut16 = (ushort*)calloc(0x10000,sizeof(ushort)); - merror(lut16,"LibRaw::kodak_thumb_loader()"); - gamma_lut(lut16); - - libraw_internal_data.output_data.histogram = save_hist; - - free(t_hist); - - // from write_ppm_tiff - copy pixels into bitmap - - S.iheight = S.height; - S.iwidth = S.width; - if (S.flip & 4) SWAP(S.height,S.width); - - if(T.thumb) free(T.thumb); - T.thumb = (char*) calloc (S.width * S.height, P1.colors); - merror (T.thumb, "LibRaw::kodak_thumb_loader()"); - T.tlength = S.width * S.height * P1.colors; - - // from write_tiff_ppm - { - int soff = flip_index (0, 0); - int cstep = flip_index (0, 1) - soff; - int rstep = flip_index (1, 0) - flip_index (0, S.width); - - for (int row=0; row < S.height; row++, soff += rstep) - { - char *ppm = T.thumb + row*S.width*P1.colors; - for (int col=0; col < S.width; col++, soff += cstep) - for(int c = 0; c < P1.colors; c++) - ppm [col*P1.colors+c] = lut16[imgdata.image[soff][c]]/256; - } - } - free(lut16); - // restore variables - free(imgdata.image); - imgdata.image = s_image; - - T.twidth = S.width; - S.width = s_width; - - S.iwidth = s_iwidth; - S.iheight = s_iheight; - - T.theight = S.height; - S.height = s_height; - - T.tcolors = P1.colors; - P1.colors = s_colors; - - P1.filters = s_filters; -} -#undef MIN -#undef MAX -#undef LIM -#undef CLIP -#undef SWAP - - -void LibRaw::foveon_thumb_loader (void) -{ - unsigned bwide, row, col, bitbuf=0, bit=1, c, i; - struct decode *dindex; - short pred[3]; - - if(T.thumb) free(T.thumb); - T.thumb = NULL; - - bwide = get4(); - if (bwide > 0) - { - if (bwide < T.twidth*3) return; - T.thumb = (char*)malloc(3*T.twidth * T.theight); - merror (T.thumb, "foveon_thumb()"); - char *buf = (char*)malloc(bwide); - merror (buf, "foveon_thumb()"); - for (row=0; row < T.theight; row++) - { - ID.input->read(buf, 1, bwide); - memmove(T.thumb+(row*T.twidth*3),buf,T.twidth*3); - } - free(buf); - T.tlength = 3*T.twidth * T.theight; - T.tformat = LIBRAW_THUMBNAIL_BITMAP; - return; - } - else - { - foveon_decoder (256, 0); - T.thumb = (char*)malloc(3*T.twidth * T.theight); - char *bufp = T.thumb; - merror (T.thumb, "foveon_thumb()"); - for (row=0; row < T.theight; row++) - { - memset (pred, 0, sizeof pred); - if (!bit) get4(); - for (bit=col=0; col < T.twidth; col++) - for(c=0;c<3;c++) - { - for (dindex=first_decode; dindex->branch[0]; ) - { - if ((bit = (bit-1) & 31) == 31) - for (i=0; i < 4; i++) - bitbuf = (bitbuf << 8) + ID.input->get_char(); - dindex = dindex->branch[bitbuf >> bit & 1]; - } - pred[c] += dindex->leaf; - (*bufp++)=pred[c]; - } - } - T.tformat = LIBRAW_THUMBNAIL_BITMAP; - T.tlength = 3*T.twidth * T.theight; - } - return; -} - - -// Äîñòàåò thumbnail èç ôàéëà, ñòàâèò thumb_format â ñîîòâåòñòâèè ñ ôîðìàòîì -int LibRaw::unpack_thumb(void) -{ - CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); - CHECK_ORDER_BIT(LIBRAW_PROGRESS_THUMB_LOAD); - - try { - if ( !ID.toffset) - { - return LIBRAW_NO_THUMBNAIL; - } - else if (thumb_load_raw) - { - kodak_thumb_loader(); - T.tformat = LIBRAW_THUMBNAIL_BITMAP; - SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); - return 0; - } - else - { - ID.input->seek(ID.toffset, SEEK_SET); - if ( write_thumb == &LibRaw::jpeg_thumb) - { - if(T.thumb) free(T.thumb); - T.thumb = (char *) malloc (T.tlength); - merror (T.thumb, "jpeg_thumb()"); - ID.input->read (T.thumb, 1, T.tlength); - T.tcolors = 3; - T.tformat = LIBRAW_THUMBNAIL_JPEG; - SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); - return 0; - } - else if (write_thumb == &LibRaw::ppm_thumb) - { - T.tlength = T.twidth * T.theight*3; - if(T.thumb) free(T.thumb); - - T.thumb = (char *) malloc (T.tlength); - merror (T.thumb, "ppm_thumb()"); - - ID.input->read(T.thumb, 1, T.tlength); - - T.tformat = LIBRAW_THUMBNAIL_BITMAP; - SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); - return 0; - - } - else if (write_thumb == &LibRaw::foveon_thumb) - { - foveon_thumb_loader(); - // may return with error, so format is set in - // foveon thumb loader itself - SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); - return 0; - } - // else if -- all other write_thumb cases! - else - { - return LIBRAW_UNSUPPORTED_THUMBNAIL; - } - } - // last resort - return LIBRAW_UNSUPPORTED_THUMBNAIL; - } - catch ( LibRaw_exceptions err) { - EXCEPTION_HANDLER(err); - } - -} - -int LibRaw::dcraw_thumb_writer(const char *fname) -{ -// CHECK_ORDER_LOW(LIBRAW_PROGRESS_THUMB_LOAD); - - if(!fname) - return ENOENT; - - FILE *tfp = fopen(fname,"wb"); - - if(!tfp) - return errno; - - if(!T.thumb) - { - fclose(tfp); - return LIBRAW_OUT_OF_ORDER_CALL; - } - - try { - switch (T.tformat) - { - case LIBRAW_THUMBNAIL_JPEG: - jpeg_thumb_writer (tfp,T.thumb,T.tlength); - break; - case LIBRAW_THUMBNAIL_BITMAP: - fprintf (tfp, "P6\n%d %d\n255\n", T.twidth, T.theight); - fwrite (T.thumb, 1, T.tlength, tfp); - break; - default: - fclose(tfp); - return LIBRAW_UNSUPPORTED_THUMBNAIL; - } - fclose(tfp); - return 0; - } - catch ( LibRaw_exceptions err) { - fclose(tfp); - EXCEPTION_HANDLER(err); - } -} - -int LibRaw::adjust_sizes_info_only(void) -{ - CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); - CHECK_ORDER_HIGH(LIBRAW_PROGRESS_FUJI_ROTATE); - if (O.use_fuji_rotate) - { - if (IO.fuji_width) - { - // restore saved values - if(IO.fheight) - { - S.height = IO.fheight; - S.width = IO.fwidth; - S.iheight = (S.height + IO.shrink) >> IO.shrink; - S.iwidth = (S.width + IO.shrink) >> IO.shrink; - S.raw_height -= 2*S.top_margin; - IO.fheight = IO.fwidth = 0; // prevent repeated calls - } - // dcraw code - IO.fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink; - S.iwidth = (ushort)(IO.fuji_width / sqrt(0.5)); - S.iheight = (ushort)( (S.iheight - IO.fuji_width) / sqrt(0.5)); - } - else - { - if (S.pixel_aspect < 1) S.iheight = (ushort)( S.iheight / S.pixel_aspect + 0.5); - if (S.pixel_aspect > 1) S.iwidth = (ushort) (S.iwidth * S.pixel_aspect + 0.5); - } - } - SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); - if (S.flip & 4) - { - unsigned short t = S.iheight; - S.iheight=S.iwidth; - S.iwidth = t; - SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP); - } - return 0; -} - -int LibRaw::rotate_fuji_raw(void) -{ - CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); - CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE); - - - if(!IO.fwidth) return LIBRAW_SUCCESS; - int row,col,r,c; - ushort (*newimage)[4]; - ushort fiwidth,fiheight; - - fiheight = (IO.fheight + IO.shrink) >> IO.shrink; - fiwidth = (IO.fwidth + IO.shrink) >> IO.shrink; - - newimage = (ushort (*)[4]) calloc (fiheight*fiwidth, sizeof (*newimage)); - merror(newimage,"rotate_fuji_raw()"); - for(row=0;row<S.height;row++) - { - for(col=0;col<S.width;col++) - { - - if (libraw_internal_data.unpacker_data.fuji_layout) { - r = IO.fuji_width - 1 - col + (row >> 1); - c = col + ((row+1) >> 1); - } else { - r = IO.fuji_width - 1 + row - (col >> 1); - c = row + ((col+1) >> 1); - } - newimage[((r) >> IO.shrink)*fiwidth + ((c) >> IO.shrink)][FC(r,c)] = - imgdata.image[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][FC(r,c)]; - } - } - // restore fuji sizes! - S.height = IO.fheight; - S.width = IO.fwidth; - S.iheight = (S.height + IO.shrink) >> IO.shrink; - S.iwidth = (S.width + IO.shrink) >> IO.shrink; - S.raw_height -= 2*S.top_margin; - IO.fheight = IO.fwidth = 0; // prevent repeated calls - - free(imgdata.image); - imgdata.image = newimage; - return LIBRAW_SUCCESS; - -} - - -int LibRaw::dcraw_process(void) -{ - int quality,i; - - - CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); - CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE); - - try { - - if(IO.fwidth) - rotate_fuji_raw(); - - - if(!own_filtering_supported() && (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT)) - O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC_BIT; // turn on black and zeroes filtering - - if(O.half_size) - O.four_color_rgb = 1; - - if (!(O.filtering_mode & LIBRAW_FILTERING_NOZEROES) && IO.zero_is_bad) - { - remove_zeroes(); - SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES); - } - if(O.bad_pixels) - { - bad_pixels(O.bad_pixels); - SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS); - } - if (O.dark_frame) - { - subtract (O.dark_frame); - SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME); - } - - quality = 2 + !IO.fuji_width; - - if(O.filtering_mode & LIBRAW_FILTERING_NOBLACKS) - C.black=0; - - if (O.user_qual >= 0) quality = O.user_qual; - if (O.user_black >= 0) C.black = O.user_black; - if (O.user_sat > 0) C.maximum = O.user_sat; - - if (P1.is_foveon && !O.document_mode) - { - foveon_interpolate(); - SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE); - } - - if (!P1.is_foveon && O.document_mode < 2) - { - scale_colors(); - SET_PROC_FLAG(LIBRAW_PROGRESS_SCALE_COLORS); - } - - pre_interpolate(); - SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE); - - if (P1.filters && !O.document_mode) - { - if (quality == 0) - lin_interpolate(); - else if (quality == 1 || P1.colors > 3) - vng_interpolate(); - else if (quality == 2) - ppg_interpolate(); - else - ahd_interpolate(); - SET_PROC_FLAG(LIBRAW_PROGRESS_INTERPOLATE); - } - if (IO.mix_green) - { - for (P1.colors=3, i=0; i < S.height * S.width; i++) - imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1; - SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN); - } - - if(!P1.is_foveon) - { - if (P1.colors == 3) - { - median_filter(); - SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER); - } - - if (O.highlight == 2) - { - blend_highlights(); - SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); - } - - if (O.highlight > 2) - { - recover_highlights(); - SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); - } - } - if (O.use_fuji_rotate) - { - fuji_rotate(); - SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); - } - - if(!libraw_internal_data.output_data.histogram) - { - libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4); - merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_process()"); - } -#ifndef NO_LCMS - if(O.camera_profile) - { - apply_profile(O.camera_profile,O.output_profile); - SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE); - } -#endif - - convert_to_rgb(); - SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB); - - if (O.use_fuji_rotate) - { - stretch(); - SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH); - } - if (O.filtering_mode & LIBRAW_FILTERING_AUTOMATIC_BIT) - O.filtering_mode = LIBRAW_FILTERING_AUTOMATIC; // restore automated mode - return 0; - } - catch ( LibRaw_exceptions err) { - EXCEPTION_HANDLER(err); - } -} - -// Supported cameras: -static const char *static_camera_list[] = -{ -"Adobe Digital Negative (DNG)", -"Apple QuickTake 100", -"Apple QuickTake 150", -"Apple QuickTake 200", -"AVT F-080C", -"AVT F-145C", -"AVT F-201C", -"AVT F-510C", -"AVT F-810C", -"Canon PowerShot 600", -"Canon PowerShot A5", -"Canon PowerShot A5 Zoom", -"Canon PowerShot A50", -"Canon PowerShot A460 (CHDK hack)", -"Canon PowerShot A530 (CHDK hack)", -"Canon PowerShot A610 (CHDK hack)", -"Canon PowerShot A620 (CHDK hack)", -"Canon PowerShot A630 (CHDK hack)", -"Canon PowerShot A640 (CHDK hack)", -"Canon PowerShot A650 (CHDK hack)", -"Canon PowerShot A710 IS (CHDK hack)", -"Canon PowerShot A720 IS (CHDK hack)", -"Canon PowerShot Pro70", -"Canon PowerShot Pro90 IS", -"Canon PowerShot G1", -"Canon PowerShot G2", -"Canon PowerShot G3", -"Canon PowerShot G5", -"Canon PowerShot G6", -"Canon PowerShot G7 (CHDK hack)", -"Canon PowerShot G9", -"Canon PowerShot G10", -"Canon PowerShot S2 IS (CHDK hack)", -"Canon PowerShot S3 IS (CHDK hack)", -"Canon PowerShot S5 IS (CHDK hack)", -"Canon PowerShot SD300 (CHDK hack)", -"Canon PowerShot S30", -"Canon PowerShot S40", -"Canon PowerShot S45", -"Canon PowerShot S50", -"Canon PowerShot S60", -"Canon PowerShot S70", -"Canon PowerShot Pro1", -"Canon EOS D30", -"Canon EOS D60", -"Canon EOS 5D", -"Canon EOS 5D Mark II", -"Canon EOS 10D", -"Canon EOS 20D", -"Canon EOS 30D", -"Canon EOS 40D", -"Canon EOS 50D", -"Canon EOS 300D / Digital Rebel / Kiss Digital", -"Canon EOS 350D / Digital Rebel XT / Kiss Digital N", -"Canon EOS 400D / Digital Rebel XTi / Kiss Digital X", -"Canon EOS 450D / Digital Rebel XSi / Kiss Digital X2", -"Canon EOS 1000D / Digital Rebel XS / Kiss Digital F", -"Canon EOS D2000C", -"Canon EOS-1D", -"Canon EOS-1DS", -"Canon EOS-1D Mark II", -"Canon EOS-1D Mark III", -"Canon EOS-1D Mark II N", -"Canon EOS-1Ds Mark II", -"Canon EOS-1Ds Mark III", -"Casio QV-2000UX", -"Casio QV-3000EX", -"Casio QV-3500EX", -"Casio QV-4000", -"Casio QV-5700", -"Casio QV-R41", -"Casio QV-R51", -"Casio QV-R61", -"Casio EX-S100", -"Casio EX-Z4", -"Casio EX-Z50", -"Casio EX-Z55", -"Casio Exlim Pro 505", -"Casio Exlim Pro 600", -"Casio Exlim Pro 700", -"Contax N Digital", -"Creative PC-CAM 600", -"Epson R-D1", -"Foculus 531C", -"Fuji FinePix E550", -"Fuji FinePix E900", -"Fuji FinePix F700", -"Fuji FinePix F710", -"Fuji FinePix F800", -"Fuji FinePix F810", -"Fuji FinePix S2Pro", -"Fuji FinePix S3Pro", -"Fuji FinePix S5Pro", -"Fuji FinePix S20Pro", -"Fuji FinePix S100FS", -"Fuji FinePix S5000", -"Fuji FinePix S5100/S5500", -"Fuji FinePix S5200/S5600", -"Fuji FinePix S6000fd", -"Fuji FinePix S7000", -"Fuji FinePix S9000/S9500", -"Fuji FinePix S9100/S9600", -"Fuji IS-1", -"Hasselblad CFV", -"Hasselblad H3D", -"Hasselblad V96C", -"Imacon Ixpress 16-megapixel", -"Imacon Ixpress 22-megapixel", -"Imacon Ixpress 39-megapixel", -"ISG 2020x1520", -"Kodak DC20 (see Oliver Hartman's page)", -"Kodak DC25 (see Jun-ichiro Itoh's page)", -"Kodak DC40", -"Kodak DC50", -"Kodak DC120 (also try kdc2tiff)", -"Kodak DCS200", -"Kodak DCS315C", -"Kodak DCS330C", -"Kodak DCS420", -"Kodak DCS460", -"Kodak DCS460A", -"Kodak DCS520C", -"Kodak DCS560C", -"Kodak DCS620C", -"Kodak DCS620X", -"Kodak DCS660C", -"Kodak DCS660M", -"Kodak DCS720X", -"Kodak DCS760C", -"Kodak DCS760M", -"Kodak EOSDCS1", -"Kodak EOSDCS3B", -"Kodak NC2000F", -"Kodak ProBack", -"Kodak PB645C", -"Kodak PB645H", -"Kodak PB645M", -"Kodak DCS Pro 14n", -"Kodak DCS Pro 14nx", -"Kodak DCS Pro SLR/c", -"Kodak DCS Pro SLR/n", -"Kodak C330", -"Kodak C603", -"Kodak P850", -"Kodak P880", -"Kodak KAI-0340", -"Konica KD-400Z", -"Konica KD-510Z", -"Leaf AFi 7", -"Leaf Aptus 17", -"Leaf Aptus 22", -"Leaf Aptus 54S", -"Leaf Aptus 65", -"Leaf Aptus 75", -"Leaf Aptus 75S", -"Leaf Cantare", -"Leaf CatchLight", -"Leaf CMost", -"Leaf DCB2", -"Leaf Valeo 6", -"Leaf Valeo 11", -"Leaf Valeo 17", -"Leaf Valeo 22", -"Leaf Volare", -"Leica Digilux 2", -"Leica Digilux 3", -"Leica D-LUX2", -"Leica D-LUX3", -"Leica D-LUX4", -"Leica V-LUX1", -"Logitech Fotoman Pixtura", -"Mamiya ZD", -"Micron 2010", -"Minolta RD175", -"Minolta DiMAGE 5", -"Minolta DiMAGE 7", -"Minolta DiMAGE 7i", -"Minolta DiMAGE 7Hi", -"Minolta DiMAGE A1", -"Minolta DiMAGE A2", -"Minolta DiMAGE A200", -"Minolta DiMAGE G400", -"Minolta DiMAGE G500", -"Minolta DiMAGE G530", -"Minolta DiMAGE G600", -"Minolta DiMAGE Z2", -"Minolta Alpha/Dynax/Maxxum 5D", -"Minolta Alpha/Dynax/Maxxum 7D", -"Nikon D1", -"Nikon D1H", -"Nikon D1X", -"Nikon D2H", -"Nikon D2Hs", -"Nikon D2X", -"Nikon D2Xs", -"Nikon D3", -"Nikon D3X", -"Nikon D40", -"Nikon D40X", -"Nikon D50", -"Nikon D60", -"Nikon D70", -"Nikon D70s", -"Nikon D80", -"Nikon D90", -"Nikon D100", -"Nikon D200", -"Nikon D300", -"Nikon D700", -"Nikon E700 (\"DIAG RAW\" hack)", -"Nikon E800 (\"DIAG RAW\" hack)", -"Nikon E880 (\"DIAG RAW\" hack)", -"Nikon E900 (\"DIAG RAW\" hack)", -"Nikon E950 (\"DIAG RAW\" hack)", -"Nikon E990 (\"DIAG RAW\" hack)", -"Nikon E995 (\"DIAG RAW\" hack)", -"Nikon E2100 (\"DIAG RAW\" hack)", -"Nikon E2500 (\"DIAG RAW\" hack)", -"Nikon E3200 (\"DIAG RAW\" hack)", -"Nikon E3700 (\"DIAG RAW\" hack)", -"Nikon E4300 (\"DIAG RAW\" hack)", -"Nikon E4500 (\"DIAG RAW\" hack)", -"Nikon E5000", -"Nikon E5400", -"Nikon E5700", -"Nikon E8400", -"Nikon E8700", -"Nikon E8800", -"Nikon Coolpix P6000", -"Nikon Coolpix S6 (\"DIAG RAW\" hack)", -"Nokia N95", -"Olympus C3030Z", -"Olympus C5050Z", -"Olympus C5060WZ", -"Olympus C7070WZ", -"Olympus C70Z,C7000Z", -"Olympus C740UZ", -"Olympus C770UZ", -"Olympus C8080WZ", -"Olympus E-1", -"Olympus E-3", -"Olympus E-10", -"Olympus E-20", -"Olympus E-300", -"Olympus E-330", -"Olympus E-400", -"Olympus E-410", -"Olympus E-420", -"Olympus E-500", -"Olympus E-510", -"Olympus E-520", -"Olympus SP310", -"Olympus SP320", -"Olympus SP350", -"Olympus SP500UZ", -"Olympus SP510UZ", -"Olympus SP550UZ", -"Olympus SP560UZ", -"Olympus SP570UZ", -"Panasonic DMC-FZ8", -"Panasonic DMC-FZ18", -"Panasonic DMC-FZ28", -"Panasonic DMC-FZ30", -"Panasonic DMC-FZ50", -"Panasonic DMC-FX150", -"Panasonic DMC-G1", -"Panasonic DMC-L1", -"Panasonic DMC-L10", -"Panasonic DMC-LC1", -"Panasonic DMC-LX1", -"Panasonic DMC-LX2", -"Panasonic DMC-LX3", -"Pentax *ist D", -"Pentax *ist DL", -"Pentax *ist DL2", -"Pentax *ist DS", -"Pentax *ist DS2", -"Pentax K10D", -"Pentax K20D", -"Pentax K100D", -"Pentax K100D Super", -"Pentax K200D", -"Pentax K2000/K-m", -"Pentax Optio S", -"Pentax Optio S4", -"Pentax Optio 33WR", -"Pentax Optio 750Z", -"Phase One LightPhase", -"Phase One H 10", -"Phase One H 20", -"Phase One H 25", -"Phase One P 20", -"Phase One P 25", -"Phase One P 30", -"Phase One P 45", -"Pixelink A782", -"Polaroid x530", -"Rollei d530flex", -"RoverShot 3320af", -"Samsung GX-1S", -"Samsung GX-10", -"Samsung S85 (hacked)", -"Sarnoff 4096x5440", -"Sigma SD9", -"Sigma SD10", -"Sigma SD14", -"Sinar 3072x2048", -"Sinar 4080x4080", -"Sinar 4080x5440", -"Sinar STI format", -"SMaL Ultra-Pocket 3", -"SMaL Ultra-Pocket 4", -"SMaL Ultra-Pocket 5", -"Sony DSC-F828", -"Sony DSC-R1", -"Sony DSC-V3", -"Sony DSLR-A100", -"Sony DSLR-A200", -"Sony DSLR-A300", -"Sony DSLR-A350", -"Sony DSLR-A700", -"Sony DSLR-A900", -"Sony XCD-SX910CR", -"STV680 VGA", - NULL -}; - -const char** LibRaw::cameraList() { return static_camera_list;} -int LibRaw::cameraCount() { return (sizeof(static_camera_list)/sizeof(static_camera_list[0]))-1; } + */ +#include "../internal/libraw_cxx_defs.h" -const char * LibRaw::strprogress(enum LibRaw_progress p) -{ - switch(p) - { - case LIBRAW_PROGRESS_START: - return "Starting"; - case LIBRAW_PROGRESS_OPEN : - return "Opening file"; - case LIBRAW_PROGRESS_IDENTIFY : - return "Reading metadata"; - case LIBRAW_PROGRESS_SIZE_ADJUST: - return "Adjusting size"; - case LIBRAW_PROGRESS_LOAD_RAW: - return "Reading RAW data"; - case LIBRAW_PROGRESS_REMOVE_ZEROES: - return "Clearing zero values"; - case LIBRAW_PROGRESS_BAD_PIXELS : - return "Removing dead pixels"; - case LIBRAW_PROGRESS_DARK_FRAME: - return "Subtracting dark frame data"; - case LIBRAW_PROGRESS_FOVEON_INTERPOLATE: - return "Interpolating Foveon sensor data"; - case LIBRAW_PROGRESS_SCALE_COLORS: - return "Scaling colors"; - case LIBRAW_PROGRESS_PRE_INTERPOLATE: - return "Pre-interpolating"; - case LIBRAW_PROGRESS_INTERPOLATE: - return "Interpolating"; - case LIBRAW_PROGRESS_MIX_GREEN : - return "Mixing green channels"; - case LIBRAW_PROGRESS_MEDIAN_FILTER : - return "Median filter"; - case LIBRAW_PROGRESS_HIGHLIGHTS: - return "Highlight recovery"; - case LIBRAW_PROGRESS_FUJI_ROTATE : - return "Rotating Fuji diagonal data"; - case LIBRAW_PROGRESS_FLIP : - return "Flipping image"; - case LIBRAW_PROGRESS_APPLY_PROFILE: - return "ICC conversion"; - case LIBRAW_PROGRESS_CONVERT_RGB: - return "Converting to RGB"; - case LIBRAW_PROGRESS_STRETCH: - return "Stretching image"; - case LIBRAW_PROGRESS_THUMB_LOAD: - return "Loading thumbnail"; - default: - return "Some strange things"; - } -} +#include "tables/cameralist.cpp" +#include "decoders/fuji_compressed.cpp" +#include "decoders/crx.cpp" +#include "decoders/fp_dng.cpp" +#include "decoders/decoders_libraw.cpp" +#include "decoders/unpack.cpp" +#include "decoders/unpack_thumb.cpp" + +#include "integration/dngsdk_glue.cpp" +#include "integration/rawspeed_glue.cpp" + +#include "tables/colorconst.cpp" +#include "utils/utils_libraw.cpp" +#include "utils/init_close_utils.cpp" +#include "utils/decoder_info.cpp" +#include "utils/open.cpp" +#include "utils/phaseone_processing.cpp" +#include "utils/thumb_utils.cpp" + +#include "write/tiff_writer.cpp" +#include "preprocessing/subtract_black.cpp" +#include "preprocessing/raw2image.cpp" +#include "postprocessing/postprocessing_utils.cpp" +#include "postprocessing/dcraw_process.cpp" +#include "postprocessing/mem_image.cpp" + +/* DS conflicts with a define in /usr/include/sys/regset.h on Solaris */ +#if defined __sun && defined DS +#undef DS +#endif +#undef ID /* used in x3f utils */ +#include "x3f/x3f_utils_patched.cpp" +#include "x3f/x3f_parse_process.cpp" diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/libraw_datastream.cpp libkdcraw/libkdcraw/libraw/src/libraw_datastream.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/libraw_datastream.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/libraw_datastream.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,705 @@ +/* -*- C++ -*- + * File: libraw_datastream.cpp + * Copyright 2008-2020 LibRaw LLC (info@libraw.org) + * + * LibRaw C++ interface (implementation) + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + +*/ + +#ifdef _WIN32 +#ifdef __MINGW32__ +#define _WIN32_WINNT 0x0500 +#include <stdexcept> +#endif +#endif + +#define LIBRAW_LIBRARY_BUILD +#include "libraw/libraw.h" +#include "libraw/libraw_types.h" +#include "libraw/libraw_datastream.h" +#include <sys/stat.h> +#ifdef USE_JASPER +#include <jasper/jasper.h> /* Decode RED camera movies */ +#else +#define NO_JASPER +#endif +#ifdef USE_JPEG +#include <jpeglib.h> +#include <jerror.h> +#else +#define NO_JPEG +#endif + +#ifdef USE_JPEG + +typedef struct +{ + struct jpeg_source_mgr pub; /* public fields */ + LibRaw_abstract_datastream *instream; /* source stream */ + JOCTET *buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} lr_jpg_source_mgr; + +typedef lr_jpg_source_mgr *lr_jpg_src_ptr; + +#define LR_JPEG_INPUT_BUF_SIZE 16384 + +static void f_init_source(j_decompress_ptr cinfo) +{ + lr_jpg_src_ptr src = (lr_jpg_src_ptr)cinfo->src; + src->start_of_file = TRUE; +} + +#ifdef ERREXIT +#undef ERREXIT +#endif + +#define ERREXIT(cinfo, code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit)((j_common_ptr)(cinfo))) + +static boolean lr_fill_input_buffer(j_decompress_ptr cinfo) +{ + lr_jpg_src_ptr src = (lr_jpg_src_ptr)cinfo->src; + size_t nbytes; + + nbytes = src->instream->read((void*)src->buffer, 1, LR_JPEG_INPUT_BUF_SIZE); + + if (nbytes <= 0) + { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET)0xFF; + src->buffer[1] = (JOCTET)JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + return TRUE; +} + +static void lr_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + struct jpeg_source_mgr *src = cinfo->src; + if (num_bytes > 0) + { + while (num_bytes > (long)src->bytes_in_buffer) + { + num_bytes -= (long)src->bytes_in_buffer; + (void)(*src->fill_input_buffer)(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->next_input_byte += (size_t)num_bytes; + src->bytes_in_buffer -= (size_t)num_bytes; + } +} + +static void lr_term_source(j_decompress_ptr cinfo) {} + +static void lr_jpeg_src(j_decompress_ptr cinfo, LibRaw_abstract_datastream *inf) +{ + lr_jpg_src_ptr src; + if (cinfo->src == NULL) + { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)( + (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(lr_jpg_source_mgr)); + src = (lr_jpg_src_ptr)cinfo->src; + src->buffer = (JOCTET *)(*cinfo->mem->alloc_small)( + (j_common_ptr)cinfo, JPOOL_PERMANENT, + LR_JPEG_INPUT_BUF_SIZE * sizeof(JOCTET)); + } + else if (cinfo->src->init_source != f_init_source) + { + ERREXIT(cinfo, JERR_BUFFER_SIZE); + } + + src = (lr_jpg_src_ptr)cinfo->src; + src->pub.init_source = f_init_source; + src->pub.fill_input_buffer = lr_fill_input_buffer; + src->pub.skip_input_data = lr_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = lr_term_source; + src->instream = inf; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} +#endif + +int LibRaw_abstract_datastream::jpeg_src(void *jpegdata) +{ +#ifdef NO_JPEG + return -1; +#else + j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; + buffering_off(); + lr_jpeg_src(cinfo, this); + return 0; // OK +#endif +} + + +// == LibRaw_file_datastream == + +LibRaw_file_datastream::~LibRaw_file_datastream() +{ + if (jas_file) + fclose(jas_file); +} + +LibRaw_file_datastream::LibRaw_file_datastream(const char *fname) + : filename(fname), _fsize(0) +#ifdef LIBRAW_WIN32_UNICODEPATHS + , + wfilename() +#endif + , + jas_file(NULL) +{ + if (filename.size() > 0) + { +#ifndef LIBRAW_WIN32_CALLS + struct stat st; + if (!stat(filename.c_str(), &st)) + _fsize = st.st_size; +#else + struct _stati64 st; + if (!_stati64(filename.c_str(), &st)) + _fsize = st.st_size; +#endif +#ifdef LIBRAW_USE_AUTOPTR + std::auto_ptr<std::filebuf> buf(new std::filebuf()); +#else + std::unique_ptr<std::filebuf> buf(new std::filebuf()); +#endif + buf->open(filename.c_str(), std::ios_base::in | std::ios_base::binary); + if (buf->is_open()) + { +#ifdef LIBRAW_USE_AUTOPTR + f = buf; +#else + f = std::move(buf); +#endif + } + } +} +#ifdef LIBRAW_WIN32_UNICODEPATHS +LibRaw_file_datastream::LibRaw_file_datastream(const wchar_t *fname) + : filename(), wfilename(fname), jas_file(NULL), _fsize(0) +{ + if (wfilename.size() > 0) + { + struct _stati64 st; + if (!_wstati64(wfilename.c_str(), &st)) + _fsize = st.st_size; +#ifdef LIBRAW_USE_AUTOPTR + std::auto_ptr<std::filebuf> buf(new std::filebuf()); +#else + std::unique_ptr<std::filebuf> buf(new std::filebuf()); +#endif + buf->open(wfilename.c_str(), std::ios_base::in | std::ios_base::binary); + if (buf->is_open()) + { +#ifdef LIBRAW_USE_AUTOPTR + f = buf; +#else + f = std::move(buf); +#endif + } + } +} +const wchar_t *LibRaw_file_datastream::wfname() +{ + return wfilename.size() > 0 ? wfilename.c_str() : NULL; +} +#endif + +int LibRaw_file_datastream::valid() { return f.get() ? 1 : 0; } + +#define LR_STREAM_CHK() \ + do \ + { \ + if (!f.get()) \ + throw LIBRAW_EXCEPTION_IO_EOF; \ + } while (0) + +int LibRaw_file_datastream::read(void *ptr, size_t size, size_t nmemb) +{ +/* Visual Studio 2008 marks sgetn as insecure, but VS2010 does not. */ +#if defined(WIN32SECURECALLS) && (_MSC_VER < 1600) + LR_STREAM_CHK(); + return int(f->_Sgetn_s(static_cast<char *>(ptr), nmemb * size, nmemb * size) / + (size > 0 ? size : 1)); +#else + LR_STREAM_CHK(); + return int(f->sgetn(static_cast<char *>(ptr), std::streamsize(nmemb * size)) / + (size > 0 ? size : 1)); +#endif +} + +int LibRaw_file_datastream::eof() +{ + LR_STREAM_CHK(); + return f->sgetc() == EOF; +} + +int LibRaw_file_datastream::seek(INT64 o, int whence) +{ + LR_STREAM_CHK(); + std::ios_base::seekdir dir; + switch (whence) + { + case SEEK_SET: + dir = std::ios_base::beg; + break; + case SEEK_CUR: + dir = std::ios_base::cur; + break; + case SEEK_END: + dir = std::ios_base::end; + break; + default: + dir = std::ios_base::beg; + } + return f->pubseekoff((long)o, dir) < 0; +} + +INT64 LibRaw_file_datastream::tell() +{ + LR_STREAM_CHK(); + return f->pubseekoff(0, std::ios_base::cur); +} + +char *LibRaw_file_datastream::gets(char *str, int sz) +{ + LR_STREAM_CHK(); + std::istream is(f.get()); + is.getline(str, sz); + if (is.fail()) + return 0; + return str; +} + +int LibRaw_file_datastream::scanf_one(const char *fmt, void *val) +{ + LR_STREAM_CHK(); + + std::istream is(f.get()); + + /* HUGE ASSUMPTION: *fmt is either "%d" or "%f" */ + if (strcmp(fmt, "%d") == 0) + { + int d; + is >> d; + if (is.fail()) + return EOF; + *(static_cast<int *>(val)) = d; + } + else + { + float f; + is >> f; + if (is.fail()) + return EOF; + *(static_cast<float *>(val)) = f; + } + + return 1; +} + +const char *LibRaw_file_datastream::fname() +{ + return filename.size() > 0 ? filename.c_str() : NULL; +} + +#undef LR_STREAM_CHK + +void *LibRaw_file_datastream::make_jas_stream() +{ +#ifdef NO_JASPER + return NULL; +#else +#ifdef LIBRAW_WIN32_UNICODEPATHS + if (wfname()) + { + jas_file = _wfopen(wfname(), L"rb"); + return jas_stream_fdopen(fileno(jas_file), "rb"); + } + else +#endif + { + return jas_stream_fopen(fname(), "rb"); + } +#endif +} + +// == LibRaw_buffer_datastream +LibRaw_buffer_datastream::LibRaw_buffer_datastream(void *buffer, size_t bsize) +{ + buf = (unsigned char *)buffer; + streampos = 0; + streamsize = bsize; +} + +LibRaw_buffer_datastream::~LibRaw_buffer_datastream() {} + +int LibRaw_buffer_datastream::read(void *ptr, size_t sz, size_t nmemb) +{ + size_t to_read = sz * nmemb; + if (to_read > streamsize - streampos) + to_read = streamsize - streampos; + if (to_read < 1) + return 0; + memmove(ptr, buf + streampos, to_read); + streampos += to_read; + return int((to_read + sz - 1) / (sz > 0 ? sz : 1)); +} + +int LibRaw_buffer_datastream::seek(INT64 o, int whence) +{ + switch (whence) + { + case SEEK_SET: + if (o < 0) + streampos = 0; + else if (size_t(o) > streamsize) + streampos = streamsize; + else + streampos = size_t(o); + return 0; + case SEEK_CUR: + if (o < 0) + { + if (size_t(-o) >= streampos) + streampos = 0; + else + streampos += (size_t)o; + } + else if (o > 0) + { + if (o + streampos > streamsize) + streampos = streamsize; + else + streampos += (size_t)o; + } + return 0; + case SEEK_END: + if (o > 0) + streampos = streamsize; + else if (size_t(-o) > streamsize) + streampos = 0; + else + streampos = streamsize + (size_t)o; + return 0; + default: + return 0; + } +} + +INT64 LibRaw_buffer_datastream::tell() +{ + return INT64(streampos); +} + +char *LibRaw_buffer_datastream::gets(char *s, int sz) +{ + unsigned char *psrc, *pdest, *str; + str = (unsigned char *)s; + psrc = buf + streampos; + pdest = str; + if(streampos >= streamsize) return NULL; + while ((size_t(psrc - buf) < streamsize) && ((pdest - str) < sz)) + { + *pdest = *psrc; + if (*psrc == '\n') + break; + psrc++; + pdest++; + } + if (size_t(psrc - buf) < streamsize) + psrc++; + if ((pdest - str) < sz) + *(++pdest) = 0; + streampos = psrc - buf; + return s; +} + +int LibRaw_buffer_datastream::scanf_one(const char *fmt, void *val) +{ + int scanf_res; + if (streampos > streamsize) + return 0; +#ifndef WIN32SECURECALLS + scanf_res = sscanf((char *)(buf + streampos), fmt, val); +#else + scanf_res = sscanf_s((char *)(buf + streampos), fmt, val); +#endif + if (scanf_res > 0) + { + int xcnt = 0; + while (streampos < streamsize) + { + streampos++; + xcnt++; + if (buf[streampos] == 0 || buf[streampos] == ' ' || + buf[streampos] == '\t' || buf[streampos] == '\n' || xcnt > 24) + break; + } + } + return scanf_res; +} + +int LibRaw_buffer_datastream::eof() +{ + return streampos >= streamsize; +} +int LibRaw_buffer_datastream::valid() { return buf ? 1 : 0; } + +void *LibRaw_buffer_datastream::make_jas_stream() +{ +#ifdef NO_JASPER + return NULL; +#else + return jas_stream_memopen((char *)buf + streampos, streamsize - streampos); +#endif +} + +int LibRaw_buffer_datastream::jpeg_src(void *jpegdata) +{ +#if defined(NO_JPEG) || !defined(USE_JPEG) + return -1; +#else + j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; + jpeg_mem_src(cinfo, (unsigned char *)buf + streampos, streamsize - streampos); + return 0; +#endif +} + +// int LibRaw_buffer_datastream + +// == LibRaw_bigfile_datastream +LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const char *fname) + : filename(fname) +#ifdef LIBRAW_WIN32_UNICODEPATHS + , + wfilename() +#endif +{ + if (filename.size() > 0) + { +#ifndef LIBRAW_WIN32_CALLS + struct stat st; + if (!stat(filename.c_str(), &st)) + _fsize = st.st_size; +#else + struct _stati64 st; + if (!_stati64(filename.c_str(), &st)) + _fsize = st.st_size; +#endif + +#ifndef WIN32SECURECALLS + f = fopen(fname, "rb"); +#else + if (fopen_s(&f, fname, "rb")) + f = 0; +#endif + } + else + { + filename = std::string(); + f = 0; + } +} + +#ifdef LIBRAW_WIN32_UNICODEPATHS +LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const wchar_t *fname) + : filename(), wfilename(fname) +{ + if (wfilename.size() > 0) + { + struct _stati64 st; + if (!_wstati64(wfilename.c_str(), &st)) + _fsize = st.st_size; +#ifndef WIN32SECURECALLS + f = _wfopen(wfilename.c_str(), L"rb"); +#else + if (_wfopen_s(&f, fname, L"rb")) + f = 0; +#endif + } + else + { + wfilename = std::wstring(); + f = 0; + } +} +const wchar_t *LibRaw_bigfile_datastream::wfname() +{ + return wfilename.size() > 0 ? wfilename.c_str() : NULL; +} +#endif + +LibRaw_bigfile_datastream::~LibRaw_bigfile_datastream() +{ + if (f) + fclose(f); +} +int LibRaw_bigfile_datastream::valid() { return f ? 1 : 0; } + +#define LR_BF_CHK() \ + do \ + { \ + if (!f) \ + throw LIBRAW_EXCEPTION_IO_EOF; \ + } while (0) + +int LibRaw_bigfile_datastream::read(void *ptr, size_t size, size_t nmemb) +{ + LR_BF_CHK(); + return int(fread(ptr, size, nmemb, f)); +} + +int LibRaw_bigfile_datastream::eof() +{ + LR_BF_CHK(); + return feof(f); +} + +int LibRaw_bigfile_datastream::seek(INT64 o, int whence) +{ + LR_BF_CHK(); +#if defined(_WIN32) +#ifdef WIN32SECURECALLS + return _fseeki64(f, o, whence); +#else + return fseek(f, (long)o, whence); +#endif +#else + return fseeko(f, o, whence); +#endif +} + +INT64 LibRaw_bigfile_datastream::tell() +{ + LR_BF_CHK(); +#if defined(_WIN32) +#ifdef WIN32SECURECALLS + return _ftelli64(f); +#else + return ftell(f); +#endif +#else + return ftello(f); +#endif +} + +char *LibRaw_bigfile_datastream::gets(char *str, int sz) +{ + LR_BF_CHK(); + return fgets(str, sz, f); +} + +int LibRaw_bigfile_datastream::scanf_one(const char *fmt, void *val) +{ + LR_BF_CHK(); + return +#ifndef WIN32SECURECALLS + fscanf(f, fmt, val) +#else + fscanf_s(f, fmt, val) +#endif + ; +} + +const char *LibRaw_bigfile_datastream::fname() +{ + return filename.size() > 0 ? filename.c_str() : NULL; +} + + +void *LibRaw_bigfile_datastream::make_jas_stream() +{ +#ifdef NO_JASPER + return NULL; +#else + return jas_stream_fdopen(fileno(f), "rb"); +#endif +} + + +// == LibRaw_windows_datastream +#ifdef LIBRAW_WIN32_CALLS + +LibRaw_windows_datastream::LibRaw_windows_datastream(const TCHAR *sFile) + : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL) +{ + HANDLE hFile = CreateFile(sFile, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + if (hFile == INVALID_HANDLE_VALUE) + throw std::runtime_error("failed to open the file"); + + try + { + Open(hFile); + } + catch (...) + { + CloseHandle(hFile); + throw; + } + + CloseHandle(hFile); // windows will defer the actual closing of this handle + // until the hMap_ is closed + reconstruct_base(); +} + +// ctor: construct with a file handle - caller is responsible for closing the +// file handle +LibRaw_windows_datastream::LibRaw_windows_datastream(HANDLE hFile) + : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL) +{ + Open(hFile); + reconstruct_base(); +} + +// dtor: unmap and close the mapping handle +LibRaw_windows_datastream::~LibRaw_windows_datastream() +{ + if (pView_ != NULL) + ::UnmapViewOfFile(pView_); + + if (hMap_ != 0) + ::CloseHandle(hMap_); +} + +void LibRaw_windows_datastream::Open(HANDLE hFile) +{ + // create a file mapping handle on the file handle + hMap_ = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0); + if (hMap_ == NULL) + throw std::runtime_error("failed to create file mapping"); + + // now map the whole file base view + if (!::GetFileSizeEx(hFile, (PLARGE_INTEGER)&cbView_)) + throw std::runtime_error("failed to get the file size"); + + pView_ = ::MapViewOfFile(hMap_, FILE_MAP_READ, 0, 0, (size_t)cbView_); + if (pView_ == NULL) + throw std::runtime_error("failed to map the file"); +} + +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/adobepano.cpp libkdcraw/libkdcraw/libraw/src/metadata/adobepano.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/adobepano.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/adobepano.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,149 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::parseAdobePanoMakernote() +{ + uchar *PrivateMknBuf; + unsigned posPrivateMknBuf; + unsigned PrivateMknLength; + unsigned PrivateOrder; + unsigned PrivateEntries, PrivateTagID, PrivateTagType, PrivateTagCount; + unsigned PrivateTagBytes; + int truncated; + +#define CHECKSPACE(s) \ + if (posPrivateMknBuf + (s) > PrivateMknLength) \ + { \ + free(PrivateMknBuf); \ + return; \ + } + + order = 0x4d4d; + truncated = 0; + PrivateMknLength = get4(); + + if ((PrivateMknLength > 4) && (PrivateMknLength < 10240000) && + (PrivateMknBuf = (uchar *)malloc(PrivateMknLength + 1024))) + { // 1024b for safety + fread(PrivateMknBuf, PrivateMknLength, 1, ifp); + PrivateOrder = sget2(PrivateMknBuf); + PrivateEntries = sget2(PrivateMknBuf + 2); + if ((PrivateEntries > 1000) || + ((PrivateOrder != 0x4d4d) && (PrivateOrder != 0x4949))) + { + free(PrivateMknBuf); + return; + } + posPrivateMknBuf = 4; + while (PrivateEntries--) + { + order = 0x4d4d; + CHECKSPACE(8); + PrivateTagID = sget2(PrivateMknBuf + posPrivateMknBuf); + PrivateTagType = sget2(PrivateMknBuf + posPrivateMknBuf + 2); + PrivateTagCount = sget4(PrivateMknBuf + posPrivateMknBuf + 4); + posPrivateMknBuf += 8; + order = PrivateOrder; + + if (truncated && !PrivateTagCount) + continue; + + PrivateTagBytes = PrivateTagCount * + tagtype_dataunit_bytes[(PrivateTagType <= LIBRAW_EXIFTAG_TYPE_IFD8) ? PrivateTagType : 0]; + if (PrivateTagID == 0x0002) + { + posPrivateMknBuf += 2; + CHECKSPACE(2); + if (sget2(PrivateMknBuf + posPrivateMknBuf)) + { + truncated = 1; + } + else + { + posPrivateMknBuf += 2; + } + } + else if (PrivateTagID == 0x0013) + { + ushort nWB, cnt, tWB; + CHECKSPACE(2); + nWB = sget2(PrivateMknBuf + posPrivateMknBuf); + posPrivateMknBuf += 2; + if (nWB > 0x100) + break; + for (cnt = 0; cnt < nWB; cnt++) + { + CHECKSPACE(2); + tWB = sget2(PrivateMknBuf + posPrivateMknBuf); + if (tWB < 0x100) + { + CHECKSPACE(4); + icWBC[tWB][0] = sget2(PrivateMknBuf + posPrivateMknBuf + 2); + icWBC[tWB][2] = sget2(PrivateMknBuf + posPrivateMknBuf + 4); + icWBC[tWB][1] = icWBC[tWB][3] = 0x100; + } + posPrivateMknBuf += 6; + } + } + else if (PrivateTagID == 0x0027) + { + ushort nWB, cnt, tWB; + CHECKSPACE(2); + nWB = sget2(PrivateMknBuf + posPrivateMknBuf); + posPrivateMknBuf += 2; + if (nWB > 0x100) + break; + for (cnt = 0; cnt < nWB; cnt++) + { + CHECKSPACE(2); + tWB = sget2(PrivateMknBuf + posPrivateMknBuf); + if (tWB < 0x100) + { + CHECKSPACE(6); + icWBC[tWB][0] = sget2(PrivateMknBuf + posPrivateMknBuf + 2); + icWBC[tWB][1] = icWBC[tWB][3] = + sget2(PrivateMknBuf + posPrivateMknBuf + 4); + icWBC[tWB][2] = sget2(PrivateMknBuf + posPrivateMknBuf + 6); + } + posPrivateMknBuf += 8; + } + } + else if (PrivateTagID == 0x0121) + { + CHECKSPACE(4); + imPana.Multishot = sget4(PrivateMknBuf + posPrivateMknBuf); + posPrivateMknBuf += 4; + } + else + { + if (PrivateTagBytes > 4) + posPrivateMknBuf += PrivateTagBytes; + else if (!truncated) + posPrivateMknBuf += 4; + else + { + if (PrivateTagBytes <= 2) + posPrivateMknBuf += 2; + else + posPrivateMknBuf += 4; + } + } + } + free(PrivateMknBuf); + } +#undef CHECKSPACE +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/canon.cpp libkdcraw/libkdcraw/libraw/src/metadata/canon.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/canon.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/canon.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,1098 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +float LibRaw::_CanonConvertAperture(ushort in) +{ + if ((in == (ushort)0xffe0) || (in == (ushort)0x7fff)) + return 0.0f; + return LibRaw::libraw_powf64l(2.0, in / 64.0); +} + +static float _CanonConvertEV(short in) +{ + short EV, Sign, Frac; + float Frac_f; + EV = in; + if (EV < 0) + { + EV = -EV; + Sign = -1; + } + else + { + Sign = 1; + } + Frac = EV & 0x1f; + EV -= Frac; // remove fraction + + if (Frac == 0x0c) + { // convert 1/3 and 2/3 codes + Frac_f = 32.0f / 3.0f; + } + else if (Frac == 0x14) + { + Frac_f = 64.0f / 3.0f; + } + else + Frac_f = (float)Frac; + + return ((float)Sign * ((float)EV + Frac_f)) / 32.0f; +} + +void LibRaw::setCanonBodyFeatures(unsigned long long id) +{ + + ilm.CamID = id; + if ((id == CanonID_EOS_1D) || + (id == CanonID_EOS_1D_Mark_II) || + (id == CanonID_EOS_1D_Mark_II_N) || + (id == CanonID_EOS_1D_Mark_III) || + (id == CanonID_EOS_1D_Mark_IV)) + { + ilm.CameraFormat = LIBRAW_FORMAT_APSH; + ilm.CameraMount = LIBRAW_MOUNT_Canon_EF; + } + else if ((id == CanonID_EOS_1DS) || + (id == CanonID_EOS_1Ds_Mark_II) || + (id == CanonID_EOS_1Ds_Mark_III) || + (id == CanonID_EOS_1D_X) || + (id == CanonID_EOS_1D_X_Mark_II) || + (id == CanonID_EOS_1D_X_Mark_III) || + (id == CanonID_EOS_1D_C) || + (id == CanonID_EOS_5D) || + (id == CanonID_EOS_5D_Mark_II) || + (id == CanonID_EOS_5D_Mark_III) || + (id == CanonID_EOS_5D_Mark_IV) || + (id == CanonID_EOS_5DS) || + (id == CanonID_EOS_5DS_R) || + (id == CanonID_EOS_6D) || + (id == CanonID_EOS_6D_Mark_II)) + { + ilm.CameraFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = LIBRAW_MOUNT_Canon_EF; + } + else if ((id == CanonID_EOS_M) || + (id == CanonID_EOS_M2) || + (id == CanonID_EOS_M3) || + (id == CanonID_EOS_M10) || + (id == CanonID_EOS_M5) || + (id == CanonID_EOS_M50) || + (id == CanonID_EOS_M6) || + (id == CanonID_EOS_M100) || + (id == CanonID_EOS_M6_Mark_II)) + { + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_Canon_EF_M; + } + else if ((id == CanonID_EOS_R) || + (id == CanonID_EOS_RP)) + { + ilm.CameraFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = LIBRAW_MOUNT_Canon_RF; + } + else if ((id == CanonID_EOS_D30) || + (id == CanonID_EOS_D60) || + (id > 0x80000000ULL)) + { + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_Canon_EF; + } +} + +void LibRaw::processCanonCameraInfo(unsigned long long id, uchar *CameraInfo, + unsigned maxlen, unsigned type, unsigned dng_writer) +{ + ushort iCanonLensID = 0, iCanonMaxFocal = 0, iCanonMinFocal = 0, + iCanonLens = 0, iCanonCurFocal = 0, iCanonFocalType = 0; + + if (maxlen < 16) + return; // too short + + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_UNDEFINED) && + (sget2(CameraInfo) == 0xaaaa) && (dng_writer == nonDNG)) { // CameraOrientation + int c, i; + for (c = i = 2; (ushort)c != 0xbbbb && i < (int)maxlen; i++) + c = c << 8 | CameraInfo[i]; + while (i < int(maxlen - 5)) + if ((sget4(CameraInfo+i) == 257) && ((c = CameraInfo[i+8]) < 3)) { + imCanon.MakernotesFlip = "065"[c] - '0'; + break; + } else i+=4; + } + + CameraInfo[0] = 0; + CameraInfo[1] = 0; + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) { + if ((maxlen == 94) || (maxlen == 138) || (maxlen == 148) || + (maxlen == 156) || (maxlen == 162) || (maxlen == 167) || + (maxlen == 171) || (maxlen == 264) || (maxlen > 400)) + imCommon.CameraTemperature = sget4(CameraInfo + ((maxlen - 3) << 2)); + else if (maxlen == 72) + imCommon.CameraTemperature = sget4(CameraInfo + ((maxlen - 1) << 2)); + else if ((maxlen == 85) || (maxlen == 93)) + imCommon.CameraTemperature = sget4(CameraInfo + ((maxlen - 2) << 2)); + else if ((maxlen == 96) || (maxlen == 104)) + imCommon.CameraTemperature = sget4(CameraInfo + ((maxlen - 4) << 2)); + } + + switch (id) + { + case CanonID_EOS_1D: + case CanonID_EOS_1DS: + iCanonCurFocal = 10; + iCanonLensID = 13; + iCanonMinFocal = 14; + iCanonMaxFocal = 16; + if (!ilm.CurFocal) + ilm.CurFocal = sget2(CameraInfo + iCanonCurFocal); + if (!ilm.MinFocal) + ilm.MinFocal = sget2(CameraInfo + iCanonMinFocal); + if (!ilm.MaxFocal) + ilm.MaxFocal = sget2(CameraInfo + iCanonMaxFocal); + imCommon.CameraTemperature = 0.0f; + break; + case CanonID_EOS_1D_Mark_II: + case CanonID_EOS_1Ds_Mark_II: + iCanonCurFocal = 9; + iCanonLensID = 12; + iCanonMinFocal = 17; + iCanonMaxFocal = 19; + iCanonFocalType = 45; + break; + case CanonID_EOS_1D_Mark_II_N: + iCanonCurFocal = 9; + iCanonLensID = 12; + iCanonMinFocal = 17; + iCanonMaxFocal = 19; + break; + case CanonID_EOS_1D_Mark_III: + case CanonID_EOS_1Ds_Mark_III: + iCanonCurFocal = 29; + iCanonLensID = 273; + iCanonMinFocal = 275; + iCanonMaxFocal = 277; + break; + case CanonID_EOS_1D_Mark_IV: + iCanonCurFocal = 30; + iCanonLensID = 335; + iCanonMinFocal = 337; + iCanonMaxFocal = 339; + break; + case CanonID_EOS_1D_X: + iCanonCurFocal = 35; + iCanonLensID = 423; + iCanonMinFocal = 425; + iCanonMaxFocal = 427; + break; + case CanonID_EOS_5D: + iCanonCurFocal = 40; + if (!sget2Rev(CameraInfo + 12)) + iCanonLensID = 151; + else + iCanonLensID = 12; + iCanonMinFocal = 147; + iCanonMaxFocal = 149; + break; + case CanonID_EOS_5D_Mark_II: + iCanonCurFocal = 30; + iCanonLensID = 230; + iCanonMinFocal = 232; + iCanonMaxFocal = 234; + break; + case CanonID_EOS_5D_Mark_III: + iCanonCurFocal = 35; + iCanonLensID = 339; + iCanonMinFocal = 341; + iCanonMaxFocal = 343; + break; + case CanonID_EOS_6D: + iCanonCurFocal = 35; + iCanonLensID = 353; + iCanonMinFocal = 355; + iCanonMaxFocal = 357; + break; + case CanonID_EOS_7D: + iCanonCurFocal = 30; + iCanonLensID = 274; + iCanonMinFocal = 276; + iCanonMaxFocal = 278; + break; + case CanonID_EOS_40D: + iCanonCurFocal = 29; + iCanonLensID = 214; + iCanonMinFocal = 216; + iCanonMaxFocal = 218; + iCanonLens = 2347; + break; + case CanonID_EOS_50D: + iCanonCurFocal = 30; + iCanonLensID = 234; + iCanonMinFocal = 236; + iCanonMaxFocal = 238; + break; + case CanonID_EOS_60D: + iCanonCurFocal = 30; + iCanonLensID = 232; + iCanonMinFocal = 234; + iCanonMaxFocal = 236; + break; + case CanonID_EOS_70D: + iCanonCurFocal = 35; + iCanonLensID = 358; + iCanonMinFocal = 360; + iCanonMaxFocal = 362; + break; + case CanonID_EOS_450D: + iCanonCurFocal = 29; + iCanonLensID = 222; + iCanonLens = 2355; + break; + case CanonID_EOS_500D: + iCanonCurFocal = 30; + iCanonLensID = 246; + iCanonMinFocal = 248; + iCanonMaxFocal = 250; + break; + case CanonID_EOS_550D: + iCanonCurFocal = 30; + iCanonLensID = 255; + iCanonMinFocal = 257; + iCanonMaxFocal = 259; + break; + case CanonID_EOS_600D: + case CanonID_EOS_1100D: + iCanonCurFocal = 30; + iCanonLensID = 234; + iCanonMinFocal = 236; + iCanonMaxFocal = 238; + break; + case CanonID_EOS_650D: + case CanonID_EOS_700D: + iCanonCurFocal = 35; + iCanonLensID = 295; + iCanonMinFocal = 297; + iCanonMaxFocal = 299; + break; + case CanonID_EOS_1000D: + iCanonCurFocal = 29; + iCanonLensID = 226; + iCanonMinFocal = 228; + iCanonMaxFocal = 230; + iCanonLens = 2359; + break; + } + if (iCanonFocalType) + { + if (iCanonFocalType >= maxlen) + return; // broken; + ilm.FocalType = CameraInfo[iCanonFocalType]; + if (!ilm.FocalType) // zero means 'prime' here, replacing with standard '1' + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + } + if (!ilm.CurFocal) + { + if (iCanonCurFocal >= maxlen) + return; // broken; + ilm.CurFocal = sget2Rev(CameraInfo + iCanonCurFocal); + } + if (!ilm.LensID) + { + if (iCanonLensID >= maxlen) + return; // broken; + ilm.LensID = sget2Rev(CameraInfo + iCanonLensID); + } + if (!ilm.MinFocal) + { + if (iCanonMinFocal >= maxlen) + return; // broken; + ilm.MinFocal = sget2Rev(CameraInfo + iCanonMinFocal); + } + if (!ilm.MaxFocal) + { + if (iCanonMaxFocal >= maxlen) + return; // broken; + ilm.MaxFocal = sget2Rev(CameraInfo + iCanonMaxFocal); + } + if (!ilm.Lens[0] && iCanonLens) + { + if (iCanonLens + 64 >= (int)maxlen) // broken; + return; + + char *pl = (char *)CameraInfo + iCanonLens; + if (!strncmp(pl, "EF-S", 4)) + { + memcpy(ilm.Lens, pl, 4); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, pl, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF_S; + ilm.LensFormat = LIBRAW_FORMAT_APSC; + memcpy(ilm.Lens + 5, pl + 4, 60); + } + else if (!strncmp(pl, "EF-M", 4)) + { + memcpy(ilm.Lens, pl, 4); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, pl, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF_M; + ilm.LensFormat = LIBRAW_FORMAT_APSC; + memcpy(ilm.Lens + 5, pl + 4, 60); + } + else if (!strncmp(pl, "EF", 2)) + { + memcpy(ilm.Lens, pl, 2); + ilm.Lens[2] = ' '; + memcpy(ilm.LensFeatures_pre, pl, 2); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + memcpy(ilm.Lens + 3, pl + 2, 62); + } + else if (!strncmp(ilm.Lens, "CN-E", 4)) + { + memmove(ilm.Lens + 5, ilm.Lens + 4, 60); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + else if (!strncmp(pl, "TS-E", 4)) + { + memcpy(ilm.Lens, pl, 4); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, pl, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + memcpy(ilm.Lens + 5, pl + 4, 60); + } + else if (!strncmp(pl, "MP-E", 4)) + { + memcpy(ilm.Lens, pl, 4); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, pl, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + memcpy(ilm.Lens + 5, pl + 4, 60); + } + else // non-Canon lens + memcpy(ilm.Lens, pl, 64); + } + return; +} + +void LibRaw::Canon_CameraSettings(unsigned len) +{ + fseek(ifp, 10, SEEK_CUR); + imgdata.shootinginfo.DriveMode = get2(); // 5 + get2(); + imgdata.shootinginfo.FocusMode = get2(); // 7 + imCanon.RecordMode = (get2(), get2()); // 9, format + fseek(ifp, 14, SEEK_CUR); + imgdata.shootinginfo.MeteringMode = get2(); // 17 + get2(); + imgdata.shootinginfo.AFPoint = get2(); // 19 + imgdata.shootinginfo.ExposureMode = get2(); // 20 + get2(); + ilm.LensID = get2(); // 22 + ilm.MaxFocal = get2(); // 23 + ilm.MinFocal = get2(); // 24 + ilm.FocalUnits = get2(); // 25 + if (ilm.FocalUnits > 1) + { + ilm.MaxFocal /= (float)ilm.FocalUnits; + ilm.MinFocal /= (float)ilm.FocalUnits; + } + ilm.MaxAp = _CanonConvertAperture(get2()); // 26 + ilm.MinAp = _CanonConvertAperture(get2()); // 27 + if (len >= 36) + { + fseek(ifp, 12, SEEK_CUR); + imgdata.shootinginfo.ImageStabilization = get2(); // 34 + } + else + return; + if (len >= 48) + { + fseek(ifp, 22, SEEK_CUR); + imCanon.SRAWQuality = get2(); // 46 + } +} + +void LibRaw::Canon_WBpresets(int skip1, int skip2) +{ + int c; + FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][RGGB_2_RGBG(c)] = get2(); + + if (skip1) + fseek(ifp, skip1, SEEK_CUR); + FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][RGGB_2_RGBG(c)] = get2(); + + if (skip1) + fseek(ifp, skip1, SEEK_CUR); + FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][RGGB_2_RGBG(c)] = get2(); + + if (skip1) + fseek(ifp, skip1, SEEK_CUR); + FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][RGGB_2_RGBG(c)] = get2(); + + if (skip1) + fseek(ifp, skip1, SEEK_CUR); + FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][RGGB_2_RGBG(c)] = get2(); + + if (skip2) + fseek(ifp, skip2, SEEK_CUR); + FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][RGGB_2_RGBG(c)] = get2(); + + return; +} + +void LibRaw::Canon_WBCTpresets(short WBCTversion) +{ + + int i; + float norm; + + if (WBCTversion == 0) + { // tint, as shot R, as shot B, CСT + for (i = 0; i < 15; i++) + { + icWBCCTC[i][2] = icWBCCTC[i][4] = 1.0f; + fseek(ifp, 2, SEEK_CUR); + icWBCCTC[i][1] = 1024.0f / fMAX(get2(), 1.f); + icWBCCTC[i][3] = 1024.0f / fMAX(get2(), 1.f); + icWBCCTC[i][0] = get2(); + } + } + else if (WBCTversion == 1) + { // as shot R, as shot B, tint, CСT + for (i = 0; i < 15; i++) + { + icWBCCTC[i][2] = icWBCCTC[i][4] = 1.0f; + icWBCCTC[i][1] = 1024.0f / fMAX(get2(), 1.f); + icWBCCTC[i][3] = 1024.0f / fMAX(get2(), 1.f); + fseek(ifp, 2, SEEK_CUR); + icWBCCTC[i][0] = get2(); + } + } + else if (WBCTversion == 2) + { // tint, offset, as shot R, as shot B, CСT + if ((unique_id == CanonID_EOS_M3) || + (unique_id == CanonID_EOS_M10) || + (imCanon.ColorDataSubVer == 0xfffc)) + { + for (i = 0; i < 15; i++) + { + fseek(ifp, 4, SEEK_CUR); + icWBCCTC[i][2] = icWBCCTC[i][4] = + 1.0f; + icWBCCTC[i][1] = 1024.0f / fMAX(1.f, get2()); + icWBCCTC[i][3] = 1024.0f / fMAX(1.f, get2()); + icWBCCTC[i][0] = get2(); + } + } + else if (imCanon.ColorDataSubVer == 0xfffd) + { + for (i = 0; i < 15; i++) + { + fseek(ifp, 2, SEEK_CUR); + norm = (signed short)get2(); + norm = 512.0f + norm / 8.0f; + icWBCCTC[i][2] = icWBCCTC[i][4] = + 1.0f; + icWBCCTC[i][1] = (float)get2(); + if (norm > 0.001f) + icWBCCTC[i][1] /= norm; + icWBCCTC[i][3] = (float)get2(); + if (norm > 0.001f) + icWBCCTC[i][3] /= norm; + icWBCCTC[i][0] = get2(); + } + } + } + return; +} + +void LibRaw::parseCanonMakernotes(unsigned tag, unsigned type, unsigned len, unsigned dng_writer) +{ + int c; + unsigned i; + + if (tag == 0x0001) { + Canon_CameraSettings(len); + + } else if (tag == 0x0002) { // focal length + ilm.FocalType = get2(); + ilm.CurFocal = get2(); + if (ilm.FocalUnits > 1) { + ilm.CurFocal /= (float)ilm.FocalUnits; + } + + } else if (tag == 0x0004) { // subdir, ShotInfo + short tempAp; + if (dng_writer == nonDNG) { + if ((i = (get4(), get2())) != 0x7fff && + (!iso_speed || iso_speed == 65535)) { + iso_speed = 50 * libraw_powf64l(2.0, i / 32.0 - 4); + } + get4(); + if (((i = get2()) != 0xffff) && !shutter) { + shutter = libraw_powf64l(2.0, (short)i / -32.0); + } + imCanon.wbi = (get2(), get2()); + shot_order = (get2(), get2()); + fseek(ifp, 4, SEEK_CUR); + } else + fseek(ifp, 24, SEEK_CUR); + tempAp = get2(); + if (tempAp != 0) + imCommon.CameraTemperature = (float)(tempAp - 128); + tempAp = get2(); + if (tempAp != -1) + imCommon.FlashGN = ((float)tempAp) / 32; + get2(); + + imCommon.FlashEC = _CanonConvertEV((signed short)get2()); + fseek(ifp, 8 - 32, SEEK_CUR); + if ((tempAp = get2()) != 0x7fff) + ilm.CurAp = _CanonConvertAperture(tempAp); + if (ilm.CurAp < 0.7f) { + fseek(ifp, 32, SEEK_CUR); + ilm.CurAp = _CanonConvertAperture(get2()); + } + if (!aperture) + aperture = ilm.CurAp; + + } else if ((tag == 0x0007) && (dng_writer == nonDNG)) { + fgets(model2, 64, ifp); + + } else if ((tag == 0x0008) && (dng_writer == nonDNG)) { + shot_order = get4(); + + } else if ((tag == 0x0009) && (dng_writer == nonDNG)) { + fread(artist, 64, 1, ifp); + + } else if (tag == 0x000c) { + unsigned tS = get4(); + sprintf(imgdata.shootinginfo.BodySerial, "%d", tS); + + } else if ((tag == 0x0029) && (dng_writer == nonDNG)) { // PowerShot G9 + int Got_AsShotWB = 0; + fseek(ifp, 8, SEEK_CUR); + for (int linenum = 0; linenum < Canon_G9_linenums_2_StdWBi.size(); linenum++) { + if (Canon_G9_linenums_2_StdWBi[linenum] != LIBRAW_WBI_Unknown ) { + FORC4 icWBC[Canon_G9_linenums_2_StdWBi[linenum]][GRBG_2_RGBG(c)] = get4(); + if (Canon_wbi2std[imCanon.wbi] == Canon_G9_linenums_2_StdWBi[linenum]) { + FORC4 cam_mul[c] = icWBC[Canon_G9_linenums_2_StdWBi[linenum]][c]; + Got_AsShotWB = 1; + } + } + fseek(ifp, 16, SEEK_CUR); + } + if (!Got_AsShotWB) + FORC4 cam_mul[c] = icWBC[LIBRAW_WBI_Auto][c]; + + } else if ((tag == 0x0081) && (dng_writer == nonDNG)) { // EOS-1D, EOS-1DS + data_offset = get4(); + fseek(ifp, data_offset + 41, SEEK_SET); + raw_height = get2() * 2; + raw_width = get2(); + filters = 0x61616161; + + } else if (tag == 0x0093) { + if (!imCanon.RF_lensID) { + fseek(ifp, 0x03d<<1, SEEK_CUR); + imCanon.RF_lensID = get2(); + } + + } else if (tag == 0x0095 && !ilm.Lens[0]) + { // lens model tag + fread(ilm.Lens, 64, 1, ifp); + if (!strncmp(ilm.Lens, "EF-S", 4)) + { + memmove(ilm.Lens + 5, ilm.Lens + 4, 60); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF_S; + ilm.LensFormat = LIBRAW_FORMAT_APSC; + } + else if (!strncmp(ilm.Lens, "EF-M", 4)) + { + memmove(ilm.Lens + 5, ilm.Lens + 4, 60); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF_M; + ilm.LensFormat = LIBRAW_FORMAT_APSC; + } + else if (!strncmp(ilm.Lens, "EF", 2)) + { + memmove(ilm.Lens + 3, ilm.Lens + 2, 62); + ilm.Lens[2] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 2); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + else if (!strncmp(ilm.Lens, "CN-E", 4)) + { + memmove(ilm.Lens + 5, ilm.Lens + 4, 60); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + else if (!strncmp(ilm.Lens, "TS-E", 4)) + { + memmove(ilm.Lens + 5, ilm.Lens + 4, 60); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + else if (!strncmp(ilm.Lens, "MP-E", 4)) + { + memmove(ilm.Lens + 5, ilm.Lens + 4, 60); + ilm.Lens[4] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 4); + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + else if (!strncmp(ilm.Lens, "RF", 2)) + { + memmove(ilm.Lens + 3, ilm.Lens + 2, 62); + ilm.Lens[2] = ' '; + memcpy(ilm.LensFeatures_pre, ilm.Lens, 2); + ilm.LensMount = LIBRAW_MOUNT_Canon_RF; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + } + else if (tag == 0x009a) + { // AspectInfo + i = get4(); + switch (i) + { + case 0: + case 12: /* APS-H crop */ + case 13: /* APS-C crop */ + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_3to2; + break; + case 1: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_1to1; + break; + case 2: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_4to3; + break; + case 7: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_16to9; + break; + case 8: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_5to4; + break; + default: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_OTHER; + break; + } + imgdata.sizes.raw_inset_crop.cwidth = get4(); + imgdata.sizes.raw_inset_crop.cheight = get4(); + imgdata.sizes.raw_inset_crop.cleft = get4(); + imgdata.sizes.raw_inset_crop.ctop = get4(); + + } else if ((tag == 0x00a4) && (dng_writer == nonDNG)) { // EOS-1D, EOS-1DS + fseek(ifp, imCanon.wbi * 48, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + + } else if (tag == 0x00a9) { + long int save1 = ftell(ifp); + fseek(ifp, (0x1 << 1), SEEK_CUR); + FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + Canon_WBpresets(0, 0); + fseek(ifp, save1, SEEK_SET); + } + else if (tag == 0x00b4) + { + switch (get2()) { + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + } + else if (tag == 0x00e0) + { // SensorInfo + imCanon.SensorWidth = (get2(), get2()); + imCanon.SensorHeight = get2(); + imCanon.SensorLeftBorder = (get2(), get2(), get2()); + imCanon.SensorTopBorder = get2(); + imCanon.SensorRightBorder = get2(); + imCanon.SensorBottomBorder = get2(); + imCanon.BlackMaskLeftBorder = get2(); + imCanon.BlackMaskTopBorder = get2(); + imCanon.BlackMaskRightBorder = get2(); + imCanon.BlackMaskBottomBorder = get2(); + } + else if (tag == 0x4001 && len > 500) + { + int bls = 0; + long int offsetChannelBlackLevel = 0L; + long int offsetChannelBlackLevel2 = 0L; + long int offsetWhiteLevels = 0L; + long int save1 = ftell(ifp); + + switch (len) + { + + case 582: + imCanon.ColorDataVer = 1; // 20D / 350D + + fseek(ifp, save1 + (0x0019 << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + fseek(ifp, save1 + (0x001e << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0041 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom1][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0046 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom2][RGGB_2_RGBG(c)] = get2(); + + fseek(ifp, save1 + (0x0023 << 1), SEEK_SET); + Canon_WBpresets(2, 2); + fseek(ifp, save1 + (0x004b << 1), SEEK_SET); + Canon_WBCTpresets(1); // ABCT + offsetChannelBlackLevel = save1 + (0x00a6 << 1); + break; + + case 653: + imCanon.ColorDataVer = 2; // 1Dmk2 / 1DsMK2 + + fseek(ifp, save1 + (0x0018 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0022 << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + fseek(ifp, save1 + (0x0090 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom1][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0095 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom2][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x009a << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom3][RGGB_2_RGBG(c)] = get2(); + + fseek(ifp, save1 + (0x0027 << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x00a4 << 1), SEEK_SET); + Canon_WBCTpresets(1); // ABCT + offsetChannelBlackLevel = save1 + (0x011e << 1); + break; + + case 796: + imCanon.ColorDataVer = 3; // 1DmkIIN / 5D / 30D / 400D + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0071 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom1][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0076 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom2][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x007b << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom3][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0080 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Custom][RGGB_2_RGBG(c)] = get2(); + + fseek(ifp, save1 + (0x004e << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x0085 << 1), SEEK_SET); + Canon_WBCTpresets(0); // BCAT + offsetChannelBlackLevel = save1 + (0x00c4 << 1); + break; + + // 1DmkIII / 1DSmkIII / 1DmkIV / 5DmkII + // 7D / 40D / 50D / 60D / 450D / 500D + // 550D / 1000D / 1100D + case 674: + case 692: + case 702: + case 1227: + case 1250: + case 1251: + case 1337: + case 1338: + case 1346: + imCanon.ColorDataVer = 4; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = get2(); + + fseek(ifp, save1 + (0x004e << 1), SEEK_SET); + FORC4 sraw_mul[RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0053 << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x00a8 << 1), SEEK_SET); + Canon_WBCTpresets(0); // BCAT + + if ((imCanon.ColorDataSubVer == 4) || + (imCanon.ColorDataSubVer == 5)) + { + offsetChannelBlackLevel = save1 + (0x02b4 << 1); + offsetWhiteLevels = save1 + (0x02b8 << 1); + } + else if ((imCanon.ColorDataSubVer == 6) || + (imCanon.ColorDataSubVer == 7)) + { + offsetChannelBlackLevel = save1 + (0x02cb << 1); + offsetWhiteLevels = save1 + (0x02cf << 1); + } + else if (imCanon.ColorDataSubVer == 9) + { + offsetChannelBlackLevel = save1 + (0x02cf << 1); + offsetWhiteLevels = save1 + (0x02d3 << 1); + } + else + offsetChannelBlackLevel = save1 + (0x00e7 << 1); + break; + + case 5120: // PowerShot G10, G12, G5 X, G7 X, G9 X, EOS M3, EOS M5, EOS M6 + imCanon.ColorDataVer = 5; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x0047 << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + + if (imCanon.ColorDataSubVer == 0xfffc) + { // -4: G7 X Mark II, G9 X Mark II, G1 X Mark III, M5, M100, M6 + fseek(ifp, save1 + (0x004f << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, 8, SEEK_CUR); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = + get2(); + fseek(ifp, 8, SEEK_CUR); + FORC4 icWBC[LIBRAW_WBI_Other][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, 8, SEEK_CUR); + Canon_WBpresets(8, 24); + fseek(ifp, 168, SEEK_CUR); + FORC4 icWBC[LIBRAW_WBI_FL_WW][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, 24, SEEK_CUR); + Canon_WBCTpresets(2); // BCADT + offsetChannelBlackLevel = save1 + (0x014d << 1); + offsetWhiteLevels = save1 + (0x0569 << 1); + } + else if (imCanon.ColorDataSubVer == 0xfffd) + { // -3: M10/M3/G1 X/G1 X II/G10/G11/G12/G15/G16/G3 X/G5 X/G7 X/G9 + // X/S100/S110/S120/S90/S95/SX1 IX/SX50 HS/SX60 HS + fseek(ifp, save1 + (0x004c << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + get2(); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = + get2(); + get2(); + FORC4 icWBC[LIBRAW_WBI_Other][RGGB_2_RGBG(c)] = get2(); + get2(); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x00ba << 1), SEEK_SET); + Canon_WBCTpresets(2); // BCADT + offsetChannelBlackLevel = save1 + (0x0108 << 1); + } + break; + + case 1273: + case 1275: + imCanon.ColorDataVer = 6; // 600D / 1200D + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = get2(); + + fseek(ifp, save1 + (0x0062 << 1), SEEK_SET); + FORC4 sraw_mul[RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0067 << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x00bc << 1), SEEK_SET); + Canon_WBCTpresets(0); // BCAT + offsetChannelBlackLevel = save1 + (0x01df << 1); + offsetWhiteLevels = save1 + (0x01e3 << 1); + break; + + // 1DX / 5DmkIII / 6D / 100D / 650D / 700D / EOS M / 7DmkII / 750D / 760D + case 1312: + case 1313: + case 1316: + case 1506: + imCanon.ColorDataVer = 7; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = get2(); + + fseek(ifp, save1 + (0x007b << 1), SEEK_SET); + FORC4 sraw_mul[RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0080 << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x00d5 << 1), SEEK_SET); + Canon_WBCTpresets(0); // BCAT + + if (imCanon.ColorDataSubVer == 10) + { + offsetChannelBlackLevel = save1 + (0x01f8 << 1); + offsetWhiteLevels = save1 + (0x01fc << 1); + } + else if (imCanon.ColorDataSubVer == 11) + { + offsetChannelBlackLevel = save1 + (0x02d8 << 1); + offsetWhiteLevels = save1 + (0x02dc << 1); + } + break; + + // 5DS / 5DS R / 80D / 1300D / 1500D / 3000D / 5D4 / 800D / 77D / 6D II / + // 200D + case 1560: + case 1592: + case 1353: + case 1602: + imCanon.ColorDataVer = 8; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = get2(); + + fseek(ifp, save1 + (0x0080 << 1), SEEK_SET); + FORC4 sraw_mul[RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0085 << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x0107 << 1), SEEK_SET); + Canon_WBCTpresets(0); // BCAT + + if (imCanon.ColorDataSubVer == 14) + { // 1300D / 1500D / 3000D + offsetChannelBlackLevel = save1 + (0x022c << 1); + offsetWhiteLevels = save1 + (0x0230 << 1); + } + else + { + offsetChannelBlackLevel = save1 + (0x030a << 1); + offsetWhiteLevels = save1 + (0x030e << 1); + } + break; + + case 1820: // M50, ColorDataSubVer 16 + case 1824: // EOS R, SX740HS, ColorDataSubVer 17 + case 1816: // EOS RP, SX70HS, ColorDataSubVer 18; + // EOS M6 Mark II, EOS 90D, G7XmkIII, ColorDataSubVer 19 + imCanon.ColorDataVer = 9; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x0047 << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + get2(); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + get2(); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0088 << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x010a << 1), SEEK_SET); + Canon_WBCTpresets(0); + offsetChannelBlackLevel = save1 + (0x0318 << 1); + offsetChannelBlackLevel2 = save1 + (0x0149 << 1); + offsetWhiteLevels = save1 + (0x031c << 1); + break; + + case 2024: // 1D X Mark III, ColorDataSubVer 32 + imCanon.ColorDataVer = 10; + imCanon.ColorDataSubVer = get2(); + fseek(ifp, save1 + (0x0055 << 1), SEEK_SET); + FORC4 cam_mul[RGGB_2_RGBG(c)] = (float)get2(); + get2(); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + get2(); + FORC4 icWBC[LIBRAW_WBI_Measured][RGGB_2_RGBG(c)] = get2(); + fseek(ifp, save1 + (0x0096 << 1), SEEK_SET); + Canon_WBpresets(2, 12); + fseek(ifp, save1 + (0x0118 << 1), SEEK_SET); + Canon_WBCTpresets(0); + offsetChannelBlackLevel = save1 + (0x0326 << 1); + offsetChannelBlackLevel2 = save1 + (0x0157 << 1); + offsetWhiteLevels = save1 + (0x032a << 1); + break; + + default: + imCanon.ColorDataSubVer = get2(); + break; + } + + if (offsetChannelBlackLevel) + { + fseek(ifp, offsetChannelBlackLevel, SEEK_SET); + FORC4 + bls += (imCanon.ChannelBlackLevel[RGGB_2_RGBG(c)] = get2()); + imCanon.AverageBlackLevel = bls / 4; + } + if (offsetWhiteLevels) + { + if ((offsetWhiteLevels - offsetChannelBlackLevel) != 8L) + fseek(ifp, offsetWhiteLevels, SEEK_SET); + imCanon.NormalWhiteLevel = get2(); + imCanon.SpecularWhiteLevel = get2(); + FORC4 + imgdata.color.linear_max[c] = imCanon.SpecularWhiteLevel; + } + + if(!imCanon.AverageBlackLevel && offsetChannelBlackLevel2) + { + fseek(ifp, offsetChannelBlackLevel2, SEEK_SET); + FORC4 + bls += (imCanon.ChannelBlackLevel[RGGB_2_RGBG(c)] = get2()); + imCanon.AverageBlackLevel = bls / 4; + } + fseek(ifp, save1, SEEK_SET); + + } else if (tag == 0x4013) { + get4(); + imCanon.AFMicroAdjMode = get4(); + float a = get4(); + float b = get4(); + if (fabsf(b) > 0.001f) + imCanon.AFMicroAdjValue = a / b; + + } else if ((tag == 0x4021) && (dng_writer == nonDNG) && + (imCanon.multishot[0] = get4()) && + (imCanon.multishot[1] = get4())) { + if (len >= 4) { + imCanon.multishot[2] = get4(); + imCanon.multishot[3] = get4(); + } + FORC4 cam_mul[c] = 1024; + } + +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/ciff.cpp libkdcraw/libkdcraw/libraw/src/metadata/ciff.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/ciff.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/ciff.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,416 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#ifdef _MSC_VER +#if _MSC_VER < 1800 /* below MSVC 2013 */ +float roundf(float f) +{ + return floorf(f + 0.5); +} + +#endif +#endif + +/* + CIFF block 0x1030 contains an 8x8 white sample. + Load this into white[][] for use in scale_colors(). + */ +void LibRaw::ciff_block_1030() +{ + static const ushort key[] = {0x410, 0x45f3}; + int i, bpp, row, col, vbits = 0; + unsigned long bitbuf = 0; + + if ((get2(), get4()) != 0x80008 || !get4()) + return; + bpp = get2(); + if (bpp != 10 && bpp != 12) + return; + for (i = row = 0; row < 8; row++) + for (col = 0; col < 8; col++) + { + if (vbits < bpp) + { + bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); + vbits += 16; + } + white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); + } +} + +/* + Parse a CIFF file, better known as Canon CRW format. + */ +void LibRaw::parse_ciff(int offset, int length, int depth) +{ + int tboff, nrecs, c, type, len, save, wbi = -1; + ushort key[] = {0x410, 0x45f3}; + ushort CanonColorInfo1_key; + ushort Appendix_A = 0; + INT64 WB_table_offset = 0; + int UseWBfromTable_as_AsShot = 1; + int Got_AsShotWB = 0; + INT64 fsize = ifp->size(); + if (metadata_blocks++ > LIBRAW_MAX_METADATA_BLOCKS) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + fseek(ifp, offset + length - 4, SEEK_SET); + tboff = get4() + offset; + fseek(ifp, tboff, SEEK_SET); + nrecs = get2(); + if (nrecs < 1) + return; + if ((nrecs | depth) > 127) + return; + + if (nrecs * 10 + offset > fsize) + return; + + while (nrecs--) + { + type = get2(); + len = get4(); + INT64 see = offset + get4(); + save = ftell(ifp); + + /* the following tags are not sub-tables + * they contain the value in the "len" field + * for such tags skip the check against filesize + */ + if ((type != 0x2007) && (type != 0x580b) && (type != 0x501c) && + (type != 0x5029) && (type != 0x5813) && (type != 0x5814) && + (type != 0x5817) && (type != 0x5834) && (type != 0x580e)) + { + + if (see >= fsize) + { // At least one byte + fseek(ifp, save, SEEK_SET); + continue; + } + fseek(ifp, see, SEEK_SET); + if ((((type >> 8) + 8) | 8) == 0x38) + { + parse_ciff(ftell(ifp), len, depth + 1); /* Parse a sub-table */ + } + } + + if (type == 0x3004) + { + parse_ciff(ftell(ifp), len, depth + 1); + } + else if (type == 0x0810) + { + fread(artist, 64, 1, ifp); + } + else if (type == 0x080a) + { + fread(make, 64, 1, ifp); + fseek(ifp, strbuflen(make) - 63, SEEK_CUR); + fread(model, 64, 1, ifp); + + } else if (type == 0x080b) { + char *p; + stmread(imCommon.firmware, (unsigned)len, ifp); + if (p = strrchr(imCommon.firmware, ' ')) { + imCanon.firmware = atof(p+1); + } + + } else if (type == 0x1810) + { + width = get4(); + height = get4(); + pixel_aspect = int_to_float(get4()); + flip = get4(); + } + else if (type == 0x1835) + { /* Get the decoder table */ + tiff_compress = get4(); + } + else if (type == 0x2007) + { + thumb_offset = see; + thumb_length = len; + } + else if (type == 0x1818) + { + shutter = libraw_powf64l(2.0f, -int_to_float((get4(), get4()))); + ilm.CurAp = aperture = libraw_powf64l(2.0f, int_to_float(get4()) / 2); + } + else if (type == 0x102a) // CanonShotInfo + { + // iso_speed = pow (2.0, (get4(),get2())/32.0 - 4) * 50; + get2(); // skip one + iso_speed = + libraw_powf64l(2.0f, (get2() + get2()) / 32.0f - 5.0f) * 100.0f; + ilm.CurAp = aperture = _CanonConvertAperture((get2(), get2())); + shutter = libraw_powf64l(2.0, -((short)get2()) / 32.0); + imCanon.wbi = wbi = (get2(), get2()); + if (wbi >= Canon_wbi2std.size()) + wbi = 0; + fseek(ifp, 32, SEEK_CUR); + if (shutter > 1e6) + shutter = get2() / 10.0; + } + else if (type == 0x102c) // CanonColorInfo2 / Appendix A: Pro90IS, G1, G2, S30, S40 + { + int CanonColorInfo2_type = get2(); // G1 1028, G2 272, Pro90 IS 769, S30 274, S40 273, EOS D30 276 + if (CanonColorInfo2_type > 512) { /* Pro90 IS, G1 */ + fseek(ifp, 118, SEEK_CUR); + FORC4 cam_mul[BG2RG1_2_RGBG(c)] = get2(); + } + else if (CanonColorInfo2_type != 276) { /* G2, S30, S40 */ + Appendix_A = 1; + WB_table_offset = -14; + fseek(ifp, 98, SEEK_CUR); + FORC4 cam_mul[GRBG_2_RGBG(c)] = get2(); + if (cam_mul[0] > 0.001f) Got_AsShotWB = 1; + } + } + else if (type == 0x10a9) // ColorBalance: Canon D60, 10D, 300D, and clones + { + int bls = 0; +/* + int table[] = { + LIBRAW_WBI_Auto, // 0 + LIBRAW_WBI_Daylight, // 1 + LIBRAW_WBI_Cloudy, // 2 + LIBRAW_WBI_Tungsten, // 3 + LIBRAW_WBI_FL_W, // 4 + LIBRAW_WBI_Flash, // 5 + LIBRAW_WBI_Custom, // 6, absent in Canon D60 + LIBRAW_WBI_Auto, // 7, use this if camera is set to b/w JPEG + LIBRAW_WBI_Shade, // 8 + LIBRAW_WBI_Kelvin // 9, absent in Canon D60 + }; +*/ + int nWB = + ((get2() - 2) / 8) - + 1; // 2 bytes this, N recs 4*2bytes each, last rec is black level + if (nWB) + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = get2(); + if (nWB >= 7) + Canon_WBpresets(0, 0); + else + FORC4 cam_mul[c] = icWBC[LIBRAW_WBI_Auto][c]; + if (nWB == 7) // mostly Canon EOS D60 + some fw#s for 300D; + // check for 0x1668000 is unreliable + { + if ((wbi >= 0) && (wbi < 9) && (wbi != 6)) + { + FORC4 cam_mul[c] = icWBC[Canon_wbi2std[wbi]][c]; + } + else + { + FORC4 cam_mul[c] = icWBC[LIBRAW_WBI_Auto][c]; + } + } + else if (nWB == 9) // Canon 10D, 300D + { + FORC4 icWBC[LIBRAW_WBI_Custom][RGGB_2_RGBG(c)] = get2(); + FORC4 icWBC[LIBRAW_WBI_Kelvin][RGGB_2_RGBG(c)] = get2(); + if ((wbi >= 0) && (wbi < 10)) + { + FORC4 cam_mul[c] = icWBC[Canon_wbi2std[wbi]][c]; + } + else + { + FORC4 cam_mul[c] = icWBC[LIBRAW_WBI_Auto][c]; + } + } + FORC4 + bls += (imCanon.ChannelBlackLevel[RGGB_2_RGBG(c)] = get2()); + imCanon.AverageBlackLevel = bls / 4; + } + else if (type == 0x102d) + { + Canon_CameraSettings(len >> 1); + } + + else if (type == 0x10b4) { + switch (get2()) { + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + + } else if (type == 0x580b) + { + if (strcmp(model, "Canon EOS D30")) + sprintf(imgdata.shootinginfo.BodySerial, "%d", len); + else + sprintf(imgdata.shootinginfo.BodySerial, "%0x-%05d", len >> 16, + len & 0xffff); + } + else if (type == 0x0032) // CanonColorInfo1 + { + if (len == 768) { // EOS D30 + + ushort q; + fseek(ifp, 4, SEEK_CUR); + for (int linenum = 0; linenum < Canon_D30_linenums_2_StdWBi.size(); linenum++) { + if (Canon_D30_linenums_2_StdWBi[linenum] != LIBRAW_WBI_Unknown) { + FORC4 { + q = get2(); + icWBC[Canon_D30_linenums_2_StdWBi[linenum]][RGGB_2_RGBG(c)] = + (int)(roundf(1024000.0f / (float)MAX(1, q))); + } +// if (Canon_wbi2std[imCanon.wbi] == *(Canon_D30_linenums_2_StdWBi + linenum)) { +// FORC4 cam_mul[c] = icWBC[*(Canon_D30_linenums_2_StdWBi + linenum)][c]; +// Got_AsShotWB = 1; +// } + } + } + fseek (ifp, 68-Canon_D30_linenums_2_StdWBi.size()*8, SEEK_CUR); + + FORC4 { + q = get2(); + cam_mul[RGGB_2_RGBG(c)] = 1024.0 / MAX(1, q); + } + if (!wbi) + cam_mul[0] = -1; // use my auto white balance + + } + else if ((cam_mul[0] <= 0.001f) || // Pro1, G3, G5, G6, S45, S50, S60, S70 + Appendix_A) // G2, S30, S40 + { + libraw_static_table_t linenums_2_StdWBi; + int AsShotWB_linenum = Canon_wbi2std.size(); + + CanonColorInfo1_key = get2(); + if ((CanonColorInfo1_key == key[0]) && (len == 2048)) { // Pro1 + linenums_2_StdWBi = Canon_KeyIs0x0410_Len2048_linenums_2_StdWBi; + WB_table_offset = 8; + + } else if ((CanonColorInfo1_key == key[0]) && (len == 3072)) { // S60, S70, G6 + linenums_2_StdWBi = Canon_KeyIs0x0410_Len3072_linenums_2_StdWBi; + WB_table_offset = 16; + + } else if (!CanonColorInfo1_key && (len == 2048)) { // G2, S30, S40; S45, S50, G3, G5 + key[0] = key[1] = 0; + linenums_2_StdWBi = Canon_KeyIsZero_Len2048_linenums_2_StdWBi; + if (imCanon.firmware < 1.02f) + UseWBfromTable_as_AsShot = 0; + + } else goto next_tag; + + if ((Canon_wbi2std[wbi] == LIBRAW_WBI_Auto) || + (Canon_wbi2std[wbi] == LIBRAW_WBI_Unknown) || + Got_AsShotWB) + UseWBfromTable_as_AsShot = 0; + + if (UseWBfromTable_as_AsShot) { + int temp_wbi; + if (Canon_wbi2std[wbi] == LIBRAW_WBI_Custom) temp_wbi = LIBRAW_WBI_Daylight; + else temp_wbi = wbi; + for (AsShotWB_linenum = 0; AsShotWB_linenum < linenums_2_StdWBi.size(); AsShotWB_linenum++) { + if (Canon_wbi2std[temp_wbi] == linenums_2_StdWBi[AsShotWB_linenum]) { + break; + } + } + } + + fseek (ifp, 78+WB_table_offset, SEEK_CUR); + for (int linenum = 0; linenum < linenums_2_StdWBi.size(); linenum++) { + if (linenums_2_StdWBi[linenum] != LIBRAW_WBI_Unknown) { + FORC4 icWBC[linenums_2_StdWBi[linenum]][GRBG_2_RGBG(c)] = get2() ^ key[c & 1]; + if (UseWBfromTable_as_AsShot && (AsShotWB_linenum == linenum)) { + FORC4 cam_mul[c] = icWBC[linenums_2_StdWBi[linenum]][c]; + Got_AsShotWB = 1; + } + } else { + fseek(ifp, 8, SEEK_CUR); + } + } + if (!Got_AsShotWB) + cam_mul[0] = -1; + } + } + else if (type == 0x1030 && wbi >= 0 && (0x18040 >> wbi & 1)) + { + ciff_block_1030(); // all that don't have 0x10a9 + } + else if (type == 0x1031) + { + raw_width = imCanon.SensorWidth = (get2(), get2()); + raw_height = imCanon.SensorHeight = get2(); + imCanon.SensorLeftBorder = (get2(), get2(), get2()); + imCanon.SensorTopBorder = get2(); + imCanon.SensorRightBorder = get2(); + imCanon.SensorBottomBorder = get2(); + imCanon.BlackMaskLeftBorder = get2(); + imCanon.BlackMaskTopBorder = get2(); + imCanon.BlackMaskRightBorder = get2(); + imCanon.BlackMaskBottomBorder = get2(); + } + else if (type == 0x501c) + { + iso_speed = len & 0xffff; + } + else if (type == 0x5029) + { + ilm.CurFocal = len >> 16; + ilm.FocalType = len & 0xffff; + if (ilm.FocalType == LIBRAW_FT_ZOOM_LENS) + { + ilm.FocalUnits = 32; + if (ilm.FocalUnits > 1) + ilm.CurFocal /= (float)ilm.FocalUnits; + } + focal_len = ilm.CurFocal; + } + else if (type == 0x5813) + { + flash_used = int_to_float(len); + } + else if (type == 0x5814) + { + canon_ev = int_to_float(len); + } + else if (type == 0x5817) + { + shot_order = len; + } + else if (type == 0x5834) + { + unique_id = ((unsigned long long)len << 32) >> 32; + setCanonBodyFeatures(unique_id); + } + else if (type == 0x580e) + { + timestamp = len; + } + else if (type == 0x180e) + { + timestamp = get4(); + } + +next_tag:; +#ifdef LOCALTIME + if ((type | 0x4000) == 0x580e) + timestamp = mktime(gmtime(×tamp)); +#endif + fseek(ifp, save, SEEK_SET); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/cr3_parser.cpp libkdcraw/libkdcraw/libraw/src/metadata/cr3_parser.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/cr3_parser.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/cr3_parser.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,539 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::selectCRXTrack(short maxTrack) +{ + if (maxTrack < 0) + return; + INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0; + uint32_t maxjpegbytes = 0; + memset(bitcounts, 0, sizeof(bitcounts)); + for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) + { + crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i]; + if (d->MediaType == 1) // RAW + { + bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height); + if (bitcounts[i] > maxbitcount) + maxbitcount = bitcounts[i]; + } + else if (d->MediaType == 2) // JPEG + { + if (d->MediaSize > maxjpegbytes) + { + maxjpegbytes = d->MediaSize; + thumb_offset = d->MediaOffset; + thumb_length = d->MediaSize; + } + } + } + if (maxbitcount < 8) + return; + int framei = -1, framecnt = 0; + for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) + { + if (bitcounts[i] == maxbitcount) + { + if (framecnt <= (int)shot_select) + framei = i; + framecnt++; + } + } + is_raw = framecnt; + if (framei >= 0 && framei < LIBRAW_CRXTRACKS_MAXCOUNT) + { + crx_data_header_t *d = + &libraw_internal_data.unpacker_data.crx_header[framei]; + data_offset = d->MediaOffset; + data_size = d->MediaSize; + raw_width = d->f_width; + raw_height = d->f_height; + load_raw = &LibRaw::crxLoadRaw; + switch (d->cfaLayout) + { + case 0: + filters = 0x94949494; + break; + case 1: + filters = 0x61616161; + break; + case 2: + filters = 0x49494949; + break; + case 3: + filters = 0x16161616; + break; + } + + libraw_internal_data.unpacker_data.crx_track_selected = framei; + + int tiff_idx = -1; + INT64 tpixels = 0; + for (unsigned i = 0; i < tiff_nifds && i < LIBRAW_IFD_MAXCOUNT; i++) + if (INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height) > tpixels) + { + tpixels = INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height); + tiff_idx = i; + } + if (tiff_idx >= 0) + flip = tiff_ifd[tiff_idx].t_flip; + } +} + +#define bad_hdr \ + (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) || \ + (get4() != 0x00000008)) +int LibRaw::parseCR3(unsigned long long oAtomList, + unsigned long long szAtomList, short &nesting, + char *AtomNameStack, short &nTrack, short &TrackType) +{ + /* + Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name + Atom size includes the length of the header and the size of all "contained" + Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located + after the Atom name if Atom size == 0, it is the last top-level Atom extending + to the end of the file Atom name is often a 4 symbol mnemonic, but can be a + 4-byte integer + */ + const char UIID_Canon[17] = + "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48"; + + /* + AtomType = 0 - unknown: "unk." + AtomType = 1 - container atom: "cont" + AtomType = 2 - leaf atom: "leaf" + AtomType = 3 - can be container, can be leaf: "both" + */ + short AtomType; + static const struct + { + char AtomName[5]; + short AtomType; + } AtomNamesList[] = { + {"dinf", 1}, + {"edts", 1}, + {"fiin", 1}, + {"ipro", 1}, + {"iprp", 1}, + {"mdia", 1}, + {"meco", 1}, + {"mere", 1}, + {"mfra", 1}, + {"minf", 1}, + {"moof", 1}, + {"moov", 1}, + {"mvex", 1}, + {"paen", 1}, + {"schi", 1}, + {"sinf", 1}, + {"skip", 1}, + {"stbl", 1}, + {"stsd", 1}, + {"strk", 1}, + {"tapt", 1}, + {"traf", 1}, + {"trak", 1}, + + {"cdsc", 2}, + {"colr", 2}, + {"dimg", 2}, + // {"dref", 2}, + {"free", 2}, + {"frma", 2}, + {"ftyp", 2}, + {"hdlr", 2}, + {"hvcC", 2}, + {"iinf", 2}, + {"iloc", 2}, + {"infe", 2}, + {"ipco", 2}, + {"ipma", 2}, + {"iref", 2}, + {"irot", 2}, + {"ispe", 2}, + {"meta", 2}, + {"mvhd", 2}, + {"pitm", 2}, + {"pixi", 2}, + {"schm", 2}, + {"thmb", 2}, + {"tkhd", 2}, + {"url ", 2}, + {"urn ", 2}, + + {"CCTP", 1}, + {"CRAW", 1}, + + {"JPEG", 2}, + {"CDI1", 2}, + {"CMP1", 2}, + + {"CNCV", 2}, + {"CCDT", 2}, + {"CTBO", 2}, + {"CMT1", 2}, + {"CMT2", 2}, + {"CMT3", 2}, + {"CMT4", 2}, + {"THMB", 2}, + {"co64", 2}, + {"mdat", 2}, + {"mdhd", 2}, + {"nmhd", 2}, + {"stsc", 2}, + {"stsz", 2}, + {"stts", 2}, + {"vmhd", 2}, + + {"dref", 3}, + {"uuid", 3}, + }; + + const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"}; + + int c, err; + + ushort tL; // Atom length represented in 4 or 8 bytes + char nmAtom[5]; // Atom name + unsigned long long oAtom, szAtom; // Atom offset and Atom size + unsigned long long oAtomContent, + szAtomContent; // offset and size of Atom content + unsigned long long lHdr; + + char UIID[16]; + uchar CMP1[36]; + char HandlerType[5], MediaFormatID[5]; + uint32_t relpos_inDir, relpos_inBox; + unsigned szItem, Tag, lTag; + ushort tItem; + + nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0'; + strcpy(HandlerType, sHandlerType[0]); + oAtom = oAtomList; + nesting++; + if (nesting > 31) + return -14; // too deep nesting + short s_order = order; + + while ((oAtom + 8ULL) <= (oAtomList + szAtomList)) + { + lHdr = 0ULL; + err = 0; + order = 0x4d4d; + fseek(ifp, oAtom, SEEK_SET); + szAtom = get4(); + FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp); + AtomNameStack[(nesting + 1) * 4] = '\0'; + tL = 4; + AtomType = 0; + + for (c = 0; c < int(sizeof AtomNamesList / sizeof *AtomNamesList); c++) + if (!strcmp(nmAtom, AtomNamesList[c].AtomName)) + { + AtomType = AtomNamesList[c].AtomType; + break; + } + + if (!AtomType) + { + err = 1; + } + + if (szAtom == 0ULL) + { + if (nesting != 0) + { + err = -2; + goto fin; + } + szAtom = szAtomList - oAtom; + oAtomContent = oAtom + 8ULL; + szAtomContent = szAtom - 8ULL; + } + else if (szAtom == 1ULL) + { + if ((oAtom + 16ULL) > (oAtomList + szAtomList)) + { + err = -3; + goto fin; + } + tL = 8; + szAtom = (((unsigned long long)get4()) << 32) | get4(); + oAtomContent = oAtom + 16ULL; + szAtomContent = szAtom - 16ULL; + } + else + { + oAtomContent = oAtom + 8ULL; + szAtomContent = szAtom - 8ULL; + } + + if (!strcmp(nmAtom, "trak")) + { + nTrack++; + TrackType = 0; + if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) + break; + } + if (!strcmp(AtomNameStack, "moovuuid")) + { + lHdr = 16ULL; + fread(UIID, 1, lHdr, ifp); + if (!strncmp(UIID, UIID_Canon, lHdr)) + { + AtomType = 1; + } + else + fseek(ifp, -lHdr, SEEK_CUR); + } + else if (!strcmp(AtomNameStack, "moovuuidCCTP")) + { + lHdr = 12ULL; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT1")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -4; + goto fin; + } + parse_tiff_ifd(oAtomContent); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT2")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -5; + goto fin; + } + parse_exif(oAtomContent); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT3")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -6; + goto fin; + } + fseek(ifp, -12L, SEEK_CUR); + parse_makernote(oAtomContent, 0); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT4")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -6; + goto fin; + } + INT64 off = ftell(ifp); + parse_gps(oAtomContent); + fseek(ifp, off, SEEK_SET); + parse_gps_libraw(oAtomContent); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr")) + { + fseek(ifp, 8L, SEEK_CUR); + FORC4 HandlerType[c] = fgetc(ifp); + for (c = 1; c < int(sizeof sHandlerType / sizeof *sHandlerType); c++) + if (!strcmp(HandlerType, sHandlerType[c])) + { + TrackType = c; + break; + } + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd")) + { + if (szAtomContent >= 16) + { + fseek(ifp, 12L, SEEK_CUR); + lHdr = 8; + } + else + { + err = -7; + goto fin; + } + FORC4 MediaFormatID[c] = fgetc(ifp); + if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW"))) + { + if (szAtomContent >= 44) + fseek(ifp, 24L, SEEK_CUR); + else + { + err = -8; + goto fin; + } + } + else + { + AtomType = 2; // only continue for CRAW + lHdr = 0; + } +#define current_track libraw_internal_data.unpacker_data.crx_header[nTrack] + + /*ImageWidth =*/ get2(); + /*ImageHeight =*/ get2(); + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW")) + { + lHdr = 82; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1")) + { + if (szAtomContent >= 40) + fread(CMP1, 1, 36, ifp); + else + { + err = -7; + goto fin; + } + if (!crxParseImageHeader(CMP1, nTrack)) + current_track.MediaType = 1; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG")) + { + current_track.MediaType = 2; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz")) + { + if (szAtomContent == 12) + fseek(ifp, 4L, SEEK_CUR); + else if (szAtomContent == 16) + fseek(ifp, 12L, SEEK_CUR); + else + { + err = -9; + goto fin; + } + current_track.MediaSize = get4(); + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64")) + { + if (szAtomContent == 16) + fseek(ifp, 8L, SEEK_CUR); + else + { + err = -10; + goto fin; + } + current_track.MediaOffset = (((unsigned long long)get4()) << 32) | get4(); + } + + if (nTrack >= 0 && nTrack < LIBRAW_CRXTRACKS_MAXCOUNT && + current_track.MediaSize && current_track.MediaOffset && + ((oAtom + szAtom) >= (oAtomList + szAtomList)) && + !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20)) + { + if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD"))) + { + order = 0x4949; + relpos_inDir = 0L; + while (relpos_inDir + 6 < current_track.MediaSize) + { + if (current_track.MediaOffset + relpos_inDir > ifp->size() - 6) // need at least 6 bytes + { + err = -11; + goto fin; + } + fseek(ifp, current_track.MediaOffset + relpos_inDir, SEEK_SET); + szItem = get4(); + tItem = get2(); + if (szItem < 1 || ( (relpos_inDir + szItem) > current_track.MediaSize)) + { + err = -11; + goto fin; + } + if ((tItem == 7) || (tItem == 8) || (tItem == 9)) + { + relpos_inBox = relpos_inDir + 12L; + while (relpos_inBox + 8 < relpos_inDir + szItem) + { + if (current_track.MediaOffset + relpos_inBox > ifp->size() - 8) // need at least 8 bytes + { + err = -11; + goto fin; + } + fseek(ifp, current_track.MediaOffset + relpos_inBox, SEEK_SET); + lTag = get4(); + Tag = get4(); + if (lTag < 8) + { + err = -12; + goto fin; + } + else if ((relpos_inBox + lTag) > (relpos_inDir + szItem)) + { + err = -11; + goto fin; + } + if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8))) + { + fseek(ifp, current_track.MediaOffset + relpos_inBox + 8L, + SEEK_SET); + short q_order = order; + order = get2(); + if (bad_hdr) + { + err = -13; + goto fin; + } + fseek(ifp, -8L, SEEK_CUR); + libraw_internal_data.unpacker_data.CR3_CTMDtag = 1; + parse_makernote(current_track.MediaOffset + relpos_inBox + 8, + 0); + libraw_internal_data.unpacker_data.CR3_CTMDtag = 0; + order = q_order; + } + relpos_inBox += lTag; + } + } + relpos_inDir += szItem; + } + order = 0x4d4d; + } + } +#undef current_track + if (AtomType == 1) + { + err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting, + AtomNameStack, nTrack, TrackType); + if (err) + goto fin; + } + oAtom += szAtom; + } + +fin: + nesting--; + if (nesting >= 0) + AtomNameStack[nesting * 4] = '\0'; + order = s_order; + return err; +} +#undef bad_hdr diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/epson.cpp libkdcraw/libkdcraw/libraw/src/metadata/epson.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/epson.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/epson.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,96 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::parseEpsonMakernote(int base, int uptag, unsigned dng_writer) +{ + +#define isRIC imgdata.sizes.raw_inset_crop + + unsigned entries, tag, type, len, save; + short morder, sorder = order; + ushort c; + INT64 fsize = ifp->size(); + + fseek(ifp, -2, SEEK_CUR); + + entries = get2(); + if (entries > 1000) + return; + morder = order; + + while (entries--) + { + order = morder; + tiff_get(base, &tag, &type, &len, &save); + INT64 pos = ifp->tell(); + if (len > 8 && pos + len > 2 * fsize) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + + tag |= uptag << 16; + if (len > 100 * 1024 * 1024) + goto next; // 100Mb tag? No! + + if (tag == 0x020b) + { + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + isRIC.cwidth = get4(); + else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT)) + isRIC.cwidth = get2(); + } + else if (tag == 0x020c) + { + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + isRIC.cheight = get4(); + else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT)) + isRIC.cheight = get2(); + } + else if (tag == 0x0400) + { // sensor area + ushort sdims[4] = {0, 0, 0, 0}; // left margin, top margin, width, height + FORC4 sdims[c] = get2(); + isRIC.cleft = (sdims[2] - sdims[0] - isRIC.cwidth) / 2; + isRIC.ctop = (sdims[3] - sdims[1] - isRIC.cheight) / 2; + } + + if (dng_writer == nonDNG) + { + + if (tag == 0x0280) + { + thumb_offset = ftell(ifp); + thumb_length = len; + } + else if (tag == 0x0401) + { + FORC4 cblack[RGGB_2_RGBG(c)] = get4(); + } + else if (tag == 0x0e80) + { + fseek(ifp, 48, SEEK_CUR); + cam_mul[0] = get2() * 567.0 / 0x10000; + cam_mul[2] = get2() * 431.0 / 0x10000; + } + } + + next: + fseek(ifp, save, SEEK_SET); + } + order = sorder; +#undef isRIC +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/exif_gps.cpp libkdcraw/libkdcraw/libraw/src/metadata/exif_gps.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/exif_gps.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/exif_gps.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,414 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +void LibRaw::parse_exif_interop(int base) +{ + unsigned entries, tag, type, len, save; + char value[4] = { 0,0,0,0 }; + entries = get2(); + INT64 fsize = ifp->size(); + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + + INT64 savepos = ftell(ifp); + if (len > 8 && savepos + len > fsize * 2) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + if (callbacks.exif_cb) + { + callbacks.exif_cb(callbacks.exifparser_data, tag | 0x40000, type, len, order, ifp, base); + fseek(ifp, savepos, SEEK_SET); + } + + switch (tag) + { + case 0x0001: // InteropIndex + fread(value, 1, MIN(4, len), ifp); + if (strncmp(value, "R98", 3) == 0 && + // Canon bug, when [Canon].ColorSpace = AdobeRGB, + // but [ExifIFD].ColorSpace = Uncalibrated and + // [InteropIFD].InteropIndex = "R98" + imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown) + imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB; + else if (strncmp(value, "R03", 3) == 0) + imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + } + fseek(ifp, save, SEEK_SET); + } +} + +void LibRaw::parse_exif(int base) +{ + unsigned entries, tag, type, len, save, c; + double expo, ape; + + unsigned kodak = !strncmp(make, "EASTMAN", 7) && tiff_nifds < 3; + + entries = get2(); + if (!strncmp(make, "Hasselblad", 10) && (tiff_nifds > 3) && (entries > 512)) + return; + INT64 fsize = ifp->size(); + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + + INT64 savepos = ftell(ifp); + if (len > 8 && savepos + len > fsize * 2) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + if (callbacks.exif_cb) + { + callbacks.exif_cb(callbacks.exifparser_data, tag, type, len, order, ifp, + base); + fseek(ifp, savepos, SEEK_SET); + } + + switch (tag) + { + case 0xA005: // Interoperability IFD + fseek(ifp, get4() + base, SEEK_SET); + parse_exif_interop(base); + break; + case 0xA001: // ExifIFD.ColorSpace + c = get2(); + if (c == 1 && imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown) + imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB; + else if (c == 2) + imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + case 0x9400: + imCommon.exifAmbientTemperature = getreal(type); + if ((imCommon.CameraTemperature > -273.15f) && + ((OlyID == OlyID_TG_5) || + (OlyID == OlyID_TG_6)) + ) + imCommon.CameraTemperature += imCommon.exifAmbientTemperature; + break; + case 0x9401: + imCommon.exifHumidity = getreal(type); + break; + case 0x9402: + imCommon.exifPressure = getreal(type); + break; + case 0x9403: + imCommon.exifWaterDepth = getreal(type); + break; + case 0x9404: + imCommon.exifAcceleration = getreal(type); + break; + case 0x9405: + imCommon.exifCameraElevationAngle = getreal(type); + break; + + case 0xa405: // FocalLengthIn35mmFormat + imgdata.lens.FocalLengthIn35mmFormat = get2(); + break; + case 0xa431: // BodySerialNumber + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + break; + case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard + imgdata.lens.MinFocal = getreal(type); + imgdata.lens.MaxFocal = getreal(type); + imgdata.lens.MaxAp4MinFocal = getreal(type); + imgdata.lens.MaxAp4MaxFocal = getreal(type); + break; + case 0xa435: // LensSerialNumber + stmread(imgdata.lens.LensSerial, len, ifp); + if (!strncmp(imgdata.lens.LensSerial, "----", 4)) + imgdata.lens.LensSerial[0] = '\0'; + break; + case 0xa420: /* 42016, ImageUniqueID */ + stmread(imgdata.color.ImageUniqueID, len, ifp); + break; + case 0xc65d: /* 50781, RawDataUniqueID */ + imgdata.color.RawDataUniqueID[16] = 0; + fread(imgdata.color.RawDataUniqueID, 1, 16, ifp); + break; + case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard + imgdata.lens.dng.MinFocal = getreal(type); + imgdata.lens.dng.MaxFocal = getreal(type); + imgdata.lens.dng.MaxAp4MinFocal = getreal(type); + imgdata.lens.dng.MaxAp4MaxFocal = getreal(type); + break; + case 0xc68b: /* 50827, OriginalRawFileName */ + stmread(imgdata.color.OriginalRawFileName, len, ifp); + break; + case 0xa433: // LensMake + stmread(imgdata.lens.LensMake, len, ifp); + break; + case 0xa434: // LensModel + stmread(imgdata.lens.Lens, len, ifp); + if (!strncmp(imgdata.lens.Lens, "----", 4)) + imgdata.lens.Lens[0] = '\0'; + break; + case 0x9205: + imgdata.lens.EXIF_MaxAp = libraw_powf64l(2.0f, (getreal(type) / 2.0f)); + break; + case 0x829a: // 33434 + shutter = getreal(type); + if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT) + tiff_ifd[tiff_nifds - 1].t_shutter = shutter; + break; + case 0x829d: // 33437, FNumber + aperture = getreal(type); + break; + case 0x8827: // 34855 + iso_speed = get2(); + break; + case 0x8831: // 34865 + if (iso_speed == 0xffff && !strncasecmp(make, "FUJI", 4)) + iso_speed = getreal(type); + break; + case 0x8832: // 34866 + if (iso_speed == 0xffff && + (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "CANON", 5))) + iso_speed = getreal(type); + break; + case 0x9003: // 36867 + case 0x9004: // 36868 + get_timestamp(0); + break; + case 0x9201: // 37377 + if ((expo = -getreal(type)) < 128 && shutter == 0.) + { + shutter = libraw_powf64l(2.0, expo); + if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT) + tiff_ifd[tiff_nifds - 1].t_shutter = shutter; + } + break; + case 0x9202: // 37378 ApertureValue + if ((fabs(ape = getreal(type)) < 256.0) && (!aperture)) + aperture = libraw_powf64l(2.0, ape / 2); + break; + case 0x9209: // 37385 + flash_used = getreal(type); + break; + case 0x920a: // 37386 + focal_len = getreal(type); + break; + case 0x927c: // 37500 + if (((make[0] == '\0') && !strncmp(model, "ov5647", 6)) || + (!strncmp(make, "RaspberryPi", 11) && + (!strncmp(model, "RP_OV5647", 9) || + !strncmp(model, "RP_imx219", 9)))) + { + char mn_text[512]; + char *pos; + char ccms[512]; + ushort l; + float num; + + fgets(mn_text, MIN(len, 511), ifp); + mn_text[511] = 0; + + pos = strstr(mn_text, "gain_r="); + if (pos) + cam_mul[0] = atof(pos + 7); + pos = strstr(mn_text, "gain_b="); + if (pos) + cam_mul[2] = atof(pos + 7); + if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f)) + cam_mul[1] = cam_mul[3] = 1.0f; + else + cam_mul[0] = cam_mul[2] = 0.0f; + + pos = strstr(mn_text, "ccm="); + if (pos) + { + pos += 4; + char *pos2 = strstr(pos, " "); + if (pos2) + { + l = pos2 - pos; + memcpy(ccms, pos, l); + ccms[l] = '\0'; +#ifdef LIBRAW_WIN32_CALLS + // Win32 strtok is already thread-safe + pos = strtok(ccms, ","); +#else + char *last = 0; + pos = strtok_r(ccms, ",", &last); +#endif + if (pos) + { + for (l = 0; l < 4; l++) + { + num = 0.0; + for (c = 0; c < 3; c++) + { + imgdata.color.ccm[l][c] = (float)atoi(pos); + num += imgdata.color.ccm[l][c]; +#ifdef LIBRAW_WIN32_CALLS + pos = strtok(NULL, ","); +#else + pos = strtok_r(NULL, ",", &last); +#endif + if (!pos) + goto end; // broken + } + if (num > 0.01) + FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num; + } + } + } + } + end:; + } + else if (!strncmp(make, "SONY", 4) && + (!strncmp(model, "DSC-V3", 6) || !strncmp(model, "DSC-F828", 8))) + { + parseSonySRF(len); + break; + } + else if ((len == 1) && !strncmp(make, "NIKON", 5)) + { + c = get4(); + if (c) + fseek(ifp, c, SEEK_SET); + is_NikonTransfer = 1; + } + parse_makernote(base, 0); + break; + case 0xa002: // 40962 + if (kodak) + raw_width = get4(); + break; + case 0xa003: // 40963 + if (kodak) + raw_height = get4(); + break; + case 0xa302: // 41730 + if (get4() == 0x20002) + for (exif_cfa = c = 0; c < 8; c += 2) + exif_cfa |= fgetc(ifp) * 0x01010101U << c; + } + fseek(ifp, save, SEEK_SET); + } +} + +void LibRaw::parse_gps_libraw(int base) +{ + unsigned entries, tag, type, len, save, c; + + entries = get2(); + if (entries > 40) + return; + if (entries > 0) + imgdata.other.parsed_gps.gpsparsed = 1; + INT64 fsize = ifp->size(); + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + if (len > 1024) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; // no GPS tags are 1k or larger + } + INT64 savepos = ftell(ifp); + if (len > 8 && savepos + len > fsize * 2) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + + if (callbacks.exif_cb) + { + callbacks.exif_cb(callbacks.exifparser_data, tag | 0x50000, type, len, order, ifp, base); + fseek(ifp, savepos, SEEK_SET); + } + + switch (tag) + { + case 0x0001: + imgdata.other.parsed_gps.latref = getc(ifp); + break; + case 0x0003: + imgdata.other.parsed_gps.longref = getc(ifp); + break; + case 0x0005: + imgdata.other.parsed_gps.altref = getc(ifp); + break; + case 0x0002: + if (len == 3) + FORC(3) imgdata.other.parsed_gps.latitude[c] = getreal(type); + break; + case 0x0004: + if (len == 3) + FORC(3) imgdata.other.parsed_gps.longitude[c] = getreal(type); + break; + case 0x0007: + if (len == 3) + FORC(3) imgdata.other.parsed_gps.gpstimestamp[c] = getreal(type); + break; + case 0x0006: + imgdata.other.parsed_gps.altitude = getreal(type); + break; + case 0x0009: + imgdata.other.parsed_gps.gpsstatus = getc(ifp); + break; + } + fseek(ifp, save, SEEK_SET); + } +} + +void LibRaw::parse_gps(int base) +{ + unsigned entries, tag, type, len, save, c; + + entries = get2(); + if (entries > 40) + return; + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + if (len > 1024) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; // no GPS tags are 1k or larger + } + switch (tag) + { + case 0x0001: + case 0x0003: + case 0x0005: + gpsdata[29 + tag / 2] = getc(ifp); + break; + case 0x0002: + case 0x0004: + case 0x0007: + FORC(6) gpsdata[tag / 3 * 6 + c] = get4(); + break; + case 0x0006: + FORC(2) gpsdata[18 + c] = get4(); + break; + case 0x0012: // 18 + case 0x001d: // 29 + fgets((char *)(gpsdata + 14 + tag / 3), MIN(len, 12), ifp); + } + fseek(ifp, save, SEEK_SET); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/fuji.cpp libkdcraw/libkdcraw/libraw/src/metadata/fuji.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/fuji.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/fuji.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,1163 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::parseAdobeRAFMakernote() +{ + + uchar *PrivateMknBuf; + unsigned posPrivateMknBuf; + unsigned PrivateMknLength; + unsigned PrivateOrder; + unsigned PrivateEntries, PrivateTagID; + unsigned PrivateTagBytes; + unsigned wb_section_offset = 0; + int posWB; + int c; + +#define CHECKSPACE(s) \ + if (posPrivateMknBuf + (s) > PrivateMknLength) \ + { \ + free(PrivateMknBuf); \ + return; \ + } +#define isWB(posWB) \ + sget2(posWB) != 0 && sget2(posWB + 2) != 0 && sget2(posWB + 4) != 0 && \ + sget2(posWB + 6) != 0 && sget2(posWB + 8) != 0 && \ + sget2(posWB + 10) != 0 && sget2(posWB) != 0xff && \ + sget2(posWB + 2) != 0xff && sget2(posWB + 4) != 0xff && \ + sget2(posWB + 6) != 0xff && sget2(posWB + 8) != 0xff && \ + sget2(posWB + 10) != 0xff && sget2(posWB) == sget2(posWB + 6) && \ + sget2(posWB) < sget2(posWB + 2) && sget2(posWB) < sget2(posWB + 4) && \ + sget2(posWB) < sget2(posWB + 8) && sget2(posWB) < sget2(posWB + 10) +#define imfRAFDataVersion imFuji.RAFDataVersion +#define imfRAFVersion imFuji.RAFVersion + + ushort use_WBcorr_coeffs = 0; + double wbR_corr = 1.0; + double wbB_corr = 1.0; + + if (strstr(model, "S7000") || + strstr(model, "S5000") || + strstr(model, "F700") || + strstr(model, "S2Pro") || + strstr(model, "S20Pro")) { + use_WBcorr_coeffs = 1; + wbR_corr = 10.0 / 17.0 / 0.652941; + wbB_corr = 2.0 /3.0 / (3.0 / 4.0 + 1.0 / 300.0); + } + + order = 0x4d4d; + PrivateMknLength = get4(); + + if ((PrivateMknLength > 4) && (PrivateMknLength < 10240000) && + (PrivateMknBuf = (uchar *)malloc(PrivateMknLength + 1024))) + { // 1024b for safety + fread(PrivateMknBuf, PrivateMknLength, 1, ifp); + PrivateOrder = sget2(PrivateMknBuf); + posPrivateMknBuf = sget4(PrivateMknBuf + 2) + 12; + + memcpy(imFuji.SerialSignature, PrivateMknBuf + 6, 0x0c); + imFuji.SerialSignature[0x0c] = 0; + memcpy(model, PrivateMknBuf + 0x12, 0x20); + model[0x20] = 0; + memcpy(model2, PrivateMknBuf + 0x32, 4); + model2[4] = 0; + strcpy(imFuji.RAFVersion, model2); + PrivateEntries = sget2(PrivateMknBuf + posPrivateMknBuf); + if ((PrivateEntries > 1000) || + ((PrivateOrder != 0x4d4d) && (PrivateOrder != 0x4949))) + { + free(PrivateMknBuf); + return; + } + posPrivateMknBuf += 2; + /* + * because Adobe DNG converter strips or misplaces 0xfnnn tags, + * Auto WB for following cameras is missing for now + * - F550EXR + * - F600EXR + * - F770EXR + * - F800EXR + * - F900EXR + * - HS10 + * - HS11 + * - HS20EXR + * - HS30EXR + * - HS50EXR + * - S1 + * - SL1000 + **/ + while (PrivateEntries--) + { + order = 0x4d4d; + CHECKSPACE(4); + PrivateTagID = sget2(PrivateMknBuf + posPrivateMknBuf); + PrivateTagBytes = sget2(PrivateMknBuf + posPrivateMknBuf + 2); + posPrivateMknBuf += 4; + order = PrivateOrder; + + if (PrivateTagID == 0x2000) + { + FORC4 icWBC[LIBRAW_WBI_Auto][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Auto][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Auto][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2100) + { + FORC4 icWBC[LIBRAW_WBI_FineWeather][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FineWeather][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FineWeather][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2200) + { + FORC4 icWBC[LIBRAW_WBI_Shade][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Shade][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Shade][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2300) + { + FORC4 icWBC[LIBRAW_WBI_FL_D][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_D][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_D][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2301) + { + FORC4 icWBC[LIBRAW_WBI_FL_N][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_N][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_N][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2302) + { + FORC4 icWBC[LIBRAW_WBI_FL_WW][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_WW][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_WW][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2310) + { + FORC4 icWBC[LIBRAW_WBI_FL_L][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_L][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_L][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2311) + { + FORC4 icWBC[LIBRAW_WBI_FL_W][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_W][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_W][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2400) + { + FORC4 icWBC[LIBRAW_WBI_Tungsten][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Tungsten][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Tungsten][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2410) + { + FORC4 icWBC[LIBRAW_WBI_Flash][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Flash][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Flash][2] *= wbB_corr; + } + } + else if (PrivateTagID == 0x2f00) + { + int nWBs = MIN(sget4(PrivateMknBuf + posPrivateMknBuf), 6); + posWB = posPrivateMknBuf + 4; + for (int wb_ind = 0; wb_ind < nWBs; wb_ind++) + { + FORC4 icWBC[LIBRAW_WBI_Custom1 + wb_ind][GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posWB + (c << 1)); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Custom1 + wb_ind][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Custom1 + wb_ind][2] *= wbB_corr; + } + posWB += 8; + } + } + else if (PrivateTagID == 0x2ff0) + { + FORC4 cam_mul[GRGB_2_RGBG(c)] = + sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)); + if (use_WBcorr_coeffs) { + cam_mul[0] *= wbR_corr; + cam_mul[2] *= wbB_corr; + } + } + + else if (PrivateTagID == 0x9650) + { + CHECKSPACE(4); + short a = (short)sget2(PrivateMknBuf + posPrivateMknBuf); + float b = fMAX(1.0f, sget2(PrivateMknBuf + posPrivateMknBuf + 2)); + imFuji.ExpoMidPointShift = a / b; + } + else if ((PrivateTagID == 0xc000) && (PrivateTagBytes > 3) && + (PrivateTagBytes < 10240000)) + { + order = 0x4949; + if (PrivateTagBytes != 4096) // not one of Fuji X-A3, X-A5, X-A7, X-A10, X-A20, X-T100, X-T200, XF10 + { + if (!sget2(PrivateMknBuf + posPrivateMknBuf)) + imfRAFDataVersion = sget2(PrivateMknBuf + posPrivateMknBuf + 2); + + for (posWB = 0; posWB < (int)PrivateTagBytes - 16; posWB++) + { + if ((!memcmp(PrivateMknBuf + posWB, "TSNERDTS", 8) && + (sget2(PrivateMknBuf + posWB + 10) > 125))) + { + posWB += 10; + icWBC[LIBRAW_WBI_Auto][1] = + icWBC[LIBRAW_WBI_Auto][3] = + sget2(PrivateMknBuf + posWB); + icWBC[LIBRAW_WBI_Auto][0] = + sget2(PrivateMknBuf + posWB + 2); + icWBC[LIBRAW_WBI_Auto][2] = + sget2(PrivateMknBuf + posWB + 4); + break; + } + } + if (imfRAFDataVersion == 0x0146 || // X20 + imfRAFDataVersion == 0x0149 || // X100S + imfRAFDataVersion == 0x0249) // X100S + { + wb_section_offset = 0x1410; + } + else if (imfRAFDataVersion == 0x014d || // X-M1 + imfRAFDataVersion == 0x014e) // X-A1, X-A2 + { + wb_section_offset = 0x1474; + } + else if (imfRAFDataVersion == 0x014f || // X-E2 + imfRAFDataVersion == 0x024f || // X-E2 + imfRAFDataVersion == 0x025d) // X-H1 + { + wb_section_offset = 0x1480; + } + else if (imfRAFDataVersion == 0x0150) // XQ1, XQ2 + { + wb_section_offset = 0x1414; + } + else if (imfRAFDataVersion == 0x0151 || // X-T1 w/diff. fws + imfRAFDataVersion == 0x0251 || imfRAFDataVersion == 0x0351 || + imfRAFDataVersion == 0x0451 || imfRAFDataVersion == 0x0551) + { + wb_section_offset = 0x14b0; + } + else if (imfRAFDataVersion == 0x0152 || // X30 + imfRAFDataVersion == 0x0153) // X100T + { + wb_section_offset = 0x1444; + } + else if (imfRAFDataVersion == 0x0154) // X-T10 + { + wb_section_offset = 0x1824; + } + else if (imfRAFDataVersion == 0x0155) // X70 + { + wb_section_offset = 0x17b4; + } + else if (imfRAFDataVersion == 0x0255) // X-Pro2 + { + wb_section_offset = 0x135c; + } + else if (imfRAFDataVersion == 0x0258 || // X-T2 + imfRAFDataVersion == 0x025b) // X-T20 + { + wb_section_offset = 0x13dc; + } + else if (imfRAFDataVersion == 0x0259) // X100F + { + wb_section_offset = 0x1370; + } + else if (imfRAFDataVersion == 0x025a) // GFX 50S + { + wb_section_offset = 0x1424; + } + else if (imfRAFDataVersion == 0x025c) // X-E3 + { + wb_section_offset = 0x141c; + } + else if (imfRAFDataVersion == 0x025e) // X-T3 + { + wb_section_offset = 0x2014; + } + else if (imfRAFDataVersion == 0x025f) // X-T30, GFX 50R, GFX 100 + { + if (!strcmp(model, "X-T30")) { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20b8)) + wb_section_offset = 0x20b8; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20c8)) + wb_section_offset = 0x20c8; + } + else if (!strcmp(model, "GFX 50R")) + wb_section_offset = 0x1424; + else if (!strcmp(model, "GFX 100")) + wb_section_offset = 0x20e4; + } + else if (imfRAFDataVersion == 0x0260) // X-Pro3 + { + wb_section_offset = 0x20e8; + } + else if (imfRAFDataVersion == 0x0261) // X100V + { + wb_section_offset = 0x2078; + } + else if (imfRAFDataVersion == 0x0262) // X-T4 + { + wb_section_offset = 0x21c8; + } + + /* try for unknown RAF Data versions */ + else if (!strcmp(model, "X-Pro2")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x135c)) + wb_section_offset = 0x135c; + } + else if (!strcmp(model, "X100F")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1370)) + wb_section_offset = 0x1370; + } + else if (!strcmp(model, "X-T2")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x13dc)) + wb_section_offset = 0x13dc; + } + else if (!strcmp(model, "X-T20")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x13dc)) + wb_section_offset = 0x13dc; + } + else if (!strcmp(model, "X20")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1410)) + wb_section_offset = 0x1410; + } + else if (!strcmp(model, "X100S")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1410)) + wb_section_offset = 0x1410; + } + else if (!strcmp(model, "XQ1")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1414)) + wb_section_offset = 0x1414; + } + else if (!strcmp(model, "XQ2")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1414)) + wb_section_offset = 0x1414; + } + else if (!strcmp(model, "X-E3")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x141c)) + wb_section_offset = 0x141c; + } + else if (!strcmp(model, "GFX 50S")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1424)) + wb_section_offset = 0x1424; + } + else if (!strcmp(model, "GFX 50R")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1424)) + wb_section_offset = 0x1424; + } + else if (!strcmp(model, "X30")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1444)) + wb_section_offset = 0x1444; + } + else if (!strcmp(model, "X100T")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1444)) + wb_section_offset = 0x1444; + } + else if (!strcmp(model, "X-M1")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1474)) + wb_section_offset = 0x1474; + } + else if (!strcmp(model, "X-A1")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1474)) + wb_section_offset = 0x1474; + } + else if (!strcmp(model, "X-A2")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1474)) + wb_section_offset = 0x1474; + } + else if (!strcmp(model, "X-E2")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1480)) + wb_section_offset = 0x1480; + } + else if (!strcmp(model, "X-H1")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1480)) + wb_section_offset = 0x1480; + } + else if (!strcmp(model, "X-T1")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x14b0)) + wb_section_offset = 0x14b0; + } + else if (!strcmp(model, "X70")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x17b4)) + wb_section_offset = 0x17b4; + } + else if (!strcmp(model, "X-T10")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1824)) + wb_section_offset = 0x1824; + } + else if (!strcmp(model, "X-E2S")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1840)) + wb_section_offset = 0x1840; + } + else if (!strcmp(model, "X-T3")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x2014)) + wb_section_offset = 0x2014; + } + else if (!strcmp(model, "X100V")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20e8)) + wb_section_offset = 0x2078; + } + else if (!strcmp(model, "X-T30")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20b8)) + wb_section_offset = 0x20b8; + } + else if (!strcmp(model, "GFX 100")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20e4)) + wb_section_offset = 0x20e4; + } + else if (!strcmp(model, "X-Pro3")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20e8)) + wb_section_offset = 0x20e8; + } + else if (!strcmp(model, "X-T4")) + { + if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x21c8)) + wb_section_offset = 0x21c8; + } + + /* no RAF Data version for the models below */ + else if (!strcmp(model, "FinePix X100")) // X100 0 0x19f0 0x19e8 + { + if (!strcmp(imfRAFVersion, "0069")) + wb_section_offset = 0x19e8; + else if (!strcmp(imfRAFVersion, "0100")) + wb_section_offset = 0x19f0; + else if (!strcmp(imfRAFVersion, "0110")) + wb_section_offset = 0x19f0; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x19e8)) + wb_section_offset = 0x19e8; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x19f0)) + wb_section_offset = 0x19f0; + } + else if (!strcmp(model, "X-E1")) // X-E1 0 0x13ac + { + if (!strcmp(imfRAFVersion, "0101")) + wb_section_offset = 0x13ac; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x13ac)) + wb_section_offset = 0x13ac; + } + else if (!strcmp(model, "X-Pro1")) // X-Pro1 0 0x13a4 + { + if (!strcmp(imfRAFVersion, "0100")) + wb_section_offset = 0x13a4; + else if (!strcmp(imfRAFVersion, "0101")) + wb_section_offset = 0x13a4; + else if (!strcmp(imfRAFVersion, "0204")) + wb_section_offset = 0x13a4; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x13a4)) + wb_section_offset = 0x13a4; + } + else if (!strcmp(model, "XF1")) // XF1 0 0x138c + { + if (!strcmp(imfRAFVersion, "0100")) + wb_section_offset = 0x138c; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x138c)) + wb_section_offset = 0x138c; + } + else if (!strcmp(model, "X-S1")) // X-S1 0 0x1284 + { + if (!strcmp(imfRAFVersion, "0100")) + wb_section_offset = 0x1284; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1284)) + wb_section_offset = 0x1284; + } + else if (!strcmp(model, "X10")) // X10 0 0x1280 0x12d4 + { + if (!strcmp(imfRAFVersion, "0100")) + wb_section_offset = 0x1280; + else if (!strcmp(imfRAFVersion, "0102")) + wb_section_offset = 0x1280; + else if (!strcmp(imfRAFVersion, "0103")) + wb_section_offset = 0x12d4; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1280)) + wb_section_offset = 0x1280; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x12d4)) + wb_section_offset = 0x12d4; + } + else if (!strcmp(model, "XF1")) // XF1 0 0x138c + { + if (!strcmp(imfRAFVersion, "0100")) + wb_section_offset = 0x138c; + else if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x138c)) + wb_section_offset = 0x138c; + } + if (wb_section_offset && + isWB(PrivateMknBuf + posPrivateMknBuf + wb_section_offset)) + { + + if (!imfRAFDataVersion) + { + posWB = posPrivateMknBuf + wb_section_offset - 6; + icWBC[LIBRAW_WBI_Auto][1] = + icWBC[LIBRAW_WBI_Auto][3] = + sget2(PrivateMknBuf + posWB); + icWBC[LIBRAW_WBI_Auto][0] = + sget2(PrivateMknBuf + posWB + 2); + icWBC[LIBRAW_WBI_Auto][2] = + sget2(PrivateMknBuf + posWB + 4); + } + + posWB = posPrivateMknBuf + wb_section_offset; + for (int wb_ind = 0; wb_ind < Fuji_wb_list1.size(); posWB += 6, wb_ind++) + { + icWBC[Fuji_wb_list1[wb_ind]][1] = + icWBC[Fuji_wb_list1[wb_ind]][3] = + sget2(PrivateMknBuf + posWB); + icWBC[Fuji_wb_list1[wb_ind]][0] = + sget2(PrivateMknBuf + posWB + 2); + icWBC[Fuji_wb_list1[wb_ind]][2] = + sget2(PrivateMknBuf + posWB + 4); + } + int found = 0; + if ((imfRAFDataVersion == 0x0260) || + (imfRAFDataVersion == 0x0261) || + (imfRAFDataVersion == 0x0262)) + posWB += 0x30; + posWB += 0xc0; + ushort Gval = sget2(PrivateMknBuf + posWB); + for (int posEndCCTsection = posWB; posEndCCTsection < (posWB + 30); + posEndCCTsection += 6) + { + if (sget2(PrivateMknBuf + posEndCCTsection) != Gval) + { + if ((imfRAFDataVersion == 0x0260) || + (imfRAFDataVersion == 0x0261) || + (imfRAFDataVersion == 0x0262)) + wb_section_offset = posEndCCTsection - 34*3*2; // 34 records, 3 2-byte values in a record + else + wb_section_offset = posEndCCTsection - 31*3*2; // 31 records, 3 2-byte values in a record + found = 1; + break; + } + } + + if (found) + { + for (int iCCT = 0; iCCT < 31; iCCT++) + { + icWBCCTC[iCCT][0] = FujiCCT_K[iCCT]; + icWBCCTC[iCCT][1] = sget2(PrivateMknBuf + wb_section_offset + iCCT * 6 + 2); + icWBCCTC[iCCT][2] = icWBCCTC[iCCT][4] = sget2(PrivateMknBuf + wb_section_offset + iCCT * 6); + icWBCCTC[iCCT][3] = sget2(PrivateMknBuf + wb_section_offset + iCCT * 6 + 4); + } + } + } + } + else // process 4K raf data + { + int wb[4]; + int nWB, tWB, pWB; + int iCCT = 0; + is_4K_RAFdata = 1; /* X-A3, X-A5, X-A7, X-A10, X-A20, X-T100, X-T200, XF10 */ + posWB = posPrivateMknBuf + 0x200; + for (int wb_ind = 0; wb_ind < 42; wb_ind++) + { + nWB = sget4(PrivateMknBuf + posWB); + posWB += 4; + tWB = sget4(PrivateMknBuf + posWB); + posWB += 4; + wb[0] = sget4(PrivateMknBuf + posWB) << 1; + posWB += 4; + wb[1] = sget4(PrivateMknBuf + posWB); + posWB += 4; + wb[3] = sget4(PrivateMknBuf + posWB); + posWB += 4; + wb[2] = sget4(PrivateMknBuf + posWB) << 1; + posWB += 4; + + if (tWB && (iCCT < 255)) + { + icWBCCTC[iCCT][0] = tWB; + FORC4 icWBCCTC[iCCT][c + 1] = wb[c]; + iCCT++; + } + if (nWB != 0x46) + { + for (pWB = 1; pWB < Fuji_wb_list2.size(); pWB += 2) + { + if (Fuji_wb_list2[pWB] == nWB) + { + FORC4 icWBC[Fuji_wb_list2[pWB - 1]][c] = + wb[c]; + break; + } + } + } + } + } + } + posPrivateMknBuf += PrivateTagBytes; + } + free(PrivateMknBuf); + } +#undef imfRAFVersion +#undef imfRAFDataVersion +#undef CHECKSPACE +} +void LibRaw::parseFujiMakernotes(unsigned tag, unsigned type, unsigned len, + unsigned dng_writer) +{ + if ((dng_writer == nonDNG) && (tag == 0x0010)) + { + char FujiSerial[sizeof(imgdata.shootinginfo.InternalBodySerial)]; + char *words[4]; + char yy[2], mm[3], dd[3], ystr[16], ynum[16]; + int year, nwords, ynum_len; + unsigned c; + memset(FujiSerial, 0, sizeof(imgdata.shootinginfo.InternalBodySerial)); + ifp->read(FujiSerial, MIN(len,sizeof(FujiSerial)), 1); + nwords = getwords(FujiSerial, words, 4, + sizeof(imgdata.shootinginfo.InternalBodySerial)); + for (int i = 0; i < nwords; i++) + { + mm[2] = dd[2] = 0; + if (strnlen(words[i], + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) < 18) + { + if (i == 0) + { + strncpy(imgdata.shootinginfo.InternalBodySerial, words[0], + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1); + } + else + { + char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; + snprintf(tbuf, sizeof(tbuf)-1, "%s %s", + imgdata.shootinginfo.InternalBodySerial, words[i]); + strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf, + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1); + } + } + else + { + strncpy( + dd, + words[i] + + strnlen(words[i], + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - + 14, + 2); + strncpy( + mm, + words[i] + + strnlen(words[i], + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - + 16, + 2); + strncpy( + yy, + words[i] + + strnlen(words[i], + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - + 18, + 2); + year = (yy[0] - '0') * 10 + (yy[1] - '0'); + if (year < 70) + year += 2000; + else + year += 1900; + + ynum_len = MIN( + int(sizeof(ynum) - 1), + (int)strnlen(words[i], + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - + 18); + strncpy(ynum, words[i], ynum_len); + ynum[ynum_len] = 0; + for (int j = 0; ynum[j] && ynum[j + 1] && sscanf(ynum + j, "%2x", &c); + j += 2) + ystr[j / 2] = c; + ystr[ynum_len / 2 + 1] = 0; + strcpy(model2, ystr); + + if (i == 0) + { + char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; + + if (nwords == 1) + { + snprintf( + tbuf, sizeof(tbuf), "%s %s %d:%s:%s", + words[0] + + strnlen(words[0], + sizeof(imgdata.shootinginfo.InternalBodySerial) - + 1) - + 12, + ystr, year, mm, dd); + } + else + { + snprintf( + tbuf, sizeof(tbuf), "%s %d:%s:%s %s", ystr, year, mm, dd, + words[0] + + strnlen(words[0], + sizeof(imgdata.shootinginfo.InternalBodySerial) - + 1) - + 12); + } + strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf, + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1); + } + else + { + char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; + snprintf( + tbuf, sizeof(tbuf), "%s %s %d:%s:%s %s", + imgdata.shootinginfo.InternalBodySerial, ystr, year, mm, dd, + words[i] + + strnlen(words[i], + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - + 12); + strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf, + sizeof(imgdata.shootinginfo.InternalBodySerial) - 1); + } + } + } + } + else + switch (tag) + { + case 0x1002: + imFuji.WB_Preset = get2(); + break; + case 0x1011: + imCommon.FlashEC = getreal(type); + break; + case 0x1020: + imFuji.Macro = get2(); + break; + case 0x1021: + imFuji.FocusMode = imgdata.shootinginfo.FocusMode = get2(); + break; + case 0x1022: + imFuji.AFMode = get2(); + break; + case 0x1023: + imFuji.FocusPixel[0] = get2(); + imFuji.FocusPixel[1] = get2(); + break; + case 0x1034: + imFuji.ExrMode = get2(); + break; + case 0x104d: + FujiCropMode = get2(); // odd: one of raw dimensions here can be lost + break; + case 0x1050: + imFuji.ShutterType = get2(); + break; + case 0x1103: + imgdata.shootinginfo.DriveMode = get2(); + imFuji.DriveMode = imgdata.shootinginfo.DriveMode & 0xff; + break; + + case 0x1400: + imFuji.DynamicRange = get2(); + break; + case 0x1401: + imFuji.FilmMode = get2(); + break; + case 0x1402: + imFuji.DynamicRangeSetting = get2(); + break; + case 0x1403: + imFuji.DevelopmentDynamicRange = get2(); + break; + case 0x140b: + imFuji.AutoDynamicRange = get2(); + break; + case 0x1443: + imFuji.DRangePriority = get2(); + break; + case 0x1444: + imFuji.DRangePriorityAuto = get2(); + break; + case 0x1445: + imFuji.DRangePriorityFixed = get2(); + break; + + case 0x1404: + ilm.MinFocal = getreal(type); + break; + case 0x1405: + ilm.MaxFocal = getreal(type); + break; + case 0x1406: + ilm.MaxAp4MinFocal = getreal(type); + break; + case 0x1407: + ilm.MaxAp4MaxFocal = getreal(type); + break; + case 0x1422: + imFuji.ImageStabilization[0] = get2(); + imFuji.ImageStabilization[1] = get2(); + imFuji.ImageStabilization[2] = get2(); + imgdata.shootinginfo.ImageStabilization = + (imFuji.ImageStabilization[0] << 9) + imFuji.ImageStabilization[1]; + break; + case 0x1431: + imFuji.Rating = get4(); + break; + case 0x3820: + imFuji.FrameRate = get2(); + break; + case 0x3821: + imFuji.FrameWidth = get2(); + break; + case 0x3822: + imFuji.FrameHeight = get2(); + break; + } + return; +} + +void LibRaw::parse_fuji(int offset) +{ + unsigned entries, tag, len, save, c; + ushort raw_inset_present = 0; + ushort use_WBcorr_coeffs = 0; + double wbR_corr = 1.0; + double wbB_corr = 1.0; + + fseek(ifp, offset, SEEK_SET); + entries = get4(); + if (entries > 255) + return; + imgdata.process_warnings |= LIBRAW_WARN_PARSEFUJI_PROCESSED; + + if (strstr(model, "S7000") || + strstr(model, "S5000") || + strstr(model, "F700") || + strstr(model, "S2Pro") || + strstr(model, "S20Pro")) { + use_WBcorr_coeffs = 1; + wbR_corr = 10.0 / 17.0 / 0.652941; + wbB_corr = 2.0 /3.0 / (3.0 / 4.0 + 1.0 / 300.0); + } + + while (entries--) + { + tag = get2(); + len = get2(); + save = ftell(ifp); + + if (tag == 0x0100) // RawImageFullSize + { + raw_height = get2(); + raw_width = get2(); + raw_inset_present = 1; + } + else if (tag == 0x0121) // RawImageSize + { + height = get2(); + if ((width = get2()) == 4284) + width += 3; + } + else if (tag == 0x0130) // FujiLayout + { + fuji_layout = fgetc(ifp) >> 7; + fuji_width = !(fgetc(ifp) & 8); + } + else if (tag == 0x0131) // XTransLayout + { + filters = 9; + char *xtrans_abs_alias = &xtrans_abs[0][0]; + FORC(36) + { + int q = fgetc(ifp); + xtrans_abs_alias[35 - c] = MAX(0, MIN(q, 2)); /* & 3;*/ + } + } + else if (tag == 0x2ff0) // WB_GRGBLevels + { + FORC4 cam_mul[GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + cam_mul[0] *= wbR_corr; + cam_mul[2] *= wbB_corr; + } + } + + else if ((tag == 0x0110) && raw_inset_present) // RawImageCropTopLeft + { + imgdata.sizes.raw_inset_crop.ctop = get2(); + imgdata.sizes.raw_inset_crop.cleft = get2(); + } + else if ((tag == 0x0111) && raw_inset_present) // RawImageCroppedSize + { + imgdata.sizes.raw_inset_crop.cheight = get2(); + imgdata.sizes.raw_inset_crop.cwidth = get2(); + } + else if ((tag == 0x0115) && raw_inset_present) // RawImageAspectRatio + { + int a = get2(); + int b = get2(); + if (a * b == 6) + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_3to2; + else if (a * b == 12) + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_4to3; + else if (a * b == 144) + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_16to9; + else if (a * b == 1) + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_1to1; + } + else if (tag == 0x9200) // RelativeExposure + { + int a = get4(); + if ((a == 0x01000100) || (a <= 0)) + imFuji.BrightnessCompensation = 0.0f; + else if (a == 0x00100100) + imFuji.BrightnessCompensation = 4.0f; + else + imFuji.BrightnessCompensation = + 24.0f - float(log((double)a) / log(2.0)); + } + else if (tag == 0x9650) // RawExposureBias + { + short a = (short)get2(); + float b = fMAX(1.0f, get2()); + imFuji.ExpoMidPointShift = a / b; + } + else if (tag == 0x2f00) // WB_GRGBLevels + { + int nWBs = get4(); + nWBs = MIN(nWBs, 6); + for (int wb_ind = 0; wb_ind < nWBs; wb_ind++) + { + FORC4 icWBC[LIBRAW_WBI_Custom1 + wb_ind][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Custom1 + wb_ind][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Custom1 + wb_ind][2] *= wbB_corr; + } + fseek(ifp, 8, SEEK_CUR); + } + } + else if (tag == 0x2000) // WB_GRGBLevelsAuto + { + FORC4 icWBC[LIBRAW_WBI_Auto][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Auto][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Auto][2] *= wbB_corr; + } + } + else if (tag == 0x2100) // WB_GRGBLevelsDaylight + { + FORC4 icWBC[LIBRAW_WBI_FineWeather][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FineWeather][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FineWeather][2] *= wbB_corr; + } + } + else if (tag == 0x2200) // WB_GRGBLevelsCloudy + { + FORC4 icWBC[LIBRAW_WBI_Shade][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Shade][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Shade][2] *= wbB_corr; + } + } + else if (tag == 0x2300) // WB_GRGBLevelsDaylightFluor + { + FORC4 icWBC[LIBRAW_WBI_FL_D][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_D][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_D][2] *= wbB_corr; + } + } + else if (tag == 0x2301) // WB_GRGBLevelsDayWhiteFluor + { + FORC4 icWBC[LIBRAW_WBI_FL_N][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_N][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_N][2] *= wbB_corr; + } + } + else if (tag == 0x2302) // WB_GRGBLevelsWhiteFluorescent + { + FORC4 icWBC[LIBRAW_WBI_FL_WW][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_WW][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_WW][2] *= wbB_corr; + } + } + else if (tag == 0x2310) // WB_GRGBLevelsWarmWhiteFluor + { + FORC4 icWBC[LIBRAW_WBI_FL_L][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_L][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_L][2] *= wbB_corr; + } + } + else if (tag == 0x2311) // WB_GRGBLevelsLivingRoomWarmWhiteFluor + { + FORC4 icWBC[LIBRAW_WBI_FL_W][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_FL_W][0] *= wbR_corr; + icWBC[LIBRAW_WBI_FL_W][2] *= wbB_corr; + } + } + else if (tag == 0x2400) // WB_GRGBLevelsTungsten + { + FORC4 icWBC[LIBRAW_WBI_Tungsten][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Tungsten][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Tungsten][2] *= wbB_corr; + } + } + else if (tag == 0x2410) + { + FORC4 icWBC[LIBRAW_WBI_Flash][GRGB_2_RGBG(c)] = get2(); + if (use_WBcorr_coeffs) { + icWBC[LIBRAW_WBI_Flash][0] *= wbR_corr; + icWBC[LIBRAW_WBI_Flash][2] *= wbB_corr; + } + } + + else if (tag == 0xc000) // RAFData + { + c = order; + order = 0x4949; + if (len > 20000) + { + tag = get4(); + if (tag > 10000) + { + imFuji.RAFDataVersion = tag >> 16; + if (!imFuji.RAFDataVersion) + imFuji.RAFDataVersion = tag; + tag = get4(); + } + if (tag > 10000) + { // if it is >1000 it normally contains 0x53545257, "WRTS" + tag = get4(); + } + width = tag; + height = get4(); + if (width > raw_width) + width = raw_width; + if (height > raw_height) + height = raw_height; + } + if (len == 4096) // X-A3, X-A5, X-A7, X-A10, X-A20, X-T100, X-T200, XF10 + { // Ill.A aligned to CCT 2850 + int wb[4]; + int nWB, tWB, pWB; + int iCCT = 0; + is_4K_RAFdata = 1; + fseek(ifp, save + 0x200, SEEK_SET); + for (int wb_ind = 0; wb_ind < 42; wb_ind++) + { + nWB = get4(); + tWB = get4(); + wb[0] = get4() << 1; + wb[1] = get4(); + wb[3] = get4(); + wb[2] = get4() << 1; + if (tWB && (iCCT < 255)) + { + icWBCCTC[iCCT][0] = tWB; + FORC4 icWBCCTC[iCCT][c + 1] = wb[c]; + iCCT++; + } + if (nWB != 70) + { + for (pWB = 1; pWB < Fuji_wb_list2.size(); pWB += 2) + { + if (Fuji_wb_list2[pWB] == nWB) + { + FORC4 icWBC[Fuji_wb_list2[pWB - 1]][c] = + wb[c]; + break; + } + } + } + } + } + else + { + libraw_internal_data.unpacker_data.posRAFData = save; + libraw_internal_data.unpacker_data.lenRAFData = (len >> 1); + } + order = c; + } + fseek(ifp, save + len, SEEK_SET); + } + height <<= fuji_layout; + width >>= fuji_layout; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/hasselblad_model.cpp libkdcraw/libkdcraw/libraw/src/metadata/hasselblad_model.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/hasselblad_model.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/hasselblad_model.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,487 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + + static const struct { + const int idx; + const char *FormatName; + } HassyRawFormat[] = { + { LIBRAW_HF_Unknown, "Unknown"}, + { LIBRAW_HF_3FR, "-3FR"}, + { LIBRAW_HF_FFF, "-FFF"}, + { LIBRAW_HF_Imacon, "Imacon"}, + { LIBRAW_HF_HasselbladDNG, "hDNG"}, + { LIBRAW_HF_AdobeDNG, "aDNG"}, + { LIBRAW_HF_AdobeDNG_fromPhocusDNG, "a(hDNG)"}, + }; + +const char* LibRaw::HassyRawFormat_idx2HR(unsigned idx) // HR means "human-readable" +{ + for (int i = 0; i < int(sizeof HassyRawFormat / sizeof *HassyRawFormat); i++) + if((unsigned)HassyRawFormat[i].idx == idx) + return HassyRawFormat[i].FormatName; + return 0; +} + +void LibRaw::process_Hassy_Lens (int LensMount) { +// long long unsigned id = +// mount*100000000ULL + series*10000000ULL + +// focal1*10000ULL + focal2*10 + version; + char *ps; + int c = atoi(strchr(imgdata.lens.Lens, ' ') +1); + if (!c) + return; + + if (LensMount == LIBRAW_MOUNT_Hasselblad_H) { + if (imgdata.lens.Lens[2] == ' ') // HC lens + ilm.LensID = LensMount*100000000ULL + 10000000ULL; + else // HCD lens + ilm.LensID = LensMount*100000000ULL + 20000000ULL; + ilm.LensFormat = LIBRAW_FORMAT_645; + } else if (LensMount == LIBRAW_MOUNT_Hasselblad_XCD) { + ilm.LensFormat = LIBRAW_FORMAT_CROP645; + ilm.LensID = LensMount*100000000ULL; + } else + return; + + ilm.LensMount = LensMount; + ilm.LensID += c*10000ULL; + if ((ps=strchr(imgdata.lens.Lens, '-'))) { + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + ilm.LensID += atoi(ps+1)*10ULL; + } else { + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + ilm.LensID += c*10ULL; + } + if (strstr(imgdata.lens.Lens, "III")) + ilm.LensID += 3ULL; + else if (strstr(imgdata.lens.Lens, "II")) + ilm.LensID += 2ULL; +} + +void LibRaw::parseHassyModel() { + +static const char *Hasselblad_Ctrl[] = { // manually selectable options only + "ELD", "ELX", "Winder CW", "CW", "Pinhole", "Flash Sync", + "SWC", "200 (Mod)", "200", "500 Mech.", "500", "H Series", + "H-Series", "H1", "H2", "Black Box", "LENSCONTROL S", "LENSCTRL S", "Generic", +}; + +static const char *Hasselblad_SensorEnclosures[] = { + "CFH", "CFV", "CFV", "CFII", "CF", "Ixpress", +}; + + char tmp_model[64]; + const char *ps; + int c; + int nPix = raw_width*raw_height; + int add_MP_toName = 1; + int norm_model_isSet = 0; + + if (model[0] == ' ') + memmove(model, model+1, MIN(sizeof(model)-1,strlen(model))); + + if (!imHassy.format) { + if (dng_version) { + if (!strncmp(software, "Adobe", 5)) { + if (!imgdata.color.OriginalRawFileName[0] || + !imgdata.color.LocalizedCameraModel[0] || + !strcasestr(imgdata.color.UniqueCameraModel, "coated")) + imHassy.format = LIBRAW_HF_AdobeDNG_fromPhocusDNG; + else + imHassy.format = LIBRAW_HF_AdobeDNG; + } else imHassy.format = LIBRAW_HF_HasselbladDNG; + } else if ((imHassy.nIFD_CM[0] != -1) && + (imHassy.nIFD_CM[1] == -1) && + !imHassy.mnColorMatrix[0][0]) { + imHassy.format = LIBRAW_HF_3FR; + } else imHassy.format = LIBRAW_HF_FFF; + } + + if (!strncmp(imHassy.SensorUnitConnector, "Hasselblad ", 11)) + memmove(imHassy.SensorUnitConnector, imHassy.SensorUnitConnector+11, 64-11); + + if (imHassy.format == LIBRAW_HF_AdobeDNG) { // Adobe DNG, use LocalizedCameraModel + imgdata.color.LocalizedCameraModel[63] = 0; // make sure 0-termination + if ((ps = strrchr(imgdata.color.LocalizedCameraModel, '-'))) + c = ps-imgdata.color.LocalizedCameraModel; + else c = strlen(imgdata.color.LocalizedCameraModel); + int cc = MIN(c, sizeof(tmp_model)-1); + memcpy(tmp_model, imgdata.color.LocalizedCameraModel,cc); + tmp_model[cc] = 0; + if (strcasestr(imgdata.color.UniqueCameraModel, "coated")) { + strncpy(normalized_model, imgdata.color.UniqueCameraModel,sizeof(imgdata.color.UniqueCameraModel)-1); + normalized_model[sizeof(imgdata.color.UniqueCameraModel) - 1] = 0; + norm_model_isSet = 1; + } + if (!strncmp(normalized_model, "Hasselblad ", 11)) + memmove(normalized_model, normalized_model+11, 64-11); + } + else + { + strncpy(tmp_model, imgdata.color.UniqueCameraModel, sizeof(imgdata.color.UniqueCameraModel) - 1); + tmp_model[63] = 0; + } + if (!strncasecmp(tmp_model, "Hasselblad ", 11)) + memmove(tmp_model, tmp_model+11, 64-11); + +// check if model tag contains manual CaptureSequenceInitiator info: + strncpy(imHassy.CaptureSequenceInitiator, model,31); + imHassy.CaptureSequenceInitiator[31] = 0; + FORC(int(sizeof Hasselblad_Ctrl / sizeof *Hasselblad_Ctrl)) { + if (strcasestr(model, Hasselblad_Ctrl[c])) { +// yes, fill 'model' with sensor unit data + strncpy(model, tmp_model,63); + model[63] = 0; + break; + } + } + + ps = strchr(model, '-'); + if (ps) { // check if model contains both host body and sensor version, resolution, MS info + strncpy(imHassy.SensorUnit, model,63); + memcpy(imHassy.HostBody, model, ps-model); + imHassy.HostBody[ps-model] = 0; + if (!strncmp(ps-2, "II-", 3)) + ps -=2; + strncpy(imHassy.Sensor, ps,7); + imHassy.Sensor[7] = 0; + add_MP_toName = 0; + } else { // model contains host body only + strncpy(imHassy.HostBody, model,63); + imHassy.HostBody[63] = 0; +// fill 'model' with sensor unit data + strncpy(model, tmp_model,63); + model[63] = 0; + } + + if (!strncmp(model, "503CWD", 6)) { + strncpy(imHassy.HostBody, model,63); + imHassy.HostBody[63] = 0; + ilm.CameraFormat = LIBRAW_FORMAT_66; + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_V; + if (model[6] == 'I' && model[7] == 'I') + strcpy(model, "CFVII"); + else strcpy(model, "CFV"); + } else if (strstr(model, "Hasselblad") && + (model[10] != ' ')) { + strcpy(model, "CFV"); + ilm.CameraMount = LIBRAW_MOUNT_DigitalBack; + } else { + FORC(int(sizeof Hasselblad_SensorEnclosures / sizeof *Hasselblad_SensorEnclosures)) { + if (strcasestr(model, Hasselblad_SensorEnclosures[c])) { + if (add_MP_toName) strcpy(model, Hasselblad_SensorEnclosures[c]); + ilm.CameraMount = LIBRAW_MOUNT_DigitalBack; + break; + } + } + } + +#define cpynorm(str) \ + if (!norm_model_isSet) { \ + strcpy(normalized_model, str); \ + norm_model_isSet = 1; \ + } + + if ((imHassy.SensorCode == 4) && + (imHassy.CoatingCode < 2)) { + strcpy(imHassy.Sensor, "-16"); + cpynorm("16-Uncoated"); + + } else if ((imHassy.SensorCode == 6) && + (imHassy.CoatingCode < 2)) { + strcpy(imHassy.Sensor, "-22"); + cpynorm("22-Uncoated"); + + } else if ((imHassy.SensorCode == 8) && + (imHassy.CoatingCode == 1)) { + strcpy(imHassy.Sensor, "-31"); + cpynorm("31-Uncoated"); + + } else if ((imHassy.SensorCode == 9) && + (imHassy.CoatingCode < 2)) { + strcpy(imHassy.Sensor, "-39"); + cpynorm("39-Uncoated"); + + } else if ((imHassy.SensorCode == 9) && + (imHassy.CoatingCode == 4)) { + strcpy(imHassy.Sensor, "-39"); + strcpy(model, "H3DII"); + add_MP_toName = 1; + cpynorm("39-Coated"); + + } else if ((imHassy.SensorCode == 13) && + (imHassy.CoatingCode == 4)) { + strcpy(imHassy.Sensor, "-40"); + cpynorm("40-Coated"); + + } else if ((imHassy.SensorCode == 13) && + (imHassy.CoatingCode == 5)) { + strcpy(imHassy.Sensor, "-40"); + cpynorm("40-Coated5"); + + } else if ((imHassy.SensorCode == 11) && + (imHassy.CoatingCode == 4)) { + if (!strncmp(model, "H3D", 3)) + strcpy(model, "H3DII-50"); + else strcpy(imHassy.Sensor, "-50"); + cpynorm("50-Coated"); + + } else if ((imHassy.SensorCode == 11) && + (imHassy.CoatingCode == 5)) { + strcpy(imHassy.Sensor, "-50"); + cpynorm("50-Coated5"); + + } else if ((imHassy.SensorCode == 15) && + (imHassy.CoatingCode == 5)) { + strcpy(imHassy.Sensor, "-50c"); + cpynorm("50-15-Coated5"); + if (!strncmp(imHassy.CaptureSequenceInitiator, "X1D", 3)) { + imHassy.SensorSubCode = 2; + add_MP_toName = 0; + strcat(imHassy.Sensor, " II"); + if (!strncasecmp(imHassy.CaptureSequenceInitiator, "X1D II 50C", 10)) { + strcpy(model, "X1D II 50C"); + strcat(normalized_model, "-II"); + } else { + strcpy(model, "X1D-50c"); + } + } + + } else if ((imHassy.SensorCode == 12) && + (imHassy.CoatingCode == 4)) { + strcpy(imHassy.Sensor, "-60"); + cpynorm("60-Coated"); + + } else if ((imHassy.SensorCode == 17) && + (imHassy.CoatingCode == 5)) { + strcpy(imHassy.Sensor, "-100c"); + cpynorm("100-17-Coated5"); + + } else if ((raw_width == 4090) || // V96C + ((raw_width == 4096) && (raw_height == 4096)) || + ((raw_width == 4088) && (raw_height == 4088)) || // Adobe crop + ((raw_width == 4080) && (raw_height == 4080))) { // Phocus crop + strcpy(imHassy.Sensor, "-16"); + cpynorm("16-Uncoated"); + if (!imHassy.SensorCode) imHassy.SensorCode = 4; + + } else if ((raw_width == 5568) && (raw_height == 3648)) { + strcpy(imHassy.Sensor, "-20c"); + + } else if (((raw_width == 4096) && (raw_height == 5456)) || + ((raw_width == 4088) && (raw_height == 5448)) || // Adobe crop + ((raw_width == 4080) && (raw_height == 5440))) { // Phocus crop + strcpy(imHassy.Sensor, "-22"); + cpynorm("22-Uncoated"); + if (!imHassy.SensorCode) imHassy.SensorCode = 6; + + } else if (((raw_width == 6542) && (raw_height == 4916)) || + ((raw_width == 6504) && (raw_height == 4880)) || // Adobe crop + ((raw_width == 6496) && (raw_height == 4872))) { // Phocus crop + strcpy(imHassy.Sensor, "-31"); + cpynorm("31-Uncoated"); + if (!imHassy.SensorCode) imHassy.SensorCode = 8; + + } else if (((raw_width == 7262) && (raw_height == 5456)) || // + ((raw_width == 7224) && (raw_height == 5420)) || // Adobe crop + ((raw_width == 7216) && (raw_height == 5412)) || // Phocus crop + ((raw_width == 7212) && (raw_height == 5412)) || // CF-39, CFV-39, possibly v.II; Phocus crop +// uncropped, when the exact size is unknown, should be: +// - greater or equal to the smallest Phocus crop for the current size +// - smaller than the smallest Phocus crop for the next size + ((nPix >= 7212*5412) && (nPix < 7304*5478))) { + strcpy(imHassy.Sensor, "-39"); + if (!imHassy.SensorCode) imHassy.SensorCode = 9; + if (!strncmp(model, "H3D", 3)) { + if (((imHassy.format == LIBRAW_HF_Imacon) || + strstr(imgdata.color.UniqueCameraModel, "H3D-39") || + strstr(imgdata.color.LocalizedCameraModel, "H3D-39") || + strstr(model, "H3D-39")) && + !strstr(imgdata.color.UniqueCameraModel, "II") && + !strstr(imgdata.color.LocalizedCameraModel, "II") && + !strstr(model, "II")) { + strcpy(model, "H3D-39"); + add_MP_toName = 0; + cpynorm("39-Uncoated"); + + } else { + strcpy(model, "H3DII-39"); + add_MP_toName = 0; + cpynorm("39-Coated"); + if (!imHassy.CoatingCode) imHassy.CoatingCode = 4; + } + + } else + cpynorm("39-Uncoated"); + + } else if (((raw_width == 7410) && (raw_height == 5586)) || // (H4D-40, H5D-40) + ((raw_width == 7312) && (raw_height == 5486)) || // Adobe crop + ((raw_width == 7304) && (raw_height == 5478))) { // Phocus crop + strcpy(imHassy.Sensor, "-40"); + if (!strncmp(model, "H4D", 3)) { + cpynorm("40-Coated"); + if (!imHassy.SensorCode) imHassy.SensorCode = 13; + if (!imHassy.CoatingCode) imHassy.CoatingCode = 4; + } else { + cpynorm("40-Coated5"); + if (!imHassy.SensorCode) imHassy.SensorCode = 13; + if (!imHassy.CoatingCode) imHassy.CoatingCode = 5; + } + + } else if (((raw_width == 8282) && (raw_height == 6240)) || // (CFV-50, H3DII-50, H5D-50) + ((raw_width == 8184) && (raw_height == 6140)) || // Adobe crop + ((raw_width == 8176) && (raw_height == 6132))) { // Phocus crop + strcpy(imHassy.Sensor, "-50"); + if (!strncmp(model, "H5D", 3)) { + cpynorm("50-Coated5"); + if (!imHassy.SensorCode) imHassy.SensorCode = 11; + if (!imHassy.CoatingCode) imHassy.CoatingCode = 5; + } else { + cpynorm("50-Coated"); // CFV-50, H3DII-50, + if (!strncmp(model, "H3D", 3)) { + strcpy(model, "H3DII-50"); + if (!imHassy.SensorCode) imHassy.SensorCode = 11; + if (!imHassy.CoatingCode) imHassy.CoatingCode = 4; + add_MP_toName = 0; + } + } + + } else if (((raw_width == 8374) && (raw_height == 6304)) || // (H5D-50c) + ((raw_width == 8384) && (raw_height == 6304)) || // (X1D-50c, "X1D II 50C") + ((raw_width == 8280) && (raw_height == 6208)) || // Adobe crop + ((raw_width == 8272) && (raw_height == 6200))) { // Phocus crop + cpynorm("50-15-Coated5"); + if (!imHassy.SensorCode) imHassy.SensorCode = 15; + if (!imHassy.CoatingCode) imHassy.CoatingCode = 5; + strcpy(imHassy.Sensor, "-50c"); + if ((raw_width == 8384) || !strncmp(imHassy.CaptureSequenceInitiator, "X1D", 3)) { + imHassy.SensorSubCode = 2; + add_MP_toName = 0; + strcat(imHassy.Sensor, " II"); + if (!strncasecmp(imHassy.CaptureSequenceInitiator, "X1D II 50C", 10)) { + strcpy(model, "X1D II 50C"); + strcat(normalized_model, "-II"); + } else { + strcpy(model, "X1D-50c"); + } + } + + } else if (((raw_width == 9044) && (raw_height == 6732)) || + ((raw_width == 8964) && (raw_height == 6716)) || // Adobe crop + ((raw_width == 8956) && (raw_height == 6708))) { // Phocus crop + strcpy(imHassy.Sensor, "-60"); + cpynorm("60-Coated"); + if (!imHassy.SensorCode) imHassy.SensorCode = 12; + if (!imHassy.CoatingCode) imHassy.CoatingCode = 4; + + + } else if (((raw_width == 10320) && (raw_height == 7752)) || // Phocus crop, A5D-80 + ((nPix >= 10320*7752) && (nPix < 10520*8000))) { + strcpy(imHassy.Sensor, "-80"); + cpynorm("80-Coated"); + + } else if (((raw_width == 12000) && (raw_height == 8816)) || + ((raw_width == 11608) && (raw_height == 8708)) || // Adobe crop + ((raw_width == 11600) && (raw_height == 8700))) { // Phocus crop + strcpy(imHassy.Sensor, "-100c"); + cpynorm("100-17-Coated5"); + if (!imHassy.SensorCode) imHassy.SensorCode = 17; + if (!imHassy.CoatingCode) imHassy.CoatingCode = 5; + + } + + if (raw_width == 4090) + strcpy(model, "V96C"); + + if ( + (raw_width == 4090) || + ((raw_width == 4096) && (raw_height == 4096)) || + ((raw_width == 5568) && (raw_height == 3648)) || + ((raw_width == 4096) && (raw_height == 5456)) || + ((raw_width == 6542) && (raw_height == 4916)) || + ((raw_width == 7262) && (raw_height == 5456)) || + ((raw_width == 7410) && (raw_height == 5586)) || + ((raw_width == 8282) && (raw_height == 6240)) || + ((raw_width == 8374) && (raw_height == 6304)) || + ((raw_width == 8384) && (raw_height == 6304)) || + ((raw_width == 9044) && (raw_height == 6732)) || + ((raw_width == 10320) && (raw_height == 7752)) || + ((raw_width == 12000) && (raw_height == 8816)) + ) + imHassy.uncropped = 1; + + + if (model[0] && add_MP_toName) + strcat(model, imHassy.Sensor); + if (imHassy.Sensor[0] == '-') + memmove(imHassy.Sensor, imHassy.Sensor+1, strlen(imHassy.Sensor)); + + if (dng_version && + (imHassy.SensorCode == 13) && + (imHassy.CoatingCode == 4)) { + c = LIBRAW_HF_AdobeDNG; + } else if ((imHassy.format == LIBRAW_HF_HasselbladDNG) || + (imHassy.format == LIBRAW_HF_AdobeDNG_fromPhocusDNG)) { + c = LIBRAW_HF_FFF; + } else if (imHassy.format == LIBRAW_HF_Imacon) { + c = LIBRAW_HF_3FR; + } else { + c = imHassy.format; + } + ps = HassyRawFormat_idx2HR(c); + if ((c == LIBRAW_HF_3FR) || + (c == LIBRAW_HF_FFF)) + strcat(normalized_model, ps); + + if (((imHassy.CaptureSequenceInitiator[0] == 'H') && + (imHassy.CaptureSequenceInitiator[1] != 'a')) || + ((imHassy.CaptureSequenceInitiator[0] == 'A') && + isdigit(imHassy.CaptureSequenceInitiator[1]))) { + ilm.CameraFormat = LIBRAW_FORMAT_645; + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_H; + if (imgdata.lens.Lens[0] == 'H') + process_Hassy_Lens(LIBRAW_MOUNT_Hasselblad_H); + } else if ((imHassy.CaptureSequenceInitiator[0] == 'X') && + isdigit(imHassy.CaptureSequenceInitiator[1])) { + ilm.CameraFormat = LIBRAW_FORMAT_CROP645; + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_XCD; + if (imgdata.lens.Lens[0] == 'H') { + process_Hassy_Lens(LIBRAW_MOUNT_Hasselblad_H); + strcpy(ilm.Adapter, "XH"); + } else { + if (imgdata.lens.Lens[0] == 'X') { + process_Hassy_Lens(LIBRAW_MOUNT_Hasselblad_XCD); + } else if (!imgdata.lens.Lens[0] && + (aperture > 1.0f) && + (focal_len > 10.0f)) { + ilm.LensID = focal_len; + if (ilm.LensID == 35) { + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + ilm.LensID = LIBRAW_MOUNT_Hasselblad_XCD*100000000ULL + + 35*10000ULL + 75*10; + } + else + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + ilm.LensID = LIBRAW_MOUNT_Hasselblad_XCD*100000000ULL + + ilm.LensID*10000ULL + ilm.LensID*10; + } + } + } + if (normalized_model[0] && !CM_found) + CM_found = adobe_coeff(maker_index, normalized_model); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/identify.cpp libkdcraw/libkdcraw/libraw/src/metadata/identify.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/identify.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/identify.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,2941 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +// clang-format on +static const struct +{ + const int CorpId; + const char *CorpName; +} CorpTable[] = { + {LIBRAW_CAMERAMAKER_Agfa, "AgfaPhoto"}, + {LIBRAW_CAMERAMAKER_Apple, "Apple"}, + {LIBRAW_CAMERAMAKER_Broadcom, "Broadcom"}, + {LIBRAW_CAMERAMAKER_Canon, "Canon"}, + {LIBRAW_CAMERAMAKER_Casio, "Casio"}, + {LIBRAW_CAMERAMAKER_CINE, "CINE"}, + {LIBRAW_CAMERAMAKER_Epson, "Epson"}, + {LIBRAW_CAMERAMAKER_Fujifilm, "Fujifilm"}, + {LIBRAW_CAMERAMAKER_Mamiya, "Mamiya"}, + {LIBRAW_CAMERAMAKER_Motorola, "Motorola"}, + {LIBRAW_CAMERAMAKER_Kodak, "Kodak"}, + {LIBRAW_CAMERAMAKER_Konica, "Konica"}, + {LIBRAW_CAMERAMAKER_Minolta, "Minolta"}, + {LIBRAW_CAMERAMAKER_Leica, "Leica"}, + {LIBRAW_CAMERAMAKER_Nikon, "Nikon"}, + {LIBRAW_CAMERAMAKER_Nokia, "Nokia"}, + {LIBRAW_CAMERAMAKER_Olympus, "Olympus"}, + {LIBRAW_CAMERAMAKER_Ricoh, "Ricoh"}, + {LIBRAW_CAMERAMAKER_Pentax, "Pentax"}, + {LIBRAW_CAMERAMAKER_PhaseOne, "Phase One"}, + {LIBRAW_CAMERAMAKER_PhaseOne, "PhaseOne"}, + {LIBRAW_CAMERAMAKER_Samsung, "Samsung"}, + {LIBRAW_CAMERAMAKER_Sigma, "Sigma"}, + {LIBRAW_CAMERAMAKER_Sinar, "Sinar"}, + {LIBRAW_CAMERAMAKER_Sony, "Sony"}, + {LIBRAW_CAMERAMAKER_YI, "YI"}, + // add corp. names below + {LIBRAW_CAMERAMAKER_Alcatel, "Alcatel"}, + {LIBRAW_CAMERAMAKER_Aptina, "Aptina"}, + {LIBRAW_CAMERAMAKER_AVT, "AVT"}, + {LIBRAW_CAMERAMAKER_Baumer, "Baumer"}, + {LIBRAW_CAMERAMAKER_Clauss, "Clauss"}, + {LIBRAW_CAMERAMAKER_Contax, "Contax"}, + {LIBRAW_CAMERAMAKER_Creative, "Creative"}, + {LIBRAW_CAMERAMAKER_DJI, "DJI"}, + {LIBRAW_CAMERAMAKER_Foculus, "Foculus"}, + {LIBRAW_CAMERAMAKER_Generic, "Generic"}, + {LIBRAW_CAMERAMAKER_Gione, "Gione"}, + {LIBRAW_CAMERAMAKER_GITUP, "GITUP"}, + {LIBRAW_CAMERAMAKER_Hasselblad, "Hasselblad"}, + {LIBRAW_CAMERAMAKER_HTC, "HTC"}, + {LIBRAW_CAMERAMAKER_I_Mobile, "I_Mobile"}, + {LIBRAW_CAMERAMAKER_Imacon, "Imacon"}, + {LIBRAW_CAMERAMAKER_JK_Imaging, "JK Imaging"}, // Kodak + {LIBRAW_CAMERAMAKER_Leaf, "Leaf"}, + {LIBRAW_CAMERAMAKER_Lenovo, "Lenovo"}, + {LIBRAW_CAMERAMAKER_LG, "LG"}, + {LIBRAW_CAMERAMAKER_Logitech, "Logitech"}, + {LIBRAW_CAMERAMAKER_Matrix, "Matrix"}, + {LIBRAW_CAMERAMAKER_Meizu, "Meizu"}, + {LIBRAW_CAMERAMAKER_Micron, "Micron"}, + {LIBRAW_CAMERAMAKER_NGM, "NGM"}, + {LIBRAW_CAMERAMAKER_OmniVison, "OmniVison"}, + {LIBRAW_CAMERAMAKER_Panasonic, "Panasonic"}, + {LIBRAW_CAMERAMAKER_Photron, "Photron"}, + {LIBRAW_CAMERAMAKER_Pixelink, "Pixelink"}, + {LIBRAW_CAMERAMAKER_Polaroid, "Polaroid"}, + {LIBRAW_CAMERAMAKER_Rollei, "Rollei"}, + {LIBRAW_CAMERAMAKER_RoverShot, "RoverShot"}, + {LIBRAW_CAMERAMAKER_SMaL, "SMaL"}, + {LIBRAW_CAMERAMAKER_ST_Micro, "ST Micro"}, + {LIBRAW_CAMERAMAKER_THL, "THL"}, + {LIBRAW_CAMERAMAKER_Xiaomi, "Xiaomi"}, + {LIBRAW_CAMERAMAKER_XIAOYI, "Xiayi"}, + {LIBRAW_CAMERAMAKER_Yuneec, "Yuneec"}, + {LIBRAW_CAMERAMAKER_DXO, "DxO"}, + {LIBRAW_CAMERAMAKER_RED, "Red"}, + {LIBRAW_CAMERAMAKER_PhotoControl, "Photo Control"}, + {LIBRAW_CAMERAMAKER_Google, "Google"}, + {LIBRAW_CAMERAMAKER_GoPro, "GoPro"}, + {LIBRAW_CAMERAMAKER_Parrot, "Parrot"}, + {LIBRAW_CAMERAMAKER_Zeiss, "Zeiss"} +}; +// clang-format on + +int LibRaw::setMakeFromIndex(unsigned makei) +{ + if (makei <= LIBRAW_CAMERAMAKER_Unknown || makei >= LIBRAW_CAMERAMAKER_TheLastOne) return 0; + + for (int i = 0; i < int(sizeof CorpTable / sizeof *CorpTable); i++) + if ((unsigned)CorpTable[i].CorpId == makei) + { + strcpy(normalized_make, CorpTable[i].CorpName); + maker_index = makei; + return 1; + } + return 0; +} + +const char *LibRaw::cameramakeridx2maker(unsigned maker) +{ + for (int i = 0; i < int(sizeof CorpTable / sizeof *CorpTable); i++) + if((unsigned)CorpTable[i].CorpId == maker) + return CorpTable[i].CorpName; + return 0; +} + + +void LibRaw::fixupArri() +{ + struct alist_t + { + const char *a_model; + const char *a_software; + ushort a_width,a_height; + int a_black; + unsigned a_filters; + float a_aspect; + } + alist[] = + { + {"ALEXA65", "Alexa65 XT", 6560 ,3100, 256,0x49494949,1.f}, + + {"ALEXALF", "Alexa LF Plus W", 3840 ,2160, 256,0x49494949,1.0f }, + {"ALEXALF", "Alexa LF Plus W", 4448 ,1856, 256,0x49494949,0.75f }, + {"ALEXALF", "Alexa LF Plus W", 4448 ,3096, 256,0x49494949,1.f }, + + {"ALEXA", "Alexa Plus 4:3 SXT", 2880 ,1620, 256,0x61616161,.75f}, + {"ALEXA", "Alexa Plus 4:3 SXT", 3168 ,1782, 256,0x61616161,0.75f}, + {"ALEXA", "Alexa Plus 4:3 SXT", 3424 ,2202, 256,0x61616161,1.f}, + {"ALEXA", "Alexa Plus 4:3 SXT", 2592 ,2160, 256,0x61616161,1.12f}, + + {"ALEXA", "Alexa Plus 4:3 XT", 2592 ,2160, 256,0x61616161,1.12f}, + {"ALEXA", "Alexa Plus 4:3 XT", 2880 ,2160, 256,0x61616161,1.f}, + {"ALEXA", "Alexa Plus 4:3 XT", 2880 ,1620, 256,0x61616161,0.75f}, + {"ALEXA", "Alexa Plus 4:3 XT", 3424 ,2202, 256,0x61616161,1.f}, + }; + for(int i = 0; i < int(sizeof(alist)/sizeof(alist[0])); i++) + if(!strncasecmp(model,alist[i].a_model,strlen(alist[i].a_model)) && software + && !strncasecmp(software,alist[i].a_software,strlen(alist[i].a_software)) + && width == alist[i].a_width && height == alist[i].a_height) + { + filters = alist[i].a_filters; + black = alist[i].a_black; + pixel_aspect = alist[i].a_aspect; + strcpy(model,software); + software[0]=0; + return; + } +} + +/* + Identify which camera created this file, and set global variables + accordingly. + */ +void LibRaw::identify() +{ + // clang-format off + static const ushort canon[][11] = { + // raw_width, raw_height, left_margin, top_margin, width_decrement, + // height_decrement, mask01, mask03, mask11, + // mask13, CFA_filters. + { 1944, 1416, 0, 0, 48, 0 }, // 00 "PowerShot Pro90 IS" + { 2144, 1560, 4, 8, 52, 2, 0, 0, 0, 25 }, // 01 "PowerShot S30", "PowerShot G1" + { 2224, 1456, 48, 6, 0, 2 }, // 02 "EOS D30" + { 2376, 1728, 12, 6, 52, 2 }, // 03 "PowerShot G2", "PowerShot S40", "PowerShot G3", "PowerShot S45" + { 2672, 1968, 12, 6, 44, 2 }, // 04 "PowerShot G5", "PowerShot S50", "PowerShot S60" + { 3152, 2068, 64, 12, 0, 0, 16 }, // 05 "EOS D60", "EOS 10D", "EOS 300D" + { 3160, 2344, 44, 12, 4, 4 }, // 06 "PowerShot G6", "PowerShot S70" + { 3344, 2484, 4, 6, 52, 6 }, // 07 "PowerShot Pro1" + { 3516, 2328, 42, 14, 0, 0 }, // 08 "EOS 350D" + { 3596, 2360, 74, 12, 0, 0 }, // 09 "EOS-1D Mark II", "EOS 20D", "EOS-1D Mark II N", "EOS 30D" + { 3744, 2784, 52, 12, 8, 12 }, // 10 "PowerShot G11", "PowerShot S90", "PowerShot G12", "PowerShot S95" + { 3944, 2622, 30, 18, 6, 2 }, // 11 "EOS 40D" + { 3948, 2622, 42, 18, 0, 2 }, // 12 "EOS 400D", "EOS 1000D" + { 3984, 2622, 76, 20, 0, 2, 14 }, // 13 "EOS-1D Mark III" + { 4032, 2656, 112, 44, 10, 0 }, // 14 APS-C crop mode: "EOS 6D Mark II"??, "EOS RP" + { 4104, 3048, 48, 12, 24, 12 }, // 15 "PowerShot G9" + { 4116, 2178, 4, 2, 0, 0 }, // 16 ?? + { 4152, 2772, 192, 12, 0, 0 }, // 17 "PowerShot SX1 IS" + { 4160, 3124, 104, 11, 8, 65 }, // 18 "PowerShot S100 (new)", "PowerShot S100V", "PowerShot G15", "PowerShot S110 (new)" + { 4176, 3062, 96, 17, 8, 0, 0, 16, 0, 7, 0x49 }, // 19 "PowerShot SX50 HS" + { 4192, 3062, 96, 17, 24, 0, 0, 16, 0, 0, 0x49 }, // 20 "PowerShot G16", "PowerShot S120" + { 4312, 2876, 22, 18, 0, 2 }, // 21 "EOS 450D" + { 4352, 2850, 144, 46, 0, 0 }, // 22 APS-C crop mode: "EOS R" + { 4352, 2874, 62, 18, 0, 0 }, // 23 "EOS 1100D" + { 4476, 2954, 90, 34, 0, 0 }, // 24 "EOS 5D" + { 4480, 3348, 12, 10, 36, 12, 0, 0, 0, 18, 0x49 }, // 25 "PowerShot G10" + { 4480, 3366, 80, 50, 0, 0 }, // 26 "PowerShot G1 X Mark II" + { 4496, 3366, 80, 50, 12, 0 }, // 27 "PowerShot G1 X" + { 4768, 3516, 96, 16, 0, 0, 0, 16 }, // 28 "PowerShot SX60 HS" + { 4832, 3204, 62, 26, 0, 0 }, // 29 "EOS 500D" + { 4832, 3228, 62, 51, 0, 0 }, // 30 "EOS 50D" + { 5108, 3349, 98, 13, 0, 0 }, // 31 "EOS-1Ds Mark II" + { 5120, 3318, 142, 45, 62, 0 }, // 32 "EOS-1D Mark IV" + { 5280, 3528, 72, 52, 0, 0 }, // 33 "EOS M10", "EOS 650D", "EOS 700D", "EOS M", "EOS 100D", "EOS M2" + { 5344, 3516, 142, 51, 0, 0 }, // 34 "EOS 550D", "EOS 600D", "EOS 60D", "EOS 1200D", "EOS 1300D", "EOS 3000D" + { 5344, 3584, 126, 100, 0, 2 }, // 35 "EOS-1D X", "EOS-1D C" + { 5344, 3950, 98, 18, 0, 0, 0, 24, 0, 0 }, // 36 "PowerShot SX70 HS" + { 5360, 3516, 158, 51, 0, 0 }, // 37 "EOS 7D" + { 5568, 3708, 72, 38, 0, 0 }, // 38; "EOS 7D Mark II", "EOS 6D", "EOS 70D", "EOS-1D X MARK II" + { 5632, 3710, 96, 17, 0, 0, 0, 16, 0, 0, 0x49 }, // 39 "PowerShot G7 X", "PowerShot G3 X", "PowerShot G9 X", "PowerShot G5 X", "PowerShot G7 X Mark II", "PowerShot G9 X Mark II" + { 5712, 3774, 62, 20, 10, 2 }, // 40 "EOS-1Ds Mark III" + { 5792, 3804, 158, 51, 0, 0 }, // 41 "EOS 5D Mark II" + { 5920, 3950, 122, 80, 2, 0 }, // 42 "EOS 5D Mark III" + { 6096, 4051, 76, 35, 0, 0 }, // 43 "EOS 1500D" + { 6096, 4056, 72, 34, 0, 0 }, // 44 "EOS M3", "EOS 760D", "EOS 750D" + { 6288, 4056, 264, 36, 0, 0 }, // 45 "EOS M5", "EOS M100", "EOS M6", "PowerShot G1 X Mark III", "EOS 80D", "EOS 800D", "EOS 77D", "EOS 200D", "EOS 250D", "EOS M50" + { 6384, 4224, 120, 44, 0, 0 }, // 46 "EOS 6D Mark II", "EOS RP" + { 6880, 4544, 136, 42, 0, 0 }, // 47 "EOS 5D Mark IV" + { 6888, 4546, 146, 48, 0, 0 }, // 48 "EOS R" + { 7128, 4732, 144, 72, 0, 0 }, // 49 "EOS M6 II", "EOS 90D" + { 8896, 5920, 160, 64, 0, 0 }, // 50 "EOS 5DS", "EOS 5DS R" + }; + + static const libraw_custom_camera_t const_table[] = { + { 786432, 1024, 768, 0, 0, 0, 0, 0, 0x94, 0, 0, "AVT", "F-080C" }, + { 1447680, 1392, 1040, 0, 0, 0, 0, 0, 0x94, 0, 0, "AVT", "F-145C" }, + { 1920000, 1600, 1200, 0, 0, 0, 0, 0, 0x94, 0, 0, "AVT", "F-201C" }, + { 5067304, 2588, 1958, 0, 0, 0, 0, 0, 0x94, 0, 0, "AVT", "F-510C" }, + { 5067316, 2588, 1958, 0, 0, 0, 0, 0, 0x94, 0, 0, "AVT", "F-510C", 12 }, + { 10134608, 2588, 1958, 0, 0, 0, 0, 9, 0x94, 0, 0, "AVT", "F-510C" }, + { 10134620, 2588, 1958, 0, 0, 0, 0, 9, 0x94, 0, 0, "AVT", "F-510C", 12 }, + { 16157136, 3272, 2469, 0, 0, 0, 0, 9, 0x94, 0, 0, "AVT", "F-810C" }, + { 15980544, 3264, 2448, 0, 0, 0, 0, 8, 0x61, 0, 1, "AgfaPhoto", "DC-833m" }, + { 9631728, 2532, 1902, 0, 0, 0, 0, 96, 0x61, 0, 0, "Alcatel", "5035D" }, + { 31850496, 4608, 3456, 0, 0, 0, 0, 0, 0x94, 0, 0, "GITUP", "GIT2 4:3" }, + { 23887872, 4608, 2592, 0, 0, 0, 0, 0, 0x94, 0, 0, "GITUP", "GIT2 16:9" }, + { 32257024, 4624, 3488, 8, 2, 16, 2, 0, 0x94, 0, 0, "GITUP", "GIT2P 4:3" }, + { 24192768, 4624, 2616, 8, 2, 16, 2, 0, 0x94, 0, 0, "GITUP", "GIT2P 16:9" }, + { 18016000, 4000, 2252, 0, 0, 0, 0, 0, 0x94, 0, 0, "GITUP", "G3DUO 16:9" }, + // {24000000, 4000, 3000, 0, 0, 0, 0, 0, 0x94, 0, 0, "GITUP", + // "G3DUO 4:3"}, // Conflict w/ Samsung WB550 + + // Android Raw dumps id start + // File Size in bytes Horizontal Res Vertical Flag then bayer order eg + // 0x16 bbgr 0x94 rggb + { 1540857, 2688, 1520, 0, 0, 0, 0, 1, 0x61, 0, 0, "Samsung", "S3" }, + { 2658304, 1212, 1096, 0, 0, 0, 0, 1, 0x16, 0, 0, "LG", "G3FrontMipi" }, + { 2842624, 1296, 1096, 0, 0, 0, 0, 1, 0x16, 0, 0, "LG", "G3FrontQCOM" }, + { 2969600, 1976, 1200, 0, 0, 0, 0, 1, 0x16, 0, 0, "Xiaomi", "MI3wMipi" }, + { 3170304, 1976, 1200, 0, 0, 0, 0, 1, 0x16, 0, 0, "Xiaomi", "MI3wQCOM" }, + { 3763584, 1584, 1184, 0, 0, 0, 0, 96, 0x61, 0, 0, "I_Mobile", "I_StyleQ6" }, + { 5107712, 2688, 1520, 0, 0, 0, 0, 1, 0x61, 0, 0, "OmniVisi", "UltraPixel1" }, + { 5382640, 2688, 1520, 0, 0, 0, 0, 1, 0x61, 0, 0, "OmniVisi", "UltraPixel2" }, + { 5664912, 2688, 1520, 0, 0, 0, 0, 1, 0x61, 0, 0, "OmniVisi", "4688" }, + { 5664912, 2688, 1520, 0, 0, 0, 0, 1, 0x61, 0, 0, "OmniVisi", "4688" }, + { 5364240, 2688, 1520, 0, 0, 0, 0, 1, 0x61, 0, 0, "OmniVisi", "4688" }, + { 6299648, 2592, 1944, 0, 0, 0, 0, 1, 0x16, 0, 0, "OmniVisi", "OV5648" }, + { 6721536, 2592, 1944, 0, 0, 0, 0, 0, 0x16, 0, 0, "OmniVisi", "OV56482" }, + { 6746112, 2592, 1944, 0, 0, 0, 0, 0, 0x16, 0, 0, "HTC", "OneSV" }, + { 9631728, 2532, 1902, 0, 0, 0, 0, 96, 0x61, 0, 0, "Sony", "5mp" }, + { 9830400, 2560, 1920, 0, 0, 0, 0, 96, 0x61, 0, 0, "NGM", "ForwardArt" }, + { 10186752, 3264, 2448, 0, 0, 0, 0, 1, 0x94, 0, 0, "Sony", "IMX219-mipi 8mp" }, + { 10223360, 2608, 1944, 0, 0, 0, 0, 96, 0x16, 0, 0, "Sony", "IMX" }, + { 10782464, 3282, 2448, 0, 0, 0, 0, 0, 0x16, 0, 0, "HTC", "MyTouch4GSlide" }, + { 10788864, 3282, 2448, 0, 0, 0, 0, 0, 0x16, 0, 0, "Xperia", "L" }, + { 15967488, 3264, 2446, 0, 0, 0, 0, 96, 0x16, 0, 0, "OmniVison", "OV8850" }, + { 16224256, 4208, 3082, 0, 0, 0, 0, 1, 0x16, 0, 0, "LG", "G3MipiL" }, + { 16424960, 4208, 3120, 0, 0, 0, 0, 1, 0x16, 0, 0, "IMX135", "MipiL" }, + { 17326080, 4164, 3120, 0, 0, 0, 0, 1, 0x16, 0, 0, "LG", "G3LQCom" }, + { 17522688, 4212, 3120, 0, 0, 0, 0, 0, 0x16, 0, 0, "Sony", "IMX135-QCOM" }, + { 19906560, 4608, 3456, 0, 0, 0, 0, 1, 0x16, 0, 0, "Gione", "E7mipi" }, + { 19976192, 5312, 2988, 0, 0, 0, 0, 1, 0x16, 0, 0, "LG", "G4" }, + { 20389888, 4632, 3480, 0, 0, 0, 0, 1, 0x16, 0, 0, "Xiaomi", "RedmiNote3Pro" }, + { 20500480, 4656, 3496, 0, 0, 0, 0, 1, 0x94, 0, 0, "Sony", "IMX298-mipi 16mp" }, + { 21233664, 4608, 3456, 0, 0, 0, 0, 1, 0x16, 0, 0, "Gione", "E7qcom" }, + { 26023936, 4192, 3104, 0, 0, 0, 0, 96, 0x94, 0, 0, "THL", "5000" }, + { 26257920, 4208, 3120, 0, 0, 0, 0, 96, 0x94, 0, 0, "Sony", "IMX214" }, + { 26357760, 4224, 3120, 0, 0, 0, 0, 96, 0x61, 0, 0, "OV", "13860" }, + { 41312256, 5248, 3936, 0, 0, 0, 0, 96, 0x61, 0, 0, "Meizu", "MX4" }, + { 42923008, 5344, 4016, 0, 0, 0, 0, 96, 0x61, 0, 0, "Sony", "IMX230" }, + // Android Raw dumps id end + { 20137344, 3664, 2748, 0, 0, 0, 0, 0x40, 0x49, 0, 0, "Aptina", "MT9J003", 0xffff }, + { 2868726, 1384, 1036, 0, 0, 0, 0, 64, 0x49, 0, 8, "Baumer", "TXG14", 1078 }, + { 5298000, 2400, 1766, 12, 12, 44, 2, 40, 0x94, 0, 2, "Canon", "PowerShot SD300" }, // chdk hack + { 6553440, 2664, 1968, 4, 4, 44, 4, 40, 0x94, 0, 2, "Canon", "PowerShot A460" }, // chdk hack + { 6573120, 2672, 1968, 12, 8, 44, 0, 40, 0x94, 0, 2, "Canon", "PowerShot A610" }, // chdk hack + { 6653280, 2672, 1992, 10, 6, 42, 2, 40, 0x94, 0, 2, "Canon", "PowerShot A530" }, // chdk hack + { 7710960, 2888, 2136, 44, 8, 4, 0, 40, 0x94, 0, 2, "Canon", "PowerShot S3 IS" }, // chdk hack + { 9219600, 3152, 2340, 36, 12, 4, 0, 40, 0x94, 0, 2, "Canon", "PowerShot A620" }, // chdk hack + { 9243240, 3152, 2346, 12, 7, 44, 13, 40, 0x49, 0, 2, "Canon", "PowerShot A470" }, // chdk hack + { 10341600, 3336, 2480, 6, 5, 32, 3, 40, 0x94, 0, 2, "Canon", "PowerShot A720 IS" }, // chdk hack + { 10383120, 3344, 2484, 12, 6, 44, 6, 40, 0x94, 0, 2, "Canon", "PowerShot A630" }, // chdk hack + { 12945240, 3736, 2772, 12, 6, 52, 6, 40, 0x94, 0, 2, "Canon", "PowerShot A640" }, // chdk hack + { 15636240, 4104, 3048, 48, 12, 24, 12, 40, 0x94, 0, 2, "Canon", "PowerShot A650" }, // chdk hack + { 15467760, 3720, 2772, 6, 12, 30, 0, 40, 0x94, 0, 2, "Canon", "PowerShot SX110 IS" }, // chdk hack + { 15534576, 3728, 2778, 12, 9, 44, 9, 40, 0x94, 0, 2, "Canon", "PowerShot SX120 IS" }, // chdk hack + { 18653760, 4080, 3048, 24, 12, 24, 12, 40, 0x94, 0, 2, "Canon", "PowerShot SX20 IS" }, // chdk hack + { 18763488, 4104, 3048, 10, 22, 82, 22, 8, 0x49, 0, 0, "Canon", "PowerShot D10" }, // ? chdk hack ? + { 19131120, 4168, 3060, 92, 16, 4, 1, 40, 0x94, 0, 2, "Canon", "PowerShot SX220 HS" }, // chdk hack + { 21936096, 4464, 3276, 25, 10, 73, 12, 40, 0x16, 0, 2, "Canon", "PowerShot SX30 IS" }, // chdk hack + { 24724224, 4704, 3504, 8, 16, 56, 8, 40, 0x49, 0, 2, "Canon", "PowerShot A3300 IS" }, // chdk hack + { 30858240, 5248, 3920, 8, 16, 56, 16, 40, 0x94, 0, 2, "Canon", "IXUS 160" }, // chdk hack + { 1976352, 1632, 1211, 0, 2, 0, 1, 0, 0x94, 0, 1, "Casio", "QV-2000UX" }, + { 3217760, 2080, 1547, 0, 0, 10, 1, 0, 0x94, 0, 1, "Casio", "QV-3*00EX" }, + { 6218368, 2585, 1924, 0, 0, 9, 0, 0, 0x94, 0, 1, "Casio", "QV-5700" }, + { 7816704, 2867, 2181, 0, 0, 34, 36, 0, 0x16, 0, 1, "Casio", "EX-Z60" }, + { 2937856, 1621, 1208, 0, 0, 1, 0, 0, 0x94, 7, 13, "Casio", "EX-S20" }, + { 4948608, 2090, 1578, 0, 0, 32, 34, 0, 0x94, 7, 1, "Casio", "EX-S100" }, + { 6054400, 2346, 1720, 2, 0, 32, 0, 0, 0x94, 7, 1, "Casio", "QV-R41" }, + { 7426656, 2568, 1928, 0, 0, 0, 0, 0, 0x94, 0, 1, "Casio", "EX-P505" }, + { 7530816, 2602, 1929, 0, 0, 22, 0, 0, 0x94, 7, 1, "Casio", "QV-R51" }, + { 7542528, 2602, 1932, 0, 0, 32, 0, 0, 0x94, 7, 1, "Casio", "EX-Z50" }, + { 7562048, 2602, 1937, 0, 0, 25, 0, 0, 0x16, 7, 1, "Casio", "EX-Z500" }, + { 7753344, 2602, 1986, 0, 0, 32, 26, 0, 0x94, 7, 1, "Casio", "EX-Z55" }, + { 9313536, 2858, 2172, 0, 0, 14, 30, 0, 0x94, 7, 1, "Casio", "EX-P600" }, + { 10834368, 3114, 2319, 0, 0, 27, 0, 0, 0x94, 0, 1, "Casio", "EX-Z750" }, + { 10843712, 3114, 2321, 0, 0, 25, 0, 0, 0x94, 0, 1, "Casio", "EX-Z75" }, + { 10979200, 3114, 2350, 0, 0, 32, 32, 0, 0x94, 7, 1, "Casio", "EX-P700" }, + { 12310144, 3285, 2498, 0, 0, 6, 30, 0, 0x94, 0, 1, "Casio", "EX-Z850" }, + { 12489984, 3328, 2502, 0, 0, 47, 35, 0, 0x94, 0, 1, "Casio", "EX-Z8" }, + { 15499264, 3754, 2752, 0, 0, 82, 0, 0, 0x94, 0, 1, "Casio", "EX-Z1050" }, + { 18702336, 4096, 3044, 0, 0, 24, 0, 80, 0x94, 7, 1, "Casio", "EX-ZR100" }, + { 7684000, 2260, 1700, 0, 0, 0, 0, 13, 0x94, 0, 1, "Casio", "QV-4000" }, + { 787456, 1024, 769, 0, 1, 0, 0, 0, 0x49, 0, 0, "Creative", "PC-CAM 600" }, + { 28829184, 4384, 3288, 0, 0, 0, 0, 36, 0x61, 0, 0, "DJI" }, + { 15151104, 4608, 3288, 0, 0, 0, 0, 0, 0x94, 0, 0, "Matrix" }, + { 3840000, 1600, 1200, 0, 0, 0, 0, 65, 0x49, 0, 0, "Foculus", "531C" }, + { 307200, 640, 480, 0, 0, 0, 0, 0, 0x94, 0, 0, "Generic" }, + { 62464, 256, 244, 1, 1, 6, 1, 0, 0x8d, 0, 0, "Kodak", "DC20" }, + { 124928, 512, 244, 1, 1, 10, 1, 0, 0x8d, 0, 0, "Kodak", "DC20" }, + { 1652736, 1536, 1076, 0, 52, 0, 0, 0, 0x61, 0, 0, "Kodak", "DCS200" }, + { 4159302, 2338, 1779, 1, 33, 1, 2, 0, 0x94, 0, 0, "Kodak", "C330" }, + { 4162462, 2338, 1779, 1, 33, 1, 2, 0, 0x94, 0, 0, "Kodak", "C330", 3160 }, + { 2247168, 1232, 912, 0, 0, 16, 0, 0, 0x00, 0, 0, "Kodak", "C330" }, + { 3370752, 1232, 912, 0, 0, 16, 0, 0, 0x00, 0, 0, "Kodak", "C330" }, + { 6163328, 2864, 2152, 0, 0, 0, 0, 0, 0x94, 0, 0, "Kodak", "C603" }, + { 6166488, 2864, 2152, 0, 0, 0, 0, 0, 0x94, 0, 0, "Kodak", "C603", 3160 }, + { 460800, 640, 480, 0, 0, 0, 0, 0, 0x00, 0, 0, "Kodak", "C603" }, + { 9116448, 2848, 2134, 0, 0, 0, 0, 0, 0x00, 0, 0, "Kodak", "C603" }, + { 12241200, 4040, 3030, 2, 0, 0, 13, 0, 0x49, 0, 0, "Kodak", "12MP" }, + { 12272756, 4040, 3030, 2, 0, 0, 13, 0, 0x49, 0, 0, "Kodak", "12MP", 31556 }, + { 18000000, 4000, 3000, 0, 0, 0, 0, 0, 0x00, 0, 0, "Kodak", "12MP" }, + { 614400, 640, 480, 0, 3, 0, 0, 64, 0x94, 0, 0, "Kodak", "KAI-0340" }, + { 15360000, 3200, 2400, 0, 0, 0, 0, 96, 0x16, 0, 0, "Lenovo", "A820" }, + { 3884928, 1608, 1207, 0, 0, 0, 0, 96, 0x16, 0, 0, "Micron", "2010", 3212 }, + { 1138688, 1534, 986, 0, 0, 0, 0, 0, 0x61, 0, 0, "Minolta", "RD175", 513 }, + { 1581060, 1305, 969, 0, 0, 18, 6, 6, 0x1e, 4, 1, "Nikon", "E900" }, // "diag raw" hack + { 2465792, 1638, 1204, 0, 0, 22, 1, 6, 0x4b, 5, 1, "Nikon", "E950" }, // "diag raw" hack; possibly also Nikon E700, E800, E775; + // Olympus C-2020Z + { 2940928, 1616, 1213, 0, 0, 0, 7, 30, 0x94, 0, 1, "Nikon", "E2100" }, // "diag raw" hack; also Nikon E2500 + { 4771840, 2064, 1541, 0, 0, 0, 1, 6, 0xe1, 0, 1, "Nikon", "E990" }, // "diag raw" hack; possibly also Nikon E880, E885, E995; + // Olympus C-3030Z + { 4775936, 2064, 1542, 0, 0, 0, 0, 30, 0x94, 0, 1, "Nikon", "E3700" }, // "diag raw" hack; Nikon E3100, E3200, E3500; + // Pentax "Optio 33WR"; possibly also Olympus C-740UZ + { 5865472, 2288, 1709, 0, 0, 0, 1, 6, 0xb4, 0, 1, "Nikon", "E4500" }, // "diag raw" hack; possibly also Olympus C-4040Z + { 5869568, 2288, 1710, 0, 0, 0, 0, 6, 0x16, 0, 1, "Nikon", "E4300" }, // "diag raw" hack; also Minolta "DiMAGE Z2" + { 7438336, 2576, 1925, 0, 0, 0, 1, 6, 0xb4, 0, 1, "Nikon", "E5000" }, // also Nikon E5700 + { 8998912, 2832, 2118, 0, 0, 0, 0, 30, 0x94, 7, 1, "Nikon", "COOLPIX S6" }, // "diag raw" hack + { 5939200, 2304, 1718, 0, 0, 0, 0, 30, 0x16, 0, 0, "Olympus", "C-770UZ" }, // possibly also Olympus C-4100Z, C-765UZ + { 3178560, 2064, 1540, 0, 0, 0, 0, 0, 0x94, 0, 1, "Pentax", "Optio S V1.01" }, + { 4841984, 2090, 1544, 0, 0, 22, 0, 0, 0x94, 7, 1, "Pentax", "Optio S" }, + { 6114240, 2346, 1737, 0, 0, 22, 0, 0, 0x94, 7, 1, "Pentax", "Optio S4" }, + { 10702848, 3072, 2322, 0, 0, 0, 21, 30, 0x94, 0, 1, "Pentax", "Optio 750Z" }, + { 4147200, 1920, 1080, 0, 0, 0, 0, 0, 0x49, 0, 0, "Photron", "BC2-HD" }, + { 4151666, 1920, 1080, 0, 0, 0, 0, 0, 0x49, 0, 0, "Photron", "BC2-HD", 8 }, + { 13248000, 2208, 3000, 0, 0, 0, 0, 13, 0x61, 0, 0, "Pixelink", "A782" }, + { 6291456, 2048, 1536, 0, 0, 0, 0, 96, 0x61, 0, 0, "RoverShot", "3320AF" }, + { 311696, 644, 484, 0, 0, 0, 0, 0, 0x16, 0, 8, "ST Micro", "STV680 VGA" }, + { 16098048, 3288, 2448, 0, 0, 24, 0, 9, 0x94, 0, 1, "Samsung", "S85" }, // hack + { 16215552, 3312, 2448, 0, 0, 48, 0, 9, 0x94, 0, 1, "Samsung", "S85" }, // hack + { 20487168, 3648, 2808, 0, 0, 0, 0, 13, 0x94, 5, 1, "Samsung", "WB550" }, + { 24000000, 4000, 3000, 0, 0, 0, 0, 13, 0x94, 5, 1, "Samsung", "WB550" }, + { 12582980, 3072, 2048, 0, 0, 0, 0, 33, 0x61, 0, 0, "Sinar", "", 68 }, // Sinarback 23; same res. as Leaf Volare & Cantare + { 33292868, 4080, 4080, 0, 0, 0, 0, 33, 0x61, 0, 0, "Sinar", "", 68 }, // Sinarback 44 + { 44390468, 4080, 5440, 0, 0, 0, 0, 33, 0x61, 0, 0, "Sinar", "", 68 }, // Sinarback 54 + { 1409024, 1376, 1024, 0, 0, 1, 0, 0, 0x49, 0, 0, "Sony", "XCD-SX910CR" }, + { 2818048, 1376, 1024, 0, 0, 1, 0, 97, 0x49, 0, 0, "Sony", "XCD-SX910CR" }, + }; + + libraw_custom_camera_t + table[64 + sizeof(const_table) / sizeof(const_table[0])]; + + + // clang-format on + + char head[64] = {0}, *cp; + int hlen, fsize, flen, zero_fsize = 1, i, c; + struct jhead jh; + + unsigned camera_count = + parse_custom_cameras(64, table, imgdata.params.custom_camera_strings); + for (int q = 0; q < int(sizeof(const_table) / sizeof(const_table[0])); q++) + memmove(&table[q + camera_count], &const_table[q], sizeof(const_table[0])); + camera_count += sizeof(const_table) / sizeof(const_table[0]); + + tiff_flip = flip = filters = UINT_MAX; /* unknown */ + raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; + maximum = height = width = top_margin = left_margin = 0; + cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; + iso_speed = shutter = aperture = focal_len = 0; + unique_id = 0ULL; + tiff_nifds = 0; + is_NikonTransfer = 0; + is_Sony = 0; + is_pana_raw = 0; + maker_index = LIBRAW_CAMERAMAKER_Unknown; + is_4K_RAFdata = 0; + FujiCropMode = 0; + is_PentaxRicohMakernotes = 0; + normalized_model[0] = 0; + normalized_make[0] = 0; + CM_found = 0; + memset(tiff_ifd, 0, sizeof tiff_ifd); + libraw_internal_data.unpacker_data.crx_track_selected = -1; + libraw_internal_data.unpacker_data.CR3_CTMDtag = 0; + imgdata.makernotes.hasselblad.nIFD_CM[0] = + imgdata.makernotes.hasselblad.nIFD_CM[1] = -1; + imgdata.makernotes.kodak.ISOCalibrationGain = 1.0f; + imCommon.CameraTemperature = imCommon.SensorTemperature = + imCommon.SensorTemperature2 = imCommon.LensTemperature = + imCommon.AmbientTemperature = imCommon.BatteryTemperature = + imCommon.exifAmbientTemperature = -1000.0f; + + imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_Unknown; + for (i = 0; i < LIBRAW_IFD_MAXCOUNT; i++) + { + tiff_ifd[i].dng_color[0].illuminant = tiff_ifd[i].dng_color[1].illuminant = + 0xffff; + for (int c = 0; c < 4; c++) + tiff_ifd[i].dng_levels.analogbalance[c] = 1.0f; + } + + memset(gpsdata, 0, sizeof gpsdata); + memset(cblack, 0, sizeof cblack); + memset(white, 0, sizeof white); + memset(mask, 0, sizeof mask); + thumb_offset = thumb_length = thumb_width = thumb_height = 0; + load_raw = thumb_load_raw = 0; + write_thumb = &LibRaw::jpeg_thumb; + data_offset = meta_offset = meta_length = tiff_bps = tiff_compress = 0; + kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; + timestamp = shot_order = tiff_samples = black = is_foveon = 0; + mix_green = profile_length = data_error = zero_is_bad = 0; + pixel_aspect = is_raw = raw_color = 1; + tile_width = tile_length = 0; + metadata_blocks = 0; + + for (i = 0; i < 4; i++) + { + cam_mul[i] = i == 1; + pre_mul[i] = i < 3; + FORC3 cmatrix[c][i] = 0; + FORC3 rgb_cam[c][i] = c == i; + } + colors = 3; + for (i = 0; i < 0x10000; i++) + curve[i] = i; + + order = get2(); + hlen = get4(); + fseek(ifp, 0, SEEK_SET); + + if (fread(head, 1, 64, ifp) < 64) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + libraw_internal_data.unpacker_data.lenRAFData = + libraw_internal_data.unpacker_data.posRAFData = 0; + + fseek(ifp, 0, SEEK_END); + flen = fsize = ftell(ifp); + 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; + parse_ciff(hlen, flen - hlen, 0); + load_raw = &LibRaw::canon_load_raw; + } + else if (parse_tiff(0)) + apply_tiff(); + } + else if (!memcmp(head, "\xff\xd8\xff\xe1", 4) && !memcmp(head + 6, "Exif", 4)) + { + fseek(ifp, 4, SEEK_SET); + data_offset = 4 + get2(); + fseek(ifp, data_offset, SEEK_SET); + if (fgetc(ifp) != 0xff) + parse_tiff(12); + thumb_offset = 0; + } + else if (!memcmp(head + 25, "ARECOYK", 7)) // 'KYOCERA' right-to-left + { + strcpy(make, "Contax"); + strcpy(model, "N Digital"); + parse_kyocera(); + } + else if (!strcmp(head, "PXN")) + { + strcpy(make, "Logitech"); + strcpy(model, "Fotoman Pixtura"); + } + else if (!strcmp(head, "qktk")) + { + strcpy(make, "Apple"); + strcpy(model, "QuickTake 100"); + load_raw = &LibRaw::quicktake_100_load_raw; + } + else if (!strcmp(head, "qktn")) + { + strcpy(make, "Apple"); + strcpy(model, "QuickTake 150"); + load_raw = &LibRaw::kodak_radc_load_raw; + } + else if (!memcmp(head, "FUJIFILM", 8)) + { + memcpy(imFuji.SerialSignature, head + 0x10, 0x0c); + imFuji.SerialSignature[0x0c] = 0; + strncpy(model, head + 0x1c, 0x20); + model[0x20] = 0; + memcpy(model2, head + 0x3c, 4); + model2[4] = 0; + strcpy(imFuji.RAFVersion, model2); + fseek(ifp, 84, SEEK_SET); + thumb_offset = get4(); + thumb_length = get4(); + fseek(ifp, 92, SEEK_SET); + parse_fuji(get4()); + if (thumb_offset > 120) + { + fseek(ifp, 120, SEEK_SET); + is_raw += (i = get4()) ? 1 : 0; + if (is_raw == 2 && shot_select) + parse_fuji(i); + } + load_raw = &LibRaw::unpacked_load_raw; + fseek(ifp, 100 + 28 * (shot_select > 0), SEEK_SET); + parse_tiff(data_offset = get4()); + parse_tiff(thumb_offset + 12); + apply_tiff(); + } + else if (!memcmp(head, "RIFF", 4)) + { + fseek(ifp, 0, SEEK_SET); + parse_riff(); + } + else if (!memcmp(head + 4, "ftypqt ", 9)) + { + fseek(ifp, 0, SEEK_SET); + parse_qt(fsize); + is_raw = 0; + } + else if (!memcmp(head, "\0\001\0\001\0@", 6)) + { + fseek(ifp, 6, SEEK_SET); + fread(make, 1, 8, ifp); + fread(model, 1, 8, ifp); + fread(model2, 1, 16, ifp); + data_offset = get2(); + get2(); + raw_width = get2(); + raw_height = get2(); + load_raw = &LibRaw::nokia_load_raw; + filters = 0x61616161; + } + else if (!memcmp(head, "NOKIARAW", 8)) + { + strcpy(make, "NOKIA"); + order = 0x4949; + fseek(ifp, 300, SEEK_SET); + data_offset = get4(); + i = get4(); // bytes count + width = get2(); + height = get2(); + + // Data integrity check + if (width < 1 || width > 16000 || height < 1 || height > 16000 || + i < (width * height) || i > (2 * width * height)) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + switch (tiff_bps = i * 8 / (width * height)) + { + case 8: + load_raw = &LibRaw::eight_bit_load_raw; + break; + case 10: + load_raw = &LibRaw::nokia_load_raw; + break; + case 0: + throw LIBRAW_EXCEPTION_IO_CORRUPT; + break; + } + raw_height = height + (top_margin = i / (width * tiff_bps / 8) - height); + mask[0][3] = 1; + filters = 0x61616161; + } + else if (!memcmp(head, "ARRI", 4)) + { + order = 0x4949; + fseek(ifp, 20, SEEK_SET); + width = get4(); + height = get4(); + strcpy(make, "ARRI"); + fseek(ifp, 668, SEEK_SET); + fread(model, 1, 64, ifp); + model[63] = 0; + fseek(ifp, 760, SEEK_SET); + fread(software, 1, 64, ifp); + if((unsigned char)software[0] == 0xff) software[0] = 0; + software[63] = 0; + data_offset = 4096; + load_raw = &LibRaw::packed_load_raw; + load_flags = 88; + filters = 0x61616161; + fixupArri(); + } + else if (!memcmp(head, "XPDS", 4)) + { + order = 0x4949; + fseek(ifp, 0x800, SEEK_SET); + fread(make, 1, 41, ifp); + raw_height = get2(); + raw_width = get2(); + fseek(ifp, 56, SEEK_CUR); + fread(model, 1, 30, ifp); + data_offset = 0x10000; + load_raw = &LibRaw::canon_rmf_load_raw; + gamma_curve(0, 12.25, 1, 1023); + } + else if (!memcmp(head + 4, "RED1", 4)) + { + strcpy(make, "Red"); + strcpy(model, "One"); + parse_redcine(); + load_raw = &LibRaw::redcine_load_raw; + gamma_curve(1 / 2.4, 12.92, 1, 4095); + filters = 0x49494949; + } + else if (!memcmp(head, "DSC-Image", 9)) + parse_rollei(); + else if (!memcmp(head, "PWAD", 4)) + parse_sinar_ia(); + else if (!memcmp(head, "\0MRM", 4)) + parse_minolta(0); + else if (!memcmp(head, "FOVb", 4)) + { + parse_x3f(); /* Does nothing if USE_X3FTOOLS is not defined */ + } + else if (!memcmp(head, "CI", 2)) + parse_cine(); +#ifdef USE_6BY9RPI + else if (!memcmp(head, "BRCM", 4)) { + fseek(ifp, 0, SEEK_SET); + strcpy(make, "RaspberryPi"); + strcpy(model, "Pi"); + parse_raspberrypi(); + } +#endif + else if (!memcmp(head + 4, "ftypcrx ", 8)) + { + int err; + unsigned long long szAtomList; + short nesting = -1; + short nTrack = -1; + short TrackType; + char AtomNameStack[128]; + strcpy(make, "Canon"); + + szAtomList = ifp->size(); + err = parseCR3(0ULL, szAtomList, nesting, AtomNameStack, nTrack, TrackType); + if ((err == 0 || err == -14) && + nTrack >= 0) // no error, or too deep nesting + selectCRXTrack(nTrack); + } + + if (make[0] == 0) + for (zero_fsize = i = 0; i < (int)camera_count; i++) + if (fsize == (int)table[i].fsize) + { + strcpy(make, table[i].t_make); + strcpy(model, table[i].t_model); + flip = table[i].flags >> 2; + zero_is_bad = table[i].flags & 2; + data_offset = table[i].offset == 0xffff ? 0 : table[i].offset; + raw_width = table[i].rw; + raw_height = table[i].rh; + left_margin = table[i].lm; + top_margin = table[i].tm; + width = raw_width - left_margin - table[i].rm; + height = raw_height - top_margin - table[i].bm; + filters = 0x1010101U * table[i].cf; + colors = 4 - !((filters & filters >> 1) & 0x5555); + load_flags = table[i].lf & 0xff; + if (table[i].lf & 0x100) /* Monochrome sensor dump */ + { + colors = 1; + filters = 0; + } + switch (tiff_bps = (fsize - data_offset) * 8 / (raw_width * raw_height)) + { + case 6: + load_raw = &LibRaw::minolta_rd175_load_raw; + ilm.CameraMount = LIBRAW_MOUNT_Minolta_A; + break; + case 8: + load_raw = &LibRaw::eight_bit_load_raw; + break; + case 10: + if ((fsize - data_offset) / raw_height * 3 >= raw_width * 4) + { + load_raw = &LibRaw::android_loose_load_raw; + break; + } + else if (load_flags & 1) + { + load_raw = &LibRaw::android_tight_load_raw; + break; + } + case 12: + load_flags |= 128; + load_raw = &LibRaw::packed_load_raw; + break; + case 16: + order = 0x4949 | 0x404 * (load_flags & 1); + tiff_bps -= load_flags >> 4; + tiff_bps -= load_flags = load_flags >> 1 & 7; + load_raw = table[i].offset == 0xffff + ? &LibRaw::unpacked_load_raw_reversed + : &LibRaw::unpacked_load_raw; + } + maximum = (1 << tiff_bps) - (1 << table[i].max); + break; + } + if (zero_fsize) + fsize = 0; + if (make[0] == 0) + parse_smal(0, flen); + if (make[0] == 0) + { + parse_jpeg(0); +#ifdef USE_6BY9RPI + if (!(strncmp(model, "ov", 2) && strncmp(model, "RP_", 3))) { + //Assume that this isn't a raw unless the header can be found + is_raw = 0; + + if (!strncasecmp(model, "RP_imx", 6)) { + const long offsets[] = { + //IMX219 offsets + 10270208, //8MPix 3280x2464 + 2678784, //1920x1080 + 2628608, //1640x1232 + 1963008, //1640x922 + 1233920, //1280x720 + 445440, //640x480 + -1 //Marker for end of table + }; + int offset_idx; + for (offset_idx = 0; offsets[offset_idx] != -1; offset_idx++) { + if (!fseek(ifp, -offsets[offset_idx], SEEK_END) && + fread(head, 1, 32, ifp) && !strncmp(head, "BRCM", 4)) { + + fseek(ifp, -32, SEEK_CUR); + strcpy(make, "SonyRPF"); + parse_raspberrypi(); + break; + } + } + } + else if (!strncasecmp(model, "RP_OV", 5) || !strncasecmp(model, "ov5647", 6)) { + const long offsets[] = { + 6404096, //5MPix 2592x1944 + 2717696, //1920x1080 + 1625600, //1296x972 + 1233920, //1296x730 + 445440, //640x480 + -1 //Marker for end of table + }; + int offset_idx; + for (offset_idx = 0; offsets[offset_idx] != -1; offset_idx++) { + if (!fseek(ifp, -offsets[offset_idx], SEEK_END) && + fread(head, 1, 32, ifp) && !strncmp(head, "BRCM", 4)) { + fseek(ifp, -32, SEEK_CUR); + strcpy(make, "OmniVision"); + width = raw_width; + //Defaults + raw_width = 2611; + filters = 0x16161616; + parse_raspberrypi(); + break; + } + } + } + }// else is_raw = 0; +#else + fseek(ifp, 0, SEEK_END); + int sz = ftell(ifp); + if (!strncmp(model, "RP_imx219", 9) && sz >= 0x9cb600 && + !fseek(ifp, -0x9cb600, SEEK_END) && fread(head, 1, 0x20, ifp) && + !strncmp(head, "BRCM", 4)) + { + strcpy(make, "Broadcom"); + strcpy(model, "RPi IMX219"); + if (raw_height > raw_width) + flip = 5; + data_offset = ftell(ifp) + 0x8000 - 0x20; + parse_broadcom(); + black = 66; + maximum = 0x3ff; + load_raw = &LibRaw::broadcom_load_raw; + thumb_offset = 0; + thumb_length = sz - 0x9cb600 - 1; + } + else if (!(strncmp(model, "ov5647", 6) && strncmp(model, "RP_OV5647", 9)) && + sz >= 0x61b800 && !fseek(ifp, -0x61b800, SEEK_END) && + fread(head, 1, 0x20, ifp) && !strncmp(head, "BRCM", 4)) + { + strcpy(make, "Broadcom"); + if (!strncmp(model, "ov5647", 6)) + strcpy(model, "RPi OV5647 v.1"); + else + strcpy(model, "RPi OV5647 v.2"); + if (raw_height > raw_width) + flip = 5; + data_offset = ftell(ifp) + 0x8000 - 0x20; + parse_broadcom(); + black = 16; + maximum = 0x3ff; + load_raw = &LibRaw::broadcom_load_raw; + thumb_offset = 0; + thumb_length = sz - 0x61b800 - 1; + } + else + is_raw = 0; +#endif + } + + // make sure strings are terminated + desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; + + for (i = 0; i < int(sizeof CorpTable / sizeof *CorpTable); i++) + { + if (strcasestr(make, CorpTable[i].CorpName)) + { /* Simplify company names */ + maker_index = CorpTable[i].CorpId; + strcpy(make, CorpTable[i].CorpName); + } + } + + if ((makeIs(LIBRAW_CAMERAMAKER_Kodak) || makeIs(LIBRAW_CAMERAMAKER_Leica)) && + ((cp = strcasestr(model, " DIGITAL CAMERA")) || + (cp = strstr(model, "FILE VERSION")))) { + *cp = 0; + } else if (makeIs(LIBRAW_CAMERAMAKER_Ricoh) && !strncasecmp(model, "PENTAX", 6)) { + maker_index = LIBRAW_CAMERAMAKER_Pentax; + strcpy(make, "Pentax"); + } else if (makeIs(LIBRAW_CAMERAMAKER_JK_Imaging) && !strncasecmp(model, "Kodak", 5)) { + maker_index = LIBRAW_CAMERAMAKER_Kodak; + strcpy(make, "Kodak"); + } + + remove_trailing_spaces(make, sizeof(make)); + remove_trailing_spaces(model, sizeof(model)); + + i = strbuflen(make); /* Remove make from model */ + if (!strncasecmp(model, make, i) && model[i++] == ' ') + memmove(model, model + i, 64 - i); + + if (makeIs(LIBRAW_CAMERAMAKER_Fujifilm) && !strncmp(model, "FinePix", 7)) { + memmove(model, model + 7, strlen(model) - 6); + if (model[0] == ' ') { + memmove(model, model + 1, strlen(model)); + } + } else if ((makeIs(LIBRAW_CAMERAMAKER_Kodak) || makeIs(LIBRAW_CAMERAMAKER_Konica)) && + !strncmp(model, "Digital Camera ", 15)) { + memmove(model, model + 15, strlen(model) - 14); + } + + desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; + if (!is_raw) + goto notraw; + + if (!height) + height = raw_height; + if (!width) + width = raw_width; + + identify_finetune_pentax(); + + + if (dng_version) + { + if (filters == UINT_MAX) + filters = 0; + if (!filters) + colors = tiff_samples; + switch (tiff_compress) + { + case 0: // Compression not set, assuming uncompressed + case 1: +#ifdef USE_DNGSDK + // Uncompressed float + if (load_raw != &LibRaw::float_dng_load_raw_placeholder) +#endif + load_raw = &LibRaw::packed_dng_load_raw; + break; + case 7: + load_raw = &LibRaw::lossless_dng_load_raw; + break; + case 8: + load_raw = &LibRaw::deflate_dng_load_raw; + break; +#ifdef USE_GPRSDK + case 9: + load_raw = &LibRaw::vc5_dng_load_raw_placeholder; + break; +#endif + case 34892: + load_raw = &LibRaw::lossy_dng_load_raw; + break; + default: + load_raw = 0; + } + GetNormalizedModel(); + if (makeIs(LIBRAW_CAMERAMAKER_Olympus) && + (OlyID == OlyID_STYLUS_1) && // don't use normalized_model below, it is 'Stylus 1' + (strchr(model+6, 's') || + strchr(model+6, 'S'))) + { + width -= 16; + } + goto dng_skip; + } + + if (makeIs(LIBRAW_CAMERAMAKER_Canon) && !fsize && tiff_bps != 15) + { + bool fromtable = false; + if (!load_raw) + load_raw = &LibRaw::lossless_jpeg_load_raw; + for (i = 0; i < int(sizeof canon / sizeof *canon); i++) + if (raw_width == canon[i][0] && raw_height == canon[i][1]) + { + width = raw_width - (left_margin = canon[i][2]); + height = raw_height - (top_margin = canon[i][3]); + width -= canon[i][4]; + height -= canon[i][5]; + mask[0][1] = canon[i][6]; + mask[0][3] = -canon[i][7]; + mask[1][1] = canon[i][8]; + mask[1][3] = -canon[i][9]; + if (canon[i][10]) + filters = canon[i][10] * 0x01010101U; + fromtable = true; + } + if ((unique_id | 0x20000ULL) == + 0x2720000ULL) // "PowerShot G11", "PowerShot S90": 0x2700000, 0x2720000 + // possibly "PowerShot SX120 IS" (if not chdk hack?): 0x2710000 + { + left_margin = 8; + top_margin = 16; + } + if(!fromtable && imgdata.makernotes.canon.AverageBlackLevel) // not known, but metadata known + { + FORC4 cblack[c] = imgdata.makernotes.canon.ChannelBlackLevel[c]; + black = cblack[4] = cblack[5] = 0; + // Prevent automatic BL calculation + mask[0][3] = 1; + mask[0][1] = 2; + + if(imgdata.makernotes.canon.SensorWidth == raw_width + && imgdata.makernotes.canon.SensorHeight == raw_height) + { + left_margin = (imgdata.makernotes.canon.SensorLeftBorder+1) & 0xfffe; // round to 2 + width = imgdata.makernotes.canon.SensorRightBorder - left_margin; + top_margin = (imgdata.makernotes.canon.SensorTopBorder +1) & 0xfffe; + height = imgdata.makernotes.canon.SensorBottomBorder - top_margin; + } + } + } + + identify_finetune_by_filesize(fsize); + + if (!strcmp(model, "KAI-0340") && find_green(16, 16, 3840, 5120) < 25) + { + height = 480; + top_margin = filters = 0; + strcpy(model, "C603"); + } + + GetNormalizedModel(); + + identify_finetune_dcr(head, fsize, flen); + + /* Early reject for damaged images */ + if (!load_raw || height < 22 || width < 22 || + (tiff_bps > 16 && + (load_raw != &LibRaw::deflate_dng_load_raw && + load_raw != &LibRaw::float_dng_load_raw_placeholder)) || + tiff_samples > 4 || colors > 4 || + colors < 1 + /* alloc in unpack() may be fooled by size adjust */ + || ((int)width + (int)left_margin > 65535) || + ((int)height + (int)top_margin > 65535)) + { + is_raw = 0; + RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY, 1, 2); + return; + } + if (!model[0]) + { + sprintf(model, "%dx%d", width, height); + strcpy(normalized_model, model); + } + + if (!(imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_ZEROFILTERS_FOR_MONOCHROMETIFFS) && + (filters == UINT_MAX)) // Default dcraw behaviour + filters = 0x94949494; + else if (filters == UINT_MAX) + { + if (tiff_nifds > 0 && tiff_samples == 1) + { + colors = 1; + filters = 0; + } + else + filters = 0x94949494; + } + + if (thumb_offset && !thumb_height) + { + fseek(ifp, thumb_offset, SEEK_SET); + if (ljpeg_start(&jh, 1)) + { + thumb_width = jh.wide; + thumb_height = jh.high; + } + } + +dng_skip: + if (dng_version) + identify_process_dng_fields(); + + /* Early reject for damaged images again (after dng fields processing) */ + if (!load_raw || height < 22 || width < 22 || + (tiff_bps > 16 && + (load_raw != &LibRaw::deflate_dng_load_raw && + load_raw != &LibRaw::float_dng_load_raw_placeholder)) || + tiff_samples > 4 || colors > 4 || colors < 1) + { + is_raw = 0; + RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY, 1, 2); + return; + } + { + // Check cam_mul range + int cmul_ok = 1; + FORCC if (cam_mul[c] <= 0.001f) cmul_ok = 0; + ; + + if (cmul_ok) + { + double cmin = cam_mul[0], cmax; + double cnorm[4]; + FORCC cmin = MIN(cmin, cam_mul[c]); + FORCC cnorm[c] = cam_mul[c] / cmin; + cmax = cmin = cnorm[0]; + FORCC + { + cmin = MIN(cmin, cnorm[c]); + cmax = MIN(cmax, cnorm[c]); + } + if (cmin <= 0.01f || cmax > 100.f) + cmul_ok = false; + } + if (!cmul_ok) + { + if (cam_mul[0] > 0) + cam_mul[0] = 0; + cam_mul[3] = 0; + } + } + if ((use_camera_matrix & (((use_camera_wb || dng_version)?1:0) | 0x2)) && + cmatrix[0][0] > 0.125) + { + memcpy(rgb_cam, cmatrix, sizeof cmatrix); + raw_color = 0; + } + if (raw_color && !CM_found) + CM_found = adobe_coeff(maker_index, normalized_model); + else if ((imgdata.color.cam_xyz[0][0] < 0.01) && !CM_found) + CM_found = adobe_coeff(maker_index, normalized_model, 1); + + if (load_raw == &LibRaw::kodak_radc_load_raw) + if ((raw_color) && !CM_found) + CM_found = adobe_coeff(LIBRAW_CAMERAMAKER_Apple, "Quicktake"); + + if ((maker_index != LIBRAW_CAMERAMAKER_Unknown) && normalized_model[0]) + SetStandardIlluminants (maker_index, normalized_model); + + // Clear erorneus fuji_width if not set through parse_fuji or for DNG + if (fuji_width && !dng_version && + !(imgdata.process_warnings & LIBRAW_WARN_PARSEFUJI_PROCESSED)) + fuji_width = 0; + + if (fuji_width) + { + fuji_width = width >> !fuji_layout; + filters = fuji_width & 1 ? 0x94949494 : 0x49494949; + width = (height >> fuji_layout) + fuji_width; + height = width - 1; + pixel_aspect = 1; + } + else + { + if (raw_height < height) + raw_height = height; + if (raw_width < width) + raw_width = width; + } + if (!tiff_bps) + tiff_bps = 12; + if (!maximum) + { + maximum = (1 << tiff_bps) - 1; + if (maximum < 0x10000 && curve[maximum] > 0 && + load_raw == &LibRaw::sony_arw2_load_raw) + maximum = curve[maximum]; + } + if (maximum > 0xffff) + maximum = 0xffff; + if (!load_raw || height < 22 || width < 22 || + (tiff_bps > 16 && + (load_raw != &LibRaw::deflate_dng_load_raw && + load_raw != &LibRaw::float_dng_load_raw_placeholder)) || + tiff_samples > 6 || colors > 4) + is_raw = 0; + + if (raw_width < 22 || raw_width > 64000 || raw_height < 22 || + pixel_aspect < 0.1 || pixel_aspect > 10. || + raw_height > 64000) + is_raw = 0; + if(raw_width <= left_margin || raw_height <= top_margin) + is_raw = 0; + if (dng_version && (tiff_samples < 1 || tiff_samples > 4)) + is_raw = 0; // we do not handle DNGs with more than 4 values per pixel +#ifdef NO_JASPER + if (load_raw == &LibRaw::redcine_load_raw) + { + is_raw = 0; + imgdata.process_warnings |= LIBRAW_WARN_NO_JASPER; + } +#endif +#ifdef NO_JPEG + if (load_raw == &LibRaw::kodak_jpeg_load_raw || + load_raw == &LibRaw::lossy_dng_load_raw) + { + is_raw = 0; + imgdata.process_warnings |= LIBRAW_WARN_NO_JPEGLIB; + } +#endif + if (!cdesc[0]) + strcpy(cdesc, colors == 3 ? "RGBG" : "GMCY"); + if (!raw_height) + raw_height = height; + if (!raw_width) + raw_width = width; + if (filters > 999 && colors == 3) + filters |= ((filters >> 2 & 0x22222222) | (filters << 2 & 0x88888888)) & + filters << 1; +notraw: + if (flip == (int)UINT_MAX) + flip = tiff_flip; + if (flip == (int)UINT_MAX) + flip = 0; + + // Convert from degrees to bit-field if needed + if (flip > 89 || flip < -89) + { + switch ((flip + 3600) % 360) + { + case 270: + flip = 5; + break; + case 180: + flip = 3; + break; + case 90: + flip = 6; + break; + } + } + + if (pana_bpp) + imgdata.color.raw_bps = pana_bpp; + else if ((load_raw == &LibRaw::phase_one_load_raw) || + (load_raw == &LibRaw::phase_one_load_raw_c)) + imgdata.color.raw_bps = ph1.format; + else + imgdata.color.raw_bps = tiff_bps; + + RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY, 1, 2); +} + +void LibRaw::identify_process_dng_fields() +{ + if (!dng_version) return; + int c; + { + /* copy DNG data from per-IFD field to color.dng */ + int iifd = find_ifd_by_offset(data_offset); + int pifd = find_ifd_by_offset(thumb_offset); + +#define CFAROUND(value, filters) \ + filters ? (filters >= 1000 ? ((value + 1) / 2) * 2 : ((value + 5) / 6) * 6) \ + : value + +#define IFDCOLORINDEX(ifd, subset, bit) \ + (tiff_ifd[ifd].dng_color[subset].parsedfields & bit) \ + ? ifd \ + : ((tiff_ifd[0].dng_color[subset].parsedfields & bit) ? 0 : -1) + +#define IFDLEVELINDEX(ifd, bit) \ + (tiff_ifd[ifd].dng_levels.parsedfields & bit) \ + ? ifd \ + : ((tiff_ifd[0].dng_levels.parsedfields & bit) ? 0 : -1) + +#define COPYARR(to, from) memmove(&to, &from, sizeof(from)) + + if (iifd < (int)tiff_nifds && iifd >= 0) + { + int sidx; + // Per field, not per structure + if (!(imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_DONT_CHECK_DNG_ILLUMINANT)) + { + int illidx[2], cmidx[2], calidx[2], abidx; + for (int i = 0; i < 2; i++) + { + illidx[i] = IFDCOLORINDEX(iifd, i, LIBRAW_DNGFM_ILLUMINANT); + cmidx[i] = IFDCOLORINDEX(iifd, i, LIBRAW_DNGFM_COLORMATRIX); + calidx[i] = IFDCOLORINDEX(iifd, i, LIBRAW_DNGFM_CALIBRATION); + } + abidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_ANALOGBALANCE); + // Data found, all in same ifd, illuminants are inited + if (illidx[0] >= 0 && illidx[0] < (int)tiff_nifds && + illidx[0] == illidx[1] && illidx[0] == cmidx[0] && + illidx[0] == cmidx[1] && + tiff_ifd[illidx[0]].dng_color[0].illuminant > 0 && + tiff_ifd[illidx[0]].dng_color[1].illuminant > 0) + { + sidx = illidx[0]; // => selected IFD + double cc[4][4], cm[4][3], cam_xyz[4][3]; + // CM -> Color Matrix + // CC -> Camera calibration + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) + cc[j][i] = i == j; + int colidx = -1; + + // IS D65 here? + for (int i = 0; i < 2; i++) + { + if (tiff_ifd[sidx].dng_color[i].illuminant == LIBRAW_WBI_D65) + { + colidx = i; + break; + } + } + + // Other daylight-type ill + if (colidx < 0) + for (int i = 0; i < 2; i++) + { + int ill = tiff_ifd[sidx].dng_color[i].illuminant; + if (ill == LIBRAW_WBI_Daylight || ill == LIBRAW_WBI_D55 || + ill == LIBRAW_WBI_D75 || ill == LIBRAW_WBI_D50 || + ill == LIBRAW_WBI_Flash) + { + colidx = i; + break; + } + } + if (colidx >= 0) // Selected + { + // Init camera matrix from DNG + FORCC for (int j = 0; j < 3; j++) cm[c][j] = + tiff_ifd[sidx].dng_color[colidx].colormatrix[c][j]; + + if (calidx[colidx] == sidx) + { + for (int i = 0; i < colors && i < 4; i++) + FORCC + cc[i][c] = tiff_ifd[sidx].dng_color[colidx].calibration[i][c]; + } + + if (abidx == sidx) + for (int i = 0; i < colors && i < 4; i++) + FORCC cc[i][c] *= tiff_ifd[sidx].dng_levels.analogbalance[i]; + int j; + FORCC for (int i = 0; i < 3; i++) + for (cam_xyz[c][i] = j = 0; j < colors && j < 4; j++) + cam_xyz[c][i] += + cc[c][j] * cm[j][i]; // add AsShotXY later * xyz[i]; + cam_xyz_coeff(cmatrix, cam_xyz); + } + } + } + + bool noFujiDNGCrop = makeIs(LIBRAW_CAMERAMAKER_Fujifilm) + && (!strcmp(normalized_model, "S3Pro") + || !strcmp(normalized_model, "S5Pro") + || !strcmp(normalized_model, "S2Pro")); + + if (!noFujiDNGCrop && + (imgdata.params.raw_processing_options &LIBRAW_PROCESSING_USE_DNG_DEFAULT_CROP)) + { + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_CROPORIGIN); + int sidx2 = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_CROPSIZE); + if (sidx >= 0 && sidx == sidx2 && + tiff_ifd[sidx].dng_levels.default_crop[2] > 0 && + tiff_ifd[sidx].dng_levels.default_crop[3] > 0) + { + int lm = tiff_ifd[sidx].dng_levels.default_crop[0]; + int lmm = CFAROUND(lm, filters); + int tm = tiff_ifd[sidx].dng_levels.default_crop[1]; + int tmm = CFAROUND(tm, filters); + int ww = tiff_ifd[sidx].dng_levels.default_crop[2]; + int hh = tiff_ifd[sidx].dng_levels.default_crop[3]; + if (lmm > lm) + ww -= (lmm - lm); + if (tmm > tm) + hh -= (tmm - tm); + if (left_margin + lm + ww <= raw_width && + top_margin + tm + hh <= raw_height) + { + left_margin += lmm; + top_margin += tmm; + width = ww; + height = hh; + } + } + } + if (!(imgdata.color.dng_color[0].parsedfields & + LIBRAW_DNGFM_FORWARDMATRIX)) // Not set already (Leica makernotes) + { + sidx = IFDCOLORINDEX(iifd, 0, LIBRAW_DNGFM_FORWARDMATRIX); + if (sidx >= 0) + COPYARR(imgdata.color.dng_color[0].forwardmatrix, + tiff_ifd[sidx].dng_color[0].forwardmatrix); + } + if (!(imgdata.color.dng_color[1].parsedfields & + LIBRAW_DNGFM_FORWARDMATRIX)) // Not set already (Leica makernotes) + { + sidx = IFDCOLORINDEX(iifd, 1, LIBRAW_DNGFM_FORWARDMATRIX); + if (sidx >= 0) + COPYARR(imgdata.color.dng_color[1].forwardmatrix, + tiff_ifd[sidx].dng_color[1].forwardmatrix); + } + for (int ss = 0; ss < 2; ss++) + { + sidx = IFDCOLORINDEX(iifd, ss, LIBRAW_DNGFM_COLORMATRIX); + if (sidx >= 0) + COPYARR(imgdata.color.dng_color[ss].colormatrix, + tiff_ifd[sidx].dng_color[ss].colormatrix); + + sidx = IFDCOLORINDEX(iifd, ss, LIBRAW_DNGFM_CALIBRATION); + if (sidx >= 0) + COPYARR(imgdata.color.dng_color[ss].calibration, + tiff_ifd[sidx].dng_color[ss].calibration); + + sidx = IFDCOLORINDEX(iifd, ss, LIBRAW_DNGFM_ILLUMINANT); + if (sidx >= 0) + imgdata.color.dng_color[ss].illuminant = + tiff_ifd[sidx].dng_color[ss].illuminant; + } + // Levels + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_ANALOGBALANCE); + if (sidx >= 0) + COPYARR(imgdata.color.dng_levels.analogbalance, + tiff_ifd[sidx].dng_levels.analogbalance); + + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_BASELINEEXPOSURE); + if (sidx >= 0) + imgdata.color.dng_levels.baseline_exposure = + tiff_ifd[sidx].dng_levels.baseline_exposure; + + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_WHITE); + if (sidx >= 0 && tiff_ifd[sidx].dng_levels.dng_whitelevel[0]) + COPYARR(imgdata.color.dng_levels.dng_whitelevel, + tiff_ifd[sidx].dng_levels.dng_whitelevel); + else if (tiff_ifd[iifd].sample_format <= 2 && tiff_ifd[iifd].bps > 0 && tiff_ifd[iifd].bps < 32) + FORC4 + imgdata.color.dng_levels.dng_whitelevel[c] = (1 << tiff_ifd[iifd].bps) - 1; + + + + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_ASSHOTNEUTRAL); + if (sidx >= 0) + { + COPYARR(imgdata.color.dng_levels.asshotneutral, + tiff_ifd[sidx].dng_levels.asshotneutral); + if (imgdata.color.dng_levels.asshotneutral[0]) + { + cam_mul[3] = 0; + FORCC + if (fabs(imgdata.color.dng_levels.asshotneutral[c]) > 0.0001) + cam_mul[c] = 1 / imgdata.color.dng_levels.asshotneutral[c]; + } + } + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_BLACK); + if (sidx >= 0) + { + imgdata.color.dng_levels.dng_fblack = + tiff_ifd[sidx].dng_levels.dng_fblack; + imgdata.color.dng_levels.dng_black = + tiff_ifd[sidx].dng_levels.dng_black; + COPYARR(imgdata.color.dng_levels.dng_cblack, + tiff_ifd[sidx].dng_levels.dng_cblack); + COPYARR(imgdata.color.dng_levels.dng_fcblack, + tiff_ifd[sidx].dng_levels.dng_fcblack); + } + + + if (pifd >= 0) + { + sidx = IFDLEVELINDEX(pifd, LIBRAW_DNGFM_PREVIEWCS); + if (sidx >= 0) + imgdata.color.dng_levels.preview_colorspace = + tiff_ifd[sidx].dng_levels.preview_colorspace; + } + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_OPCODE2); + if (sidx >= 0) + meta_offset = tiff_ifd[sidx].opcode2_offset; + + sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_LINTABLE); + INT64 linoff = -1; + int linlen = 0; + if (sidx >= 0) + { + linoff = tiff_ifd[sidx].lineartable_offset; + linlen = tiff_ifd[sidx].lineartable_len; + } + + if (linoff >= 0 && linlen > 0) + { + INT64 pos = ftell(ifp); + fseek(ifp, linoff, SEEK_SET); + linear_table(linlen); + fseek(ifp, pos, SEEK_SET); + } + // Need to add curve too + } + /* Copy DNG black level to LibRaw's */ + if (load_raw == &LibRaw::lossy_dng_load_raw) + { + maximum = 0xffff; + FORC4 imgdata.color.linear_max[c] = imgdata.color.dng_levels.dng_whitelevel[c] = 0xffff; + } + else + { + maximum = imgdata.color.dng_levels.dng_whitelevel[0]; + } + black = imgdata.color.dng_levels.dng_black; + + if (tiff_samples == 2 && imgdata.color.dng_levels.dng_cblack[4] * imgdata.color.dng_levels.dng_cblack[5] * tiff_samples + == imgdata.color.dng_levels.dng_cblack[LIBRAW_CBLACK_SIZE - 1]) + { + unsigned ff = filters; + if (filters > 999 && colors == 3) + filters |= ((filters >> 2 & 0x22222222) | (filters << 2 & 0x88888888)) & + filters << 1; + + /* Special case, Fuji SuperCCD dng */ + int csum[4] = { 0,0,0,0 }, ccount[4] = { 0,0,0,0 }; + int i = 6 + shot_select; + for (unsigned row = 0; row < imgdata.color.dng_levels.dng_cblack[4]; row++) + for (unsigned col = 0; col < imgdata.color.dng_levels.dng_cblack[5]; col++) + { + csum[FC(row, col)] += imgdata.color.dng_levels.dng_cblack[i]; + ccount[FC(row, col)]++; + i += tiff_samples; + } + for (int c = 0; c < 4; c++) + if (ccount[c]) + imgdata.color.dng_levels.dng_cblack[c] += csum[c] / ccount[c]; + imgdata.color.dng_levels.dng_cblack[4] = imgdata.color.dng_levels.dng_cblack[5] = 0; + filters = ff; + } + else if (tiff_samples > 2 && tiff_samples <= 4 && imgdata.color.dng_levels.dng_cblack[4] * imgdata.color.dng_levels.dng_cblack[5] * tiff_samples + == imgdata.color.dng_levels.dng_cblack[LIBRAW_CBLACK_SIZE - 1]) + { + /* Special case, per_channel blacks in RepeatDim, average for per-channel */ + int csum[4] = { 0,0,0,0 }, ccount[4] = { 0,0,0,0 }; + int i = 6; + for (unsigned row = 0; row < imgdata.color.dng_levels.dng_cblack[4]; row++) + for (unsigned col = 0; col < imgdata.color.dng_levels.dng_cblack[5]; col++) + for (unsigned c = 0; c < tiff_samples && c < 4; c++) + { + csum[c] += imgdata.color.dng_levels.dng_cblack[i]; + ccount[c]++; + i++; + } + for (int c = 0; c < 4; c++) + if (ccount[c]) + imgdata.color.dng_levels.dng_cblack[c] += csum[c] / ccount[c]; + imgdata.color.dng_levels.dng_cblack[4] = imgdata.color.dng_levels.dng_cblack[5] = 0; + } + + memmove(cblack, imgdata.color.dng_levels.dng_cblack, sizeof(cblack)); + + if (iifd < (int)tiff_nifds && iifd >= 0) + { + int sidx = IFDLEVELINDEX(iifd, LIBRAW_DNGFM_LINEARRESPONSELIMIT); + if (sidx >= 0) + { + imgdata.color.dng_levels.LinearResponseLimit = + tiff_ifd[sidx].dng_levels.LinearResponseLimit; + if (imgdata.color.dng_levels.LinearResponseLimit > 0.1 && + imgdata.color.dng_levels.LinearResponseLimit <= 1.0) + { + // And approx promote it to linear_max: + int bl4 = 0, bl64 = 0; + for (int chan = 0; chan < colors && chan < 4; chan++) + bl4 += cblack[chan]; + bl4 /= LIM(colors, 1, 4); + + if (cblack[4] * cblack[5] > 0) + { + unsigned cnt = 0; + for (unsigned c = 0; c < 4096 && c < cblack[4] * cblack[5]; c++) + { + bl64 += cblack[c + 6]; + cnt++; + } + bl64 /= LIM(cnt, 1, 4096); + } + int rblack = black + bl4 + bl64; + for (int chan = 0; chan < colors && chan < 4; chan++) + imgdata.color.linear_max[chan] = + (maximum - rblack) * + imgdata.color.dng_levels.LinearResponseLimit + + rblack; + } + } + } + } +} + +void LibRaw::identify_finetune_pentax() +{ + if (makeIs(LIBRAW_CAMERAMAKER_Pentax) || + makeIs(LIBRAW_CAMERAMAKER_Samsung)) { + if (height == 2624 && + width == 3936) // Pentax K10D, Samsung GX10; + { + height = 2616; + width = 3896; + } + if (height == 3136 && + width == 4864) // Pentax K20D, Samsung GX20; + { + height = 3124; + width = 4688; + filters = 0x16161616; + } + } + + if (makeIs(LIBRAW_CAMERAMAKER_Pentax)) { + if ((width == 4352) && + ((unique_id == PentaxID_K_r) || + (unique_id == PentaxID_K_x))) + { + width = 4309; + filters = 0x16161616; + } + if ((width >= 4960) && + ((unique_id == PentaxID_K_5) || + (unique_id == PentaxID_K_5_II) || + (unique_id == PentaxID_K_5_II_s))) + { + left_margin = 10; + width = 4950; + filters = 0x16161616; + } + if ((width == 6080) && (unique_id == PentaxID_K_70)) + { + height = 4016; + top_margin = 32; + width = 6020; + left_margin = 60; + } + if ((width == 4736) && (unique_id == PentaxID_K_7)) + { + height = 3122; + width = 4684; + filters = 0x16161616; + top_margin = 2; + } + if ((width == 6080) && (unique_id == PentaxID_K_3_II)) + { + left_margin = 4; + width = 6040; + } + if ((width == 6112) && (unique_id == PentaxID_KP)) + { + // From DNG, maybe too strict + left_margin = 54; + top_margin = 28; + width = 6028; + height = raw_height - top_margin; + } + if ((width == 6080) && (unique_id == PentaxID_K_3)) + { + left_margin = 4; + width = 6040; + } + if ((width == 7424) && (unique_id == PentaxID_645D)) + { + height = 5502; + width = 7328; + filters = 0x61616161; + top_margin = 29; + left_margin = 48; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Ricoh) && + (height == 3014) && (width == 4096)) // Ricoh GX200 + width = 4014; +} + +void LibRaw::identify_finetune_by_filesize(int fsize) +{ + + if (fsize == 4771840) + { // hack Nikon 3mpix: E880, E885, E990, E995; + // Olympus C-3030Z + if (!timestamp && nikon_e995()) + strcpy(model, "E995"); + } + else if (fsize == 2940928) + { // hack Nikon 2mpix: E2100, E2500 + if (!timestamp && !nikon_e2100()) + strcpy(model, "E2500"); + } + else if (fsize == 4775936) + { // hack Nikon 3mpix: E3100, E3200, E3500, E3700; + // Pentax "Optio 33WR"; + // Olympus C-740UZ + if (!timestamp) + nikon_3700(); + } + else if (fsize == 5869568) + { // hack Nikon 4mpix: E4300; + // hack Minolta "DiMAGE Z2" + if (!timestamp && minolta_z2()) + { + maker_index = LIBRAW_CAMERAMAKER_Minolta; + strcpy(make, "Minolta"); + strcpy(model, "DiMAGE Z2"); + } + } +} + +void LibRaw::identify_finetune_dcr(char head[64], int fsize, int flen) +{ + static const short pana[][6] = { + // raw_width, raw_height, left_margin, top_margin, width_increment, + // height_increment + {3130, 1743, 4, 0, -6, 0}, /* 00 */ + {3130, 2055, 4, 0, -6, 0}, /* 01 */ + {3130, 2319, 4, 0, -6, 0}, /* 02 DMC-FZ8 */ + {3170, 2103, 18, 0, -42, 20}, /* 03 */ + {3170, 2367, 18, 13, -42, -21}, /* 04 */ + {3177, 2367, 0, 0, -1, 0}, /* 05 DMC-L1 */ + {3304, 2458, 0, 0, -1, 0}, /* 06 DMC-FZ30 */ + {3330, 2463, 9, 0, -5, 0}, /* 07 DMC-FZ18 */ + {3330, 2479, 9, 0, -17, 4}, /* 08 */ + {3370, 1899, 15, 0, -44, 20}, /* 09 */ + {3370, 2235, 15, 0, -44, 20}, /* 10 */ + {3370, 2511, 15, 10, -44, -21}, /* 11 */ + {3690, 2751, 3, 0, -8, -3}, /* 12 DMC-FZ50 */ + {3710, 2751, 0, 0, -3, 0}, /* 13 DMC-L10 */ + {3724, 2450, 0, 0, 0, -2}, /* 14 */ + {3770, 2487, 17, 0, -44, 19}, /* 15 */ + {3770, 2799, 17, 15, -44, -19}, /* 16 */ + {3880, 2170, 6, 0, -6, 0}, /* 17 DMC-LX1 */ + {4060, 3018, 0, 0, 0, -2}, /* 18 DMC-FZ35, DMC-FZ38 */ + {4290, 2391, 3, 0, -8, -1}, /* 19 DMC-LX2 */ + {4330, 2439, 17, 15, -44, -19}, /* 20 "D-LUX 3" */ + {4508, 2962, 0, 0, -3, -4}, /* 21 */ + {4508, 3330, 0, 0, -3, -6}, /* 22 */ + {10480, 7794, 0, 0, -2, 0}, /* 23: G9 in high-res */ + }; + int i,c; + struct jhead jh; + + if (makeIs(LIBRAW_CAMERAMAKER_Canon) && !tiff_flip && imCanon.MakernotesFlip) + { + tiff_flip = imCanon.MakernotesFlip; + } + + else if (makeIs(LIBRAW_CAMERAMAKER_Nikon)) + { + if (!load_raw) + load_raw = &LibRaw::packed_load_raw; + if (model[0] == 'E') // Nikon E8800, E8700, E8400, E5700, E5400, E5000, + // others are diag hacks? + load_flags |= !data_offset << 2 | 2; + } + /* Set parameters based on camera name (for non-DNG files). */ + + /* Always 512 for arw2_load_raw */ + else if (makeIs(LIBRAW_CAMERAMAKER_Sony) && + (raw_width > 3888) && !black && !cblack[0]) + { + black = (load_raw == &LibRaw::sony_arw2_load_raw) + ? 512 + : (128 << (tiff_bps - 12)); + } + + if (is_foveon) { + if (height * 2 < width) + pixel_aspect = 0.5; + if (height > width) + pixel_aspect = 2; + filters = 0; + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Pentax)) { + if ((unique_id == PentaxID_K_1) || + (unique_id == PentaxID_K_1_Mark_II)) { + top_margin = 18; + height = raw_height - top_margin; + if (raw_width == 7392) { + left_margin = 6; + width = 7376; + } + + } + else if (unique_id == PentaxID_Optio_S_V101) { // (fsize == 3178560) + cam_mul[0] *= 4; + cam_mul[2] *= 4; + + } + else if (unique_id == PentaxID_Optio_33WR) { // (fsize == 4775936) + flip = 1; + filters = 0x16161616; + + } + else if (unique_id == PentaxID_staristD) { + load_raw = &LibRaw::unpacked_load_raw; + data_error = -1; + + } + else if (unique_id == PentaxID_staristDS) { + height -= 2; + } + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Canon)) { + if (tiff_bps == 15) { // Canon sRAW + if (width == 3344) + width = 3272; + else if (width == 3872) + width = 3866; + + if (height > width) { + SWAP(height, width); + SWAP(raw_height, raw_width); + } + if (width == 7200 && + height == 3888) { // Canon EOS 5DS (R); + raw_width = width = 6480; + raw_height = height = 4320; + } + filters = 0; + tiff_samples = colors = 3; + load_raw = &LibRaw::canon_sraw_load_raw; + } + + if (!strcmp(normalized_model, "PowerShot 600")) { + height = 613; + width = 854; + raw_width = 896; + colors = 4; + filters = 0xe1e4e1e4; + load_raw = &LibRaw::canon_600_load_raw; + + } + else if (!strcmp(normalized_model, "PowerShot A5") || + !strcmp(normalized_model, "PowerShot A5 Zoom")) { + height = 773; + width = 960; + raw_width = 992; + pixel_aspect = 256 / 235.0; + filters = 0x1e4e1e4e; + goto canon_a5; + + } + else if (!strcmp(normalized_model, "PowerShot A50")) { + height = 968; + width = 1290; + raw_width = 1320; + filters = 0x1b4e4b1e; + goto canon_a5; + + } + else if (!strcmp(normalized_model, "PowerShot Pro70")) { + height = 1024; + width = 1552; + filters = 0x1e4b4e1b; + canon_a5: + colors = 4; + tiff_bps = 10; + load_raw = &LibRaw::packed_load_raw; + load_flags = 40; + + } + else if (!strcmp(normalized_model, "PowerShot Pro90 IS") || + !strcmp(normalized_model, "PowerShot G1")) { + colors = 4; + filters = 0xb4b4b4b4; + + } + else if (!strcmp(normalized_model, "PowerShot A610")) { // chdk hack + if (canon_s2is()) + strcpy(model + 10, "S2 IS"); // chdk hack + + } + else if (!strcmp(normalized_model, "PowerShot SX220 HS")) { // chdk hack + mask[1][3] = -4; + top_margin = 16; + left_margin = 92; + + } + else if (!strcmp(normalized_model, "PowerShot S120")) { // chdk hack + raw_width = 4192; + raw_height = 3062; + width = 4022; + height = 3016; + mask[0][0] = top_margin = 31; + mask[0][2] = top_margin + height; + left_margin = 120; + mask[0][1] = 23; + mask[0][3] = 72; + + } + else if (!strcmp(normalized_model, "PowerShot G16")) { + mask[0][0] = 0; + mask[0][2] = 80; + mask[0][1] = 0; + mask[0][3] = 16; + top_margin = 29; + left_margin = 120; + width = raw_width - left_margin - 48; + height = raw_height - top_margin - 14; + + } + else if (!strcmp(normalized_model, "PowerShot SX50 HS")) { + top_margin = 17; + } + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Nikon)) { + if (!strcmp(model, "D1")) + { + imgdata.other.analogbalance[0] = cam_mul[0]; + imgdata.other.analogbalance[2] = cam_mul[2]; + imgdata.other.analogbalance[1] = imgdata.other.analogbalance[3] = + cam_mul[1]; + cam_mul[0] = cam_mul[1] = cam_mul[2] = 1.0f; + } + + else if (!strcmp(model, "D1X")) + { + width -= 4; + pixel_aspect = 0.5; + } + else if (!strcmp(model, "D40X") || + !strcmp(model, "D60") || + !strcmp(model, "D80") || + !strcmp(model, "D3000")) + { + height -= 3; + width -= 4; + } + else if (!strcmp(model, "D3") || + !strcmp(model, "D3S") || + !strcmp(model, "D700")) + { + width -= 4; + left_margin = 2; + } + else if (!strcmp(model, "D3100")) + { + width -= 28; + left_margin = 6; + } + else if (!strcmp(model, "D5000") || + !strcmp(model, "D90")) + { + width -= 42; + } + else if (!strcmp(model, "D5100") || + !strcmp(model, "D7000") || + !strcmp(model, "COOLPIX A")) + { + width -= 44; + } + else if (!strcmp(model, "D3200") || + !strcmp(model, "D600") || + !strcmp(model, "D610") || + !strncmp(model, "D800", 4)) // Nikons: D800, D800E + { + width -= 46; + } + else if (!strcmp(model, "D4") || + !strcmp(model, "Df")) + { + width -= 52; + left_margin = 2; + } + else if (!strcmp(model, "D500")) + { + // Empty - to avoid width-1 below + } + else if (!strncmp(model, "D40", 3) || + !strncmp(model, "D50", 3) || + !strncmp(model, "D70", 3)) + { + width--; + } + else if (!strcmp(model, "D100")) + { + if (load_flags) // compressed NEF + raw_width = (width += 3) + 3; + } + else if (!strcmp(model, "D200")) + { + left_margin = 1; + width -= 4; + filters = 0x94949494; + } + else if (!strncmp(model, "D2H", 3)) // Nikons: D2H, D2Hs + { + left_margin = 6; + width -= 14; + } + else if (!strncmp(model, "D2X", 3)) // Nikons: D2X, D2Xs + { + if (width == 3264) // in-camera Hi-speed crop: On + width -= 32; + else + width -= 8; + } + else if (!strncmp(model, "D300", 4)) // Nikons: D300, D300s + { + width -= 32; + } + else if (raw_width == 4032) // Nikon "COOLPIX P7700", "COOLPIX P7800", + // "COOLPIX P330", "COOLPIX P340" + { + if (!strcmp(normalized_model, "COOLPIX P7700")) + { + maximum = 65504; + load_flags = 0; + } + else if (!strcmp(normalized_model, "COOLPIX P7800")) + { + maximum = 65504; + load_flags = 0; + } + else if (!strcmp(model, "COOLPIX P340")) + { + load_flags = 0; + } + } + else if (!strncmp(model, "COOLPIX P", 9) && + raw_width != 4032) // Nikon "COOLPIX P1000", "COOLPIX P6000", + // "COOLPIX P7000", "COOLPIX P7100" + { + load_flags = 24; + filters = 0x94949494; + /* the following 'if' is most probably obsolete, because we now read black + * level from metadata */ + if ((model[9] == '7') && /* P7000, P7100 */ + ((iso_speed >= 400) || (iso_speed == 0)) && + !strstr(software, "V1.2")) /* v. 1.2 seen for P7000 only */ + black = 255; + } + else if (!strncmp(model, "COOLPIX B700", 12)) + { + load_flags = 24; + } + else if (!strncmp(model, "1 ", + 2)) // Nikons: "1 AW1", "1 J1", "1 J2", "1 J3", "1 J4", + // "1 J5", "1 S1", "1 S2", "1 V1", "1 V2", "1 V3" + { + height -= 2; + } + else if (fsize == 1581060) // hack Nikon 1mpix: E900 + { + simple_coeff(3); + pre_mul[0] = 1.2085; + pre_mul[1] = 1.0943; + pre_mul[3] = 1.1103; + } + else if ((fsize == 4771840) && // hack Nikon 3mpix: E880, E885, E990 + strcmp(model, "E995")) // but not E995 + { + filters = 0xb4b4b4b4; + simple_coeff(3); + pre_mul[0] = 1.196; + pre_mul[1] = 1.246; + pre_mul[2] = 1.018; + } + else if ((fsize == 4775936) && // hack Nikon 3mpix: E3100, E3200, E3500 + (atoi(model + 1) < 3700)) // but not E3700; + { + filters = 0x49494949; + } + else if (fsize == 5869568) // hack Nikon 4mpix: E4300; + { + load_flags = 6; + } + else if (!strcmp(model, "E2500")) + { + height -= 2; + load_flags = 6; + colors = 4; + filters = 0x4b4b4b4b; + } + } + + else if (makeIs(LIBRAW_CAMERAMAKER_Olympus)) { + if (OlyID == OlyID_C_740UZ) { // (fsize == 4775936) + i = find_green(12, 32, 1188864, 3576832); + c = find_green(12, 32, 2383920, 2387016); + if (abs(i) < abs(c)) { + SWAP(i, c); + load_flags = 24; + } + if (i < 0) + filters = 0x61616161; + } + else if (OlyID == OlyID_C_770UZ) { + height = 1718; + width = 2304; + filters = 0x16161616; + load_raw = &LibRaw::packed_load_raw; + load_flags = 30; + } + else { + height += height & 1; + if (exif_cfa) + filters = exif_cfa; + + if (width == 4100) // Olympus E-PL2, E-PL1, E-P2, E-P1, E-620, E-600, E-5, E-30; + width -= 4; + + if (width == 4080) // Olympus E-PM1, E-PL3, E-P3; + width -= 24; + + if (width == 10400) // Olympus PEN-F, E-M1-II, E-M1-III, E-M1X + width -= 12; + + if (width == 8200) // E-M1-III in 50Mp mode, E-M1X + width -= 30; + + if (width == 9280) { // Olympus E-M5 Mark II; + width -= 6; + height -= 6; + } + + if (load_raw == &LibRaw::unpacked_load_raw) + load_flags = 4; + tiff_bps = 12; + if ((OlyID == OlyID_E_300) || + (OlyID == OlyID_E_500)) { + width -= 20; + if (load_raw == &LibRaw::unpacked_load_raw) { + maximum = 0xfc3; + memset(cblack, 0, sizeof cblack); + } + + } + else if (OlyID == OlyID_STYLUS_1) { + width -= 16; + maximum = 0xfff; + + } + else if (OlyID == OlyID_E_330) { + width -= 30; + if (load_raw == &LibRaw::unpacked_load_raw) + maximum = 0xf79; + + } + else if (OlyID == OlyID_SP_550UZ) { + thumb_length = flen - (thumb_offset = 0xa39800); + thumb_height = 480; + thumb_width = 640; + + } + else if (OlyID == OlyID_TG_4) { + width -= 16; + + } + else if ((OlyID == OlyID_TG_5) || + (OlyID == OlyID_TG_6)) { + width -= 26; + } + } + + } + else if (makeIs(LIBRAW_CAMERAMAKER_RoverShot) && + (fsize == 6291456)) { // RoverShot 3320AF + fseek(ifp, 0x300000, SEEK_SET); + if ((order = guess_byte_order(0x10000)) == 0x4d4d) + { + height -= (top_margin = 16); + width -= (left_margin = 28); + maximum = 0xf5c0; + strcpy(make, "ISG"); + model[0] = 0; + } + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Fujifilm)) { + if (!strcmp(model, "S2Pro")) + { + height = 2144; + width = 2880; + flip = 6; + } + else if (load_raw != &LibRaw::packed_load_raw && strncmp(model, "X-", 2) && + filters >= 1000) // Bayer and not an X-model + maximum = (is_raw == 2 && shot_select) ? 0x2f00 : 0x3e00; + + if (FujiCropMode == 1) + { // FF crop on GFX + width = raw_width; + height = raw_height; + } + else if (FujiCropMode == 4) + { /* electronic shutter, high speed mode (1.25x crop) */ + height = raw_height; + } + + top_margin = (raw_height >= height) ? (raw_height - height) >> 2 << 1 : 0; + left_margin = (raw_width >= width) ? (raw_width - width) >> 2 << 1 : 0; + + if (!strcmp(model, "X-T3") || !strcmp(model, "X-T4") || !strcmp(model, "X100V") || !strcmp(model, "X-T30") || !strcmp(model, "X-Pro3")) + { + top_margin = 0; + if (FujiCropMode == 0) + { + top_margin = 6; + height = 4170; + left_margin = 0; + width = 6246; + } + else if (FujiCropMode == 4) + { /* electronic shutter, high speed mode (1.25x crop) */ + left_margin = 624; + width = 5004; + } + } + + if (width == 2848 || // Fujifilm X-S1, X10, XF1 + width == 3664) // Fujifilm "HS10 HS11" + filters = 0x16161616; + + if (width == 4032 || // Fujifilm X20, X30, XQ1, XQ2 + width == 4952) // Fujifilm X-A1, X-A2, X-E1, X-M1, X-Pro1 + left_margin = 0; + + if (width == 3328 && + (width -= 66)) // Fujifilm F550EXR, F600EXR, F770EXR, F800EXR, F900EXR, + // HS20EXR, HS30EXR, HS33EXR, HS50EXR + left_margin = 34; + + if (width == 4936) // Fujifilm X-E2S, X-E2, X-T10, X-T1, X100S, X100T, X70 + left_margin = 4; + + if (width == 6032) // Fujifilm X100F, X-T2, X-T20, X-Pro2, X-H1, X-E3 + left_margin = 0; + + if (!strcmp(normalized_model, "DBP for GX680")) + { + /* + 7712 2752 -> 5504 3856 + */ + + /* + width = 688; + height = 30848; + raw_width = 688; + raw_height = 30848; + */ + + raw_width = 5504; + raw_height = 3856; + left_margin = 32; + top_margin = 8; + width = raw_width - left_margin - 32; + height = raw_height - top_margin - 8; + + load_raw = &LibRaw::unpacked_load_raw_FujiDBP; + // maximum = 0x0fff; + filters = 0x16161616; + load_flags = 0; + flip = 6; + } + + if (!strcmp(model, "HS50EXR") || !strcmp(model, "F900EXR")) + { + width += 2; + left_margin = 0; + filters = 0x16161616; + } + if (!strncmp(model, "GFX 50", 6)) + { + left_margin = 0; + top_margin = 0; + } + if (!strncmp(model, "GFX 100", 7)) + { + left_margin = 0; + width = raw_width - 146; + height = raw_height - (top_margin = 2); + if (tiff_bps == 16) + maximum = 0xffff; + } + if (!strcmp(normalized_model, "S5100")) + { + height -= (top_margin = 6); + } + if (fuji_layout) + raw_width *= is_raw; + if (filters == 9) + FORC(36) + ((char *)xtrans)[c] = + xtrans_abs[(c / 6 + top_margin) % 6][(c + left_margin) % 6]; + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Konica)) { + if (!strcmp(model, "KD-400Z")) { + height = 1712; + width = 2312; + raw_width = 2336; + goto konica_400z; + } + else if (!strcmp(model, "KD-510Z")) { + goto konica_510z; + } + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Minolta)) { + if (fsize == 5869568) { // hack Minolta "DiMAGE Z2" + load_flags = 30; + } + + if (!load_raw && (maximum = 0xfff)) + { + load_raw = &LibRaw::unpacked_load_raw; + } + if (!strncmp(model, "DiMAGE A", + 8)) // Minolta "DiMAGE A1", "DiMAGE A2", "DiMAGE A200" + { + if (!strcmp(model, "DiMAGE A200")) + filters = 0x49494949; + tiff_bps = 12; + load_raw = &LibRaw::packed_load_raw; + } + else if (!strncmp(normalized_model, "DG-", 3)) + { + load_raw = &LibRaw::packed_load_raw; + } + else if (!strncmp(model, "DiMAGE G", + 8)) // hack Minolta "DiMAGE G400", "DiMAGE G500", + // "DiMAGE G530", "DiMAGE G600" + { + if (model[8] == '4') // DiMAGE G400 + { + height = 1716; + width = 2304; + } + else if (model[8] == '5') // DiMAGE G500 / G530 + { + konica_510z: + height = 1956; + width = 2607; + raw_width = 2624; + } + else if (model[8] == '6') // DiMAGE G600 + { + height = 2136; + width = 2848; + } + data_offset += 14; + filters = 0x61616161; + konica_400z: + load_raw = &LibRaw::unpacked_load_raw; + maximum = 0x3df; + order = 0x4d4d; + } + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Samsung)) { + if (raw_width == 4704) // Samsung NX100, NX10, NX11, + { + height -= top_margin = 8; + width -= 2 * (left_margin = 8); + load_flags = 32; + } + else if (!strcmp(model, "NX3000")) // Samsung NX3000; raw_width: 5600 + { + top_margin = 38; + left_margin = 92; + width = 5456; + height = 3634; + filters = 0x61616161; + colors = 3; + } + else if (raw_height == 3714) // Samsung NX2000, NX300M, NX300, NX30, EK-GN120 + { + height -= top_margin = 18; + left_margin = raw_width - (width = 5536); + if (raw_width != 5600) + left_margin = top_margin = 0; + filters = 0x61616161; + colors = 3; + } + else if (raw_width == 5632) // Samsung NX1000, NX200, NX20, NX210 + { + order = 0x4949; + height = 3694; + top_margin = 2; + width = 5574 - (left_margin = 32 + tiff_bps); + if (tiff_bps == 12) + load_flags = 80; + } + else if (raw_width == 5664) // Samsung "NX mini" + { + height -= top_margin = 17; + left_margin = 96; + width = 5544; + filters = 0x49494949; + } + else if (raw_width == 6496) // Samsung NX1, NX500 + { + filters = 0x61616161; + if (!black && !cblack[0] && !cblack[1] && !cblack[2] && !cblack[3]) + black = 1 << (tiff_bps - 7); + } + else if (!strcmp(model, "EX1")) // Samsung EX1; raw_width: 3688 + { + order = 0x4949; + height -= 20; + top_margin = 2; + if ((width -= 6) > 3682) + { + height -= 10; + width -= 46; + top_margin = 8; + } + } + else if (!strcmp(model, "WB2000")) // Samsung WB2000; raw_width: 3728 + { + order = 0x4949; + height -= 3; + top_margin = 2; + if ((width -= 10) > 3718) + { + height -= 28; + width -= 56; + top_margin = 8; + } + } + else if (!strcmp(model, "WB550")) // Samsung WB550; raw_width: 4000 + { + order = 0x4949; + } + else if (!strcmp(model, "EX2F")) // Samsung EX2F; raw_width: 4176 + { + height = 3030; + width = 4040; + top_margin = 15; + left_margin = 24; + order = 0x4949; + filters = 0x49494949; + load_raw = &LibRaw::unpacked_load_raw; + } + } + + else if (makeIs(LIBRAW_CAMERAMAKER_ST_Micro) && !strcmp(model, "STV680 VGA")) + { + black = 16; + } + else if (!strcmp(model, "N95")) + { + height = raw_height - (top_margin = 2); + } + else if (!strcmp(model, "640x480")) + { + gamma_curve(0.45, 4.5, 1, 255); + } + else if (makeIs(LIBRAW_CAMERAMAKER_Hasselblad)) + { + if (load_raw == &LibRaw::lossless_jpeg_load_raw) + load_raw = &LibRaw::hasselblad_load_raw; + + if ((imHassy.SensorCode == 4) && !strncmp(model, "V96C", 4)) { // Hasselblad V96C + strcpy(model, "V96C"); + strcpy(normalized_model, model); + height -= (top_margin = 6); + width -= (left_margin = 3) + 7; + filters = 0x61616161; + + } + else if ((imHassy.SensorCode == 9) && imHassy.uncropped) { // various Hasselblad '-39' + height = 5444; + width = 7248; + top_margin = 4; + left_margin = 7; + filters = 0x61616161; + + } + else if ((imHassy.SensorCode == 13) && imHassy.uncropped) { // Hasselblad H4D-40, H5D-40 + height -= 84; + width -= 82; + top_margin = 4; + left_margin = 41; + filters = 0x61616161; + + } + else if ((imHassy.SensorCode == 11) && imHassy.uncropped) { // Hasselblad H5D-50 + height -= 84; + width -= 82; + top_margin = 4; + left_margin = 41; + filters = 0x61616161; + + } + else if ((imHassy.SensorCode == 15) && + !imHassy.SensorSubCode && // Hasselblad H5D-50c + imHassy.uncropped) { + left_margin = 52; + top_margin = 100; + width = 8272; + height = 6200; + black = 256; + + } + else if ((imHassy.SensorCode == 15) && + (imHassy.SensorSubCode == 2) && // various Hasselblad X1D cameras + imHassy.uncropped) { + top_margin = 96; + height -= 96; + left_margin = 48; + width -= 106; + maximum = 0xffff; + tiff_bps = 16; + + } + else if ((imHassy.SensorCode == 12) && imHassy.uncropped) { // Hasselblad H4D-60 + if (black > 500) { // (imHassy.format == LIBRAW_HF_FFF) + top_margin = 12; + left_margin = 44; + width = 8956; + height = 6708; + memset(cblack, 0, sizeof(cblack)); + black = 512; + } + else { // (imHassy.format == LIBRAW_HF_3FR) + top_margin = 8; + left_margin = 40; + width = 8964; + height = 6716; + black += load_flags = 256; + maximum = 0x8101; + } + + } + else if ((imHassy.SensorCode == 17) && imHassy.uncropped) { // Hasselblad H6D-100c, A6D-100c + left_margin = 64; + width = 11608; + top_margin = 108; + height = raw_height - top_margin; + } + + if (tiff_samples > 1) + { + is_raw = tiff_samples + 1; + if (!shot_select && !half_size) + filters = 0; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Sinar)) + { + if (!load_raw) + load_raw = &LibRaw::unpacked_load_raw; + if (is_raw > 1 && !shot_select) + filters = 0; + maximum = 0x3fff; + } + + if (load_raw == &LibRaw::sinar_4shot_load_raw) + { + if (is_raw > 1 && !shot_select) + filters = 0; + } + else if (makeIs(LIBRAW_CAMERAMAKER_Leaf)) + { + maximum = 0x3fff; + fseek(ifp, data_offset, SEEK_SET); + if (ljpeg_start(&jh, 1) && jh.bits == 15) + maximum = 0x1fff; + if (tiff_samples > 1) + filters = 0; + if (tiff_samples > 1 || tile_length < raw_height) + { + load_raw = &LibRaw::leaf_hdr_load_raw; + raw_width = tile_width; + } + if ((width | height) == 2048) + { + if (tiff_samples == 1) + { + filters = 1; + strcpy(cdesc, "RBTG"); + strcpy(model, "CatchLight"); + strcpy(normalized_model, model); + top_margin = 8; + left_margin = 18; + height = 2032; + width = 2016; + } + else + { + strcpy(model, "DCB2"); + strcpy(normalized_model, model); + top_margin = 10; + left_margin = 16; + height = 2028; + width = 2022; + } + } + else if (width + height == 3144 + 2060) + { + if (!model[0]) + { + strcpy(model, "Cantare"); + strcpy(normalized_model, model); + } + if (width > height) + { + top_margin = 6; + left_margin = 32; + height = 2048; + width = 3072; + filters = 0x61616161; + } + else + { + left_margin = 6; + top_margin = 32; + width = 2048; + height = 3072; + filters = 0x16161616; + } + if (!cam_mul[0] || model[0] == 'V') + filters = 0; + else + is_raw = tiff_samples; + } + else if (width == 2116) // Leaf "Valeo 6" + { + strcpy(model, "Valeo 6"); + strcpy(normalized_model, model); + height -= 2 * (top_margin = 30); + width -= 2 * (left_margin = 55); + filters = 0x49494949; + } + else if (width == 3171) // Leaf "Valeo 6" + { + strcpy(model, "Valeo 6"); + strcpy(normalized_model, model); + height -= 2 * (top_margin = 24); + width -= 2 * (left_margin = 24); + filters = 0x16161616; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Panasonic)) + { + if (raw_width > 0 && + ((flen - data_offset) / (raw_width * 8 / 7) == raw_height)) + load_raw = &LibRaw::panasonic_load_raw; + if (!load_raw) + { + load_raw = &LibRaw::unpacked_load_raw; + load_flags = 4; + } + zero_is_bad = 1; + if ((height += 12) > raw_height) + height = raw_height; + for (i = 0; i < int(sizeof pana / sizeof *pana); i++) + if (raw_width == pana[i][0] && raw_height == pana[i][1]) + { + left_margin = pana[i][2]; + top_margin = pana[i][3]; + width += pana[i][4]; + height += pana[i][5]; + } + if (!tiff_bps && pana_bpp >= 12 && pana_bpp <= 14) + tiff_bps = pana_bpp; + + filters = 0x01010101U * + (uchar) "\x94\x61\x49\x16"[((filters - 1) ^ (left_margin & 1) ^ + (top_margin << 1)) & + 3]; + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Contax) && + !strcmp(model, "N Digital")) { + height = 2047; + width = 3072; + filters = 0x61616161; + data_offset = 0x1a00; + load_raw = &LibRaw::packed_load_raw; + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Sony)) { + if (!strcmp(model, "DSC-F828")) { // Sony DSC-F828 + width = 3288; + left_margin = 5; + mask[1][3] = -17; + data_offset = 862144; + load_raw = &LibRaw::sony_load_raw; + filters = 0x9c9c9c9c; + colors = 4; + strcpy(cdesc, "RGBE"); + + } + else if (!strcmp(model, "DSC-V3")) { // Sony DSC-V3 + width = 3109; + left_margin = 59; + mask[0][1] = 9; + data_offset = 787392; + load_raw = &LibRaw::sony_load_raw; + + } + else if (raw_width == 3984) { // Sony DSC-R1; + width = 3925; + order = 0x4d4d; + + } + else if (raw_width == 4288) { // Sony ILCE-7S, ILCE-7SM2, DSLR-A700, DSLR-A500; + width -= 32; + + } + else if (raw_width == 4600) { // Sony DSLR-A290, DSLR-A350, DSLR-A380; + if (!strcmp(model, "DSLR-A350")) + height -= 4; + black = 0; + + } + else if (raw_width == 4928) { + // Sony DSLR-A580, NEX-C3, SLT-A35, DSC-HX99, SLT-A55, + // NEX-5N, SLT-A37, SLT-A57, NEX-F3, NEX-6, NEX-5R, NEX-3N, NEX-5T; + if (height < 3280) + width -= 8; + + } + else if (raw_width == 5504) { + // Sony ILCE-3000, SLT-A58, DSC-RX100M3, ILCE-QX1, + // DSC-RX10M4, DSC-RX100M6, DSC-RX100, DSC-RX100M2, DSC-RX10, + // ILCE-5000, DSC-RX100M4, DSC-RX10M2, DSC-RX10M3, + // DSC-RX100M5, DSC-RX100M5A; + width -= height > 3664 ? 8 : 32; + + } + else if (raw_width == 6048) { + // Sony SLT-A65, DSC-RX1, SLT-A77, DSC-RX1, ILCA-77M2, + // ILCE-7M3, NEX-7, SLT-A99, ILCE-7, DSC-RX1R, ILCE-6000, + // ILCE-5100, ILCE-7M2, ILCA-68, ILCE-6300, ILCE-9, + // ILCE-6500, ILCE-6400; + width -= 24; + if (strstr(normalized_model, "RX1") || + strstr(normalized_model, "A99")) + width -= 6; + + } + else if (raw_width == 7392) { // Sony ILCE-7R; + width -= 30; + + } + else if (raw_width == 8000) { + // Sony ILCE-7RM2, ILCE-7RM2, ILCE-7RM3, DSC-RX1RM2, ILCA-99M2; + width -= 32; + + } + else if (raw_width == 9600) { // Sony ILCE-7RM4 + width -= 32; + + } + else if (!strcmp(model, "DSLR-A100")) { + if (width == 3880) { + height--; + width = ++raw_width; + } + else { + height -= 4; + width -= 4; + order = 0x4d4d; + load_flags = 2; + } + filters = 0x61616161; + } + } + + else if (!strcmp(model, "PIXL")) { + height -= top_margin = 4; + width -= left_margin = 32; + gamma_curve(0, 7, 1, 255); + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Kodak)) { + + if (!strncasecmp(model, "EasyShare", 9)) { + data_offset = data_offset < 0x15000 ? 0x15000 : 0x17000; + load_raw = &LibRaw::packed_load_raw; + + } + else if (!strcmp(model, "C603") || + !strcmp(model, "C330") || + !strcmp(model, "12MP")) { + order = 0x4949; + if (filters && data_offset) { + fseek(ifp, data_offset < 4096 ? 168 : 5252, SEEK_SET); + read_shorts(curve, 256); + } + else + gamma_curve(0, 3.875, 1, 255); + + load_raw = filters ? &LibRaw::eight_bit_load_raw + : strcmp(model, "C330") ? &LibRaw::kodak_c603_load_raw + : &LibRaw::kodak_c330_load_raw; + load_flags = tiff_bps > 16; + tiff_bps = 8; + + } + else { + if (!strncmp(model, "NC2000", 6) || + !strncmp(model, "EOSDCS", 6) || + !strncmp(model, "DCS4", 4)) { + width -= 4; + left_margin = 2; + + } + else if (!strcmp(model, "DCS660M")) { + black = 214; + + } + else if (!strcmp(model, "EOS D2000C")) { + filters = 0x61616161; + if (!black) black = curve[200]; + } + + if (filters == UINT_MAX) filters = 0x61616161; + + if (!strcmp(model + 4, "20X")) + strcpy(cdesc, "MYCY"); + if (!strcmp(model, "DC25")) { + data_offset = 15424; + } + + if (!strncmp(model, "DC2", 3)) { + raw_height = 2 + (height = 242); + if (!strncmp(model, "DC290", 5)) + iso_speed = 100; + if (!strncmp(model, "DC280", 5)) + iso_speed = 70; + if (flen < 100000) { + raw_width = 256; + width = 249; + pixel_aspect = (4.0 * height) / (3.0 * width); + } + else { + raw_width = 512; + width = 501; + pixel_aspect = (493.0 * height) / (373.0 * width); + } + top_margin = left_margin = 1; + colors = 4; + filters = 0x8d8d8d8d; + simple_coeff(1); + pre_mul[1] = 1.179; + pre_mul[2] = 1.209; + pre_mul[3] = 1.036; + load_raw = &LibRaw::eight_bit_load_raw; + + } + else if (!strcmp(model, "DC40")) { + height = 512; + width = 768; + data_offset = 1152; + load_raw = &LibRaw::kodak_radc_load_raw; + tiff_bps = 12; + FORC4 cam_mul[c] = 1.0f; + + } + else if (!strcmp(model, "DC50")) { + height = 512; + width = 768; + iso_speed = 84; + data_offset = 19712; + load_raw = &LibRaw::kodak_radc_load_raw; + FORC4 cam_mul[c] = 1.0f; + + } + else if (!strcmp(model, "DC120")) { + raw_height = height = 976; + raw_width = width = 848; + iso_speed = 160; + pixel_aspect = height / 0.75 / width; + load_raw = tiff_compress == 7 ? &LibRaw::kodak_jpeg_load_raw + : &LibRaw::kodak_dc120_load_raw; + + } + else if (!strcmp(model, "DCS200")) { + thumb_height = 128; + thumb_width = 192; + thumb_offset = 6144; + thumb_misc = 360; + iso_speed = 140; + write_thumb = &LibRaw::layer_thumb; + black = 17; + } + } + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Logitech) && + !strcmp(model, "Fotoman Pixtura")) { + height = 512; + width = 768; + data_offset = 3632; + load_raw = &LibRaw::kodak_radc_load_raw; + filters = 0x61616161; + simple_coeff(2); + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Apple) && + !strncmp(model, "QuickTake", 9)) { + if (head[5]) + strcpy(model + 10, "200"); + fseek(ifp, 544, SEEK_SET); + height = get2(); + width = get2(); + data_offset = (get4(), get2()) == 30 ? 738 : 736; + if (height > width) { + SWAP(height, width); + fseek(ifp, data_offset - 6, SEEK_SET); + flip = ~get2() & 3 ? 5 : 6; + } + filters = 0x61616161; + + } + else if (makeIs(LIBRAW_CAMERAMAKER_Rollei) && + !load_raw) { + switch (raw_width) { + case 1316: // Rollei d530flex + height = 1030; + width = 1300; + top_margin = 1; + left_margin = 6; + break; + case 2568: + height = 1960; + width = 2560; + top_margin = 2; + left_margin = 8; + } + filters = 0x16161616; + load_raw = &LibRaw::rollei_load_raw; + + } + else if (!strcmp(model, "GRAS-50S5C")) { + height = 2048; + width = 2440; + load_raw = &LibRaw::unpacked_load_raw; + data_offset = 0; + filters = 0x49494949; + order = 0x4949; + maximum = 0xfffC; + + } + else if (!strcmp(model, "BB-500CL")) { + height = 2058; + width = 2448; + load_raw = &LibRaw::unpacked_load_raw; + data_offset = 0; + filters = 0x94949494; + order = 0x4949; + maximum = 0x3fff; + + } + else if (!strcmp(model, "BB-500GE")) { + height = 2058; + width = 2456; + load_raw = &LibRaw::unpacked_load_raw; + data_offset = 0; + filters = 0x94949494; + order = 0x4949; + maximum = 0x3fff; + + } + else if (!strcmp(model, "SVS625CL")) { + height = 2050; + width = 2448; + load_raw = &LibRaw::unpacked_load_raw; + data_offset = 0; + filters = 0x94949494; + order = 0x4949; + maximum = 0x0fff; + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/identify_tools.cpp libkdcraw/libkdcraw/libraw/src/metadata/identify_tools.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/identify_tools.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/identify_tools.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,140 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +short LibRaw::guess_byte_order(int words) +{ + uchar test[4][2]; + int t = 2, msb; + double diff, sum[2] = {0, 0}; + + fread(test[0], 2, 2, ifp); + for (words -= 2; words--;) + { + fread(test[t], 2, 1, ifp); + for (msb = 0; msb < 2; msb++) + { + diff = (test[t ^ 2][msb] << 8 | test[t ^ 2][!msb]) - + (test[t][msb] << 8 | test[t][!msb]); + sum[msb] += diff * diff; + } + t = (t + 1) & 3; + } + return sum[0] < sum[1] ? 0x4d4d : 0x4949; +} + +float LibRaw::find_green(int bps, int bite, int off0, int off1) +{ + UINT64 bitbuf = 0; + int vbits, col, i, c; + ushort img[2][2064]; + double sum[] = {0, 0}; + if (width > 2064) + return 0.f; // too wide + + FORC(2) + { + fseek(ifp, c ? off1 : off0, SEEK_SET); + for (vbits = col = 0; col < width; col++) + { + for (vbits -= bps; vbits < 0; vbits += bite) + { + bitbuf <<= bite; + for (i = 0; i < bite; i += 8) + bitbuf |= (unsigned)(fgetc(ifp) << i); + } + img[c][col] = bitbuf << (64 - bps - vbits) >> (64 - bps); + } + } + FORC(width - 1) + { + sum[c & 1] += ABS(img[0][c] - img[1][c + 1]); + sum[~c & 1] += ABS(img[1][c] - img[0][c + 1]); + } + if (sum[0] >= 1.0 && sum[1] >= 1.0) + return 100 * log(sum[0] / sum[1]); + else + return 0.f; +} + +void LibRaw::trimSpaces(char *s) +{ + char *p = s; + int l = strlen(p); + if (!l) + return; + while (isspace(p[l - 1])) + p[--l] = 0; /* trim trailing spaces */ + while (*p && isspace(*p)) + ++p, --l; /* trim leading spaces */ + memmove(s, p, l + 1); +} + +void LibRaw::remove_trailing_spaces(char *string, size_t len) +{ + if (len < 1) + return; // not needed, b/c sizeof of make/model is 64 + string[len - 1] = 0; + if (len < 3) + return; // also not needed + len = strnlen(string, len - 1); + for (int i = len - 1; i >= 0; i--) + { + if (isspace((unsigned char)string[i])) + string[i] = 0; + else + break; + } +} + +void LibRaw::remove_caseSubstr(char *string, char *subStr) // replace a substring with an equal length of spaces +{ + char *found; + while ((found = strcasestr(string,subStr))) { + if (!found) return; + int fill_len = strlen(subStr); + int p = found - string; + for (int i=p; i<p+fill_len; i++) { + string[i] = 32; + } + } + trimSpaces (string); +} + +void LibRaw::removeExcessiveSpaces(char *string) // replace repeating spaces with one space +{ + int orig_len = strlen(string); + int i = 0; // counter for resulting string + int j = -1; + bool prev_char_is_space = false; + while (++j < orig_len && string[j] == ' '); + while (j < orig_len) { + if (string[j] != ' ') { + string[i++] = string[j++]; + prev_char_is_space = false; + } else if (string[j++] == ' ') { + if (!prev_char_is_space) { + string[i++] = ' '; + prev_char_is_space = true; + } + } + } + if (string[i-1] == ' ') + string[i-1] = 0; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/kodak.cpp libkdcraw/libkdcraw/libraw/src/metadata/kodak.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/kodak.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/kodak.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,363 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::Kodak_KDC_WBtags(int wb, int wbi) +{ + int c; + FORC3 icWBC[wb][c] = get4(); + icWBC[wb][3] = icWBC[wb][1]; + if (wbi == wb) + FORC4 cam_mul[c] = icWBC[wb][c]; + return; +} + +void LibRaw::Kodak_DCR_WBtags(int wb, unsigned type, int wbi) +{ + float mul[3] = {1.0f, 1.0f, 1.0f}, num, mul2; + int c; + FORC3 mul[c] = (num = getreal(type)) <= 0.001f ? 1.0f : num; + icWBC[wb][1] = icWBC[wb][3] = mul[1]; + mul2 = mul[1] * mul[1]; + icWBC[wb][0] = mul2 / mul[0]; + icWBC[wb][2] = mul2 / mul[2]; + if (wbi == wb) + FORC4 cam_mul[c] = icWBC[wb][c]; + return; +} + +short LibRaw::KodakIllumMatrix(unsigned type, float *romm_camIllum) +{ + int c, j, romm_camTemp[9], romm_camScale[3]; + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SRATIONAL)) + { + for (j = 0; j < 9; j++) + ((float *)romm_camIllum)[j] = getreal(type); + return 1; + } + else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SLONG)) + { + FORC3 + { + romm_camScale[c] = 0; + for (j = 0; j < 3; j++) + { + romm_camTemp[c * 3 + j] = get4(); + romm_camScale[c] += romm_camTemp[c * 3 + j]; + } + } + if ((romm_camScale[0] > 0x1fff) && (romm_camScale[1] > 0x1fff) && + (romm_camScale[2] > 0x1fff)) + { + FORC3 for (j = 0; j < 3; j++)((float *)romm_camIllum)[c * 3 + j] = + ((float)romm_camTemp[c * 3 + j]) / ((float)romm_camScale[c]); + return 1; + } + } + return 0; +} + +/* Thanks to Alexey Danilchenko for wb as-shot parsing code */ +void LibRaw::parse_kodak_ifd(int base) +{ + unsigned entries, tag, type, len, save; + int c, wbi = -1; + + static const int wbtag_kdc[] = { + LIBRAW_WBI_Auto, // 64037 / 0xfa25 + LIBRAW_WBI_Fluorescent, // 64040 / 0xfa28 + LIBRAW_WBI_Tungsten, // 64039 / 0xfa27 + LIBRAW_WBI_Daylight, // 64041 / 0xfa29 + -1, + -1, + LIBRAW_WBI_Shade // 64042 / 0xfa2a + }; + + static const int wbtag_dcr[] = { + LIBRAW_WBI_Daylight, // 2120 / 0x0848 + LIBRAW_WBI_Tungsten, // 2121 / 0x0849 + LIBRAW_WBI_Fluorescent, // 2122 / 0x084a + LIBRAW_WBI_Flash, // 2123 / 0x084b + LIBRAW_WBI_Custom, // 2124 / 0x084c + LIBRAW_WBI_Auto // 2125 / 0x084d + }; + + // int a_blck = 0; + + entries = get2(); + if (entries > 1024) + return; + INT64 fsize = ifp->size(); + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + INT64 savepos = ftell(ifp); + if (len > 8 && len + savepos > 2 * fsize) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + if (callbacks.exif_cb) + { + callbacks.exif_cb(callbacks.exifparser_data, tag | 0x20000, type, len, + order, ifp, base); + fseek(ifp, savepos, SEEK_SET); + } + if (tag == 0x03eb) // 1003 + imgdata.sizes.raw_inset_crop.cleft = get2(); + else if (tag == 0x03ec) // 1004 + imgdata.sizes.raw_inset_crop.ctop = get2(); + else if (tag == 0x03ed) // 1005 + imgdata.sizes.raw_inset_crop.cwidth = get2(); + else if (tag == 0x03ee) // 1006 + imgdata.sizes.raw_inset_crop.cheight = get2(); + else if (tag == 0x03ef) // 1007 + { + if (!strcmp(model, "EOS D2000C")) + black = get2(); + else + imKodak.BlackLevelTop = get2(); + } + else if (tag == 0x03f0) // 1008 + { + if (!strcmp(model, "EOS D2000C")) + { + if (black) // already set by tag 1007 (0x03ef) + black = (black + get2()) / 2; + else + black = get2(); + } + else + imKodak.BlackLevelBottom = get2(); + } + + else if (tag == 0x03f1) + { // 1009 Kodak TextualInfo + if (len > 0) + { + char kti[1024]; + char *pkti; + int nsym = MIN(len, 1023); + fread(kti, 1, nsym, ifp); + kti[nsym] = 0; +#ifdef LIBRAW_WIN32_CALLS + pkti = strtok(kti, "\x0a"); +#else + char *last = 0; + pkti = strtok_r(kti, "\x0a", &last); +#endif + while (pkti != NULL) + { + c = 12; + if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Camera body:", c))) + { + while ((pkti[c] == ' ') && (c < (int)strlen(pkti))) + { + c++; + } + strcpy(ilm.body, pkti + c); + } + c = 5; + if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Lens:", c))) + { + ilm.CurFocal = atoi(pkti + c); + } + c = 9; + if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Aperture:", c))) + { + while (((pkti[c] == ' ') || (pkti[c] == 'f')) && (c < (int)strlen(pkti))) + { + c++; + } + ilm.CurAp = atof(pkti + c); + } + c = 10; + if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "ISO Speed:", c))) + { + iso_speed = atoi(pkti + c); + } + c = 13; + if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Focal Length:", c))) + { + ilm.CurFocal = atoi(pkti + c); + } + c = 13; + if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Max Aperture:", c))) + { + while (((pkti[c] == ' ') || (pkti[c] == 'f')) && (c < (int)strlen(pkti))) + { + c++; + } + ilm.MaxAp4CurFocal = atof(pkti + c); + } + c = 13; + if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Min Aperture:", c))) + { + while (((pkti[c] == ' ') || (pkti[c] == 'f')) && (c < (int)strlen(pkti))) + { + c++; + } + ilm.MinAp4CurFocal = atof(pkti + c); + } +#ifdef LIBRAW_WIN32_CALLS + pkti = strtok(NULL, "\x0a"); +#else + pkti = strtok_r(NULL, "\x0a", &last); +#endif + } + } + } + + else if (tag == 0x03f3) // 1011 + imCommon.FlashEC = getreal(type); + + else if (tag == 0x03fc) // 1020 + { + wbi = getint(type); + if ((wbi >= 0) && (wbi < 6) && (wbi != -2)) + wbi = wbtag_dcr[wbi]; + } + else if (tag == 0x03fd && len == 72) // 1021 + { /* WB set in software */ + fseek(ifp, 40, SEEK_CUR); + FORC3 cam_mul[c] = 2048.0 / fMAX(1.0f, get2()); + wbi = -2; + } + + else if ((tag == 0x0406) && (len == 1)) // 1030 + imCommon.CameraTemperature = getreal(type); + else if ((tag == 0x0413) && (len == 1)) // 1043 + imCommon.SensorTemperature = getreal(type); + else if (tag == 0x0848) // 2120 + Kodak_DCR_WBtags(LIBRAW_WBI_Daylight, type, wbi); + else if (tag == 0x0849) // 2121 + Kodak_DCR_WBtags(LIBRAW_WBI_Tungsten, type, wbi); + else if (tag == 0x084a) // 2122 + Kodak_DCR_WBtags(LIBRAW_WBI_Fluorescent, type, wbi); + else if (tag == 0x084b) // 2123 + Kodak_DCR_WBtags(LIBRAW_WBI_Flash, type, wbi); + else if (tag == 0x084c) // 2124 + Kodak_DCR_WBtags(LIBRAW_WBI_Custom, type, wbi); + else if (tag == 0x084d) // 2125 + { + if (wbi == -1) + wbi = LIBRAW_WBI_Auto; + Kodak_DCR_WBtags(LIBRAW_WBI_Auto, type, wbi); + } + else if (tag == 0x089f) // 2207 + imKodak.ISOCalibrationGain = getreal(type); + else if (tag == 0x0903) // 2307 + imKodak.AnalogISO = iso_speed = getreal(type); + else if (tag == 0x090d) // 2317 + linear_table(len); + else if (tag == 0x09ce) // 2510 + stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp); + else if (tag == 0x0e92) // 3730 + { + imKodak.val018percent = get2(); + imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = + imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = + (int)(((float)imKodak.val018percent) / 18.0f * 170.0f); + } + else if (tag == 0x0e93) // 3731 + imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = + imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = + imKodak.val170percent = get2(); + else if (tag == 0x0e94) // 3732 + imKodak.val100percent = get2(); + /* + else if (tag == 0x1784) // 6020 + iso_speed = getint(type); + */ + else if (tag == 0xfa00) // 64000 + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + else if (tag == 0xfa0d) // 64013 + { + wbi = fgetc(ifp); + if ((wbi >= 0) && (wbi < 7)) + wbi = wbtag_kdc[wbi]; + } + else if (tag == 0xfa13) // 64019 + width = getint(type); + else if (tag == 0xfa14) // 64020 + height = (getint(type) + 1) & -2; + /* + height = getint(type); + + else if (tag == 0xfa16) // 64022 + raw_width = get2(); + else if (tag == 0xfa17) // 64023 + raw_height = get2(); + */ + else if (tag == 0xfa18) // 64024 + { + imKodak.offset_left = getint(LIBRAW_EXIFTAG_TYPE_SSHORT); + if (type != LIBRAW_EXIFTAG_TYPE_SSHORT) + imKodak.offset_left += 1; + } + else if (tag == 0xfa19) // 64025 + { + imKodak.offset_top = getint(LIBRAW_EXIFTAG_TYPE_SSHORT); + if (type != LIBRAW_EXIFTAG_TYPE_SSHORT) + imKodak.offset_top += 1; + } + + else if (tag == 0xfa25) // 64037 + Kodak_KDC_WBtags(LIBRAW_WBI_Auto, wbi); + else if (tag == 0xfa27) // 64039 + Kodak_KDC_WBtags(LIBRAW_WBI_Tungsten, wbi); + else if (tag == 0xfa28) // 64040 + Kodak_KDC_WBtags(LIBRAW_WBI_Fluorescent, wbi); + else if (tag == 0xfa29) // 64041 + Kodak_KDC_WBtags(LIBRAW_WBI_Daylight, wbi); + else if (tag == 0xfa2a) // 64042 + Kodak_KDC_WBtags(LIBRAW_WBI_Shade, wbi); + + else if (tag == 0xfa31) // 64049 + imgdata.sizes.raw_inset_crop.cwidth = get2(); + else if (tag == 0xfa32) // 64050 + imgdata.sizes.raw_inset_crop.cheight = get2(); + else if (tag == 0xfa3e) // 64062 + imgdata.sizes.raw_inset_crop.cleft = get2(); + else if (tag == 0xfa3f) // 64063 + imgdata.sizes.raw_inset_crop.ctop = get2(); + + else if (((tag == 0x07e4) || (tag == 0xfb01)) && + (len == 9)) // 2020 or 64257 + { + if (KodakIllumMatrix(type, (float *)imKodak.romm_camDaylight)) + { + romm_coeff(imKodak.romm_camDaylight); + } + } + else if (((tag == 0x07e5) || (tag == 0xfb02)) && + (len == 9)) // 2021 or 64258 + KodakIllumMatrix(type, (float *)imKodak.romm_camTungsten); + else if (((tag == 0x07e6) || (tag == 0xfb03)) && + (len == 9)) // 2022 or 64259 + KodakIllumMatrix(type, (float *)imKodak.romm_camFluorescent); + else if (((tag == 0x07e7) || (tag == 0xfb04)) && + (len == 9)) // 2023 or 64260 + KodakIllumMatrix(type, (float *)imKodak.romm_camFlash); + else if (((tag == 0x07e8) || (tag == 0xfb05)) && + (len == 9)) // 2024 or 64261 + KodakIllumMatrix(type, (float *)imKodak.romm_camCustom); + else if (((tag == 0x07e9) || (tag == 0xfb06)) && + (len == 9)) // 2025 or 64262 + KodakIllumMatrix(type, (float *)imKodak.romm_camAuto); + + fseek(ifp, save, SEEK_SET); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/leica.cpp libkdcraw/libkdcraw/libraw/src/metadata/leica.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/leica.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/leica.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,357 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::setLeicaBodyFeatures(int LeicaMakernoteSignature) +{ + if (LeicaMakernoteSignature == -3) + { // M8 + ilm.CameraFormat = LIBRAW_FORMAT_APSH; + ilm.CameraMount = LIBRAW_MOUNT_Leica_M; + } + else if (LeicaMakernoteSignature == -2) + { // DMR + ilm.CameraFormat = LIBRAW_FORMAT_Leica_DMR; + if ((model[0] == 'R') || (model[6] == 'R')) + ilm.CameraMount = LIBRAW_MOUNT_Leica_R; + } + else if (LeicaMakernoteSignature == 0) + { // DIGILUX 2 + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + } + else if ((LeicaMakernoteSignature == 0x0100) || // X1 + (LeicaMakernoteSignature == 0x0500) || // X2, X-E (Typ 102) + (LeicaMakernoteSignature == 0x0700) || // X (Typ 113) + (LeicaMakernoteSignature == 0x1000)) + { // X-U (Typ 113) + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + } + else if (LeicaMakernoteSignature == 0x0400) + { // X VARIO (Typ 107) + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + } + else if ((LeicaMakernoteSignature == 0x0200) || // M10, M10-D, S (Typ 007) + (LeicaMakernoteSignature == + 0x02ff) || // M (Typ 240), M (Typ 262), M-D (Typ 262), M Monochrom + // (Typ 246), S (Typ 006), S-E (Typ 006), S2, S3 + (LeicaMakernoteSignature == 0x0300)) + { // M9, M9 Monochrom, M Monochrom, M-E + if ((model[0] == 'M') || (model[6] == 'M')) + { + ilm.CameraFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = LIBRAW_MOUNT_Leica_M; + } + else if ((model[0] == 'S') || (model[6] == 'S')) + { + ilm.CameraFormat = LIBRAW_FORMAT_LeicaS; + ilm.CameraMount = LIBRAW_MOUNT_Leica_S; + } + } + else if ((LeicaMakernoteSignature == 0x0600) || // T (Typ 701), TL + (LeicaMakernoteSignature == 0x0900) || // SL2, SL (Typ 601), CL, Q2 + (LeicaMakernoteSignature == 0x1a00)) // TL2 + { + if ((model[0] == 'S') || (model[6] == 'S')) + { + ilm.CameraFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = LIBRAW_MOUNT_LPS_L; + } + else if ((model[0] == 'T') || (model[6] == 'T') || (model[0] == 'C') || + (model[6] == 'C')) + { + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_LPS_L; + } + else if (((model[0] == 'Q') || (model[6] == 'Q')) && + ((model[1] == '2') || (model[7] == '2'))) + { + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + } + } + else if (LeicaMakernoteSignature == 0x0800) + { // Q (Typ 116) + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + } +} + +void LibRaw::parseLeicaLensID() +{ + ilm.LensID = get4(); + if (ilm.LensID) + { + ilm.LensID = ((ilm.LensID >> 2) << 8) | (ilm.LensID & 0x3); + if ((ilm.LensID > 0x00ff) && (ilm.LensID < 0x3b00)) + { + ilm.LensMount = ilm.CameraMount; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + } +} + +int LibRaw::parseLeicaLensName(unsigned len) +{ +#define plln ilm.Lens + if (!len) + { + strcpy(plln, "N/A"); + return 0; + } + stmread(plln, len, ifp); + if ((plln[0] == ' ') || !strncasecmp(plln, "not ", 4) || + !strncmp(plln, "---", 3) || !strncmp(plln, "***", 3)) + { + strcpy(plln, "N/A"); + return 0; + } + else + return 1; +#undef plln +} + +int LibRaw::parseLeicaInternalBodySerial(unsigned len) +{ +#define plibs imgdata.shootinginfo.InternalBodySerial + if (!len) + { + strcpy(plibs, "N/A"); + return 0; + } + stmread(plibs, len, ifp); + if (!strncmp(plibs, "000000000000", 12)) + { + plibs[0] = '0'; + plibs[1] = '\0'; + return 1; + } + + if (strnlen(plibs, len) == 13) + { + for (int i = 3; i < 13; i++) + { + if (!isdigit(plibs[i])) + goto non_std; + } + memcpy(plibs + 15, plibs + 9, 4); + memcpy(plibs + 12, plibs + 7, 2); + memcpy(plibs + 9, plibs + 5, 2); + memcpy(plibs + 6, plibs + 3, 2); + plibs[3] = plibs[14] = ' '; + plibs[8] = plibs[11] = '/'; + if (((short)(plibs[3] - '0') * 10 + (short)(plibs[4] - '0')) < 70) + { + memcpy(plibs + 4, "20", 2); + } + else + { + memcpy(plibs + 4, "19", 2); + } + return 2; + } +non_std: +#undef plibs + return 1; +} + +void LibRaw::parseLeicaMakernote(int base, int uptag, unsigned MakernoteTagType) +{ + int c; + uchar ci, cj; + unsigned entries, tag, type, len, save; + short morder, sorder = order; + char buf[10]; + int LeicaMakernoteSignature = -1; + INT64 fsize = ifp->size(); + fread(buf, 1, 10, ifp); + if (strncmp(buf, "LEICA", 5)) + { + fseek(ifp, -10, SEEK_CUR); + if (uptag == 0x3400) + LeicaMakernoteSignature = 0x3400; + else + LeicaMakernoteSignature = -2; // DMR + } + else + { + fseek(ifp, -2, SEEK_CUR); + LeicaMakernoteSignature = ((uchar)buf[6] << 8) | (uchar)buf[7]; + if (!LeicaMakernoteSignature && + (!strncmp(model, "M8", 2) || !strncmp(model + 6, "M8", 2))) + LeicaMakernoteSignature = -3; + if ((LeicaMakernoteSignature != 0x0000) && + (LeicaMakernoteSignature != 0x0200) && + (LeicaMakernoteSignature != 0x0800) && + (LeicaMakernoteSignature != 0x0900) && + (LeicaMakernoteSignature != 0x02ff)) + base = ftell(ifp) - 8; + } + setLeicaBodyFeatures(LeicaMakernoteSignature); + + entries = get2(); + if (entries > 1000) + return; + morder = order; + + while (entries--) + { + order = morder; + tiff_get(base, &tag, &type, &len, &save); + + INT64 pos = ifp->tell(); + if (len > 8 && pos + len > 2 * fsize) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + tag |= uptag << 16; + if (len > 100 * 1024 * 1024) + goto next; // 100Mb tag? No! + + if (LeicaMakernoteSignature == -3) + { // M8 + if (tag == 0x0310) + { + parseLeicaLensID(); + } + else if ((tag == 0x0313) && (fabs(ilm.CurAp) < 0.17f)) + { + ilm.CurAp = getreal(type); + if (ilm.CurAp > 126.3) + { + ilm.CurAp = 0.0f; + } + } + else if (tag == 0x0320) + { + imCommon.CameraTemperature = getreal(type); + } + } + else if (LeicaMakernoteSignature == -2) + { // DMR + if (tag == 0x000d) + { + FORC3 cam_mul[c] = get2(); + cam_mul[3] = cam_mul[1]; + } + } + else if (LeicaMakernoteSignature == 0) + { // DIGILUX 2 + if (tag == 0x0007) + { + imgdata.shootinginfo.FocusMode = get2(); + } + else if (tag == 0x001a) + { + imgdata.shootinginfo.ImageStabilization = get2(); + } + } + else if ((LeicaMakernoteSignature == 0x0100) || // X1 + (LeicaMakernoteSignature == 0x0400) || // X VARIO + (LeicaMakernoteSignature == 0x0500) || // X2, X-E (Typ 102) + (LeicaMakernoteSignature == 0x0700) || // X (Typ 113) + (LeicaMakernoteSignature == 0x1000)) + { // X-U (Typ 113) + if (tag == 0x040d) + { + ci = fgetc(ifp); + cj = fgetc(ifp); + imgdata.shootinginfo.ExposureMode = ((ushort)ci << 8) | cj; + } + } + else if ((LeicaMakernoteSignature == 0x0600) || // TL, T (Typ 701) + (LeicaMakernoteSignature == 0x1a00)) + { // TL2 + if (tag == 0x040d) + { + ci = fgetc(ifp); + cj = fgetc(ifp); + imgdata.shootinginfo.ExposureMode = ((ushort)ci << 8) | cj; + } + else if (tag == 0x0303) + { + parseLeicaLensName(len); + } + } + else if (LeicaMakernoteSignature == 0x0200) + { // M10, M10-D, S (Typ 007) + } + else if (LeicaMakernoteSignature == 0x02ff) + { // M (Typ 240), M (Typ 262), M-D (Typ 262), M Monochrom (Typ 246), + // S (Typ 006), S-E (Typ 006), S2, S3 + if (tag == 0x0303) + { + if (parseLeicaLensName(len)) + { + ilm.LensMount = ilm.CameraMount; + ilm.LensFormat = ilm.CameraFormat; + } + } + } + else if (LeicaMakernoteSignature == 0x0300) + { // M9, M9 Monochrom, M Monochrom, M-E + if (tag == 0x3400) + { + parseLeicaMakernote(base, 0x3400, MakernoteTagType); + } + } + else if ((LeicaMakernoteSignature == 0x0800) || // Q (Typ 116) + (LeicaMakernoteSignature == 0x0900)) + { // SL (Typ 601), CL + if ((tag == 0x0304) && (len == 1) && ((c = fgetc(ifp)) != 0) && + (ilm.CameraMount == LIBRAW_MOUNT_LPS_L)) + { + strcpy(ilm.Adapter, "M-Adapter L"); + ilm.LensMount = LIBRAW_MOUNT_Leica_M; + ilm.LensFormat = LIBRAW_FORMAT_FF; + ilm.LensID = c * 256; + } + else if (tag == 0x0500) + { + parseLeicaInternalBodySerial(len); + } + } + else if (LeicaMakernoteSignature == 0x3400) + { // tag 0x3400 in M9, M9 Monochrom, M Monochrom + if (tag == 0x34003402) + { + imCommon.CameraTemperature = getreal(type); + } + else if (tag == 0x34003405) + { + parseLeicaLensID(); + } + else if ((tag == 0x34003406) && (fabs(ilm.CurAp) < 0.17f)) + { + ilm.CurAp = getreal(type); + if (ilm.CurAp > 126.3) + { + ilm.CurAp = 0.0f; + } + } + } + + next: + fseek(ifp, save, SEEK_SET); + } + order = sorder; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/makernotes.cpp libkdcraw/libkdcraw/libraw/src/metadata/makernotes.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/makernotes.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/makernotes.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,894 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::parseSigmaMakernote (int base, int uptag, unsigned dng_writer) { +unsigned wb_table1 [] = { + LIBRAW_WBI_Auto, LIBRAW_WBI_Daylight, LIBRAW_WBI_Shade, LIBRAW_WBI_Cloudy, + LIBRAW_WBI_Tungsten, LIBRAW_WBI_Fluorescent, LIBRAW_WBI_Flash, + LIBRAW_WBI_Custom, LIBRAW_WBI_Custom1, LIBRAW_WBI_Custom2 +}; + + unsigned entries, tag, type, len, save; + unsigned i; + + entries = get2(); + if (entries > 1000) + return; + while (entries--) { + tiff_get(base, &tag, &type, &len, &save); + if (tag == 0x0027) { + ilm.LensID = get2(); + } else if (tag == 0x002a) { + ilm.MinFocal = getreal(type); + ilm.MaxFocal = getreal(type); + } else if (tag == 0x002b) { + ilm.MaxAp4MinFocal = getreal(type); + ilm.MaxAp4MaxFocal = getreal(type); + } else if (tag == 0x0120) { + const unsigned tblsz = (sizeof wb_table1 / sizeof wb_table1[0]); + if ((len >= tblsz) && (len%3 == 0) && len/3 <= tblsz) { + for (i=0; i<(len/3); i++) { + icWBC[wb_table1[i]][0] = (int)(getreal(type)*10000.0); + icWBC[wb_table1[i]][1] = icWBC[wb_table1[i]][3] = (int)(getreal(type)*10000.0); + icWBC[wb_table1[i]][2] = (int)(getreal(type)*10000.0); + } + } + } + fseek(ifp, save, SEEK_SET); + } + + return; +} + +void LibRaw::parse_makernote_0xc634(int base, int uptag, unsigned dng_writer) +{ + + if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SKIP_MAKERNOTES) + return; + + if (metadata_blocks++ > LIBRAW_MAX_METADATA_BLOCKS) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + if (!strncmp(make, "NIKON", 5)) + { + parseNikonMakernote(base, uptag, AdobeDNG); + return; + } + else if (!strncasecmp(make, "LEICA", 5)) + { + parseLeicaMakernote(base, uptag, is_0xc634); + return; + } + + short morder, sorder = order; + char buf[10]; + INT64 fsize = ifp->size(); + + fread(buf, 1, 10, ifp); + + if (!strcmp(buf, "EPSON")) + { + parseEpsonMakernote(base, uptag, AdobeDNG); + return; + } + else if (!strcmp(buf, "SIGMA")) + { + parseSigmaMakernote(base, uptag, AdobeDNG); + return; + } + + unsigned entries, tag, type, len, save, c; + + uchar *CanonCameraInfo; + unsigned lenCanonCameraInfo = 0; + unsigned typeCanonCameraInfo = 0; + + uchar *table_buf_0x0116; + ushort table_buf_0x0116_len = 0; + uchar *table_buf_0x2010; + ushort table_buf_0x2010_len = 0; + uchar *table_buf_0x9050; + ushort table_buf_0x9050_len = 0; + uchar *table_buf_0x9400; + ushort table_buf_0x9400_len = 0; + uchar *table_buf_0x9402; + ushort table_buf_0x9402_len = 0; + uchar *table_buf_0x9403; + ushort table_buf_0x9403_len = 0; + uchar *table_buf_0x9406; + ushort table_buf_0x9406_len = 0; + uchar *table_buf_0x940c; + ushort table_buf_0x940c_len = 0; + uchar *table_buf_0x940e; + ushort table_buf_0x940e_len = 0; + + if (!strcmp(buf, "OLYMPUS") || !strcmp(buf, "PENTAX ") || + (!strncmp(make, "SAMSUNG", 7) && (dng_writer == CameraDNG))) + { + base = ftell(ifp) - 10; + fseek(ifp, -2, SEEK_CUR); + order = get2(); + if (buf[0] == 'O') + get2(); + } + else if (is_PentaxRicohMakernotes && (dng_writer == CameraDNG)) + { + base = ftell(ifp) - 10; + fseek(ifp, -4, SEEK_CUR); + order = get2(); + is_PentaxRicohMakernotes = 1; + } + else if (!strncmp(buf, "SONY", 4) || + !strcmp(buf, "Panasonic")) + { + order = 0x4949; + fseek(ifp, 2, SEEK_CUR); + } + else if (!strncmp(buf, "FUJIFILM", 8)) + { + base = ftell(ifp) - 10; + order = 0x4949; + fseek(ifp, 2, SEEK_CUR); + } + else if (!strcmp(buf, "OLYMP") || + !strcmp(buf, "Ricoh")) + { + fseek(ifp, -2, SEEK_CUR); + } + else if (!strcmp(buf, "AOC") || !strcmp(buf, "QVC")) + { + fseek(ifp, -4, SEEK_CUR); + } + else + { + fseek(ifp, -10, SEEK_CUR); + if ((!strncmp(make, "SAMSUNG", 7) && (dng_writer == AdobeDNG))) + base = ftell(ifp); + } + + entries = get2(); + if (entries > 1000) + return; + + if (!strncasecmp(make, "SONY", 4) || + !strncasecmp(make, "Konica", 6) || + !strncasecmp(make, "Minolta", 7) || + (!strncasecmp(make, "Hasselblad", 10) && + (!strncasecmp(model, "Stellar", 7) || + !strncasecmp(model, "Lunar", 5) || + !strncasecmp(model, "Lusso", 5) || + !strncasecmp(model, "HV", 2)))) + is_Sony = 1; + + morder = order; + while (entries--) + { + order = morder; + + tiff_get(base, &tag, &type, &len, &save); + + INT64 pos = ifp->tell(); + if (len > 8 && pos + len > 2 * fsize) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + tag |= uptag << 16; + if (len > 100 * 1024 * 1024) + goto next; // 100Mb tag? No! + + if (!strncmp(make, "Canon", 5)) + { + if (tag == 0x000d && len < 256000) + { // camera info + if (!tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + { + CanonCameraInfo = (uchar *)malloc(MAX(16, len)); + fread(CanonCameraInfo, len, 1, ifp); + } + else + { + CanonCameraInfo = (uchar *)malloc(MAX(16, len * 4)); + fread(CanonCameraInfo, len, 4, ifp); + } + lenCanonCameraInfo = len; + typeCanonCameraInfo = type; + } + + else if (tag == 0x0010) + { // Canon ModelID + unique_id = get4(); + setCanonBodyFeatures(unique_id); + if (lenCanonCameraInfo) + { + processCanonCameraInfo(unique_id, CanonCameraInfo, lenCanonCameraInfo, + typeCanonCameraInfo, AdobeDNG); + free(CanonCameraInfo); + CanonCameraInfo = 0; + lenCanonCameraInfo = 0; + } + } + + else + parseCanonMakernotes(tag, type, len, AdobeDNG); + } + + else if (!strncmp(make, "FUJI", 4)) { + parseFujiMakernotes(tag, type, len, AdobeDNG); + + } else if (!strncasecmp(make, "Hasselblad", 10) && !is_Sony) { + if (tag == 0x0011) { + imHassy.SensorCode = getint(type); + } else if ((tag == 0x0015) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_ASCII)) { + stmread (imHassy.SensorUnitConnector, len, ifp); + } else if (tag == 0x0016) { + imHassy.CoatingCode = getint(type); + } else if ((tag == 0x002a) && + tagtypeIs(LIBRAW_EXIFTAG_TYPE_SRATIONAL) && + (len == 12)) { + FORC4 for (int i = 0; i < 3; i++) + imHassy.mnColorMatrix[c][i] = getreal(type); + + } else if (tag == 0x0031) { + imHassy.RecommendedCrop[0] = getint(type); + imHassy.RecommendedCrop[1] = getint(type); + } + + } else if (!strncmp(make, "OLYMPUS", 7) || + (!strncasecmp(make, "CLAUSS", 6) && + !strncasecmp(model, "piX 5oo", 7))) + { + + int SubDirOffsetValid = + strncmp(model, "E-300", 5) && strncmp(model, "E-330", 5) && + strncmp(model, "E-400", 5) && strncmp(model, "E-500", 5) && + strncmp(model, "E-1", 3); + + if ((tag == 0x2010) || (tag == 0x2020) || (tag == 0x2030) || + (tag == 0x2031) || (tag == 0x2040) || (tag == 0x2050) || + (tag == 0x3000)) + { + fseek(ifp, save - 4, SEEK_SET); + fseek(ifp, base + get4(), SEEK_SET); + parse_makernote_0xc634(base, tag, dng_writer); + } + + if (!SubDirOffsetValid && + ((len > 4) || + ((tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) || + tagtypeIs(LIBRAW_EXIFTAG_TYPE_SSHORT)) && (len > 2)) || + ((tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG) || + tagtypeIs(LIBRAW_EXIFTAG_TYPE_SLONG)) && (len > 1)) || + tagtypeIs(LIBRAW_EXIFTAG_TYPE_RATIONAL) || + (type > LIBRAW_EXIFTAG_TYPE_SLONG))) + goto skip_Oly_broken_tags; + + else if ((tag >= 0x20100000) && (tag <= 0x2010ffff)) + parseOlympus_Equipment((tag & 0x0000ffff), type, len, AdobeDNG); + + else if ((tag >= 0x20200000) && (tag <= 0x2020ffff)) + parseOlympus_CameraSettings(base, (tag & 0x0000ffff), type, len, + AdobeDNG); + + else if ((tag == 0x20300108) || (tag == 0x20310109)) { + imOly.ColorSpace = get2(); + switch (imOly.ColorSpace) { + case 0: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_ProPhotoRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + + } else if ((tag >= 0x20400000) && (tag <= 0x2040ffff)) + parseOlympus_ImageProcessing((tag & 0x0000ffff), type, len, AdobeDNG); + + else if ((tag >= 0x30000000) && (tag <= 0x3000ffff)) + parseOlympus_RawInfo((tag & 0x0000ffff), type, len, AdobeDNG); + + else + switch (tag) + { + case 0x0207: + getOlympus_CameraType2(); + break; + case 0x1002: + ilm.CurAp = libraw_powf64l(2.0f, getreal(type) / 2); + break; + case 0x1007: + imCommon.SensorTemperature = (float)get2(); + break; + case 0x1008: + imCommon.LensTemperature = (float)get2(); + break; + case 0x20501500: + getOlympus_SensorTemperature(len); + break; + } + + skip_Oly_broken_tags:; + } + + else if (!strncmp(make, "PENTAX", 6) || !strncmp(model, "PENTAX", 6) || + is_PentaxRicohMakernotes) + { + parsePentaxMakernotes(base, tag, type, len, dng_writer); + } + else if (!strncmp(make, "SAMSUNG", 7)) + { + if (dng_writer == AdobeDNG) + parseSamsungMakernotes(base, tag, type, len, dng_writer); + else + parsePentaxMakernotes(base, tag, type, len, dng_writer); + } + else if (is_Sony) + { + parseSonyMakernotes( + base, tag, type, len, AdobeDNG, table_buf_0x0116, + table_buf_0x0116_len, table_buf_0x2010, table_buf_0x2010_len, + table_buf_0x9050, table_buf_0x9050_len, table_buf_0x9400, + table_buf_0x9400_len, table_buf_0x9402, table_buf_0x9402_len, + table_buf_0x9403, table_buf_0x9403_len, table_buf_0x9406, + table_buf_0x9406_len, table_buf_0x940c, table_buf_0x940c_len, + table_buf_0x940e, table_buf_0x940e_len); + } + next: + fseek(ifp, save, SEEK_SET); + } + + order = sorder; +} + +void LibRaw::parse_makernote(int base, int uptag) +{ + + if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SKIP_MAKERNOTES) + return; + + if (metadata_blocks++ > LIBRAW_MAX_METADATA_BLOCKS) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + if (!strncmp(make, "NIKON", 5)) + { + parseNikonMakernote(base, uptag, nonDNG); + return; + } + else if (!strncasecmp(make, "LEICA", 5)) + { + parseLeicaMakernote(base, uptag, is_0x927c); + return; + } + + if (!strncmp(make, "Nokia", 5)) + return; + + char buf[10]; + char another_buf[128]; + + fseek(ifp, -12, SEEK_CUR); + fread (another_buf, 1, 12, ifp); + if (!strncmp(another_buf, "SONY", 4) || + !strncmp(another_buf, "VHAB", 4)) { // Sony branded as Hasselblad + is_Sony = 1; + } + + fread(buf, 1, 10, ifp); + + if (!strncmp(buf, "KDK", 3) || /* these aren't TIFF tables */ + !strncmp(buf, "VER", 3) || + !strncmp(buf, "IIII", 4) || + !strncmp(buf, "MMMM", 4)) + return; + + if (!strcmp(buf, "EPSON")) + { + parseEpsonMakernote(base, uptag, nonDNG); + return; + } + else if (!strcmp(buf, "SIGMA")) + { + parseSigmaMakernote(base, uptag, CameraDNG); + return; + } + + + unsigned entries, tag, type, len, save, c; + unsigned i, wb[4] = {0, 0, 0, 0}; + short morder, sorder = order; + + uchar *CanonCameraInfo; + unsigned lenCanonCameraInfo = 0; + unsigned typeCanonCameraInfo = 0; + imCanon.wbi = 0; + + uchar *table_buf_0x0116; + ushort table_buf_0x0116_len = 0; + uchar *table_buf_0x2010; + ushort table_buf_0x2010_len = 0; + uchar *table_buf_0x9050; + ushort table_buf_0x9050_len = 0; + uchar *table_buf_0x9400; + ushort table_buf_0x9400_len = 0; + uchar *table_buf_0x9402; + ushort table_buf_0x9402_len = 0; + uchar *table_buf_0x9403; + ushort table_buf_0x9403_len = 0; + uchar *table_buf_0x9406; + ushort table_buf_0x9406_len = 0; + uchar *table_buf_0x940c; + ushort table_buf_0x940c_len = 0; + uchar *table_buf_0x940e; + ushort table_buf_0x940e_len = 0; + + INT64 fsize = ifp->size(); + + /* + The MakerNote might have its own TIFF header (possibly with + its own byte-order!), or it might just be a table. + */ + + if (!strncmp(buf, "KC", 2) || /* Konica KD-400Z, KD-510Z */ + !strncmp(buf, "MLY", 3)) /* Minolta DiMAGE G series */ + { + order = 0x4d4d; + while ((i = ftell(ifp)) < data_offset && i < 16384) + { + wb[0] = wb[2]; + wb[2] = wb[1]; + wb[1] = wb[3]; + wb[3] = get2(); + if (wb[1] == 256 && wb[3] == 256 && wb[0] > 256 && wb[0] < 640 && + wb[2] > 256 && wb[2] < 640) + FORC4 cam_mul[c] = wb[c]; + } + goto quit; + } + + if (!strcmp(buf, "OLYMPUS") || + !strcmp(buf, "PENTAX ")) + { + base = ftell(ifp) - 10; + fseek(ifp, -2, SEEK_CUR); + order = get2(); + if (buf[0] == 'O') + get2(); + } + else if (!strncmp(buf, "SONY", 4) || // DSLR-A100 + !strcmp(buf, "Panasonic")) { + if (buf[0] == 'S') + is_Sony = 1; + goto nf; + } + else if (!strncmp(buf, "FUJIFILM", 8)) + { + base = ftell(ifp) - 10; + nf: + order = 0x4949; + fseek(ifp, 2, SEEK_CUR); + } + else if (!strcmp (buf, "OLYMP") || + !strncmp(buf, "LEICA", 5) || + !strcmp (buf, "Ricoh")) + { + fseek(ifp, -2, SEEK_CUR); + } + else if (!strcmp(buf, "AOC") || // Pentax, tribute to Asahi Optical Co. + !strcmp(buf, "QVC")) // Casio, from "QV-Camera" + { + fseek(ifp, -4, SEEK_CUR); + } + else if (!strncmp(buf, "CMT3", 4)) + { + order = sget2((uchar *)(buf + 4)); + fseek(ifp, 2L, SEEK_CUR); + } + else if (libraw_internal_data.unpacker_data.CR3_CTMDtag) + { + order = sget2((uchar *)buf); + fseek(ifp, -2L, SEEK_CUR); + } + else + { + fseek(ifp, -10, SEEK_CUR); + if (!strncmp(make, "SAMSUNG", 7)) + base = ftell(ifp); + } + + if (!is_Sony && + (!strncasecmp(make, "SONY", 4) || + !strncasecmp(make, "Konica", 6) || + !strncasecmp(make, "Minolta", 7) || + (!strncasecmp(make, "Hasselblad", 10) && + (!strncasecmp(model, "Stellar", 7) || + !strncasecmp(model, "Lunar", 5) || + !strncasecmp(model, "Lusso", 5) || + !strncasecmp(model, "HV", 2))))) { + is_Sony = 1; + } + + if (strcasestr(make, "Kodak") && + (sget2((uchar *)buf) > 1) && // check number of entries + (sget2((uchar *)buf) < 128) && + (sget2((uchar *)(buf + 4)) > 0) && // check type + (sget2((uchar *)(buf + 4)) < 13) && + (sget4((uchar *)(buf + 6)) < 256) // check count + ) + imKodak.MakerNoteKodak8a = 1; // Kodak P712 / P850 / P880 + + entries = get2(); + if (entries > 1000) + return; + + morder = order; + while (entries--) + { + order = morder; + tiff_get(base, &tag, &type, &len, &save); + tag |= uptag << 16; + + INT64 _pos = ftell(ifp); + INT64 _pos2; + if (len > 100 * 1024 * 1024) + goto next; // 100Mb tag? No! + if (len > 8 && _pos + len > 2 * fsize) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + if (imKodak.MakerNoteKodak8a) + { + if ((tag == 0xff00) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG) && (len == 1)) + { + INT64 _pos1 = get4(); + if ((_pos1 < fsize) && (_pos1 > 0)) + { + fseek(ifp, _pos1, SEEK_SET); + parse_makernote(base, tag); + } + } + else if (tag == 0xff00f90b) + { + imKodak.clipBlack = get2(); + } + else if (tag == 0xff00f90c) + { + imKodak.clipWhite = imgdata.color.linear_max[0] = + imgdata.color.linear_max[1] = imgdata.color.linear_max[2] = + imgdata.color.linear_max[3] = get2(); + } + } + else if (!strncmp(make, "Canon", 5)) + { + if (tag == 0x000d && len < 256000) // camera info + { + if (!tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + { + CanonCameraInfo = (uchar *)malloc(MAX(16, len)); + fread(CanonCameraInfo, len, 1, ifp); + } + else + { + CanonCameraInfo = (uchar *)malloc(MAX(16, len * 4)); + fread(CanonCameraInfo, len, 4, ifp); + } + lenCanonCameraInfo = len; + typeCanonCameraInfo = type; + } + + else if (tag == 0x0010) // Canon ModelID + { + unique_id = get4(); + setCanonBodyFeatures(unique_id); + if (lenCanonCameraInfo) + { + processCanonCameraInfo(unique_id, CanonCameraInfo, lenCanonCameraInfo, + typeCanonCameraInfo, nonDNG); + free(CanonCameraInfo); + CanonCameraInfo = 0; + lenCanonCameraInfo = 0; + } + } + + else + parseCanonMakernotes(tag, type, len, nonDNG); + } + + else if (!strncmp(make, "FUJI", 4)) + parseFujiMakernotes(tag, type, len, nonDNG); + + else if (!strncasecmp(model, "Hasselblad X1D", 14) || + !strncasecmp(model, "Hasselblad H6D", 14) || + !strncasecmp(model, "Hasselblad A6D", 14)) + { + if (tag == 0x0045) + { + imHassy.BaseISO = get4(); + } + else if (tag == 0x0046) + { + imHassy.Gain = getreal(type); + } + } + + else if (!strncmp(make, "PENTAX", 6) || + !strncmp(make, "RICOH", 5) || + !strncmp(model, "PENTAX", 6)) + { + if (!strncmp(model, "GR", 2) || + !strncmp(model, "GXR", 3)) + { + parseRicohMakernotes(base, tag, type, len, CameraDNG); + } + else + { + parsePentaxMakernotes(base, tag, type, len, nonDNG); + } + } + + else if (!strncmp(make, "SAMSUNG", 7)) + { + if (!dng_version) + parseSamsungMakernotes(base, tag, type, len, nonDNG); + else + parsePentaxMakernotes(base, tag, type, len, CameraDNG); + } + + else if (is_Sony) + { + if ((tag == 0xb028) && (len == 1) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + { // DSLR-A100 + if ((c = get4())) + { + fseek(ifp, c, SEEK_SET); + parse_makernote(base, tag); + } + } + else + { + parseSonyMakernotes( + base, tag, type, len, nonDNG, table_buf_0x0116, + table_buf_0x0116_len, table_buf_0x2010, table_buf_0x2010_len, + table_buf_0x9050, table_buf_0x9050_len, table_buf_0x9400, + table_buf_0x9400_len, table_buf_0x9402, table_buf_0x9402_len, + table_buf_0x9403, table_buf_0x9403_len, table_buf_0x9406, + table_buf_0x9406_len, table_buf_0x940c, table_buf_0x940c_len, + table_buf_0x940e, table_buf_0x940e_len); + } + } + fseek(ifp, _pos, SEEK_SET); + + if (!strncasecmp(make, "Hasselblad", 10) && !is_Sony) { + if (tag == 0x0011) + imHassy.SensorCode = getint(type); + else if (tag == 0x0016) + imHassy.CoatingCode = getint(type); + else if ((tag == 0x002a) && + tagtypeIs(LIBRAW_EXIFTAG_TYPE_SRATIONAL) && + (len == 12)) { + FORC4 for (int i = 0; i < 3; i++) + imHassy.mnColorMatrix[c][i] = getreal(type); + + } else if (tag == 0x0031) { + imHassy.RecommendedCrop[0] = getint(type); + imHassy.RecommendedCrop[1] = getint(type); + } + } + + if ((tag == 0x0004 || tag == 0x0114) && !strncmp(make, "KONICA", 6)) + { + fseek(ifp, tag == 0x0004 ? 140 : 160, SEEK_CUR); + switch (get2()) + { + case 72: + flip = 0; + break; + case 76: + flip = 6; + break; + case 82: + flip = 5; + break; + } + } + + _pos2 = ftell(ifp); + if (!strncasecmp(make, "Olympus", 7) || + (!strncasecmp(make, "CLAUSS", 6) && !strncasecmp(model, "piX 5oo", 7))) + { + if ((tag == 0x2010) || (tag == 0x2020) || (tag == 0x2030) || + (tag == 0x2031) || (tag == 0x2040) || (tag == 0x2050) || + (tag == 0x3000)) + { + if (tagtypeIs(LIBRAW_EXIFTOOLTAGTYPE_binary)) + { + parse_makernote(base, tag); + } + else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_IFD)) + { + fseek(ifp, base + get4(), SEEK_SET); + parse_makernote(base, tag); + } + } + else if (tag == 0x0207) + { + getOlympus_CameraType2(); + } + else if ((tag == 0x0404) || (tag == 0x101a)) + { + if (!imgdata.shootinginfo.BodySerial[0]) + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + } + else if (tag == 0x1002) + { + ilm.CurAp = libraw_powf64l(2.0f, getreal(type) / 2); + } + else if (tag == 0x1007) + { + imCommon.SensorTemperature = (float)get2(); + } + else if (tag == 0x1008) + { + imCommon.LensTemperature = (float)get2(); + } + else if ((tag == 0x1011) && strcmp(software, "v757-71")) + { + for (i = 0; i < 3; i++) + { + if (!imOly.ColorSpace) + { + FORC3 cmatrix[i][c] = ((short)get2()) / 256.0; + } + else + { + FORC3 imgdata.color.ccm[i][c] = ((short)get2()) / 256.0; + } + } + } + else if (tag == 0x1012) + { + FORC4 cblack[RGGB_2_RGBG(c)] = get2(); + } + else if (tag == 0x1017) + { + cam_mul[0] = get2() / 256.0; + } + else if (tag == 0x1018) + { + cam_mul[2] = get2() / 256.0; + } + else if ((tag >= 0x20100000) && (tag <= 0x2010ffff)) + { + parseOlympus_Equipment((tag & 0x0000ffff), type, len, nonDNG); + } + else if ((tag >= 0x20200000) && (tag <= 0x2020ffff)) + { + parseOlympus_CameraSettings(base, (tag & 0x0000ffff), type, len, + nonDNG); + } + else if ((tag == 0x20300108) || (tag == 0x20310109)) + { + imOly.ColorSpace = get2(); + switch (imOly.ColorSpace) { + case 0: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_ProPhotoRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + } + else if ((tag >= 0x20400000) && (tag <= 0x2040ffff)) + { + parseOlympus_ImageProcessing((tag & 0x0000ffff), type, len, nonDNG); + } + else if (tag == 0x20501500) + { + getOlympus_SensorTemperature(len); + } + else if ((tag >= 0x30000000) && (tag <= 0x3000ffff)) + { + parseOlympus_RawInfo((tag & 0x0000ffff), type, len, nonDNG); + } + } + fseek(ifp, _pos2, SEEK_SET); + + if ((tag == 0x0015) && + tagtypeIs(LIBRAW_EXIFTAG_TYPE_ASCII) && + is_raw) + { // Hasselblad + stmread (imHassy.SensorUnitConnector, len, ifp); + } + + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_UNDEFINED) && + ((tag == 0x0081) || // Minolta + (tag == 0x0100))) // Olympus + { + thumb_offset = ftell(ifp); + thumb_length = len; + } + if ((tag == 0x0088) && // Minolta, possibly Olympus too + tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG) && + (thumb_offset = get4())) + thumb_offset += base; + + if ((tag == 0x0089) && // Minolta, possibly Olympus too + tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + thumb_length = get4(); + + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_UNDEFINED) && // Nikon + ((tag == 0x008c) || + (tag == 0x0096))) { + meta_offset = ftell(ifp); + } + + if ((tag == 0x00a1) && + tagtypeIs(LIBRAW_EXIFTAG_TYPE_UNDEFINED) && + strncasecmp(make, "Samsung", 7)) + { + order = 0x4949; + fseek(ifp, 140, SEEK_CUR); + FORC3 cam_mul[c] = get4(); + } + + if (tag == 0xb001 && tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT)) // Sony ModelID + { + unique_id = get2(); + } + if (tag == 0x0200 && len == 3) // Olympus + shot_order = (get4(), get4()); + + if (tag == 0x0f00 && tagtypeIs(LIBRAW_EXIFTAG_TYPE_UNDEFINED)) + { + if (len == 614) + fseek(ifp, 176, SEEK_CUR); + else if (len == 734 || len == 1502) // Kodak, Minolta, Olympus + fseek(ifp, 148, SEEK_CUR); + else + goto next; + goto get2_256; + } + + if (tag == 0x2011 && len == 2) // Casio + { + get2_256: + order = 0x4d4d; + cam_mul[0] = get2() / 256.0; + cam_mul[2] = get2() / 256.0; + } + + next: + fseek(ifp, save, SEEK_SET); + } +quit: + order = sorder; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/mediumformat.cpp libkdcraw/libkdcraw/libraw/src/metadata/mediumformat.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/mediumformat.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/mediumformat.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,501 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::parse_phase_one(int base) +{ + unsigned entries, tag, type, len, data, save, i, c; + float romm_cam[3][3]; + char *cp; + + memset(&ph1, 0, sizeof ph1); + fseek(ifp, base, SEEK_SET); + order = get4() & 0xffff; + if (get4() >> 8 != 0x526177) + return; /* "Raw" */ + unsigned offset = get4(); + if (offset == 0xbad0bad) + return; + fseek(ifp, offset + base, SEEK_SET); + entries = get4(); + if (entries > 8192) + return; // too much?? + get4(); + while (entries--) + { + tag = get4(); + type = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek(ifp, base + data, SEEK_SET); + switch (tag) + { + + case 0x0102: + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && + (imgdata.shootinginfo.BodySerial[1] == 0x49)) + { + unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | + (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - + 0x41; + } + else + { + unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | + (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - + 0x41; + } + setPhaseOneFeatures(unique_id); + break; + case 0x0203: + stmread(imgdata.makernotes.phaseone.Software, len, ifp); + case 0x0204: + stmread(imgdata.makernotes.phaseone.SystemType, len, ifp); + case 0x0211: + imCommon.SensorTemperature2 = int_to_float(data); + break; + case 0x0401: + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + ilm.CurAp = libraw_powf64l(2.0f, (int_to_float(data) / 2.0f)); + else + ilm.CurAp = libraw_powf64l(2.0f, (getreal(type) / 2.0f)); + break; + case 0x0403: + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + ilm.CurFocal = int_to_float(data); + else + ilm.CurFocal = getreal(type); + break; + case 0x0410: + stmread(ilm.body, len, ifp); + if (((unsigned char)ilm.body[0]) == 0xff) + ilm.body[0] = 0; + break; + case 0x0412: + stmread(ilm.Lens, len, ifp); + if (((unsigned char)ilm.Lens[0]) == 0xff) + ilm.Lens[0] = 0; + break; + case 0x0414: + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + { + ilm.MaxAp4CurFocal = libraw_powf64l(2.0f, (int_to_float(data) / 2.0f)); + } + else + { + ilm.MaxAp4CurFocal = libraw_powf64l(2.0f, (getreal(type) / 2.0f)); + } + break; + case 0x0415: + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + { + ilm.MinAp4CurFocal = libraw_powf64l(2.0f, (int_to_float(data) / 2.0f)); + } + else + { + ilm.MinAp4CurFocal = libraw_powf64l(2.0f, (getreal(type) / 2.0f)); + } + break; + case 0x0416: + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + { + ilm.MinFocal = int_to_float(data); + } + else + { + ilm.MinFocal = getreal(type); + } + if (ilm.MinFocal > 1000.0f) + { + ilm.MinFocal = 0.0f; + } + break; + case 0x0417: + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_LONG)) + { + ilm.MaxFocal = int_to_float(data); + } + else + { + ilm.MaxFocal = getreal(type); + } + break; + + case 0x0100: + flip = "0653"[data & 3] - '0'; + break; + case 0x0106: + for (i = 0; i < 9; i++) + imgdata.color.P1_color[0].romm_cam[i] = ((float *)romm_cam)[i] = + getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + romm_coeff(romm_cam); + break; + case 0x0107: + FORC3 cam_mul[c] = getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + break; + case 0x0108: + raw_width = data; + break; + case 0x0109: + raw_height = data; + break; + case 0x010a: + left_margin = data; + break; + case 0x010b: + top_margin = data; + break; + case 0x010c: + width = data; + break; + case 0x010d: + height = data; + break; + case 0x010e: + ph1.format = data; + break; + case 0x010f: + data_offset = data + base; + break; + case 0x0110: + meta_offset = data + base; + meta_length = len; + break; + case 0x0112: + ph1.key_off = save - 4; + break; + case 0x0210: + ph1.tag_210 = int_to_float(data); + imCommon.SensorTemperature = ph1.tag_210; + break; + case 0x021a: + ph1.tag_21a = data; + break; + case 0x021c: + strip_offset = data + base; + break; + case 0x021d: + ph1.t_black = data; + break; + case 0x0222: + ph1.split_col = data; + break; + case 0x0223: + ph1.black_col = data + base; + break; + case 0x0224: + ph1.split_row = data; + break; + case 0x0225: + ph1.black_row = data + base; + break; + case 0x0226: + for (i = 0; i < 9; i++) + imgdata.color.P1_color[1].romm_cam[i] = getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + break; + case 0x0301: + model[63] = 0; + imgdata.makernotes.phaseone.FirmwareString[255] = 0; + fread(imgdata.makernotes.phaseone.FirmwareString, 1, 255, ifp); + memcpy(model, imgdata.makernotes.phaseone.FirmwareString, 63); + if ((cp = strstr(model, " camera"))) + *cp = 0; + else if ((cp = strchr(model, ','))) + *cp = 0; + /* minus and the letter after it are not always present + if present, last letter means: + C : Contax 645AF + H : Hasselblad H1 / H2 + M : Mamiya + V : Hasselblad 555ELD / 553ELX / 503CW / 501CM; not included below + because of adapter conflicts (Mamiya RZ body) if not present, Phase One + 645 AF, Mamiya 645AFD Series, or anything + */ + strcpy(imgdata.makernotes.phaseone.SystemModel, model); + if ((cp = strchr(model, '-'))) + { + if (cp[1] == 'C') + { + strcpy(ilm.body, "Contax 645AF"); + ilm.CameraMount = LIBRAW_MOUNT_Contax645; + ilm.CameraFormat = LIBRAW_FORMAT_645; + } + else if (cp[1] == 'M') + { + strcpy(ilm.body, "Mamiya 645"); + ilm.CameraMount = LIBRAW_MOUNT_Mamiya645; + ilm.CameraFormat = LIBRAW_FORMAT_645; + } + else if (cp[1] == 'H') + { + strcpy(ilm.body, "Hasselblad H1/H2"); + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_H; + ilm.CameraFormat = LIBRAW_FORMAT_645; + } + *cp = 0; + } + } + fseek(ifp, save, SEEK_SET); + } + + if (!ilm.body[0] && !imgdata.shootinginfo.BodySerial[0]) + { + fseek(ifp, meta_offset, SEEK_SET); + order = get2(); + fseek(ifp, 6, SEEK_CUR); + fseek(ifp, meta_offset + get4(), SEEK_SET); + entries = get4(); + get4(); + while (entries--) + { + tag = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek(ifp, meta_offset + data, SEEK_SET); + if (tag == 0x0407) + { + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && + (imgdata.shootinginfo.BodySerial[1] == 0x49)) + { + unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | + (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - + 0x41; + } + else + { + unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | + (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - + 0x41; + } + setPhaseOneFeatures(unique_id); + } + fseek(ifp, save, SEEK_SET); + } + } + load_raw = ph1.format < 3 ? &LibRaw::phase_one_load_raw + : &LibRaw::phase_one_load_raw_c; + maximum = 0xffff; + strcpy(make, "Phase One"); + if (model[0]) + return; + switch (raw_height) + { + case 2060: + strcpy(model, "LightPhase"); + break; + case 2682: + strcpy(model, "H 10"); + break; + case 4128: + strcpy(model, "H 20"); + break; + case 5488: + strcpy(model, "H 25"); + break; + } +} + +void LibRaw::parse_mos(int offset) +{ + char data[40]; + int from, i, c, neut[4], planes = 0, frot = 0; + unsigned skip; + static const char *mod[] = { + /* DM22, DM28, DM40, DM56 are somewhere here too */ + "", // 0 + "DCB2", // 1 + "Volare", // 2 + "Cantare", // 3 + "CMost", // 4 + "Valeo 6", // 5 + "Valeo 11", // 6 + "Valeo 22", // 7 + "Valeo 11p", // 8 + "Valeo 17", // 9 + "", // 10 + "Aptus 17", // 11 + "Aptus 22", // 12 + "Aptus 75", // 13 + "Aptus 65", // 14 + "Aptus 54S", // 15 + "Aptus 65S", // 16 + "Aptus 75S", // 17 + "AFi 5", // 18 + "AFi 6", // 19 + "AFi 7", // 20 + "AFi-II 7", // 21 + "Aptus-II 7", // 22 (same CMs as Mamiya DM33) + "", // 23 + "Aptus-II 6", // 24 (same CMs as Mamiya DM28) + "AFi-II 10", // 25 + "", // 26 + "Aptus-II 10", // 27 (same CMs as Mamiya DM56) + "Aptus-II 5", // 28 (same CMs as Mamiya DM22) + "", // 29 + "DM33", // 30, make is Mamiya + "", // 31 + "", // 32 + "Aptus-II 10R", // 33 + "Aptus-II 8", // 34 (same CMs as Mamiya DM40) + "", // 35 + "Aptus-II 12", // 36 + "", // 37 + "AFi-II 12" // 38 + }; + float romm_cam[3][3]; + + fseek(ifp, offset, SEEK_SET); + while (!feof(ifp)) + { + if (get4() != 0x504b5453) + break; + get4(); + fread(data, 1, 40, ifp); + skip = get4(); + from = ftell(ifp); + + if (!strcmp(data, "CameraObj_camera_type")) + { + stmread(ilm.body, (unsigned)skip, ifp); + if (ilm.body[0]) + { + if (!strncmp(ilm.body, "Mamiya R", 8)) + { + ilm.CameraMount = LIBRAW_MOUNT_Mamiya67; + ilm.CameraFormat = LIBRAW_FORMAT_67; + } + else if (!strncmp(ilm.body, "Hasselblad 5", 12)) + { + ilm.CameraFormat = LIBRAW_FORMAT_66; + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_V; + } + else if (!strncmp(ilm.body, "Hasselblad H", 12)) + { + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_H; + ilm.CameraFormat = LIBRAW_FORMAT_645; + } + else if (!strncmp(ilm.body, "Mamiya 6", 8) || + !strncmp(ilm.body, "Phase One 6", 11)) + { + ilm.CameraMount = LIBRAW_MOUNT_Mamiya645; + ilm.CameraFormat = LIBRAW_FORMAT_645; + } + else if (!strncmp(ilm.body, "Large F", 7)) + { + ilm.CameraMount = LIBRAW_MOUNT_LF; + ilm.CameraFormat = LIBRAW_FORMAT_LF; + } + else if (!strncmp(model, "Leaf AFi", 8)) + { + ilm.CameraMount = LIBRAW_MOUNT_Rollei_bayonet; + ilm.CameraFormat = LIBRAW_FORMAT_66; + } + } + } + if (!strcmp(data, "back_serial_number")) + { + char buffer[sizeof(imgdata.shootinginfo.BodySerial)]; + char *words[4]; + stmread(buffer, (unsigned)skip, ifp); + /*nwords = */ + getwords(buffer, words, 4, sizeof(imgdata.shootinginfo.BodySerial)); + strcpy(imgdata.shootinginfo.BodySerial, words[0]); + } + if (!strcmp(data, "CaptProf_serial_number")) + { + char buffer[sizeof(imgdata.shootinginfo.InternalBodySerial)]; + char *words[4]; + stmread(buffer, (unsigned)skip, ifp); + /*nwords =*/ getwords(buffer, words, 4, + sizeof(imgdata.shootinginfo.InternalBodySerial)); + strcpy(imgdata.shootinginfo.InternalBodySerial, words[0]); + } + + if (!strcmp(data, "JPEG_preview_data")) + { + thumb_offset = from; + thumb_length = skip; + } + if (!strcmp(data, "icc_camera_profile")) + { + profile_offset = from; + profile_length = skip; + } + if (!strcmp(data, "ShootObj_back_type")) + { + fscanf(ifp, "%d", &i); + if ((unsigned)i < sizeof mod / sizeof(*mod)) + { + strcpy(model, mod[i]); + if (!strncmp(model, "AFi", 3)) + { + ilm.CameraMount = LIBRAW_MOUNT_Rollei_bayonet; + ilm.CameraFormat = LIBRAW_FORMAT_66; + } + ilm.CamID = i; + } + } + if (!strcmp(data, "icc_camera_to_tone_matrix")) + { + for (i = 0; i < 9; i++) + ((float *)romm_cam)[i] = int_to_float(get4()); + romm_coeff(romm_cam); + } + if (!strcmp(data, "CaptProf_color_matrix")) + { + for (i = 0; i < 9; i++) + fscanf(ifp, "%f", (float *)romm_cam + i); + romm_coeff(romm_cam); + } + if (!strcmp(data, "CaptProf_number_of_planes")) + fscanf(ifp, "%d", &planes); + if (!strcmp(data, "CaptProf_raw_data_rotation")) + fscanf(ifp, "%d", &flip); + if (!strcmp(data, "CaptProf_mosaic_pattern")) + FORC4 + { + fscanf(ifp, "%d", &i); + if (i == 1) + frot = c ^ (c >> 1); // 0123 -> 0132 + } + if (!strcmp(data, "ImgProf_rotation_angle")) + { + fscanf(ifp, "%d", &i); + flip = i - flip; + } + if (!strcmp(data, "NeutObj_neutrals") && !cam_mul[0]) + { + FORC4 fscanf(ifp, "%d", neut + c); + FORC3 + if (neut[c + 1]) + cam_mul[c] = (float)neut[0] / neut[c + 1]; + } + if (!strcmp(data, "Rows_data")) + load_flags = get4(); + parse_mos(from); + fseek(ifp, skip + from, SEEK_SET); + } + if (planes) + filters = (planes == 1) * 0x01010101U * + (uchar) "\x94\x61\x16\x49"[(flip / 90 + frot) & 3]; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/minolta.cpp libkdcraw/libkdcraw/libraw/src/metadata/minolta.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/minolta.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/minolta.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,112 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::parse_minolta(int base) +{ + int tag, len, offset, high = 0, wide = 0, i, c; + short sorder = order; + INT64 save; + + fseek(ifp, base, SEEK_SET); + if (fgetc(ifp) || fgetc(ifp) - 'M' || fgetc(ifp) - 'R') + return; + order = fgetc(ifp) * 0x101; + offset = base + get4() + 8; + INT64 fsize = ifp->size(); + if (offset > fsize - 8) // At least 8 bytes for tag/len + offset = fsize - 8; + + while ((save = ftell(ifp)) < offset) + { + for (tag = i = 0; i < 4; i++) + tag = tag << 8 | fgetc(ifp); + len = get4(); + if (len < 0) + return; // just ignore wrong len?? or raise bad file exception? + if ((INT64)len + save + 8LL > fsize) + return; // just ignore out of file metadata, stop parse + switch (tag) + { + case 0x505244: /* PRD */ + fseek(ifp, 8, SEEK_CUR); + high = get2(); + wide = get2(); + imSony.prd_ImageHeight = get2(); + imSony.prd_ImageWidth = get2(); + fseek(ifp, 1L, SEEK_CUR); + imSony.prd_RawBitDepth = (ushort)fgetc(ifp); + imSony.prd_StorageMethod = (ushort)fgetc(ifp); + fseek(ifp, 4L, SEEK_CUR); + imSony.prd_BayerPattern = (ushort)fgetc(ifp); + break; + case 0x524946: /* RIF */ + if (!strncasecmp(model, "DSLR-A100", 9)) + { + fseek(ifp, 8, SEEK_CUR); + icWBC[LIBRAW_WBI_Tungsten][0] = get2(); + icWBC[LIBRAW_WBI_Tungsten][2] = get2(); + icWBC[LIBRAW_WBI_Daylight][0] = get2(); + icWBC[LIBRAW_WBI_Daylight][2] = get2(); + icWBC[LIBRAW_WBI_Cloudy][0] = get2(); + icWBC[LIBRAW_WBI_Cloudy][2] = get2(); + icWBC[LIBRAW_WBI_FL_W][0] = get2(); + icWBC[LIBRAW_WBI_FL_W][2] = get2(); + icWBC[LIBRAW_WBI_Flash][0] = get2(); + icWBC[LIBRAW_WBI_Flash][2] = get2(); + get4(); + icWBC[LIBRAW_WBI_Shade][0] = get2(); + icWBC[LIBRAW_WBI_Shade][2] = get2(); + icWBC[LIBRAW_WBI_FL_D][0] = get2(); + icWBC[LIBRAW_WBI_FL_D][2] = get2(); + icWBC[LIBRAW_WBI_FL_N][0] = get2(); + icWBC[LIBRAW_WBI_FL_N][2] = get2(); + icWBC[LIBRAW_WBI_FL_WW][0] = get2(); + icWBC[LIBRAW_WBI_FL_WW][2] = get2(); + icWBC[LIBRAW_WBI_Daylight][1] = icWBC[LIBRAW_WBI_Daylight][3] = icWBC + [LIBRAW_WBI_Tungsten] + [1] = icWBC[LIBRAW_WBI_Tungsten][3] = icWBC[LIBRAW_WBI_Flash][1] = + icWBC[LIBRAW_WBI_Flash][3] = icWBC[LIBRAW_WBI_Cloudy][1] = + icWBC[LIBRAW_WBI_Cloudy][3] = icWBC[LIBRAW_WBI_Shade][1] = + icWBC[LIBRAW_WBI_Shade][3] = icWBC[LIBRAW_WBI_FL_D][1] = + icWBC[LIBRAW_WBI_FL_D][3] = + icWBC[LIBRAW_WBI_FL_N][1] = + icWBC[LIBRAW_WBI_FL_N][3] = + icWBC[LIBRAW_WBI_FL_W][1] = + icWBC[LIBRAW_WBI_FL_W][3] = + icWBC[LIBRAW_WBI_FL_WW][1] = + icWBC[LIBRAW_WBI_FL_WW][3] = + 0x100; + } + break; + case 0x574247: /* WBG */ + get4(); + i = strcmp(model, "DiMAGE A200") ? 0 : 3; + FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); + break; + case 0x545457: /* TTW */ + parse_tiff(ftell(ifp)); + data_offset = offset; + } + fseek(ifp, save + len + 8, SEEK_SET); + } + raw_height = high; + raw_width = wide; + order = sorder; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/misc_parsers.cpp libkdcraw/libkdcraw/libraw/src/metadata/misc_parsers.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/misc_parsers.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/misc_parsers.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,680 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +/* + Returns 1 for a Coolpix 2100, 0 for anything else. + */ +int LibRaw::nikon_e2100() +{ + uchar t[12]; + int i; + + fseek(ifp, 0, SEEK_SET); + for (i = 0; i < 1024; i++) + { + fread(t, 1, 12, ifp); + if (((t[2] & t[4] & t[7] & t[9]) >> 4 & t[1] & t[6] & t[8] & t[11] & 3) != + 3) + return 0; + } + return 1; +} + +void LibRaw::nikon_3700() +{ + int bits, i; + uchar dp[24]; + static const struct + { + int bits; + char t_make[12], t_model[15]; + int t_maker_idx; + } table[] = {{0x00, "Pentax", "Optio 33WR", LIBRAW_CAMERAMAKER_Pentax}, + {0x03, "Nikon", "E3200", LIBRAW_CAMERAMAKER_Nikon}, + {0x32, "Nikon", "E3700", LIBRAW_CAMERAMAKER_Nikon}, + {0x33, "Olympus", "C-740UZ", LIBRAW_CAMERAMAKER_Olympus}}; + + fseek(ifp, 3072, SEEK_SET); + fread(dp, 1, 24, ifp); + bits = (dp[8] & 3) << 4 | (dp[20] & 3); + for (i = 0; i < int(sizeof table / sizeof *table); i++) + if (bits == table[i].bits) + { + strcpy(make, table[i].t_make); + maker_index = table[i].t_maker_idx; + strcpy(model, table[i].t_model); + } +} + +/* + Separates a Minolta DiMAGE Z2 from a Nikon E4300. + */ +int LibRaw::minolta_z2() +{ + int i, nz; + char tail[424]; + + fseek(ifp, -sizeof tail, SEEK_END); + fread(tail, 1, sizeof tail, ifp); + for (nz = i = 0; i < int(sizeof tail); i++) + if (tail[i]) + nz++; + return nz > 20; +} + +int LibRaw::canon_s2is() +{ + unsigned row; + + for (row = 0; row < 100; row++) + { + fseek(ifp, row * 3340 + 3284, SEEK_SET); + if (getc(ifp) > 15) + return 1; + } + return 0; +} + +void LibRaw::parse_redcine() +{ + unsigned i, len, rdvo; + + order = 0x4d4d; + is_raw = 0; + fseek(ifp, 52, SEEK_SET); + width = get4(); + height = get4(); + fseek(ifp, 0, SEEK_END); + fseek(ifp, -(i = ftello(ifp) & 511), SEEK_CUR); + if (get4() != i || get4() != 0x52454f42) + { + fseek(ifp, 0, SEEK_SET); + while ((len = get4()) != (unsigned)EOF) + { + if (get4() == 0x52454456) + if (is_raw++ == shot_select) + data_offset = ftello(ifp) - 8; + fseek(ifp, len - 8, SEEK_CUR); + } + } + else + { + rdvo = get4(); + fseek(ifp, 12, SEEK_CUR); + is_raw = get4(); + fseeko(ifp, rdvo + 8 + shot_select * 4, SEEK_SET); + data_offset = get4(); + } +} + +void LibRaw::parse_cine() +{ + unsigned off_head, off_setup, off_image, i, temp; + + order = 0x4949; + fseek(ifp, 4, SEEK_SET); + is_raw = get2() == 2; + fseek(ifp, 14, SEEK_CUR); + is_raw *= get4(); + off_head = get4(); + off_setup = get4(); + off_image = get4(); + timestamp = get4(); + if ((i = get4())) + timestamp = i; + fseek(ifp, off_head + 4, SEEK_SET); + raw_width = get4(); + raw_height = get4(); + switch (get2(), get2()) + { + case 8: + load_raw = &LibRaw::eight_bit_load_raw; + break; + case 16: + load_raw = &LibRaw::unpacked_load_raw; + } + fseek(ifp, off_setup + 792, SEEK_SET); + strcpy(make, "CINE"); + sprintf(model, "%d", get4()); + fseek(ifp, 12, SEEK_CUR); + switch ((i = get4()) & 0xffffff) + { + case 3: + filters = 0x94949494; + break; + case 4: + filters = 0x49494949; + break; + default: + is_raw = 0; + } + fseek(ifp, 72, SEEK_CUR); + switch ((get4() + 3600) % 360) + { + case 270: + flip = 4; + break; + case 180: + flip = 1; + break; + case 90: + flip = 7; + break; + case 0: + flip = 2; + } + cam_mul[0] = getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + cam_mul[2] = getreal(LIBRAW_EXIFTAG_TYPE_FLOAT); + temp = get4(); + maximum = ~((~0u) << LIM(temp, 1, 31)); + fseek(ifp, 668, SEEK_CUR); + shutter = get4() / 1000000000.0; + fseek(ifp, off_image, SEEK_SET); + if (shot_select < is_raw) + fseek(ifp, shot_select * 8, SEEK_CUR); + data_offset = (INT64)get4() + 8; + data_offset += (INT64)get4() << 32; +} + +void LibRaw::parse_qt(int end) +{ + unsigned save, size; + char tag[4]; + + order = 0x4d4d; + while (ftell(ifp) + 7 < end) + { + save = ftell(ifp); + if ((size = get4()) < 8) + return; + if ((int)size < 0) + return; // 2+GB is too much + if (save + size < save) + return; // 32bit overflow + fread(tag, 4, 1, ifp); + if (!memcmp(tag, "moov", 4) || !memcmp(tag, "udta", 4) || + !memcmp(tag, "CNTH", 4)) + parse_qt(save + size); + if (!memcmp(tag, "CNDA", 4)) + parse_jpeg(ftell(ifp)); + fseek(ifp, save + size, SEEK_SET); + } +} + +void LibRaw::parse_smal(int offset, int fsize) +{ + int ver; + + fseek(ifp, offset + 2, SEEK_SET); + order = 0x4949; + ver = fgetc(ifp); + if (ver == 6) + fseek(ifp, 5, SEEK_CUR); + if (get4() != (unsigned)fsize) + return; + if (ver > 6) + data_offset = get4(); + raw_height = height = get2(); + raw_width = width = get2(); + strcpy(make, "SMaL"); + sprintf(model, "v%d %dx%d", ver, width, height); + if (ver == 6) + load_raw = &LibRaw::smal_v6_load_raw; + if (ver == 9) + load_raw = &LibRaw::smal_v9_load_raw; +} + +void LibRaw::parse_riff() +{ + unsigned i, size, end; + char tag[4], date[64], month[64]; + static const char mon[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + struct tm t; + + order = 0x4949; + fread(tag, 4, 1, ifp); + size = get4(); + end = ftell(ifp) + size; + if (!memcmp(tag, "RIFF", 4) || !memcmp(tag, "LIST", 4)) + { + int maxloop = 1000; + get4(); + while (ftell(ifp) + 7 < end && !feof(ifp) && maxloop--) + parse_riff(); + } + else if (!memcmp(tag, "nctg", 4)) + { + while (ftell(ifp) + 7 < end) + { + i = get2(); + size = get2(); + if ((i + 1) >> 1 == 10 && size == 20) + get_timestamp(0); + else + fseek(ifp, size, SEEK_CUR); + } + } + else if (!memcmp(tag, "IDIT", 4) && size < 64) + { + fread(date, 64, 1, ifp); + date[size] = 0; + memset(&t, 0, sizeof t); + if (sscanf(date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, &t.tm_hour, + &t.tm_min, &t.tm_sec, &t.tm_year) == 6) + { + for (i = 0; i < 12 && strcasecmp(mon[i], month); i++) + ; + t.tm_mon = i; + t.tm_year -= 1900; + if (mktime(&t) > 0) + timestamp = mktime(&t); + } + } + else + fseek(ifp, size, SEEK_CUR); +} + +void LibRaw::parse_rollei() +{ + char line[128], *val; + struct tm t; + + fseek(ifp, 0, SEEK_SET); + memset(&t, 0, sizeof t); + do + { + line[0] = 0; + if (!fgets(line, 128, ifp)) + break; + if(!line[0]) break; // zero-length + if ((val = strchr(line, '='))) + *val++ = 0; + else + val = line + strbuflen(line); + if (!strcmp(line, "DAT")) + sscanf(val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); + if (!strcmp(line, "TIM")) + sscanf(val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); + if (!strcmp(line, "HDR")) + thumb_offset = atoi(val); + if (!strcmp(line, "X ")) + raw_width = atoi(val); + if (!strcmp(line, "Y ")) + raw_height = atoi(val); + if (!strcmp(line, "TX ")) + thumb_width = atoi(val); + if (!strcmp(line, "TY ")) + thumb_height = atoi(val); + if (!strcmp(line, "APT")) + aperture = atof(val); + if (!strcmp(line, "SPE")) + shutter = atof(val); + if (!strcmp(line, "FOCLEN")) + focal_len = atof(val); + if (!strcmp(line, "BLKOFS")) + black = atoi(val) +1; + if (!strcmp(line, "ORI")) + switch (atoi(val)) { + case 1: + flip = 6; + break; + case 2: + flip = 3; + break; + case 3: + flip = 5; + break; + } + if (!strcmp(line, "CUTRECT")) { + sscanf(val, "%hu %hu %hu %hu", + &imgdata.sizes.raw_inset_crop.cleft, + &imgdata.sizes.raw_inset_crop.ctop, + &imgdata.sizes.raw_inset_crop.cwidth, + &imgdata.sizes.raw_inset_crop.cheight); + } + } while (strncmp(line, "EOHD", 4)); + data_offset = thumb_offset + thumb_width * thumb_height * 2; + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); + strcpy(make, "Rollei"); + strcpy(model, "d530flex"); + write_thumb = &LibRaw::rollei_thumb; +} + +void LibRaw::parse_sinar_ia() +{ + int entries, off; + char str[8], *cp; + + order = 0x4949; + fseek(ifp, 4, SEEK_SET); + entries = get4(); + if (entries < 1 || entries > 8192) + return; + fseek(ifp, get4(), SEEK_SET); + while (entries--) + { + off = get4(); + get4(); + fread(str, 8, 1, ifp); + str[7] = 0; // Ensure end of string + if (!strcmp(str, "META")) + meta_offset = off; + if (!strcmp(str, "THUMB")) + thumb_offset = off; + if (!strcmp(str, "RAW0")) + data_offset = off; + } + fseek(ifp, meta_offset + 20, SEEK_SET); + fread(make, 64, 1, ifp); + make[63] = 0; + if ((cp = strchr(make, ' '))) + { + strcpy(model, cp + 1); + *cp = 0; + } + raw_width = get2(); + raw_height = get2(); + load_raw = &LibRaw::unpacked_load_raw; + thumb_width = (get4(), get2()); + thumb_height = get2(); + write_thumb = &LibRaw::ppm_thumb; + maximum = 0x3fff; +} + +void LibRaw::parse_kyocera() +{ + + int c; + static const ushort table[13] = {25, 32, 40, 50, 64, 80, 100, + 125, 160, 200, 250, 320, 400}; + + fseek(ifp, 33, SEEK_SET); + get_timestamp(1); + fseek(ifp, 52, SEEK_SET); + c = get4(); + if ((c > 6) && (c < 20)) + iso_speed = table[c - 7]; + shutter = libraw_powf64l(2.0f, (((float)get4()) / 8.0f)) / 16000.0f; + FORC4 cam_mul[RGGB_2_RGBG(c)] = get4(); + fseek(ifp, 88, SEEK_SET); + aperture = libraw_powf64l(2.0f, ((float)get4()) / 16.0f); + fseek(ifp, 112, SEEK_SET); + focal_len = get4(); + + fseek(ifp, 104, SEEK_SET); + ilm.MaxAp4CurFocal = libraw_powf64l(2.0f, ((float)get4()) / 16.0f); + fseek(ifp, 124, SEEK_SET); + stmread(ilm.Lens, 32, ifp); + ilm.CameraMount = LIBRAW_MOUNT_Contax_N; + ilm.CameraFormat = LIBRAW_FORMAT_FF; + if (ilm.Lens[0]) + { + ilm.LensMount = LIBRAW_MOUNT_Contax_N; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } +} + +int LibRaw::parse_jpeg(int offset) +{ + int len, save, hlen, mark; + fseek(ifp, offset, SEEK_SET); + if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) + return 0; + + while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) + { + order = 0x4d4d; + len = get2() - 2; + save = ftell(ifp); + if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) + { + fgetc(ifp); + raw_height = get2(); + raw_width = get2(); + } + order = get2(); + hlen = get4(); + if (get4() == 0x48454150 && (save + hlen) >= 0 && + (save + hlen) <= ifp->size()) /* "HEAP" */ + { + parse_ciff(save + hlen, len - hlen, 0); + } + if (parse_tiff(save + 6)) + apply_tiff(); + fseek(ifp, save + len, SEEK_SET); + } + return 1; +} + +void LibRaw::parse_thumb_note(int base, unsigned toff, unsigned tlen) +{ + unsigned entries, tag, type, len, save; + + entries = get2(); + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + if (tag == toff) + thumb_offset = get4() + base; + if (tag == tlen) + thumb_length = get4(); + fseek(ifp, save, SEEK_SET); + } +} + +void LibRaw::parse_broadcom() +{ + + /* This structure is at offset 0xb0 from the 'BRCM' ident. */ + struct + { + uint8_t umode[32]; + uint16_t uwidth; + uint16_t uheight; + uint16_t padding_right; + uint16_t padding_down; + uint32_t unknown_block[6]; + uint16_t transform; + uint16_t format; + uint8_t bayer_order; + uint8_t bayer_format; + } header; + + header.bayer_order = 0; + fseek(ifp, 0xb0 - 0x20, SEEK_CUR); + fread(&header, 1, sizeof(header), ifp); + /* load_flags is not used in broadcom loader, so reuse it for raw_stride */ + load_flags = + ((((((header.uwidth + header.padding_right) * 5) + 3) >> 2) + 0x1f) & + (~0x1f)); + raw_width = width = header.uwidth; + raw_height = height = header.uheight; + filters = 0x16161616; /* default Bayer order is 2, BGGR */ + + switch (header.bayer_order) + { + case 0: /* RGGB */ + filters = 0x94949494; + break; + case 1: /* GBRG */ + filters = 0x49494949; + break; + case 3: /* GRBG */ + filters = 0x61616161; + break; + } +} + +/* + Returns 1 for a Coolpix 995, 0 for anything else. + */ +int LibRaw::nikon_e995() +{ + int i, histo[256]; + const uchar often[] = {0x00, 0x55, 0xaa, 0xff}; + + memset(histo, 0, sizeof histo); + fseek(ifp, -2000, SEEK_END); + for (i = 0; i < 2000; i++) + histo[fgetc(ifp)]++; + for (i = 0; i < 4; i++) + if (histo[often[i]] < 200) + return 0; + return 1; +} + +/* + Since the TIFF DateTime string has no timezone information, + assume that the camera's clock was set to Universal Time. + */ +void LibRaw::get_timestamp(int reversed) +{ + struct tm t; + char str[20]; + int i; + + str[19] = 0; + if (reversed) + for (i = 19; i--;) + str[i] = fgetc(ifp); + else + fread(str, 19, 1, ifp); + memset(&t, 0, sizeof t); + if (sscanf(str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday, + &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) + return; + t.tm_year -= 1900; + t.tm_mon -= 1; + t.tm_isdst = -1; + if (mktime(&t) > 0) + timestamp = mktime(&t); +} + +#ifdef USE_6BY9RPI +void LibRaw::parse_raspberrypi() +{ + //This structure is at offset 0xB0 from the 'BRCM' ident. + struct brcm_raw_header { + uint8_t name[32]; + uint16_t h_width; + uint16_t h_height; + uint16_t padding_right; + uint16_t padding_down; + uint32_t dummy[6]; + uint16_t transform; + uint16_t format; + uint8_t bayer_order; + uint8_t bayer_format; + }; + //Values taken from https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h +#define BRCM_FORMAT_BAYER 33 +#define BRCM_BAYER_RAW8 2 +#define BRCM_BAYER_RAW10 3 +#define BRCM_BAYER_RAW12 4 +#define BRCM_BAYER_RAW14 5 +#define BRCM_BAYER_RAW16 6 + + struct brcm_raw_header header; + uint8_t brcm_tag[4]; + + // Sanity check that the caller has found a BRCM header + if (!fread(brcm_tag, 1, sizeof(brcm_tag), ifp) || + memcmp(brcm_tag, "BRCM", sizeof(brcm_tag))) + return; + + width = raw_width; + data_offset = ftell(ifp) + 0x8000 - sizeof(brcm_tag); + + if (!fseek(ifp, 0xB0 - sizeof(brcm_tag), SEEK_CUR) && + fread(&header, 1, sizeof(header), ifp)) { + switch (header.bayer_order) { + case 0: //RGGB + filters = 0x94949494; + break; + case 1: //GBRG + filters = 0x49494949; + break; + default: + case 2: //BGGR + filters = 0x16161616; + break; + case 3: //GRBG + filters = 0x61616161; + break; + } + + if (header.format == BRCM_FORMAT_BAYER) { + switch (header.bayer_format) { + case BRCM_BAYER_RAW8: + load_raw = &LibRaw::rpi_load_raw8; + //1 pixel per byte + raw_stride = ((header.h_width + header.padding_right) + 31)&(~31); + width = header.h_width; + raw_height = height = header.h_height; + is_raw = 1; + order = 0x4d4d; + break; + case BRCM_BAYER_RAW10: + load_raw = &LibRaw::nokia_load_raw; + //4 pixels per 5 bytes + raw_stride = (((((header.h_width + header.padding_right) * 5) + 3) >> 2) + 31)&(~31); + width = header.h_width; + raw_height = height = header.h_height; + is_raw = 1; + order = 0x4d4d; + break; + case BRCM_BAYER_RAW12: + load_raw = &LibRaw::rpi_load_raw12; + //2 pixels per 3 bytes + raw_stride = (((((header.h_width + header.padding_right) * 3) + 1) >> 1) + 31)&(~31); + width = header.h_width; + raw_height = height = header.h_height; + is_raw = 1; + order = 0x4d4d; + break; + case BRCM_BAYER_RAW14: + load_raw = &LibRaw::rpi_load_raw14; + //4 pixels per 7 bytes + raw_stride = (((((header.h_width + header.padding_right) * 7) + 3) >> 2) + 31)&(~31); + width = header.h_width; + raw_height = height = header.h_height; + is_raw = 1; + order = 0x4d4d; + break; + case BRCM_BAYER_RAW16: + load_raw = &LibRaw::rpi_load_raw16; + //1 pixel per 2 bytes + raw_stride = (((header.h_width + header.padding_right) << 1) + 31)&(~31); + width = header.h_width; + raw_height = height = header.h_height; + is_raw = 1; + order = 0x4d4d; + break; + default: + break; + } + } + } +} +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/nikon.cpp libkdcraw/libkdcraw/libraw/src/metadata/nikon.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/nikon.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/nikon.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,824 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +static const uchar xlat[2][256] = { + {0xc1, 0xbf, 0x6d, 0x0d, 0x59, 0xc5, 0x13, 0x9d, 0x83, 0x61, 0x6b, 0x4f, + 0xc7, 0x7f, 0x3d, 0x3d, 0x53, 0x59, 0xe3, 0xc7, 0xe9, 0x2f, 0x95, 0xa7, + 0x95, 0x1f, 0xdf, 0x7f, 0x2b, 0x29, 0xc7, 0x0d, 0xdf, 0x07, 0xef, 0x71, + 0x89, 0x3d, 0x13, 0x3d, 0x3b, 0x13, 0xfb, 0x0d, 0x89, 0xc1, 0x65, 0x1f, + 0xb3, 0x0d, 0x6b, 0x29, 0xe3, 0xfb, 0xef, 0xa3, 0x6b, 0x47, 0x7f, 0x95, + 0x35, 0xa7, 0x47, 0x4f, 0xc7, 0xf1, 0x59, 0x95, 0x35, 0x11, 0x29, 0x61, + 0xf1, 0x3d, 0xb3, 0x2b, 0x0d, 0x43, 0x89, 0xc1, 0x9d, 0x9d, 0x89, 0x65, + 0xf1, 0xe9, 0xdf, 0xbf, 0x3d, 0x7f, 0x53, 0x97, 0xe5, 0xe9, 0x95, 0x17, + 0x1d, 0x3d, 0x8b, 0xfb, 0xc7, 0xe3, 0x67, 0xa7, 0x07, 0xf1, 0x71, 0xa7, + 0x53, 0xb5, 0x29, 0x89, 0xe5, 0x2b, 0xa7, 0x17, 0x29, 0xe9, 0x4f, 0xc5, + 0x65, 0x6d, 0x6b, 0xef, 0x0d, 0x89, 0x49, 0x2f, 0xb3, 0x43, 0x53, 0x65, + 0x1d, 0x49, 0xa3, 0x13, 0x89, 0x59, 0xef, 0x6b, 0xef, 0x65, 0x1d, 0x0b, + 0x59, 0x13, 0xe3, 0x4f, 0x9d, 0xb3, 0x29, 0x43, 0x2b, 0x07, 0x1d, 0x95, + 0x59, 0x59, 0x47, 0xfb, 0xe5, 0xe9, 0x61, 0x47, 0x2f, 0x35, 0x7f, 0x17, + 0x7f, 0xef, 0x7f, 0x95, 0x95, 0x71, 0xd3, 0xa3, 0x0b, 0x71, 0xa3, 0xad, + 0x0b, 0x3b, 0xb5, 0xfb, 0xa3, 0xbf, 0x4f, 0x83, 0x1d, 0xad, 0xe9, 0x2f, + 0x71, 0x65, 0xa3, 0xe5, 0x07, 0x35, 0x3d, 0x0d, 0xb5, 0xe9, 0xe5, 0x47, + 0x3b, 0x9d, 0xef, 0x35, 0xa3, 0xbf, 0xb3, 0xdf, 0x53, 0xd3, 0x97, 0x53, + 0x49, 0x71, 0x07, 0x35, 0x61, 0x71, 0x2f, 0x43, 0x2f, 0x11, 0xdf, 0x17, + 0x97, 0xfb, 0x95, 0x3b, 0x7f, 0x6b, 0xd3, 0x25, 0xbf, 0xad, 0xc7, 0xc5, + 0xc5, 0xb5, 0x8b, 0xef, 0x2f, 0xd3, 0x07, 0x6b, 0x25, 0x49, 0x95, 0x25, + 0x49, 0x6d, 0x71, 0xc7}, + {0xa7, 0xbc, 0xc9, 0xad, 0x91, 0xdf, 0x85, 0xe5, 0xd4, 0x78, 0xd5, 0x17, + 0x46, 0x7c, 0x29, 0x4c, 0x4d, 0x03, 0xe9, 0x25, 0x68, 0x11, 0x86, 0xb3, + 0xbd, 0xf7, 0x6f, 0x61, 0x22, 0xa2, 0x26, 0x34, 0x2a, 0xbe, 0x1e, 0x46, + 0x14, 0x68, 0x9d, 0x44, 0x18, 0xc2, 0x40, 0xf4, 0x7e, 0x5f, 0x1b, 0xad, + 0x0b, 0x94, 0xb6, 0x67, 0xb4, 0x0b, 0xe1, 0xea, 0x95, 0x9c, 0x66, 0xdc, + 0xe7, 0x5d, 0x6c, 0x05, 0xda, 0xd5, 0xdf, 0x7a, 0xef, 0xf6, 0xdb, 0x1f, + 0x82, 0x4c, 0xc0, 0x68, 0x47, 0xa1, 0xbd, 0xee, 0x39, 0x50, 0x56, 0x4a, + 0xdd, 0xdf, 0xa5, 0xf8, 0xc6, 0xda, 0xca, 0x90, 0xca, 0x01, 0x42, 0x9d, + 0x8b, 0x0c, 0x73, 0x43, 0x75, 0x05, 0x94, 0xde, 0x24, 0xb3, 0x80, 0x34, + 0xe5, 0x2c, 0xdc, 0x9b, 0x3f, 0xca, 0x33, 0x45, 0xd0, 0xdb, 0x5f, 0xf5, + 0x52, 0xc3, 0x21, 0xda, 0xe2, 0x22, 0x72, 0x6b, 0x3e, 0xd0, 0x5b, 0xa8, + 0x87, 0x8c, 0x06, 0x5d, 0x0f, 0xdd, 0x09, 0x19, 0x93, 0xd0, 0xb9, 0xfc, + 0x8b, 0x0f, 0x84, 0x60, 0x33, 0x1c, 0x9b, 0x45, 0xf1, 0xf0, 0xa3, 0x94, + 0x3a, 0x12, 0x77, 0x33, 0x4d, 0x44, 0x78, 0x28, 0x3c, 0x9e, 0xfd, 0x65, + 0x57, 0x16, 0x94, 0x6b, 0xfb, 0x59, 0xd0, 0xc8, 0x22, 0x36, 0xdb, 0xd2, + 0x63, 0x98, 0x43, 0xa1, 0x04, 0x87, 0x86, 0xf7, 0xa6, 0x26, 0xbb, 0xd6, + 0x59, 0x4d, 0xbf, 0x6a, 0x2e, 0xaa, 0x2b, 0xef, 0xe6, 0x78, 0xb6, 0x4e, + 0xe0, 0x2f, 0xdc, 0x7c, 0xbe, 0x57, 0x19, 0x32, 0x7e, 0x2a, 0xd0, 0xb8, + 0xba, 0x29, 0x00, 0x3c, 0x52, 0x7d, 0xa8, 0x49, 0x3b, 0x2d, 0xeb, 0x25, + 0x49, 0xfa, 0xa3, 0xaa, 0x39, 0xa7, 0xc5, 0xa7, 0x50, 0x11, 0x36, 0xfb, + 0xc6, 0x67, 0x4a, 0xf5, 0xa5, 0x12, 0x65, 0x7e, 0xb0, 0xdf, 0xaf, 0x4e, + 0xb3, 0x61, 0x7f, 0x2f} }; + + + +void LibRaw::processNikonLensData(uchar *LensData, unsigned len) +{ + + ushort i; + if (imgdata.lens.nikon.LensType & 0x80) { + strcpy (ilm.LensFeatures_pre, "AF-P"); + } else if (!(imgdata.lens.nikon.LensType & 0x01)) { + ilm.LensFeatures_pre[0] = 'A'; + ilm.LensFeatures_pre[1] = 'F'; + } else { + ilm.LensFeatures_pre[0] = 'M'; + ilm.LensFeatures_pre[1] = 'F'; + } + + if (imgdata.lens.nikon.LensType & 0x40) { + ilm.LensFeatures_suf[0] = 'E'; + } else if (imgdata.lens.nikon.LensType & 0x04) { + ilm.LensFeatures_suf[0] = 'G'; + } else if (imgdata.lens.nikon.LensType & 0x02) { + ilm.LensFeatures_suf[0] = 'D'; + } + + if (imgdata.lens.nikon.LensType & 0x08) + { + ilm.LensFeatures_suf[1] = ' '; + ilm.LensFeatures_suf[2] = 'V'; + ilm.LensFeatures_suf[3] = 'R'; + } + + if (imgdata.lens.nikon.LensType & 0x10) + { + ilm.LensMount = ilm.CameraMount = LIBRAW_MOUNT_Nikon_CX; + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_1INCH; + } + else + ilm.LensMount = ilm.CameraMount = LIBRAW_MOUNT_Nikon_F; + + if (imgdata.lens.nikon.LensType & 0x20) + { + strcpy(ilm.Adapter, "FT-1"); + ilm.LensMount = LIBRAW_MOUNT_Nikon_F; + ilm.CameraMount = LIBRAW_MOUNT_Nikon_CX; + ilm.CameraFormat = LIBRAW_FORMAT_1INCH; + } + + imgdata.lens.nikon.LensType = imgdata.lens.nikon.LensType & 0xdf; + + if ((len < 20) || (len == 58)) + { + switch (len) + { + case 9: + i = 2; + break; + case 15: + i = 7; + break; + case 16: + i = 8; + break; + case 58: // "Z 6", "Z 7", "Z 50", D780 + if (model[6] == 'Z') + ilm.CameraMount = LIBRAW_MOUNT_Nikon_Z; + if (imNikon.HighSpeedCropFormat != 12) + ilm.CameraFormat = LIBRAW_FORMAT_FF; + i = 1; + while ((LensData[i] == LensData[0]) && (i < 17)) + i++; + if (i == 17) + { + ilm.LensMount = LIBRAW_MOUNT_Nikon_Z; + ilm.LensID = sget2(LensData + 0x2c); + switch (ilm.LensID) { + case 11: case 12: + ilm.LensFormat = LIBRAW_FORMAT_APSC; + break; + case 1: case 2: case 4: case 8: + case 9: case 13: case 14: case 15: + ilm.LensFormat = LIBRAW_FORMAT_FF; + break; + } + if (ilm.MaxAp4CurFocal < 0.7f) + ilm.MaxAp4CurFocal = libraw_powf64l( + 2.0f, (float)sget2(LensData + 0x32) / 384.0f - 1.0f); + if (ilm.CurAp < 0.7f) + ilm.CurAp = libraw_powf64l( + 2.0f, (float)sget2(LensData + 0x34) / 384.0f - 1.0f); + if (fabsf(ilm.CurFocal) < 1.1f) + ilm.CurFocal = sget2(LensData + 0x38); + return; + } + i = 9; + ilm.LensMount = LIBRAW_MOUNT_Nikon_F; + if (ilm.CameraMount == LIBRAW_MOUNT_Nikon_Z) + strcpy(ilm.Adapter, "FTZ"); + break; + } + imgdata.lens.nikon.LensIDNumber = LensData[i]; + imgdata.lens.nikon.LensFStops = LensData[i + 1]; + ilm.LensFStops = (float)imgdata.lens.nikon.LensFStops / 12.0f; + if (fabsf(ilm.MinFocal) < 1.1f) + { + if ((imgdata.lens.nikon.LensType ^ (uchar)0x01) || LensData[i + 2]) + ilm.MinFocal = + 5.0f * libraw_powf64l(2.0f, (float)LensData[i + 2] / 24.0f); + if ((imgdata.lens.nikon.LensType ^ (uchar)0x01) || LensData[i + 3]) + ilm.MaxFocal = + 5.0f * libraw_powf64l(2.0f, (float)LensData[i + 3] / 24.0f); + if ((imgdata.lens.nikon.LensType ^ (uchar)0x01) || LensData[i + 4]) + ilm.MaxAp4MinFocal = + libraw_powf64l(2.0f, (float)LensData[i + 4] / 24.0f); + if ((imgdata.lens.nikon.LensType ^ (uchar)0x01) || LensData[i + 5]) + ilm.MaxAp4MaxFocal = + libraw_powf64l(2.0f, (float)LensData[i + 5] / 24.0f); + } + imgdata.lens.nikon.MCUVersion = LensData[i + 6]; + if (i != 2) + { + if ((LensData[i - 1]) && (fabsf(ilm.CurFocal) < 1.1f)) + ilm.CurFocal = + 5.0f * libraw_powf64l(2.0f, (float)LensData[i - 1] / 24.0f); + if (LensData[i + 7]) + imgdata.lens.nikon.EffectiveMaxAp = + libraw_powf64l(2.0f, (float)LensData[i + 7] / 24.0f); + } + ilm.LensID = (unsigned long long)LensData[i] << 56 | + (unsigned long long)LensData[i + 1] << 48 | + (unsigned long long)LensData[i + 2] << 40 | + (unsigned long long)LensData[i + 3] << 32 | + (unsigned long long)LensData[i + 4] << 24 | + (unsigned long long)LensData[i + 5] << 16 | + (unsigned long long)LensData[i + 6] << 8 | + (unsigned long long)imgdata.lens.nikon.LensType; + } + else if ((len == 459) || (len == 590)) + { + memcpy(ilm.Lens, LensData + 390, 64); + } + else if (len == 509) + { + memcpy(ilm.Lens, LensData + 391, 64); + } + else if (len == 879) + { + memcpy(ilm.Lens, LensData + 680, 64); + } + + return; +} + +void LibRaw::Nikon_NRW_WBtag(int wb, int skip) +{ + + int r, g0, g1, b; + if (skip) + get4(); // skip wb "CCT", it is not unique + r = get4(); + g0 = get4(); + g1 = get4(); + b = get4(); + if (r && g0 && g1 && b) + { + icWBC[wb][0] = r << 1; + icWBC[wb][1] = g0; + icWBC[wb][2] = b << 1; + icWBC[wb][3] = g1; + } + return; +} + +void LibRaw::parseNikonMakernote(int base, int uptag, unsigned dng_writer) +{ + + unsigned offset = 0, entries, tag, type, len, save; + + unsigned c, i; + uchar *LensData_buf; + uchar ColorBalanceData_buf[324]; + int ColorBalanceData_ready = 0; + uchar ci, cj, ck; + unsigned serial = 0; + unsigned custom_serial = 0; + unsigned LensData_len = 0; + + short morder, sorder = order; + char buf[10]; + INT64 fsize = ifp->size(); + + fread(buf, 1, 10, ifp); + + if (!strcmp(buf, "Nikon")) + { + if (buf[6] != '\2') + return; + base = ftell(ifp); + order = get2(); + if (get2() != 42) + goto quit; + offset = get4(); + fseek(ifp, offset - 8, SEEK_CUR); + } + else + { + fseek(ifp, -10, SEEK_CUR); + } + + entries = get2(); + if (entries > 1000) + return; + morder = order; + + while (entries--) + { + order = morder; + tiff_get(base, &tag, &type, &len, &save); + + INT64 pos = ifp->tell(); + if (len > 8 && pos + len > 2 * fsize) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + tag |= uptag << 16; + if (len > 100 * 1024 * 1024) + goto next; // 100Mb tag? No! + + if (tag == 0x0002) + { + if (!iso_speed) + iso_speed = (get2(), get2()); + } + else if (tag == 0x000a) + { + ilm.LensMount = ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + } + else if ((tag == 0x000c) && (len == 4) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_RATIONAL)) + { + cam_mul[0] = getreal(type); + cam_mul[2] = getreal(type); + cam_mul[1] = getreal(type); + cam_mul[3] = getreal(type); + } + else if (tag == 0x0011) + { + if (is_raw) + { + fseek(ifp, get4() + base, SEEK_SET); + parse_tiff_ifd(base); + } + } + else if (tag == 0x0012) + { + ci = fgetc(ifp); + cj = fgetc(ifp); + ck = fgetc(ifp); + if (ck) + imCommon.FlashEC = (float)(ci * cj) / (float)ck; + } + else if (tag == 0x0014) + { + if (tagtypeIs(LIBRAW_EXIFTOOLTAGTYPE_binary)) + { + if (len == 2560) + { // E5400, E8400, E8700, E8800 + fseek(ifp, 0x4e0L, SEEK_CUR); + order = 0x4d4d; + cam_mul[0] = get2() / 256.0; + cam_mul[2] = get2() / 256.0; + cam_mul[1] = cam_mul[3] = 1.0; + icWBC[LIBRAW_WBI_Auto][0] = get2(); + icWBC[LIBRAW_WBI_Auto][2] = get2(); + icWBC[LIBRAW_WBI_Daylight][0] = get2(); + icWBC[LIBRAW_WBI_Daylight][2] = get2(); + fseek(ifp, 0x18L, SEEK_CUR); + icWBC[LIBRAW_WBI_Tungsten][0] = get2(); + icWBC[LIBRAW_WBI_Tungsten][2] = get2(); + fseek(ifp, 0x18L, SEEK_CUR); + icWBC[LIBRAW_WBI_FL_W][0] = get2(); + icWBC[LIBRAW_WBI_FL_W][2] = get2(); + icWBC[LIBRAW_WBI_FL_N][0] = get2(); + icWBC[LIBRAW_WBI_FL_N][2] = get2(); + icWBC[LIBRAW_WBI_FL_D][0] = get2(); + icWBC[LIBRAW_WBI_FL_D][2] = get2(); + icWBC[LIBRAW_WBI_Cloudy][0] = get2(); + icWBC[LIBRAW_WBI_Cloudy][2] = get2(); + fseek(ifp, 0x18L, SEEK_CUR); + icWBC[LIBRAW_WBI_Flash][0] = get2(); + icWBC[LIBRAW_WBI_Flash][2] = get2(); + + icWBC[LIBRAW_WBI_Auto][1] = icWBC[LIBRAW_WBI_Auto][3] = + icWBC[LIBRAW_WBI_Daylight][1] = icWBC[LIBRAW_WBI_Daylight][3] = + icWBC[LIBRAW_WBI_Tungsten][1] = icWBC[LIBRAW_WBI_Tungsten][3] = + icWBC[LIBRAW_WBI_FL_W][1] = icWBC[LIBRAW_WBI_FL_W][3] = + icWBC[LIBRAW_WBI_FL_N][1] = icWBC[LIBRAW_WBI_FL_N][3] = + icWBC[LIBRAW_WBI_FL_D][1] = icWBC[LIBRAW_WBI_FL_D][3] = + icWBC[LIBRAW_WBI_Cloudy][1] = icWBC[LIBRAW_WBI_Cloudy][3] = + icWBC[LIBRAW_WBI_Flash][1] = icWBC[LIBRAW_WBI_Flash][3] = 256; + + if (strncmp(model, "E8700", 5)) + { + fseek(ifp, 0x18L, SEEK_CUR); + icWBC[LIBRAW_WBI_Shade][0] = get2(); + icWBC[LIBRAW_WBI_Shade][2] = get2(); + icWBC[LIBRAW_WBI_Shade][1] = icWBC[LIBRAW_WBI_Shade][3] = 256; + } + } + else if (len == 1280) + { // E5000, E5700 + cam_mul[0] = cam_mul[1] = cam_mul[2] = cam_mul[3] = 1.0; + } + else + { + fread(buf, 1, 10, ifp); + if (!strncmp(buf, "NRW ", 4)) + { // P6000, P7000, P7100, B700, P1000 + if (!strcmp(buf + 4, "0100")) + { // P6000 + fseek(ifp, 0x13deL, SEEK_CUR); + cam_mul[0] = get4() << 1; + cam_mul[1] = get4(); + cam_mul[3] = get4(); + cam_mul[2] = get4() << 1; + Nikon_NRW_WBtag(LIBRAW_WBI_Daylight, 0); + Nikon_NRW_WBtag(LIBRAW_WBI_Cloudy, 0); + fseek(ifp, 0x10L, SEEK_CUR); + Nikon_NRW_WBtag(LIBRAW_WBI_Tungsten, 0); + Nikon_NRW_WBtag(LIBRAW_WBI_FL_W, 0); + Nikon_NRW_WBtag(LIBRAW_WBI_Flash, 0); + fseek(ifp, 0x10L, SEEK_CUR); + Nikon_NRW_WBtag(LIBRAW_WBI_Custom, 0); + Nikon_NRW_WBtag(LIBRAW_WBI_Auto, 0); + } + else + { // P7000, P7100, B700, P1000 + fseek(ifp, 0x16L, SEEK_CUR); + black = get2(); + if (cam_mul[0] < 0.1f) + { + fseek(ifp, 0x16L, SEEK_CUR); + cam_mul[0] = get4() << 1; + cam_mul[1] = get4(); + cam_mul[3] = get4(); + cam_mul[2] = get4() << 1; + } + else + { + fseek(ifp, 0x26L, SEEK_CUR); + } + if (len != 332) + { // not A1000 + Nikon_NRW_WBtag(LIBRAW_WBI_Daylight, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_Cloudy, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_Shade, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_Tungsten, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_FL_W, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_FL_N, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_FL_D, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_HT_Mercury, 1); + fseek(ifp, 0x14L, SEEK_CUR); + Nikon_NRW_WBtag(LIBRAW_WBI_Custom, 1); + Nikon_NRW_WBtag(LIBRAW_WBI_Auto, 1); + } + else + { + fseek(ifp, 0xc8L, SEEK_CUR); + Nikon_NRW_WBtag(LIBRAW_WBI_Auto, 1); + } + } + } + } + } + } + else if (tag == 0x001b) + { + imNikon.HighSpeedCropFormat = get2(); + imNikon.SensorHighSpeedCrop.cwidth = get2(); + imNikon.SensorHighSpeedCrop.cheight = get2(); + imNikon.SensorWidth = get2(); + imNikon.SensorHeight = get2(); + imNikon.SensorHighSpeedCrop.cleft = get2(); + imNikon.SensorHighSpeedCrop.ctop = get2(); + switch (imNikon.HighSpeedCropFormat) + { + case 0: + case 1: + case 2: + case 4: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_3to2; + break; + case 11: + ilm.CameraFormat = LIBRAW_FORMAT_FF; + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_3to2; + break; + case 12: + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_3to2; + break; + case 3: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_5to4; + break; + case 6: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_16to9; + break; + case 17: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_1to1; + break; + default: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_OTHER; + break; + } + } + else if (tag == 0x001d) + { // serial number + if (len > 0) + { + int model_len = (int)strbuflen(model); + while ((c = fgetc(ifp)) && (len-- > 0) && (c != (unsigned)EOF)) + { + if ((!custom_serial) && (!isdigit(c))) + { + if (((model_len == 3) && !strcmp(model, "D50")) || + ((model_len >= 4) && !isalnum(model[model_len - 4]) && + !strncmp(&model[model_len - 3], "D50", 3))) + { + custom_serial = 34; + } + else + { + custom_serial = 96; + } + break; + } + serial = serial * 10 + (isdigit(c) ? c - '0' : c % 10); + } + if (!imgdata.shootinginfo.BodySerial[0]) + sprintf(imgdata.shootinginfo.BodySerial, "%d", serial); + } + } + else if (tag == 0x001e) { + switch (get2()) { + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + } else if (tag == 0x0025) + { + if (!iso_speed || (iso_speed == 65535)) + { + iso_speed = + int(100.0 * + libraw_powf64l(2.0f, double((uchar)fgetc(ifp)) / 12.0 - 5.0)); + } + } + else if (tag == 0x003b) + { // WB for multi-exposure (ME); all 1s for regular exposures + imNikon.ME_WB[0] = getreal(type); + imNikon.ME_WB[2] = getreal(type); + imNikon.ME_WB[1] = getreal(type); + imNikon.ME_WB[3] = getreal(type); + } + else if (tag == 0x003d) + { // not corrected for file bitcount, to be patched in open_datastream + FORC4 cblack[RGGB_2_RGBG(c)] = get2(); + i = cblack[3]; + FORC3 if (i > cblack[c]) i = cblack[c]; + FORC4 cblack[c] -= i; + black += i; + } + else if (tag == 0x0045) + { /* upper left pixel (x,y), size (width,height) */ + imgdata.sizes.raw_inset_crop.cleft = get2(); + imgdata.sizes.raw_inset_crop.ctop = get2(); + imgdata.sizes.raw_inset_crop.cwidth = get2(); + imgdata.sizes.raw_inset_crop.cheight = get2(); + } + else if (tag == 0x0082) + { // lens attachment + stmread(ilm.Attachment, len, ifp); + } + else if (tag == 0x0083) + { // lens type + imgdata.lens.nikon.LensType = fgetc(ifp); + } + else if (tag == 0x0084) + { // lens + ilm.MinFocal = getreal(type); + ilm.MaxFocal = getreal(type); + ilm.MaxAp4MinFocal = getreal(type); + ilm.MaxAp4MaxFocal = getreal(type); + } + else if (tag == 0x008b) + { // lens f-stops + ci = fgetc(ifp); + cj = fgetc(ifp); + ck = fgetc(ifp); + if (ck) + { + imgdata.lens.nikon.LensFStops = ci * cj * (12 / ck); + ilm.LensFStops = (float)imgdata.lens.nikon.LensFStops / 12.0f; + } + } + else if ((tag == 0x008c) || (tag == 0x0096)) + { + meta_offset = ftell(ifp); + } + else if (tag == 0x0093) + { + imNikon.NEFCompression = i = get2(); + if ((i == 7) || (i == 9)) + { + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (tag == 0x0097) + { // ver97 + FORC4 imNikon.ColorBalanceVersion = + imNikon.ColorBalanceVersion * 10 + fgetc(ifp) - '0'; + switch (imNikon.ColorBalanceVersion) + { + case 100: // NIKON D100 + fseek(ifp, 0x44L, SEEK_CUR); + FORC4 cam_mul[RBGG_2_RGBG(c)] = get2(); + break; + case 102: // NIKON D2H + fseek(ifp, 0x6L, SEEK_CUR); + FORC4 cam_mul[RGGB_2_RGBG(c)] = get2(); + break; + case 103: // NIKON D70, D70s + fseek(ifp, 0x10L, SEEK_CUR); + FORC4 cam_mul[c] = get2(); + } + if (imNikon.ColorBalanceVersion >= 200) + { + /* + 204: NIKON D2X, D2Xs + 205: NIKON D50 + 206: NIKON D2Hs + 207: NIKON D200 + 208: NIKON D40, D40X, D80 + 209: NIKON D3, D3X, D300, D700 + 210: NIKON D60 + 211: NIKON D90, D5000 + 212: NIKON D300S + 213: NIKON D3000 + 214: NIKON D3S + 215: NIKON D3100 + 216: NIKON D5100, D7000 + 217: NIKON D4, D600, D800, D800E, D3200 + -= unknown =- + 218: NIKON D5200, D7100 + 219: NIKON D5300 + 220: NIKON D610, Df + 221: NIKON D3300 + 222: NIKON D4S + 223: NIKON D750, D810 + 224: NIKON D3400, D3500, D5500, D5600, D7200 + 225: NIKON D5, D500 + 226: NIKON D7500 + 227: NIKON D850 + */ + if (imNikon.ColorBalanceVersion != 205) + { + fseek(ifp, 0x118L, SEEK_CUR); + } + ColorBalanceData_ready = + (fread(ColorBalanceData_buf, 324, 1, ifp) == 1); + } + if ((imNikon.ColorBalanceVersion >= 400) && + (imNikon.ColorBalanceVersion <= 405)) + { // 1 J1, 1 V1, 1 J2, 1 V2, 1 J3, 1 S1, 1 AW1, 1 S2, 1 J4, 1 V3, 1 J5 + ilm.CameraFormat = LIBRAW_FORMAT_1INCH; + ilm.CameraMount = LIBRAW_MOUNT_Nikon_CX; + } + else if ((imNikon.ColorBalanceVersion >= 500) && + (imNikon.ColorBalanceVersion <= 502)) + { // P7700, P7800, P330, P340 + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + } + else if (imNikon.ColorBalanceVersion == 601) + { // Coolpix A + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + } + } + else if (tag == 0x0098) + { // contains lens data + FORC4 imNikon.LensDataVersion = + imNikon.LensDataVersion * 10 + fgetc(ifp) - '0'; + switch (imNikon.LensDataVersion) + { + case 100: + LensData_len = 9; + break; + case 101: + case 201: // encrypted, starting from v.201 + case 202: + case 203: + LensData_len = 15; + break; + case 204: + LensData_len = 16; + break; + case 400: + LensData_len = 459; + break; + case 401: + LensData_len = 590; + break; + case 402: + LensData_len = 509; + break; + case 403: + LensData_len = 879; + break; + case 800: + LensData_len = 58; + break; + } + if (LensData_len) + { + LensData_buf = (uchar *)malloc(LensData_len); + fread(LensData_buf, LensData_len, 1, ifp); + } + } + else if (tag == 0x00a0) + { + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + } + else if (tag == 0x00a7) + { // shutter count + imNikon.key = fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp); + if (custom_serial) + { + ci = xlat[0][custom_serial]; + } + else + { + ci = xlat[0][serial & 0xff]; + } + cj = xlat[1][imNikon.key]; + ck = 0x60; + if (((unsigned)(imNikon.ColorBalanceVersion - 200) < 18) && + ColorBalanceData_ready) + { + for (i = 0; i < 324; i++) + ColorBalanceData_buf[i] ^= (cj += ci * ck++); + i = "66666>666;6A;:;555"[imNikon.ColorBalanceVersion - 200] - '0'; + FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = + sget2(ColorBalanceData_buf + (i & -2) + c * 2); + } + + if (LensData_len) + { + if (imNikon.LensDataVersion > 200) + { + cj = xlat[1][imNikon.key]; + ck = 0x60; + for (i = 0; i < LensData_len; i++) + { + LensData_buf[i] ^= (cj += ci * ck++); + } + } + processNikonLensData(LensData_buf, LensData_len); + LensData_len = 0; + free(LensData_buf); + } + } + else if (tag == 0x00a8) + { // contains flash data + FORC4 imNikon.FlashInfoVersion = + imNikon.FlashInfoVersion * 10 + fgetc(ifp) - '0'; + } + else if (tag == 0x00b0) + { + get4(); // ME (multi-exposure) tag version, 4 symbols + imNikon.ExposureMode = get4(); + imNikon.nMEshots = get4(); + imNikon.MEgainOn = get4(); + } + else if (tag == 0x00b9) + { + imNikon.AFFineTune = fgetc(ifp); + imNikon.AFFineTuneIndex = fgetc(ifp); + imNikon.AFFineTuneAdj = (int8_t)fgetc(ifp); + } + else if ((tag == 0x0100) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_UNDEFINED)) + { + thumb_offset = ftell(ifp); + thumb_length = len; + } + else if (tag == 0x0e01) + { /* Nikon Software / in-camera edit Note */ + int loopc = 0; + int WhiteBalanceAdj_active = 0; + order = 0x4949; + fseek(ifp, 22, SEEK_CUR); + for (offset = 22; offset + 22 < len; offset += 22 + i) + { + if (loopc++ > 1024) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + tag = get4(); + fseek(ifp, 14, SEEK_CUR); + i = get4() - 4; + + if (tag == 0x76a43204) + { + WhiteBalanceAdj_active = fgetc(ifp); + } + else if (tag == 0xbf3c6c20) + { + if (WhiteBalanceAdj_active) + { + union { + double dbl; + unsigned long long lng; + } un; + un.dbl = getreal(LIBRAW_EXIFTAG_TYPE_DOUBLE); + if ((un.lng != 0x3FF0000000000000ULL) && + (un.lng != 0x000000000000F03FULL)) + { + cam_mul[0] = un.dbl; + cam_mul[2] = getreal(LIBRAW_EXIFTAG_TYPE_DOUBLE); + cam_mul[1] = cam_mul[3] = 1.0; + i -= 16; + } + else + i -= 8; + } + fseek(ifp, i, SEEK_CUR); + } + else if (tag == 0x76a43207) + { + flip = get2(); + } + else + { + fseek(ifp, i, SEEK_CUR); + } + } + } + else if (tag == 0x0e22) + { + FORC4 imNikon.NEFBitDepth[c] = get2(); + } + next: + fseek(ifp, save, SEEK_SET); + } +quit: + order = sorder; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/normalize_model.cpp libkdcraw/libkdcraw/libraw/src/metadata/normalize_model.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/normalize_model.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/normalize_model.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,1381 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +void LibRaw::GetNormalizedModel() +{ + + int i, j; + char *ps; + + static const struct + { + unsigned long long id; + char t_model[20]; + } unique[] = +// clang-format off + { + { CanonID_EOS_M50, "EOS M50"}, // Kiss M + { CanonID_EOS_M6_Mark_II, "EOS M6 Mark II"}, + { CanonID_EOS_M200, "EOS M200"}, + { CanonID_EOS_D30, "EOS D30"}, + { CanonID_EOS_D60, "EOS D60"}, + { CanonID_EOS_M3, "EOS M3"}, + { CanonID_EOS_M10, "EOS M10"}, + { CanonID_EOS_M5, "EOS M5"}, + { CanonID_EOS_M100, "EOS M100"}, + { CanonID_EOS_M6, "EOS M6"}, + { CanonID_EOS_1D, "EOS-1D"}, + { CanonID_EOS_1DS, "EOS-1DS"}, + { CanonID_EOS_10D, "EOS 10D"}, + { CanonID_EOS_1D_Mark_III, "EOS-1D Mark III"}, + { CanonID_EOS_300D, "EOS 300D"}, // Digital Rebel / Kiss Digital + { CanonID_EOS_1D_Mark_II, "EOS-1D Mark II"}, + { CanonID_EOS_20D, "EOS 20D"}, + { CanonID_EOS_450D, "EOS 450D"}, // Digital Rebel XSi / Kiss X2 + { CanonID_EOS_1Ds_Mark_II, "EOS-1Ds Mark II"}, + { CanonID_EOS_350D, "EOS 350D"}, // Digital Rebel XT / Kiss Digital N + { CanonID_EOS_40D, "EOS 40D"}, + { CanonID_EOS_5D, "EOS 5D"}, + { CanonID_EOS_1Ds_Mark_III, "EOS-1Ds Mark III"}, + { CanonID_EOS_5D_Mark_II, "EOS 5D Mark II"}, + { CanonID_EOS_1D_Mark_II_N, "EOS-1D Mark II N"}, + { CanonID_EOS_30D, "EOS 30D"}, + { CanonID_EOS_400D, "EOS 400D"}, // Digital Rebel XTi / Kiss Digital X + { CanonID_EOS_7D, "EOS 7D"}, + { CanonID_EOS_500D, "EOS 500D"}, // Rebel T1i / Kiss X3 + { CanonID_EOS_1000D, "EOS 1000D"}, // Digital Rebel XS / Kiss F + { CanonID_EOS_50D, "EOS 50D"}, + { CanonID_EOS_1D_X, "EOS-1D X"}, + { CanonID_EOS_550D, "EOS 550D"}, // Rebel T2i / Kiss X4 + { CanonID_EOS_1D_Mark_IV, "EOS-1D Mark IV"}, + { CanonID_EOS_5D_Mark_III, "EOS 5D Mark III"}, + { CanonID_EOS_600D, "EOS 600D"}, // Rebel T3i / Kiss X5 + { CanonID_EOS_60D, "EOS 60D"}, + { CanonID_EOS_1100D, "EOS 1100D"}, // Rebel T3 / Kiss X50 + { CanonID_EOS_7D_Mark_II, "EOS 7D Mark II"}, + { CanonID_EOS_650D, "EOS 650D"}, // Rebel T4i / Kiss X6i + { CanonID_EOS_6D, "EOS 6D"}, + { CanonID_EOS_1D_C, "EOS-1D C"}, + { CanonID_EOS_70D, "EOS 70D"}, + { CanonID_EOS_700D, "EOS 700D"}, // Rebel T5i / Kiss X7i + { CanonID_EOS_1200D, "EOS 1200D"}, // Rebel T5 / Kiss X70 / Hi + { CanonID_EOS_1D_X_Mark_II, "EOS-1D X Mark II"}, + { CanonID_EOS_M, "EOS M"}, + { CanonID_EOS_100D, "EOS 100D"}, // Rebel SL1 / Kiss X7 + { CanonID_EOS_760D, "EOS 760D"}, // Rebel T6s / 8000D + { CanonID_EOS_5D_Mark_IV, "EOS 5D Mark IV"}, + { CanonID_EOS_80D, "EOS 80D"}, + { CanonID_EOS_M2, "EOS M2"}, + { CanonID_EOS_5DS, "EOS 5DS"}, + { CanonID_EOS_750D, "EOS 750D"}, // Rebel T6i / Kiss X8i + { CanonID_EOS_5DS_R, "EOS 5DS R"}, + { CanonID_EOS_1300D, "EOS 1300D"}, // Rebel T6 / Kiss X80 + { CanonID_EOS_800D, "EOS 800D"}, // Rebel T7i / Kiss X9i + { CanonID_EOS_6D_Mark_II, "EOS 6D Mark II"}, + { CanonID_EOS_77D, "EOS 77D"}, // 9000D + { CanonID_EOS_200D, "EOS 200D"}, // Rebel SL2 / Kiss X9 + { CanonID_EOS_3000D, "EOS 3000D"}, // Rebel T100 / 4000D + { CanonID_EOS_1D_X_Mark_III, "EOS-1D X Mark III"}, + { CanonID_EOS_R, "EOS R"}, + { CanonID_EOS_1500D, "EOS 1500D"}, // Rebel T7 / 2000D / Kiss X90 + { CanonID_EOS_RP, "EOS RP"}, + { CanonID_EOS_250D, "EOS 250D"}, // Rebel SL3 / 200D II / Kiss X10 + { CanonID_EOS_90D, "EOS 90D"}, + }, +#if 0 + olyque[] = { + { OlyID_E_20, "E-20"}, + { OlyID_E_20, "E-20,E-20N,E-20P"}, + { OlyID_E_1, "E-1"}, + { OlyID_E_300, "E-300"}, + { OlyID_SP_550UZ, "SP-550UZ"}, + { OlyID_SP_550UZ, "SP550UZ"}, + { OlyID_SP_510UZ, "SP-510UZ"}, + { OlyID_SP_510UZ, "SP510UZ"}, + { OlyID_SP_560UZ, "SP-560UZ"}, + { OlyID_SP_560UZ, "SP560UZ"}, + { OlyID_SP_570UZ, "SP-570UZ"}, + { OlyID_SP_570UZ, "SP570UZ"}, + { OlyID_SP_565UZ, "SP-565UZ"}, + { OlyID_SP_565UZ, "SP565UZ"}, + { OlyID_XZ_1, "XZ-1"}, + { OlyID_XZ_2, "XZ-2"}, + { OlyID_XZ_10, "XZ-10"}, + { OlyID_STYLUS_1, "Stylus 1"}, + { OlyID_STYLUS_1, "STYLUS1"}, + { OlyID_STYLUS_1, "STYLUS1,1s"}, + { OlyID_SH_2, "SH-2"}, + { OlyID_TG_4, "TG-4"}, + { OlyID_TG_5, "TG-5"}, + { OlyID_TG_6, "TG-6"}, + { OlyID_E_10, "E-10"}, + { OlyID_AIR_A01, "AIR A01"}, + { OlyID_AIR_A01, "AIR-A01"}, + { OlyID_E_330, "E-330"}, + { OlyID_E_500, "E-500"}, + { OlyID_E_400, "E-400"}, + { OlyID_E_510, "E-510"}, + { OlyID_E_3, "E-3"}, + { OlyID_E_410, "E-410"}, + { OlyID_E_420, "E-420"}, + { OlyID_E_30, "E-30"}, + { OlyID_E_520, "E-520"}, + { OlyID_E_P1, "E-P1"}, + { OlyID_E_620, "E-620"}, + { OlyID_E_P2, "E-P2"}, + { OlyID_E_PL1, "E-PL1"}, + { OlyID_E_450, "E-450"}, + { OlyID_E_600, "E-600"}, + { OlyID_E_P3, "E-P3"}, + { OlyID_E_5, "E-5"}, + { OlyID_E_PL2, "E-PL2"}, + { OlyID_E_M5, "E-M5"}, + { OlyID_E_PL3, "E-PL3"}, + { OlyID_E_PM1, "E-PM1"}, + { OlyID_E_PL1s, "E-PL1s"}, + { OlyID_E_PL5, "E-PL5"}, + { OlyID_E_PM2, "E-PM2"}, + { OlyID_E_P5, "E-P5"}, + { OlyID_E_PL6, "E-PL6"}, + { OlyID_E_PL7, "E-PL7"}, + { OlyID_E_M1, "E-M1"}, + { OlyID_E_M10, "E-M10"}, + { OlyID_E_M5_Mark_II, "E-M5 Mark II"}, + { OlyID_E_M5_Mark_II, "E-M5MarkII"}, + { OlyID_E_M5_Mark_II, "E-M5_M2"}, + { OlyID_E_M10_Mark_II, "E-M10 Mark II"}, // Clauss piX 5oo + { OlyID_E_M10_Mark_II, "E-M10MarkII"}, + { OlyID_E_M10_Mark_II, "E-M10_M2"}, + { OlyID_PEN_F, "PEN-F"}, + { OlyID_E_PL8, "E-PL8"}, + { OlyID_E_M1_Mark_II, "E-M1 Mark II"}, + { OlyID_E_M1_Mark_II, "E-M1MarkII"}, + { OlyID_E_M1_Mark_II, "E-M1_M2"}, + { OlyID_E_M10_Mark_III, "E-M10 Mark III"}, + { OlyID_E_M10_Mark_III, "E-M10_M3"}, + { OlyID_E_PL9, "E-PL9"}, + { OlyID_E_M1X, "E-M1X"}, + { OlyID_E_PL10, "E-PL10"}, + { OlyID_E_M5_Mark_III, "E-M5 Mark III"}, + { OlyID_E_M5_Mark_III, "E-M5MarkIII"}, + { OlyID_E_M5_Mark_III, "E-M5_M3"}, + { OlyID_E_M1_Mark_III, "E-M1 Mark III"}, + { OlyID_E_M1_Mark_III, "E-M1MarkIII"}, + { OlyID_E_M1_Mark_III, "E-M1_M3"}, + { OlyID_C_3030Z, "C-3030Z"}, + { OlyID_C_3030Z, "C3030Z"}, + { OlyID_C_5050Z, "C-5050Z"}, + { OlyID_C_5050Z, "C5050Z"}, + { OlyID_C_350Z, "C-350Z"}, + { OlyID_C_350Z, "X200,D560Z,C350Z"}, + { OlyID_C_740UZ, "C-740UZ"}, + { OlyID_C_740UZ, "C740UZ"}, + { OlyID_C_5060WZ, "C-5060WZ"}, + { OlyID_C_5060WZ, "C5060WZ"}, + { OlyID_C_8080WZ, "C-8080WZ"}, + { OlyID_C_8080WZ, "C8080WZ"}, + { OlyID_C_770UZ, "C-770UZ"}, + { OlyID_C_770UZ, "C770UZ"}, + { OlyID_C_7070WZ, "C-7070WZ"}, + { OlyID_C_7070WZ, "C7070WZ"}, + { OlyID_C_7000Z, "C-7000Z"}, + { OlyID_C_7000Z, "C70Z,C7000Z"}, + { OlyID_SP_500UZ, "SP-500UZ"}, + { OlyID_SP_500UZ, "SP500UZ"}, + { OlyID_SP_310, "SP-310"}, + { OlyID_SP_310, "SP310"}, + { OlyID_SP_350, "SP-350"}, + { OlyID_SP_350, "SP350"}, + { OlyID_SP_320, "SP-320"}, + { OlyID_SP_320, "SP320"}, + }, + + penique[] = { + { PentaxID_Optio_S, "Optio S"}, + { PentaxID_Optio_S_V101, "Optio S V1.01"}, + { PentaxID_staristD, "*istD"}, + { PentaxID_staristD, "*ist D"}, + { PentaxID_Optio_33WR, "Optio 33WR"}, + { PentaxID_Optio_S4, "Optio S4"}, + { PentaxID_Optio_750Z, "Optio 750Z"}, + { PentaxID_staristDS, "*istDS"}, + { PentaxID_staristDS, "*ist DS"}, + { PentaxID_staristDL, "*istDL"}, + { PentaxID_staristDL, "*ist DL"}, + { PentaxID_staristDS2, "*istDS2"}, + { PentaxID_staristDS2, "*ist DS2"}, + { PentaxID_GX_1S, "GX-1S"}, // Samsung + { PentaxID_staristDL2, "*istDL2"}, + { PentaxID_staristDL2, "*ist DL2"}, + { PentaxID_GX_1L, "GX-1L"}, // Samsung + { PentaxID_K100D, "K100D"}, + { PentaxID_K110D, "K110D"}, + { PentaxID_K100D_Super, "K100D Super"}, + { PentaxID_K10D, "K10D"}, + { PentaxID_GX10, "GX10"}, // Samsung + { PentaxID_GX10, "GX-10"}, // Samsung + { PentaxID_K20D, "K20D"}, + { PentaxID_GX20, "GX20"}, // Samsung + { PentaxID_GX20, "GX-20"}, // Samsung + { PentaxID_K200D, "K200D"}, + { PentaxID_K2000, "K2000"}, + { PentaxID_K_m, "K-m"}, + { PentaxID_K_7, "K-7"}, + { PentaxID_K_x, "K-x"}, + { PentaxID_645D, "645D"}, + { PentaxID_K_r, "K-r"}, + { PentaxID_K_5, "K-5"}, + { PentaxID_Q, "Q"}, + { PentaxID_K_01, "K-01"}, + { PentaxID_K_30, "K-30"}, + { PentaxID_Q10, "Q10"}, + { PentaxID_K_5_II, "K-5 II"}, + { PentaxID_K_5_II_s, "K-5 II s"}, + { PentaxID_Q7, "Q7"}, + { PentaxID_MX_1, "MX-1"}, + { PentaxID_K_50, "K-50"}, + { PentaxID_K_3, "K-3"}, + { PentaxID_K_500, "K-500"}, + { PentaxID_645Z, "645Z"}, + { PentaxID_K_S1, "K-S1"}, + { PentaxID_K_S2, "K-S2"}, // Ricoh + { PentaxID_Q_S1, "Q-S1"}, + { PentaxID_K_1, "K-1"}, // Ricoh + { PentaxID_K_3_II, "K-3 II"}, // Ricoh + { PentaxID_GR_III, "GR III"}, // Ricoh + { PentaxID_K_70, "K-70"}, // Ricoh + { PentaxID_KP, "KP"}, // Ricoh + { PentaxID_K_1_Mark_II, "K-1 Mark II"}, // Ricoh + }, +#endif + sonique[] = { + { SonyID_DSC_R1, "DSC-R1"}, + { SonyID_DSLR_A100, "DSLR-A100"}, + { SonyID_DSLR_A900, "DSLR-A900"}, + { SonyID_DSLR_A700, "DSLR-A700"}, + { SonyID_DSLR_A200, "DSLR-A200"}, + { SonyID_DSLR_A350, "DSLR-A350"}, + { SonyID_DSLR_A300, "DSLR-A300"}, + { SonyID_DSLR_A900_APSC, "DSLR-A900"}, + { SonyID_DSLR_A380, "DSLR-A380"}, // DSLR-A390 + { SonyID_DSLR_A330, "DSLR-A330"}, + { SonyID_DSLR_A230, "DSLR-A230"}, + { SonyID_DSLR_A290, "DSLR-A290"}, + { SonyID_DSLR_A850, "DSLR-A850"}, + { SonyID_DSLR_A850_APSC, "DSLR-A850"}, + { SonyID_DSLR_A550, "DSLR-A550"}, + { SonyID_DSLR_A500, "DSLR-A500"}, + { SonyID_DSLR_A450, "DSLR-A450"}, + { SonyID_NEX_5, "NEX-5"}, + { SonyID_NEX_3, "NEX-3"}, + { SonyID_SLT_A33, "SLT-A33"}, + { SonyID_SLT_A55, "SLT-A55"}, // SLT-A55V + { SonyID_DSLR_A560, "DSLR-A560"}, + { SonyID_DSLR_A580, "DSLR-A580"}, + { SonyID_NEX_C3, "NEX-C3"}, + { SonyID_SLT_A35, "SLT-A35"}, + { SonyID_SLT_A65, "SLT-A65"}, // SLT-A65V + { SonyID_SLT_A77, "SLT-A77"}, // SLT-A77V + { SonyID_NEX_5N, "NEX-5N"}, + { SonyID_NEX_7, "NEX-7"}, // Hasselblad Lunar + { SonyID_NEX_VG20, "NEX-VG20"}, + { SonyID_SLT_A37, "SLT-A37"}, + { SonyID_SLT_A57, "SLT-A57"}, + { SonyID_NEX_F3, "NEX-F3"}, + { SonyID_SLT_A99, "SLT-A99"}, // SLT-A99V / Hasselblad HV + { SonyID_NEX_6, "NEX-6"}, + { SonyID_NEX_5R, "NEX-5R"}, + { SonyID_DSC_RX100, "DSC-RX100"}, // Hasselblad Stellar + { SonyID_DSC_RX1, "DSC-RX1"}, + { SonyID_NEX_VG900, "NEX-VG900"}, + { SonyID_NEX_VG30, "NEX-VG30"}, + { SonyID_ILCE_3000, "ILCE-3000"}, // ILCE-3500 + { SonyID_SLT_A58, "SLT-A58"}, + { SonyID_NEX_3N, "NEX-3N"}, + { SonyID_ILCE_7, "ILCE-7"}, + { SonyID_NEX_5T, "NEX-5T"}, + { SonyID_DSC_RX100M2, "DSC-RX100M2"}, // Hasselblad Stellar II + { SonyID_DSC_RX10, "DSC-RX10"}, + { SonyID_DSC_RX1R, "DSC-RX1R"}, + { SonyID_ILCE_7R, "ILCE-7R"}, // Hasselblad Lusso + { SonyID_ILCE_6000, "ILCE-6000"}, + { SonyID_ILCE_5000, "ILCE-5000"}, + { SonyID_DSC_RX100M3, "DSC-RX100M3"}, + { SonyID_ILCE_7S, "ILCE-7S"}, + { SonyID_ILCA_77M2, "ILCA-77M2"}, + { SonyID_ILCE_5100, "ILCE-5100"}, + { SonyID_ILCE_7M2, "ILCE-7M2"}, + { SonyID_DSC_RX100M4, "DSC-RX100M4"}, + { SonyID_DSC_RX10M2, "DSC-RX10M2"}, + { SonyID_DSC_RX1RM2, "DSC-RX1RM2"}, + { SonyID_ILCE_QX1, "ILCE-QX1"}, + { SonyID_ILCE_7RM2, "ILCE-7RM2"}, + { SonyID_ILCE_7SM2, "ILCE-7SM2"}, + { SonyID_ILCA_68, "ILCA-68"}, + { SonyID_ILCA_99M2, "ILCA-99M2"}, + { SonyID_DSC_RX10M3, "DSC-RX10M3"}, + { SonyID_DSC_RX100M5, "DSC-RX100M5"}, + { SonyID_ILCE_6300, "ILCE-6300"}, + { SonyID_ILCE_9, "ILCE-9"}, + { SonyID_ILCE_6500, "ILCE-6500"}, + { SonyID_ILCE_7RM3, "ILCE-7RM3"}, + { SonyID_ILCE_7M3, "ILCE-7M3"}, + { SonyID_DSC_RX0, "DSC-RX0"}, + { SonyID_DSC_RX10M4, "DSC-RX10M4"}, + { SonyID_DSC_RX100M6, "DSC-RX100M6"}, + { SonyID_DSC_HX99, "DSC-HX99"}, + { SonyID_DSC_RX100M5A, "DSC-RX100M5A"}, + { SonyID_ILCE_6400, "ILCE-6400"}, + { SonyID_DSC_RX0M2, "DSC-RX0M2"}, + { SonyID_DSC_RX100M7, "DSC-RX100M7"}, + { SonyID_ILCE_7RM4, "ILCE-7RM4"}, + { SonyID_ILCE_9M2, "ILCE-9M2"}, + { SonyID_ILCE_6600, "ILCE-6600"}, + { SonyID_ILCE_6100, "ILCE-6100"}, + }; + + static const char *orig; + + static const char fujialias[][16] = { + "@DBP for GX680", "DX-2000", + "@F500EXR", "F505EXR", + "@F600EXR", "F605EXR", + "@F770EXR", "F775EXR", + "@HS10", "HS10 HS11", + "@HS20EXR", "HS22EXR", + "@HS30EXR", "HS33EXR", "HS35EXR", + "@S5100", "S5500", + "@S5200", "S5600", + "@S6000fd", "S6500fd", + "@S9000", "S9500", + "@S9100", "S9600", + "@S200EXR", "S205EXR", + "@X-T1 IR", "X-T1IR", + }; + + static const char kodakalias[][16] = { + "@DCS Pro 14N", "Camerz ZDS 14", // Camerz rebadge make: "Photo Control" + "@DCS720X", "SCS2000", + "@DCS520C", "EOS D2000C", "EOS D2000", // EOS rebadge make: Canon + "@DCS560C", "EOS D6000C", "EOS D6000", // EOS rebadge make: Canon + "@DCS460M", "DCS460A", // 'A' was supposed to stand for 'achromatic', marketing changed it to 'M' + "@DCS460", "DCS460C", "DCS460D", + "@DCS465", "DCS465C", "DCS465D", + "@EOSDCS1", "EOSDCS1B", "EOSDCS1C", + "@EOSDCS3", "EOSDCS3B", "EOSDCS3C", + }; + + static const struct + { + const char *Kmodel; + ushort mount; + } Kodak_mounts[] = { + {"DCS465", LIBRAW_MOUNT_DigitalBack}, + {"DCS5", LIBRAW_MOUNT_Canon_EF}, + {"DCS Pro SLR/c", LIBRAW_MOUNT_Canon_EF}, + {"DCS", LIBRAW_MOUNT_Nikon_F}, + {"EOS", LIBRAW_MOUNT_Canon_EF}, + {"NC2000", LIBRAW_MOUNT_Nikon_F}, // AP "News Camera" + {"Pixpro S-1", LIBRAW_MOUNT_mFT}, + {"ProBack", LIBRAW_MOUNT_DigitalBack}, + {"SCS1000", LIBRAW_MOUNT_Canon_EF}, + }; + + static const char *KodakMonochrome[] = { + "DCS420M", "DCS420A", "DCS420I", + "DCS460M", "DCS460A", "DCS460I", + "DCS465M", "DCS465A", "DCS465I", + "DCS560M", "DCS660M", "DCS760M", "EOS D2000M", "EOS D6000M", + "EOSDCS1M", "EOSDCS1I", + "EOSDCS3M", "EOSDCS3I", + "EOSDCS5M", "EOSDCS5I", + "NC2000M", "NC2000A", "NC2000I", + }; + + static const char leafalias[][16] = { + // Leaf re-badged to Mamiya + "@Aptus-II 5", "DM22", + "@Aptus-II 6", "DM28", + "@Aptus-II 7", "DM33", + "@Aptus-II 8", "DM40", + "@Aptus-II 10", "DM56", + }; + + static const char KonicaMinolta_aliases[][24] = { + "@DG-5D", "DYNAX 5D", "MAXXUM 5D", "ALPHA-5 DIGITAL", "ALPHA SWEET DIGITAL", + "@DG-7D", "DYNAX 7D", "MAXXUM 7D", "ALPHA-7 DIGITAL", + }; + + static const char nikonalias[][16] = { + "@COOLPIX 2100", "E2100", "@COOLPIX 2500", "E2500", + "@COOLPIX 3200", "E3200", "@COOLPIX 3700", "E3700", + "@COOLPIX 4300", "E4300", "@COOLPIX 4500", "E4500", + "@COOLPIX 5000", "E5000", "@COOLPIX 5400", "E5400", + "@COOLPIX 5700", "E5700", "@COOLPIX 8400", "E8400", + "@COOLPIX 8700", "E8700", "@COOLPIX 8800", "E8800", + "@COOLPIX 700", "E700", "@COOLPIX 800", "E800", + "@COOLPIX 880", "E880", "@COOLPIX 900", "E900", + "@COOLPIX 950", "E950", "@COOLPIX 990", "E990", + "@COOLPIX 995", "E995", "@COOLPIX P7700", "COOLPIX Deneb", + "@COOLPIX P7800", "COOLPIX Kalon", + }; + + static const char olyalias[][32] = { // Olympus + "@AIR A01", "AIR-A01", + "@C-3030Z", "C3030Z", + "@C-5050Z", "C5050Z", + "@C-5060WZ", "C5060WZ", + "@C-7000Z", "C7000Z", "C70Z,C7000Z", "C70Z", + "@C-7070WZ", "C7070WZ", + "@C-8080WZ", "C8080WZ", + "@C-350Z", "C350Z", "X200,D560Z,C350Z", "X200", "D560Z", + "@C-740UZ", "C740UZ", + "@C-770UZ", "C770UZ", + "@E-20", "E-20,E-20N,E-20P", "E-20N", "E-20P", + "@E-M10 Mark II", "E-M10MarkII", "E-M10_M2", "piX 5oo", + "@E-M10 Mark III", "E-M10MarkIII", "E-M10_M3", + "@E-M1 Mark II", "E-M1MarkII", "E-M1_M2", + "@E-M1 Mark III", "E-M1MarkIII", "E-M1_M3", + "@E-M5 Mark III", "E-M5MarkIII", "E-M5_M3", + "@E-M5 Mark II", "E-M5MarkII", "E-M5_M2", + "@SH-2", "SH-3", + "@SP-310", "SP310", + "@SP-320", "SP320", + "@SP-350", "SP350", + "@SP-500UZ", "SP500UZ", + "@SP-510UZ", "SP510UZ", + "@SP-550UZ", "SP550UZ", + "@SP-560UZ", "SP560UZ", + "@SP-565UZ", "SP565UZ", + "@SP-570UZ", "SP570UZ", + "@Stylus 1", "STYLUS1", "STYLUS1s", "STYLUS1,1s", + }; + + static const char panalias[][16] = { // Panasonic, PanaLeica +// fixed lens + "@DMC-FX150", "DMC-FX180", + "@DC-FZ1000M2", "DC-FZ10002", "V-Lux 5", + "@DMC-FZ1000", "V-LUX (Typ 114)", + "@DMC-FZ2500", "DMC-FZ2000", "DMC-FZH1", + "@DMC-FZ100", "V-LUX 2", + "@DMC-FZ150", "V-LUX 3", + "@DMC-FZ200", "V-LUX 4", + "@DMC-FZ300", "DMC-FZ330", + "@DMC-FZ35", "DMC-FZ38", + "@DMC-FZ40", "DMC-FZ42", "DMC-FZ45", "DC-FZ40", "DC-FZ42", "DC-FZ45", + "@DMC-FZ50", "V-LUX 1", "V-LUX1", + "@DMC-FZ70", "DMC-FZ72", + "@DC-FZ80", "DC-FZ81", "DC-FZ82", "DC-FZ83", "DC-FZ85", + "@DMC-LC1", "DIGILUX 2", "Digilux 2", "DIGILUX2", + "@DMC-LF1", "C (Typ 112)", + "@DC-LX100M2", "D-Lux 7", + "@DMC-LX100", "D-LUX (Typ 109)", "D-Lux (Typ 109)", + "@DMC-LX1", "D-Lux2", "D-LUX2", "D-LUX 2", + "@DMC-LX2", "D-LUX 3", "D-LUX3", + "@DMC-LX3", "D-LUX 4", + "@DMC-LX5", "D-LUX 5", + "@DMC-LX7", "D-LUX 6", + "@DMC-LX9", "DMC-LX10", "DMC-LX15", + "@DMC-ZS100", "DMC-ZS110", "DMC-TZ100", "DMC-TZ101", "DMC-TZ110", "DMC-TX1", + "@DC-ZS200", "DC-ZS220", "DC-TZ200", "DC-TZ202", "DC-TZ220", "DC-TX2", "C-Lux", "CAM-DC25", + "@DMC-ZS40", "DMC-TZ60", "DMC-TZ61", + "@DMC-ZS50", "DMC-TZ70", "DMC-TZ71", + "@DMC-ZS60", "DMC-TZ80", "DMC-TZ81", "DMC-TZ82", "DMC-TZ85", + "@DC-ZS70", "DC-TZ90", "DC-TZ91", "DC-TZ92", "DC-TZ93", + "@DC-ZS80", "DC-TZ95", "DC-TZ96", "DC-TZ97", + +// interchangeable lens + "@DC-G99", "DC-G90", "DC-G91", "DC-G95", + "@DMC-G7", "DMC-G70", + "@DMC-G8", "DMC-G80", "DMC-G81", "DMC-G85", + "@DMC-GH4", "AG-GH4", "CGO4", + "@DC-GF10", "DC-GF90", "DC-GX880", + "@DC-GF9", "DC-GX850", "DC-GX800", + "@DMC-GM1", "DMC-GM1S", + "@DMC-GX85", "DMC-GX80", "DMC-GX7MK2", + "@DC-GX9", "DC-GX7MK3", + "@DMC-L1", "DIGILUX 3", "DIGILUX3", // full 4/3 mount, not m43 + }; + + static const char phase1alias[][16] = { + "@H20", "H 20", + "@H25", "H 25", + "@P20+", "P 20+", + "@P20", "P 20", + "@P21+", "P 21+", "M18", // "Mamiya M18" + "@P21", "P 21", + "@P25+", "P 25+", "M22", // "Mamiya M22" + "@P25", "P 25", + "@P30+", "P 30+", "M31", // "Mamiya M31" + "@P30", "P 30", + "@P40+", "P 40+", + "@P40", "P 40", + "@P45+", "P 45+", + "@P45", "P 45", + "@P65+", "P 65+", + "@P65", "P 65", + }; + + static const char SamsungPentax_aliases[][16] = { + "@*istDL2", "*ist DL2", "GX-1L", + "@*istDS2", "*ist DS2", "GX-1S", + "@*istDL", "*ist DL", + "@*istDS", "*ist DS", + "@*istD", "*ist D", + "@K10D", "GX10", "GX-10", + "@K20D", "GX20", "GX-20", + "@K-m", "K2000", + }; + + static const char samsungalias[][64] = { + "@EX1", "TL500", + "@NX U", "EK-GN100", "EK-GN110", "EK-GN120", "EK-KN120", "Galaxy NX", + "@NX mini", "NXF1", + "@WB2000", "TL350", + // "@WB5000", "WB5000/HZ25W", // no spaces around the slash separating names + // "@WB5500", "WB5500 / VLUU WB5500 / SAMSUNG HZ50W", + // "@WB500", "WB510 / VLUU WB500 / SAMSUNG HZ10W", + // "@WB550", "WB560 / VLUU WB550 / SAMSUNG HZ15W", + // "@WB650", "SAMSUNG WB650 / VLUU WB650 / SAMSUNG WB660" aka HZ35W + }; + +//clang-format on + if (makeIs(LIBRAW_CAMERAMAKER_VLUU)) { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Samsung); + } + + if (makeIs(LIBRAW_CAMERAMAKER_Samsung) && + (ilm.CameraMount == LIBRAW_MOUNT_Pentax_K)) { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Pentax); + + } else if (makeIs(LIBRAW_CAMERAMAKER_Unknown)) { + if (strcasestr(model, "Google")) { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Google); + } +#ifdef USE_6BY9RPI + else if(strcasestr(make,"RaspberryPi")) + setMakeFromIndex(LIBRAW_CAMERAMAKER_Broadcom); +#endif + } + else if (makeIs(LIBRAW_CAMERAMAKER_Hasselblad) && is_Sony) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Sony); + } + else if (makeIs(LIBRAW_CAMERAMAKER_Clauss) && (OlyID == OlyID_E_M10_Mark_II)) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Olympus); + + } else if (makeIs(LIBRAW_CAMERAMAKER_Canon) && + (!strncmp(model, "EOS D2000", 9) || // don't use unique_id here + !strncmp(model, "EOS D6000", 9) || // because ids for Monochrome models are unknown + !strncmp(model, "EOSDCS", 6))) { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Kodak); +// if (unique_id == CanonID_EOS_D2000C) { +// +// } else if (unique_id == CanonID_EOS_D6000C) { +/// +// } + + } else if (makeIs(LIBRAW_CAMERAMAKER_PhotoControl) && + !strncasecmp(model, "Camerz ZDS 14", 13)) { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Kodak); + + } else { + strcpy(normalized_make, make); + } + + if (makeIs(LIBRAW_CAMERAMAKER_Apple)) { + if ((imgdata.color.UniqueCameraModel[0]) && + (!strncmp(model, "iPad", 4) || !strncmp(model, "iPhone", 6))) + strcpy(model, imgdata.color.UniqueCameraModel); + + } else if (makeIs(LIBRAW_CAMERAMAKER_Kodak)) { + if ((model[6] == ' ') && + (!strncmp(model, "DCS4", 4) || + !strncmp(model, "NC2000", 6))) + { + model[6] = 0; + } + if ((model[6] != 'A') && + (model[6] != 'I') && + (model[6] != 'M') && + !strncmp(model, "NC2000", 6)) + { + model[6] = 0; + } + } + + else if (makeIs(LIBRAW_CAMERAMAKER_Ricoh) && + !strncmp(model, "GXR", 3)) { + strcpy(ilm.body, "Ricoh GXR"); + if (!imgdata.lens.Lens[0] && imgdata.color.UniqueCameraModel[0]) { + strcpy (imgdata.lens.Lens, imgdata.color.UniqueCameraModel); + remove_caseSubstr (imgdata.lens.Lens, (char *)"Ricoh"); + remove_caseSubstr (imgdata.lens.Lens, (char *)"Lens"); + removeExcessiveSpaces (imgdata.lens.Lens); + } + if (ilm.LensID == LIBRAW_LENS_NOT_SET) { + if (strstr(imgdata.lens.Lens, "50mm")) + ilm.LensID = 1; + else if (strstr(imgdata.lens.Lens, "S10")) + ilm.LensID = 2; + else if (strstr(imgdata.lens.Lens, "P10")) + ilm.LensID = 3; + else if (strstr(imgdata.lens.Lens, "28mm")) + ilm.LensID = 5; + else if (strstr(imgdata.lens.Lens, "A16")) + ilm.LensID = 6; + } + switch (ilm.LensID) { + case 1: // GR Lens A12 50mm F2.5 Macro + strcpy(model, "GXR A12 50mm"); + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_RicohModule; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + break; + case 2: + strcpy(model, "GXR S10"); + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_1div1p7INCH; + ilm.CameraMount = LIBRAW_MOUNT_RicohModule; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + break; + case 3: // Ricoh Lens P10 28-300mm F3.5-5.6 VC + strcpy(model, "GXR P10"); + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_1div2p3INCH; + ilm.CameraMount = LIBRAW_MOUNT_RicohModule; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + break; + case 5: // GR Lens A12 28mm F2.5 + strcpy(model, "GXR A12 28mm"); + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_RicohModule; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + break; + case 6: // Ricoh Lens A16 24-85mm F3.5-5.5 + strcpy(model, "GXR A16"); + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_RicohModule; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + break; + case 8: // Ricoh Mount A12 (Leica M lenses) + strcpy(model, "GXR Mount A12"); + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_Leica_M; + ilm.LensID = LIBRAW_LENS_NOT_SET; + break; + } + } + + strcpy(normalized_model, model); + + if (makeIs(LIBRAW_CAMERAMAKER_Canon)) + { + if ((unique_id) && (unique_id != CanonID_EOS_D2000C) && (unique_id != CanonID_EOS_D6000C)) + { + for (i = 0; i < int(sizeof unique / sizeof *unique); i++) + { + if (unique_id == unique[i].id) + { + strcpy(model, unique[i].t_model); + strcpy(normalized_model, unique[i].t_model); + break; + } + } + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Fujifilm)) + { + for (i = 0; i < int(sizeof fujialias / sizeof *fujialias); i++) + { + if (fujialias[i][0] == '@') + { + orig = fujialias[i] + 1; + if (!strcmp(model, orig)) break; + } + else if (!strcmp(model, fujialias[i])) + { + strcpy(normalized_model, orig); + break; + } + } + + } else if (makeIs(LIBRAW_CAMERAMAKER_Hasselblad)) { + parseHassyModel(); + } + else if (makeIs(LIBRAW_CAMERAMAKER_Mamiya)) + { + for (i = 0; i < int(sizeof phase1alias / sizeof *phase1alias); i++) + { // re-badged Phase One backs + if (phase1alias[i][0] == '@') orig = phase1alias[i] + 1; + else if (!strcmp(model, phase1alias[i])) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_PhaseOne); + strcpy(normalized_model, orig); + break; + } + } + for (i = 0; i < int(sizeof leafalias / sizeof *leafalias); i++) + { // re-badged Leaf backs + if (leafalias[i][0] == '@') orig = leafalias[i] + 1; + else if (!strcmp(model, leafalias[i])) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Leaf); + strcpy(normalized_model, orig); + break; + } + } + + /* repeating, because make for some Mamiya re-badged Leaf backs is set to + * Leaf */ + } + else if (makeIs(LIBRAW_CAMERAMAKER_Leaf)) + { + for (i = 0; i < int(sizeof leafalias / sizeof *leafalias); i++) + { // re-badged Leaf backs + if (leafalias[i][0] == '@') + { + orig = leafalias[i] + 1; + if (!strcmp(model, orig)) break; + } + else if (!strcmp(model, leafalias[i])) + { // maybe to change regular "make" to "Mamiya" too + strcpy(normalized_model, orig); + break; + } + } + if ((ps = strchr(normalized_model, '('))) + *ps = 0; + } + else if (makeIs(LIBRAW_CAMERAMAKER_Minolta) || + makeIs(LIBRAW_CAMERAMAKER_Konica)) + { + if (makeIs(LIBRAW_CAMERAMAKER_Konica) && !strncasecmp(model, "DiMAGE", 6)) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Minolta); + strcpy(make, "Minolta"); + } + else + { + for (i = 0; + i<int(sizeof KonicaMinolta_aliases / sizeof *KonicaMinolta_aliases); + i++) + { + if (KonicaMinolta_aliases[i][0] == '@') + { + orig = KonicaMinolta_aliases[i] + 1; + if (!strcmp(model, orig)) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Minolta); + strcpy(make, "Minolta"); + break; + } + } + else if (!strcasecmp(model, KonicaMinolta_aliases[i])) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Minolta); + strcpy(make, "Minolta"); + strcpy(normalized_model, orig); + break; + } + } + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Nikon)) + { + for (i = 0; i < int(sizeof nikonalias / sizeof *nikonalias); i++) + { + if (nikonalias[i][0] == '@') + { + orig = nikonalias[i] + 1; + if (!strcmp(model, orig)) break; + } + else if (!strcmp(model, nikonalias[i])) + { + strcpy(normalized_model, orig); + break; + } + } + + } else if (makeIs(LIBRAW_CAMERAMAKER_Olympus)) { + for (i = 0; i < int(sizeof olyalias / sizeof *olyalias); i++) { + if (olyalias[i][0] == '@') { + orig = olyalias[i] + 1; + if (!strcmp(model, orig)) break; + } else if (!strcmp(model, olyalias[i])) { + strcpy(normalized_model, orig); + break; + } + } + + if (!OlyID) { + if (!strcmp(normalized_model, "C-740UZ")) { + ilm.CamID = OlyID = unique_id = OlyID_C_740UZ; + + } else if (!strcmp(normalized_model, "C-770UZ")) { + ilm.CamID = OlyID = unique_id = OlyID_C_770UZ; + } + } + + } else if (makeIs(LIBRAW_CAMERAMAKER_Panasonic) || + makeIs(LIBRAW_CAMERAMAKER_Leica) || + makeIs(LIBRAW_CAMERAMAKER_Yuneec)) + { + for (i = 0; i < int(sizeof panalias / sizeof *panalias); i++) + { + if (panalias[i][0] == '@') + { + orig = panalias[i] + 1; + if (!strcmp(model, orig)) break; + } + else if (!strcmp(model, panalias[i])) + { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Panasonic); + strcpy(normalized_model, orig); + break; + } + } + } else if (makeIs(LIBRAW_CAMERAMAKER_Pentax)) { + + if (!unique_id) { + if (!strcmp(model, "Optio S")) { + ilm.CamID = unique_id = PentaxID_Optio_S; + } else if (!strcmp(model, "Optio S V1.01")) { + ilm.CamID = unique_id = PentaxID_Optio_S_V101; + } else if (!strcmp(model, "Optio S4")) { + ilm.CamID = unique_id = PentaxID_Optio_S4; + } else if (!strcmp(model, "Optio 750Z")) { + ilm.CamID = unique_id = PentaxID_Optio_750Z; + } else if (!strcmp(model, "Optio 33WR")) { + ilm.CamID = unique_id = PentaxID_Optio_33WR; + } + } + + for (i = 0; + i < int(sizeof SamsungPentax_aliases / sizeof *SamsungPentax_aliases); + i++) { + if (SamsungPentax_aliases[i][0] == '@') { + orig = SamsungPentax_aliases[i] + 1; + if (!strcmp(model, orig)) break; + } else if (!strcmp(model, SamsungPentax_aliases[i])) { + strcpy(normalized_model, orig); + break; + } + } + if (!strncmp(model, "GR", 2)) { + setMakeFromIndex(LIBRAW_CAMERAMAKER_Ricoh); + strcpy(make, "Ricoh"); + } + + } else if (makeIs(LIBRAW_CAMERAMAKER_PhaseOne)) + { + for (i = 0; i < int(sizeof phase1alias / sizeof *phase1alias); i++) + { + if (phase1alias[i][0] == '@') + { + orig = phase1alias[i] + 1; + if (!strcmp(model, orig)) break; + } + else if (!strcmp(model, phase1alias[i])) + { + strcpy(normalized_model, orig); + break; + } + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Samsung)) + { + j = 0; + if (strstr(model, "WB5500") || strstr(model, "HZ50W")) + { + strcpy(model, "WB5500"); + j++; + } + else if (strstr(model, "WB5000") || strstr(model, "HZ25W")) + { + strcpy(model, "WB5000"); + j++; + } + else if (strstr(model, "WB550") || strstr(model, "HZ15W")) + { + strcpy(model, "WB550"); + j++; + } + else if (strstr(model, "WB500") || strstr(model, "HZ10W")) + { + strcpy(model, "WB500"); + j++; + } + if (j) + { + strcpy(normalized_model, model); + } + else + { + for (i = 0; i < int(sizeof samsungalias / sizeof *samsungalias); i++) + { + if (samsungalias[i][0] == '@') + { + orig = samsungalias[i] + 1; + if (!strcmp(model, orig)) break; + } + else if (!strcmp(model, samsungalias[i])) + { + strcpy(normalized_model, orig); + break; + } + } + } + + } else if (makeIs(LIBRAW_CAMERAMAKER_Sony)) { + if (unique_id) + { + for (i = 0; i < int(sizeof sonique / sizeof *sonique); i++) + { + if (unique_id == sonique[i].id) + { + if (!strcmp(make, "Sony")) + strcpy(model, sonique[i].t_model); + strcpy(normalized_model, sonique[i].t_model); + break; + } + } + } + + } else if (makeIs(LIBRAW_CAMERAMAKER_Kodak)) { + remove_caseSubstr (normalized_model, (char *)"EasyShare"); + remove_caseSubstr (normalized_model, (char *)"ZOOM"); + removeExcessiveSpaces (normalized_model); + for (i = 0; i < int(sizeof kodakalias / sizeof *kodakalias); i++) + { + if (kodakalias[i][0] == '@') + { + orig = kodakalias[i] + 1; + if (!strcmp(model, orig)) break; + } + else if (!strcmp(model, kodakalias[i])) + { + strcpy(normalized_model, orig); + break; + } + } + + if (strstr(model, "DC25")) + { + strcpy(model, "DC25"); + strcpy(normalized_model, model); + } + else if (!strcmp(model, "40")) + { + strcpy(model, "DC40"); + strcpy(normalized_model, model); + } + else if (strstr(model, "DC50")) + { + strcpy(model, "DC50"); + strcpy(normalized_model, model); + } + else if (strstr(model, "DC120")) + { + strcpy(model, "DC120"); + strcpy(normalized_model, model); + } + + for (i = 0; i < int(sizeof KodakMonochrome / sizeof *KodakMonochrome); i++) + { + if (!strncmp(model, KodakMonochrome[i], strlen(KodakMonochrome[i]))) + { + colors = 1; + filters = 0; + } + } + } + + if (ilm.body[0]) + { + if ((ilm.CameraMount != LIBRAW_MOUNT_Hasselblad_V) && + !strncmp(ilm.body, "Hasselblad ", 11) && + ((ilm.body[11] == 'C') || (ilm.body[11] == '2') || + (ilm.body[11] == '5') || (ilm.body[11] == '9'))) + { + ilm.CameraFormat = LIBRAW_FORMAT_66; + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_V; + } + else if (!strncmp(ilm.body, "XF", 2) || !strncmp(ilm.body, "645DF", 5)) + { + ilm.CameraMount = LIBRAW_MOUNT_Mamiya645; + ilm.CameraFormat = LIBRAW_FORMAT_645; + } + else if (!strncmp(ilm.body, "Sinarcam", 2)) + { + ilm.CameraMount = LIBRAW_MOUNT_LF; + ilm.CameraFormat = LIBRAW_FORMAT_LF; + strcat(ilm.body, " shutter system"); + } + } + + if (makeIs(LIBRAW_CAMERAMAKER_Kodak)) + { + if (((ilm.CameraMount == LIBRAW_MOUNT_DigitalBack) || + (ilm.CameraMount == LIBRAW_MOUNT_Unknown)) && + !strncmp(model2, "PB645", 5)) + { + ilm.CameraFormat = LIBRAW_FORMAT_645; + if (model2[5] == 'C') + { + ilm.CameraMount = LIBRAW_MOUNT_Contax645; + strcpy(ilm.body, "Contax 645"); + } + else if (model2[5] == 'H') + { + ilm.CameraMount = LIBRAW_MOUNT_Hasselblad_H; + strcpy(ilm.body, "Hasselblad H1/H2"); + } + else if (model2[5] == 'M') + { + ilm.CameraMount = LIBRAW_MOUNT_Mamiya645; + strcpy(ilm.body, "Mamiya 645"); + } + + } else if (!strncasecmp(model, "PIXPRO S-1", 10)) { + ilm.CameraFormat = LIBRAW_FORMAT_FT; + } else if (!strncasecmp(model, "PIXPRO ", 7)) { + ilm.CameraFormat = LIBRAW_FORMAT_1div2p3INCH; + } + } + + else if (makeIs(LIBRAW_CAMERAMAKER_Fujifilm)) + { + if (!strncmp(normalized_model, "DBP", 3)) + { + strcpy(ilm.body, "Fujifilm GX680"); + } + } + + if ((ilm.CameraFormat == LIBRAW_FORMAT_Unknown) || + (ilm.CameraMount == LIBRAW_MOUNT_Unknown) || + (ilm.CameraMount == LIBRAW_MOUNT_IL_UM)) + { + + if (makeIs(LIBRAW_CAMERAMAKER_Canon)) + { + if (strncmp(normalized_model, "EOS", 3)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Nikon)) + { + if (normalized_model[0] == 'D') + { + ilm.CameraMount = LIBRAW_MOUNT_Nikon_F; + } + else + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Panasonic)) + { + if (!strncmp(normalized_model, "DC-S", 4)) + { + ilm.CameraFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = LIBRAW_MOUNT_LPS_L; + } + else if (!strncmp(normalized_model, "DMC-L1", 6) || + !strncmp(normalized_model, "DMC-L10", 7)) + { + ilm.CameraFormat = ilm.CameraMount = LIBRAW_FORMAT_FT; + } + else if (!strncmp(normalized_model + 2, "-G", 2) || + !strncmp(normalized_model + 3, "-G", 2)) + { + ilm.CameraFormat = LIBRAW_FORMAT_FT; + ilm.CameraMount = LIBRAW_MOUNT_mFT; + } + else + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + if (!strncmp(normalized_model + 2, "-LX100", 6) || // DC-LX100M2 + !strncmp(normalized_model + 3, "-LX100", 6)) + { // DMC-LX100 + ilm.CameraFormat = ilm.LensFormat = LIBRAW_FORMAT_FT; + } + else if (!strncmp(normalized_model, "DMC-CM1", 7)) + { + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + } + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Fujifilm)) + { + if (!strncmp(normalized_model, "GFX ", 4)) + { + ilm.CameraFormat = LIBRAW_FORMAT_CROP645; + ilm.CameraMount = LIBRAW_MOUNT_Fuji_GF; + } + else if (!strncmp(normalized_model, "X-", 2) && + strncmp(normalized_model, "X-S1", 4)) + { + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_Fuji_X; + } + else if (((normalized_model[0] == 'S') && // S2Pro, S3Pro, S5Pro + (normalized_model[2] == 'P')) || + !strncasecmp(normalized_model, "IS Pro", 6)) + { + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_Nikon_F; + } + else if (!strncmp(normalized_model, "DBP", 3)) + { + ilm.CameraFormat = LIBRAW_FORMAT_68; + ilm.CameraMount = LIBRAW_MOUNT_Fuji_GX; + } + else + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Samsung)) + { + if ((normalized_model[0] == 'N') && (normalized_model[1] == 'X')) + { // DNG converters delete makernotes + if ((normalized_model[2] == 'F') && (normalized_model[3] == '1')) + { + ilm.CameraMount = LIBRAW_MOUNT_Samsung_NX_M; + ilm.CameraFormat = LIBRAW_FORMAT_1INCH; + } + else + { + ilm.CameraMount = LIBRAW_MOUNT_Samsung_NX; + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + } + } + else + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Kodak)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + for (i = 0; i < int(sizeof Kodak_mounts / sizeof *Kodak_mounts); i++) + { + if (!strncmp(normalized_model, Kodak_mounts[i].Kmodel, + strlen(Kodak_mounts[i].Kmodel))) + { + ilm.CameraMount = Kodak_mounts[i].mount; + break; + } + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Minolta)) + { + if (!strcmp(normalized_model, "DG-5D") || + !strcmp(normalized_model, "DG-7D")) + { + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.CameraMount = LIBRAW_MOUNT_Minolta_A; + } + else if (!strncasecmp(normalized_model, "DiMAGE", 6)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Casio) || + makeIs(LIBRAW_CAMERAMAKER_Creative)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + else if (makeIs(LIBRAW_CAMERAMAKER_Sigma)) + { + if (!strncmp(normalized_model, "fp", 2)) + { + ilm.CameraFormat = LIBRAW_FORMAT_FF; + ilm.CameraMount = LIBRAW_MOUNT_LPS_L; + } + else if (!strncasecmp(normalized_model, "SD", 2)) + { + ilm.CameraMount = LIBRAW_MOUNT_Sigma_X3F; + if (!strcmp(normalized_model, "SD1") || (normalized_model[4] == 'M')) + { + ilm.CameraFormat = LIBRAW_FORMAT_SigmaMerrill; + } + else if (normalized_model[11] == 'H') + { // 'sd Quattro H' + ilm.CameraFormat = LIBRAW_FORMAT_SigmaAPSH; + } + else if (normalized_model[4] == 'Q') + { // 'sd Quattro' + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + } + else + { + ilm.CameraFormat = LIBRAW_FORMAT_SigmaAPSC; + } + } + else if (!strncasecmp(normalized_model, "DP", 2)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + if (normalized_model[4] == 'M') + { + ilm.CameraFormat = LIBRAW_FORMAT_SigmaMerrill; + } + else if (normalized_model[4] == 'Q') + { + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + } + else + { + ilm.CameraFormat = LIBRAW_FORMAT_SigmaAPSC; + } + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Konica)) + { + if (!strncmp(model, "KD-", 3)) + { // Konica KD-400Z, KD-510Z + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Mamiya)) + { + if (!strncmp(normalized_model, "ZD", 2)) + { + ilm.CameraFormat = LIBRAW_FORMAT_3648; + ilm.CameraMount = LIBRAW_MOUNT_Mamiya645; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Sony)) + { + if (!strncmp(normalized_model, "XCD-", 4)) + { + ilm.CameraMount = LIBRAW_MOUNT_C; + } + else if (!strncmp(normalized_model, "DSC-V3", 6) || + !strncmp(normalized_model, "DSC-F828", 8)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + imSony.CameraType = LIBRAW_SONY_DSC; + } + } + else if (makeIs(LIBRAW_CAMERAMAKER_Polaroid) && + !strncmp(normalized_model, "x530", 4)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + else if (makeIs(LIBRAW_CAMERAMAKER_Rollei) && + !strncmp(normalized_model, "d530flex", 8)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + else if (makeIs(LIBRAW_CAMERAMAKER_Pentax) && + !strncmp(normalized_model, "Optio", 5)) { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + else if (makeIs(LIBRAW_CAMERAMAKER_Epson) && + !strncmp(normalized_model, "R-D1", 4)) + { + ilm.CameraMount = LIBRAW_MOUNT_Leica_M; + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + } + } + + if ((ilm.LensMount == LIBRAW_MOUNT_Canon_RF) && + (ilm.LensID == 61182) && + (imCanon.RF_lensID != 0)) { + ilm.LensID = imCanon.RF_lensID; + } + + if (ilm.LensMount == LIBRAW_MOUNT_Unknown) + { + if (makeIs(LIBRAW_CAMERAMAKER_Samsung)) + { + if ((imgdata.lens.Lens[0] == 'N') && (imgdata.lens.Lens[1] == 'X')) + { // same DNG problem + if (imgdata.lens.Lens[2] == '-') + { + ilm.LensMount = LIBRAW_MOUNT_Samsung_NX_M; + ilm.LensFormat = LIBRAW_FORMAT_1INCH; + } + else + { + ilm.LensMount = LIBRAW_MOUNT_Samsung_NX; + ilm.LensFormat = LIBRAW_FORMAT_APSC; + } + } + } + } + + if (ilm.LensID == LIBRAW_LENS_NOT_SET) + { + if (makeIs(LIBRAW_CAMERAMAKER_Samsung)) + { + if ((ilm.LensMount == LIBRAW_MOUNT_Samsung_NX) && xmpdata && (strlen(xmpdata) > 9) && + (ps = strstr(xmpdata, "LensID=\"("))) + { + ilm.LensID = atoi(ps + 9); + } + } + } + + if (ilm.CameraMount == LIBRAW_MOUNT_FixedLens) + { + if (ilm.CameraFormat) + ilm.LensFormat = ilm.CameraFormat; + if (ilm.LensMount == LIBRAW_MOUNT_Unknown) + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + } + + if ((ilm.CameraMount != LIBRAW_MOUNT_Unknown) && + (ilm.CameraMount != LIBRAW_MOUNT_FixedLens) && + (ilm.LensMount == LIBRAW_MOUNT_Unknown)) { + if (ilm.LensID == LIBRAW_LENS_NOT_SET) ilm.LensMount = LIBRAW_MOUNT_IL_UM; + else ilm.LensMount = ilm.CameraMount; + } +} + +void LibRaw::SetStandardIlluminants (unsigned makerIdx, const char* normModel) { + int i = -1; + int c; + if (!icWBC[LIBRAW_WBI_Ill_A][0] && + !icWBC[LIBRAW_WBI_D65][0]) { + if (makerIdx == LIBRAW_CAMERAMAKER_Olympus) { + while (++i, icWBCCTC[i][0]) { + if (icWBCCTC[i][0] == 3000) + FORC4 icWBC[LIBRAW_WBI_Ill_A][c] = icWBCCTC[i][c+1]; + else if (icWBCCTC[i][0] == 6600) + FORC4 icWBC[LIBRAW_WBI_D65][c] = icWBCCTC[i][c+1]; + } + } + } + + if (!icWBC[LIBRAW_WBI_Ill_A][0] && icWBC[LIBRAW_WBI_Tungsten][0]) + FORC4 icWBC[LIBRAW_WBI_Ill_A][c] = icWBC[LIBRAW_WBI_Tungsten][c]; + + if (!icWBC[LIBRAW_WBI_D65][0] && icWBC[LIBRAW_WBI_FL_N][0]) + FORC4 icWBC[LIBRAW_WBI_D65][c] = icWBC[LIBRAW_WBI_FL_N][c]; + + return; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/olympus.cpp libkdcraw/libkdcraw/libraw/src/metadata/olympus.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/olympus.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/olympus.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,510 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +void LibRaw::setOlympusBodyFeatures(unsigned long long id) +{ + ilm.CamID = id; + + if ((id == OlyID_E_1) || + (id == OlyID_E_300) || + ((id & 0x00ffff0000ULL) == 0x0030300000ULL)) + { + ilm.CameraFormat = LIBRAW_FORMAT_FT; + + if ((id == OlyID_E_1) || + (id == OlyID_E_300) || + ((id >= OlyID_E_330) && (id <= OlyID_E_520)) || + (id == OlyID_E_620) || + (id == OlyID_E_450) || + (id == OlyID_E_600) || + (id == OlyID_E_5)) + { + ilm.CameraMount = LIBRAW_MOUNT_FT; + } + else + { + ilm.CameraMount = LIBRAW_MOUNT_mFT; + } + } + else + { + ilm.LensMount = ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + return; +} + +void LibRaw::getOlympus_CameraType2() +{ + + if (OlyID != 0x0ULL) + return; + + int i = 0; + fread(imOly.CameraType2, 6, 1, ifp); + imOly.CameraType2[5] = 0; + while ((i < 6) && imOly.CameraType2[i]) + { + OlyID = OlyID << 8 | imOly.CameraType2[i]; + if (i < 5 && isspace(imOly.CameraType2[i + 1])) { + imOly.CameraType2[i + 1] = '\0'; + break; + } + i++; + } + if (OlyID == OlyID_NORMA) { + if (strcmp(model, "SP510UZ")) OlyID = OlyID_SP_510UZ; + else OlyID = 0x0ULL; + } + unique_id = OlyID; + setOlympusBodyFeatures(OlyID); + return; +} + +void LibRaw::getOlympus_SensorTemperature(unsigned len) +{ + if (OlyID != 0x0ULL) + { + short temp = get2(); + if ((OlyID == OlyID_E_1) || + (OlyID == OlyID_E_M5) || + (len != 1)) + imCommon.SensorTemperature = (float)temp; + else if ((temp != -32768) && (temp != 0)) + { + if (temp > 199) + imCommon.SensorTemperature = 86.474958f - 0.120228f * (float)temp; + else + imCommon.SensorTemperature = (float)temp; + } + } + return; +} + +void LibRaw::parseOlympus_Equipment(unsigned tag, unsigned type, unsigned len, + unsigned dng_writer) +{ + // uptag 2010 + + switch (tag) + { + case 0x0100: + getOlympus_CameraType2(); + break; + case 0x0101: + if ((!imgdata.shootinginfo.BodySerial[0]) && (dng_writer == nonDNG)) + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + break; + case 0x0102: + stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp); + break; + case 0x0201: + { + unsigned char bits[4]; + fread(bits, 1, 4, ifp); + ilm.LensID = (unsigned long long)bits[0] << 16 | + (unsigned long long)bits[2] << 8 | (unsigned long long)bits[3]; + ilm.LensMount = LIBRAW_MOUNT_FT; + ilm.LensFormat = LIBRAW_FORMAT_FT; + if (((ilm.LensID < 0x20000) || (ilm.LensID > 0x4ffff)) && + (ilm.LensID & 0x10)) + ilm.LensMount = LIBRAW_MOUNT_mFT; + } + break; + case 0x0202: + if ((!imgdata.lens.LensSerial[0])) + stmread(imgdata.lens.LensSerial, len, ifp); + break; + case 0x0203: + stmread(ilm.Lens, len, ifp); + break; + case 0x0205: + ilm.MaxAp4MinFocal = libraw_powf64l(sqrt(2.0f), get2() / 256.0f); + break; + case 0x0206: + ilm.MaxAp4MaxFocal = libraw_powf64l(sqrt(2.0f), get2() / 256.0f); + break; + case 0x0207: + ilm.MinFocal = (float)get2(); + break; + case 0x0208: + ilm.MaxFocal = (float)get2(); + if (ilm.MaxFocal > 1000.0f) + ilm.MaxFocal = ilm.MinFocal; + break; + case 0x020a: + ilm.MaxAp4CurFocal = libraw_powf64l(sqrt(2.0f), get2() / 256.0f); + break; + case 0x0301: + ilm.TeleconverterID = fgetc(ifp) << 8; + fgetc(ifp); + ilm.TeleconverterID = ilm.TeleconverterID | fgetc(ifp); + break; + case 0x0303: + stmread(ilm.Teleconverter, len, ifp); + if (!strlen(ilm.Teleconverter) && strchr(ilm.Lens, '+')) { + if (strstr(ilm.Lens, "MC-20")) + strcpy(ilm.Teleconverter, "MC-20"); + else if (strstr(ilm.Lens, "MC-14")) + strcpy(ilm.Teleconverter, "MC-14"); + else if (strstr(ilm.Lens, "EC-20")) + strcpy(ilm.Teleconverter, "EC-20"); + else if (strstr(ilm.Lens, "EC-14")) + strcpy(ilm.Teleconverter, "EC-14"); } + break; + case 0x0403: + stmread(ilm.Attachment, len, ifp); + break; + } + + return; +} +void LibRaw::parseOlympus_CameraSettings(int base, unsigned tag, unsigned type, + unsigned len, unsigned dng_writer) +{ + // uptag 0x2020 + + int c; + uchar uc; + switch (tag) + { + case 0x0101: + if (dng_writer == nonDNG) + { + thumb_offset = get4() + base; + } + break; + case 0x0102: + if (dng_writer == nonDNG) + { + thumb_length = get4(); + } + break; + case 0x0200: + imgdata.shootinginfo.ExposureMode = get2(); + break; + case 0x0202: + imgdata.shootinginfo.MeteringMode = get2(); + break; + case 0x0301: + imgdata.shootinginfo.FocusMode = imOly.FocusMode[0] = get2(); + if (len == 2) + { + imOly.FocusMode[1] = get2(); + } + break; + case 0x0304: + for (c = 0; c < 64; c++) + { + imOly.AFAreas[c] = get4(); + } + break; + case 0x0305: + for (c = 0; c < 5; c++) + { + imOly.AFPointSelected[c] = getreal(type); + } + break; + case 0x0306: + fread(&uc, 1, 1, ifp); + imOly.AFFineTune = uc; + break; + case 0x0307: + FORC3 imOly.AFFineTuneAdj[c] = get2(); + break; + case 0x0401: + imCommon.FlashEC = getreal(type); + break; + case 0x0507: + imOly.ColorSpace = get2(); + switch (imOly.ColorSpace) { + case 0: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_ProPhotoRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + break; + case 0x0600: + imgdata.shootinginfo.DriveMode = imOly.DriveMode[0] = get2(); + for (c = 1; c < (int)len && c < 5; c++) + { + imOly.DriveMode[c] = get2(); + } + break; + case 0x0604: + imgdata.shootinginfo.ImageStabilization = get4(); + break; + } + + return; +} + +void LibRaw::parseOlympus_ImageProcessing(unsigned tag, unsigned type, + unsigned len, unsigned dng_writer) +{ + // uptag 0x2040 + + int i, c, wb[4], nWB, tWB, wbG; + ushort CT; + short sorder; + + if ((tag == 0x0100) && (dng_writer == nonDNG)) + { + cam_mul[0] = get2() / 256.0; + cam_mul[2] = get2() / 256.0; + } + else if ((tag == 0x0101) && (len == 2) && + ((OlyID == OlyID_E_410) || (OlyID == OlyID_E_510))) + { + for (i = 0; i < 64; i++) + { + icWBCCTC[i][2] = icWBCCTC[i][4] = icWBC[i][1] = icWBC[i][3] = 0x100; + } + for (i = 64; i < 256; i++) + { + icWBC[i][1] = icWBC[i][3] = 0x100; + } + } + else if ((tag > 0x0101) && (tag <= 0x0111)) + { + nWB = tag - 0x0101; + tWB = Oly_wb_list2[nWB << 1]; + CT = Oly_wb_list2[(nWB << 1) | 1]; + wb[0] = get2(); + wb[2] = get2(); + if (tWB != 0x100) + { + icWBC[tWB][0] = wb[0]; + icWBC[tWB][2] = wb[2]; + } + if (CT) + { + icWBCCTC[nWB - 1][0] = CT; + icWBCCTC[nWB - 1][1] = wb[0]; + icWBCCTC[nWB - 1][3] = wb[2]; + } + if (len == 4) + { + wb[1] = get2(); + wb[3] = get2(); + if (tWB != 0x100) + { + icWBC[tWB][1] = wb[1]; + icWBC[tWB][3] = wb[3]; + } + if (CT) + { + icWBCCTC[nWB - 1][2] = wb[1]; + icWBCCTC[nWB - 1][4] = wb[3]; + } + } + } + else if ((tag >= 0x0112) && (tag <= 0x011e)) + { + nWB = tag - 0x0112; + wbG = get2(); + tWB = Oly_wb_list2[nWB << 1]; + if (nWB) + icWBCCTC[nWB - 1][2] = icWBCCTC[nWB - 1][4] = wbG; + if (tWB != 0x100) + icWBC[tWB][1] = icWBC[tWB][3] = wbG; + } + else if (tag == 0x011f) + { + wbG = get2(); + if (icWBC[LIBRAW_WBI_Flash][0]) + icWBC[LIBRAW_WBI_Flash][1] = + icWBC[LIBRAW_WBI_Flash][3] = wbG; + FORC4 if (icWBC[LIBRAW_WBI_Custom1 + c][0]) + icWBC[LIBRAW_WBI_Custom1 + c][1] = + icWBC[LIBRAW_WBI_Custom1 + c][3] = wbG; + } + else if (tag == 0x0121) + { + icWBC[LIBRAW_WBI_Flash][0] = get2(); + icWBC[LIBRAW_WBI_Flash][2] = get2(); + if (len == 4) + { + icWBC[LIBRAW_WBI_Flash][1] = get2(); + icWBC[LIBRAW_WBI_Flash][3] = get2(); + } + } + else if ((tag == 0x0200) && (dng_writer == nonDNG) && + strcmp(software, "v757-71")) + { + for (i = 0; i < 3; i++) + { + if (!imOly.ColorSpace) + { + FORC3 cmatrix[i][c] = ((short)get2()) / 256.0; + } + else + { + FORC3 imgdata.color.ccm[i][c] = ((short)get2()) / 256.0; + } + } + } + else if ((tag == 0x0600) && (dng_writer == nonDNG)) + { + FORC4 cblack[RGGB_2_RGBG(c)] = get2(); + } + else if ((tag == 0x0612) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.cleft = get2(); + } + else if ((tag == 0x0613) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.ctop = get2(); + } + else if ((tag == 0x0614) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.cwidth = get2(); + } + else if ((tag == 0x0615) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.cheight = get2(); + } + else if ((tag == 0x0805) && (len == 2)) + { + imOly.SensorCalibration[0] = getreal(type); + imOly.SensorCalibration[1] = getreal(type); + if ((dng_writer == nonDNG)&& (OlyID != OlyID_XZ_1)) + FORC4 imgdata.color.linear_max[c] = imOly.SensorCalibration[0]; + } + else if (tag == 0x1112) + { + sorder = order; + order = 0x4d4d; + c = get2(); + order = sorder; + switch (c) + { + case 0x21: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_3to2; + break; + case 0x31: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_16to9; + break; + case 0x41: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_1to1; + break; + case 0x91: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_4to3; + break; + } + } + else if (tag == 0x1113) + { + imgdata.sizes.raw_inset_crop.cleft = get2(); + imgdata.sizes.raw_inset_crop.ctop = get2(); + imgdata.sizes.raw_inset_crop.cwidth = + get2() - imgdata.sizes.raw_inset_crop.cleft; + imgdata.sizes.raw_inset_crop.cheight = + get2() - imgdata.sizes.raw_inset_crop.ctop; + } + else if (tag == 0x1306) + { + c = get2(); + if ((c != 0) && (c != 100)) + { + if (c < 61) + imCommon.CameraTemperature = (float)c; + else + imCommon.CameraTemperature = (float)(c - 32) / 1.8f; + if ((imCommon.exifAmbientTemperature > -273.15f) && + ((OlyID == OlyID_TG_5) || + (OlyID == OlyID_TG_6)) + ) + imCommon.CameraTemperature += imCommon.exifAmbientTemperature; + } + } + + return; +} + +void LibRaw::parseOlympus_RawInfo(unsigned tag, unsigned type, unsigned len, + unsigned dng_writer) +{ + // uptag 0x3000 + + int wb_ind, c, i; + + if ((tag == 0x0110) && strcmp(software, "v757-71")) + { + icWBC[LIBRAW_WBI_Auto][0] = get2(); + icWBC[LIBRAW_WBI_Auto][2] = get2(); + if (len == 2) + { + for (i = 0; i < 256; i++) + icWBC[i][1] = icWBC[i][3] = 0x100; + } + } + else if ((((tag >= 0x0120) && (tag <= 0x0124)) || + ((tag >= 0x0130) && (tag <= 0x0133))) && + strcmp(software, "v757-71")) + { + if (tag <= 0x0124) + wb_ind = tag - 0x0120; + else + wb_ind = tag - 0x0130 + 5; + + icWBC[Oly_wb_list1[wb_ind]][0] = get2(); + icWBC[Oly_wb_list1[wb_ind]][2] = get2(); + } + else if ((tag == 0x0200) && (dng_writer == nonDNG)) + { + for (i = 0; i < 3; i++) + { + if (!imOly.ColorSpace) + { + FORC3 cmatrix[i][c] = ((short)get2()) / 256.0; + } + else + { + FORC3 imgdata.color.ccm[i][c] = ((short)get2()) / 256.0; + } + } + } + else if ((tag == 0x0600) && (dng_writer == nonDNG)) + { + FORC4 cblack[RGGB_2_RGBG(c)] = get2(); + } + else if ((tag == 0x0612) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.cleft = get2(); + } + else if ((tag == 0x0613) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.ctop = get2(); + } + else if ((tag == 0x0614) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.cwidth = get2(); + } + else if ((tag == 0x0615) && (dng_writer == nonDNG)) + { + imgdata.sizes.raw_inset_crop.cheight = get2(); + } + return; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/p1.cpp libkdcraw/libkdcraw/libraw/src/metadata/p1.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/p1.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/p1.cpp 2022-11-07 07:46:31.734795008 +0300 @@ -0,0 +1,190 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::setPhaseOneFeatures(unsigned long long id) +{ + + ushort i; + static const struct + { + unsigned long long id; + char t_model[32]; + int CamMnt; + int CamFmt; + } p1_unique[] = { + // Phase One section: + {0x001ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x00aULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x00cULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x010ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x011ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x012ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x013ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x014ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x015ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x016ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x017ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x018ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x019ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x020ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x022ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x023ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x024ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x025ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x026ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x027ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x028ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x029ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x02aULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x02cULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x02dULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x02eULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x02fULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x030ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x031ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x032ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x033ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x034ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x035ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x036ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x037ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x043ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x044ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x045ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x046ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x047ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x048ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x049ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x04aULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x04cULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x04dULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x04eULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x04fULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x050ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x051ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x052ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x053ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x054ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x055ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x056ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x057ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x063ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x064ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x065ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x066ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x067ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x068ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x069ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x06aULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x070ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x071ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x072ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x073ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x083ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x084ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x085ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x086ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x087ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x088ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x089ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x08aULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x08cULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x08dULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x08eULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x08fULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x094ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x095ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x096ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x097ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x0a0ULL, "A-250", LIBRAW_MOUNT_Alpa, LIBRAW_FORMAT_69}, + {0x0a1ULL, "A-260", LIBRAW_MOUNT_Alpa, LIBRAW_FORMAT_69}, + {0x0a2ULL, "A-280", LIBRAW_MOUNT_Alpa, LIBRAW_FORMAT_69}, + {0x0a7ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x0a8ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x0a9ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x0aaULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x0acULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x0adULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x0aeULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x0afULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x0b0ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x0b1ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x0b2ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x0b3ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x0b4ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x0b5ULL, "Hasselblad H", LIBRAW_MOUNT_Hasselblad_H, LIBRAW_FORMAT_645}, + {0x0b6ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x0b7ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x0d0ULL, "Hasselblad V", LIBRAW_MOUNT_Hasselblad_V, LIBRAW_FORMAT_66}, + {0x0d3ULL, "PhaseOne/Mamiya", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x1c0ULL, "Phase One 645AF", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x1c9ULL, "Phase One 645DF", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x1d7ULL, "Phase One 645DF+", LIBRAW_MOUNT_Mamiya645, LIBRAW_FORMAT_645}, + {0x2c0ULL, "Phase One iXA", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x2c1ULL, "Phase One iXA - R", LIBRAW_MOUNT_Unknown, + LIBRAW_FORMAT_Unknown}, + {0x2c2ULL, "Phase One iXU 150", LIBRAW_MOUNT_Unknown, + LIBRAW_FORMAT_Unknown}, + {0x2c3ULL, "Phase One iXU 150 - NIR", LIBRAW_MOUNT_Unknown, + LIBRAW_FORMAT_Unknown}, + {0x2c4ULL, "Phase One iXU 180", LIBRAW_MOUNT_Unknown, + LIBRAW_FORMAT_Unknown}, + {0x2d1ULL, "Phase One iXR", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + // Leaf section: + {0x14dULL, "Mamiya", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x149ULL, "Universal", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x14aULL, "Hasselblad H1/H2", LIBRAW_MOUNT_Hasselblad_H, + LIBRAW_FORMAT_645}, + {0x14cULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x150ULL, "AFi", LIBRAW_MOUNT_Rollei_bayonet, LIBRAW_FORMAT_66}, + {0x147ULL, "Mamiya", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x144ULL, "Universal", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x145ULL, "Hasselblad H1/H2", LIBRAW_MOUNT_Hasselblad_H, + LIBRAW_FORMAT_645}, + {0x146ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x14fULL, "AFi", LIBRAW_MOUNT_Rollei_bayonet, LIBRAW_FORMAT_66}, + {0x154ULL, "Mamiya", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x151ULL, "Universal", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x152ULL, "Hasselblad H1/H2", LIBRAW_MOUNT_Hasselblad_H, + LIBRAW_FORMAT_645}, + {0x153ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x143ULL, "Mamiya", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x140ULL, "Universal", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x142ULL, "Hasselblad H1/H2", LIBRAW_MOUNT_Hasselblad_H, + LIBRAW_FORMAT_645}, + {0x141ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x14eULL, "AFi", LIBRAW_MOUNT_Rollei_bayonet, LIBRAW_FORMAT_66}, + {0x171ULL, "Universal", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x172ULL, "Mamiya", LIBRAW_MOUNT_Unknown, LIBRAW_FORMAT_Unknown}, + {0x173ULL, "Hasselblad H1/H2", LIBRAW_MOUNT_Hasselblad_H, + LIBRAW_FORMAT_645}, + {0x174ULL, "Contax 645", LIBRAW_MOUNT_Contax645, LIBRAW_FORMAT_645}, + {0x175ULL, "AFi", LIBRAW_MOUNT_Rollei_bayonet, LIBRAW_FORMAT_66}, + }; + ilm.CamID = id; + if (id && !ilm.body[0]) + { + for (i = 0; i < sizeof p1_unique / sizeof *p1_unique; i++) + if (id == p1_unique[i].id) + { + strcpy(ilm.body, p1_unique[i].t_model); + ilm.CameraFormat = p1_unique[i].CamFmt; + ilm.CameraMount = p1_unique[i].CamMnt; + } + } + return; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/pentax.cpp libkdcraw/libkdcraw/libraw/src/metadata/pentax.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/pentax.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/pentax.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,537 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +void LibRaw::setPentaxBodyFeatures(unsigned long long id) +{ + + ilm.CamID = id; + + switch (id) { + case PentaxID_staristD: + case PentaxID_staristDS: + case PentaxID_staristDL: + case PentaxID_staristDS2: + case PentaxID_GX_1S: + case PentaxID_staristDL2: + case PentaxID_GX_1L: + case PentaxID_K100D: + case PentaxID_K110D: + case PentaxID_K100D_Super: + case PentaxID_K10D: + case PentaxID_GX10: + case PentaxID_K20D: + case PentaxID_GX20: + case PentaxID_K200D: + case PentaxID_K2000: + case PentaxID_K_m: + case PentaxID_K_7: + case PentaxID_K_x: + case PentaxID_K_r: + case PentaxID_K_5: + case PentaxID_K_01: + case PentaxID_K_30: + case PentaxID_K_5_II: + case PentaxID_K_5_II_s: + case PentaxID_K_50: + case PentaxID_K_3: + case PentaxID_K_500: + case PentaxID_K_S1: + case PentaxID_K_S2: + case PentaxID_K_3_II: + case PentaxID_K_70: + case PentaxID_KP: + ilm.CameraMount = LIBRAW_MOUNT_Pentax_K; + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + break; + case PentaxID_K_1: + case PentaxID_K_1_Mark_II: + ilm.CameraMount = LIBRAW_MOUNT_Pentax_K; + ilm.CameraFormat = LIBRAW_FORMAT_FF; + break; + case PentaxID_645D: + case PentaxID_645Z: + ilm.CameraMount = LIBRAW_MOUNT_Pentax_645; + ilm.CameraFormat = LIBRAW_FORMAT_CROP645; + break; + case PentaxID_Q: + case PentaxID_Q10: + ilm.CameraMount = LIBRAW_MOUNT_Pentax_Q; + ilm.CameraFormat = LIBRAW_FORMAT_1div2p3INCH; + break; + case PentaxID_Q7: + case PentaxID_Q_S1: + ilm.CameraMount = LIBRAW_MOUNT_Pentax_Q; + ilm.CameraFormat = LIBRAW_FORMAT_1div1p7INCH; + break; + case PentaxID_MX_1: + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + ilm.CameraFormat = LIBRAW_FORMAT_1div1p7INCH; + ilm.FocalType = LIBRAW_FT_ZOOM_LENS; + break; + case PentaxID_GR_III: + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + break; + default: + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + } + return; +} + +void LibRaw::PentaxISO(ushort c) +{ + int code[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 50, 100, 200, 400, 800, + 1600, 3200, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278}; + double value[] = { + 50, 64, 80, 100, 125, 160, 200, 250, 320, + 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, + 3200, 4000, 5000, 6400, 8000, 10000, 12800, 16000, 20000, + 25600, 32000, 40000, 51200, 64000, 80000, 102400, 128000, 160000, + 204800, 258000, 325000, 409600, 516000, 650000, 819200, 50, 100, + 200, 400, 800, 1600, 3200, 50, 70, 100, 140, + 200, 280, 400, 560, 800, 1100, 1600, 2200, 3200, + 4500, 6400, 9000, 12800, 18000, 25600, 36000, 51200}; +#define numel (sizeof(code) / sizeof(code[0])) + int i; + for (i = 0; i < (int)numel; i++) + { + if (code[i] == c) + { + iso_speed = value[i]; + return; + } + } + if (i == numel) + iso_speed = 65535.0f; +} +#undef numel + +void LibRaw::PentaxLensInfo(unsigned long long id, unsigned len) // tag 0x0207 +{ + ushort iLensData = 0; + uchar *table_buf; + table_buf = (uchar *)malloc(MAX(len, 128)); + fread(table_buf, len, 1, ifp); + if ((id < PentaxID_K100D) || + (((id == PentaxID_K100D) || + (id == PentaxID_K110D) || + (id == PentaxID_K100D_Super)) && + ((!table_buf[20] || + (table_buf[20] == 0xff))))) + { + iLensData = 3; + if (ilm.LensID == LIBRAW_LENS_NOT_SET) + ilm.LensID = (((unsigned)table_buf[0]) << 8) + table_buf[1]; + } + else + switch (len) + { + case 90: // LensInfo3 + iLensData = 13; + if (ilm.LensID == LIBRAW_LENS_NOT_SET) + ilm.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[3]) << 8) + + table_buf[4]; + break; + case 91: // LensInfo4 + iLensData = 12; + if (ilm.LensID == LIBRAW_LENS_NOT_SET) + ilm.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[3]) << 8) + + table_buf[4]; + break; + case 80: // LensInfo5 + case 128: + iLensData = 15; + if (ilm.LensID == LIBRAW_LENS_NOT_SET) + ilm.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[4]) << 8) + + table_buf[5]; + break; + case 168: // Ricoh GR III, id 0x1320e + break; + default: + if (id >= 0x12b9cULL) // LensInfo2 + { + iLensData = 4; + if (ilm.LensID == LIBRAW_LENS_NOT_SET) + ilm.LensID = ((unsigned)((table_buf[0] & 0x0f) + table_buf[2]) << 8) + + table_buf[3]; + } + } + if (iLensData) + { + if (table_buf[iLensData + 9] && (fabs(ilm.CurFocal) < 0.1f)) + ilm.CurFocal = 10 * (table_buf[iLensData + 9] >> 2) * + libraw_powf64l(4, (table_buf[iLensData + 9] & 0x03) - 2); + if (table_buf[iLensData + 10] & 0xf0) + ilm.MaxAp4CurFocal = libraw_powf64l( + 2.0f, (float)((table_buf[iLensData + 10] & 0xf0) >> 4) / 4.0f); + if (table_buf[iLensData + 10] & 0x0f) + ilm.MinAp4CurFocal = libraw_powf64l( + 2.0f, (float)((table_buf[iLensData + 10] & 0x0f) + 10) / 4.0f); + + if (iLensData != 12) + { + switch (table_buf[iLensData] & 0x06) + { + case 0: + ilm.MinAp4MinFocal = 22.0f; + break; + case 2: + ilm.MinAp4MinFocal = 32.0f; + break; + case 4: + ilm.MinAp4MinFocal = 45.0f; + break; + case 6: + ilm.MinAp4MinFocal = 16.0f; + break; + } + if (table_buf[iLensData] & 0x70) + ilm.LensFStops = + ((float)(((table_buf[iLensData] & 0x70) >> 4) ^ 0x07)) / 2.0f + + 5.0f; + + ilm.MinFocusDistance = (float)(table_buf[iLensData + 3] & 0xf8); + ilm.FocusRangeIndex = (float)(table_buf[iLensData + 3] & 0x07); + + if ((table_buf[iLensData + 14] > 1) && (fabs(ilm.MaxAp4CurFocal) < 0.7f)) + ilm.MaxAp4CurFocal = libraw_powf64l( + 2.0f, (float)((table_buf[iLensData + 14] & 0x7f) - 1) / 32.0f); + } + else if ((id != 0x12e76ULL) && // K-5 + (table_buf[iLensData + 15] > 1) && + (fabs(ilm.MaxAp4CurFocal) < 0.7f)) + { + ilm.MaxAp4CurFocal = libraw_powf64l( + 2.0f, (float)((table_buf[iLensData + 15] & 0x7f) - 1) / 32.0f); + } + } + free(table_buf); + return; +} + +void LibRaw::parsePentaxMakernotes(int base, unsigned tag, unsigned type, + unsigned len, unsigned dng_writer) +{ + + int c; + if (tag == 0x0005) + { + unique_id = get4(); + setPentaxBodyFeatures(unique_id); + } + else if (tag == 0x0008) + { /* 4 is raw, 7 is raw w/ pixel shift, 8 is raw w/ dynamic pixel shift */ + imPentax.Quality = get2(); + } + else if (tag == 0x000d) + { + imgdata.shootinginfo.FocusMode = imPentax.FocusMode = get2(); + } + else if (tag == 0x000e) + { + imgdata.shootinginfo.AFPoint = imPentax.AFPointSelected = get2(); + } + else if (tag == 0x000f) + { + imPentax.AFPointsInFocus = getint(type); + } + else if (tag == 0x0010) + { + imPentax.FocusPosition = get2(); + } + else if (tag == 0x0013) + { + ilm.CurAp = (float)get2() / 10.0f; + } + else if (tag == 0x0014) + { + PentaxISO(get2()); + } + else if (tag == 0x0017) + { + imgdata.shootinginfo.MeteringMode = get2(); + } + else if (tag == 0x001b) { + cam_mul[2] = get2() / 256.0; + } + else if (tag == 0x001c) { + cam_mul[0] = get2() / 256.0; + } + else if (tag == 0x001d) + { + ilm.CurFocal = (float)get4() / 100.0f; + } + else if (tag == 0x0034) + { + uchar uc; + FORC4 + { + fread(&uc, 1, 1, ifp); + imPentax.DriveMode[c] = uc; + } + imgdata.shootinginfo.DriveMode = imPentax.DriveMode[0]; + } + else if (tag == 0x0037) { + switch (get2()) { + case 0: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + } + else if (tag == 0x0038) + { + imgdata.sizes.raw_inset_crop.cleft = get2(); + imgdata.sizes.raw_inset_crop.ctop = get2(); + } + else if (tag == 0x0039) + { + imgdata.sizes.raw_inset_crop.cwidth = get2(); + imgdata.sizes.raw_inset_crop.cheight = get2(); + } + else if (tag == 0x003f) + { + unsigned a = unsigned(fgetc(ifp)) << 8; + ilm.LensID = a | fgetc(ifp); + } + else if (tag == 0x0047) + { + imCommon.CameraTemperature = (float)fgetc(ifp); + } + else if (tag == 0x004d) + { + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SLONG)) + imCommon.FlashEC = getreal(type) / 256.0f; + else + imCommon.FlashEC = (float)((signed short)fgetc(ifp)) / 6.0f; + } + else if (tag == 0x005c) + { + fgetc(ifp); + imgdata.shootinginfo.ImageStabilization = (short)fgetc(ifp); + } + else if (tag == 0x0072) + { + imPentax.AFAdjustment = get2(); + } + else if ((tag == 0x007e) && (dng_writer == nonDNG)) + { + imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = + imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = + get4(); + } + else if (tag == 0x0080) + { + short a = (short)fgetc(ifp); + switch (a) + { + case 0: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_4to3; + break; + case 1: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_3to2; + break; + case 2: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_16to9; + break; + case 3: + imgdata.sizes.raw_inset_crop.aspect = LIBRAW_IMAGE_ASPECT_1to1; + break; + } + } + + else if ((tag == 0x0200) && (dng_writer == nonDNG)) { // Pentax black level + FORC4 cblack[RGGB_2_RGBG(c)] = get2(); + } + + else if ((tag == 0x0201) && (dng_writer == nonDNG)) { // Pentax As Shot WB + FORC4 cam_mul[RGGB_2_RGBG(c)] = get2(); + } + + else if ((tag == 0x0203) && (dng_writer == nonDNG)) + { + for (int i = 0; i < 3; i++) + FORC3 cmatrix[i][c] = ((short)get2()) / 8192.0; + } + else if (tag == 0x0205) + { // Pentax K-m has multiexposure set to 8 when no multi-exposure is in effect + if (len < 25) + { + fseek(ifp, 10, SEEK_CUR); + imPentax.MultiExposure = fgetc(ifp) & 0x0f; + } + } + else if (tag == 0x0207) + { + if (len < 65535) // Safety belt + PentaxLensInfo(ilm.CamID, len); + } + else if ((tag >= 0x020d) && (tag <= 0x0214)) + { + FORC4 icWBC[Pentax_wb_list1[tag - 0x020d]][RGGB_2_RGBG(c)] = get2(); + } + + else if ((tag == 0x0220) && (dng_writer == nonDNG)) { + meta_offset = ftell(ifp); + } + + else if (tag == 0x0221) + { + int nWB = get2(); + if (nWB <= int(sizeof(icWBCCTC) / sizeof(icWBCCTC[0]))) + FORC(nWB) + { + icWBCCTC[c][0] = (unsigned)0xcfc6 - get2(); + fseek(ifp, 2, SEEK_CUR); + icWBCCTC[c][1] = get2(); + icWBCCTC[c][2] = icWBCCTC[c][4] = 0x2000; + icWBCCTC[c][3] = get2(); + } + } + else if (tag == 0x0215) + { + fseek(ifp, 16, SEEK_CUR); + sprintf(imgdata.shootinginfo.InternalBodySerial, "%d", get4()); + } + else if (tag == 0x0229) + { + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + } + else if (tag == 0x022d) + { + int wb_ind; + getc(ifp); + for (int wb_cnt = 0; wb_cnt < Pentax_wb_list2.size(); wb_cnt++) + { + wb_ind = getc(ifp); + if (wb_ind >= 0 && wb_ind < Pentax_wb_list2.size() ) + FORC4 icWBC[Pentax_wb_list2[wb_ind]][RGGB_2_RGBG(c)] = get2(); + } + } + else if (tag == 0x0239) + { // Q-series lens info (LensInfoQ) + char LensInfo[20]; + fseek(ifp, 12, SEEK_CUR); + stread(ilm.Lens, 30, ifp); + strcat(ilm.Lens, " "); + stread(LensInfo, 20, ifp); + strcat(ilm.Lens, LensInfo); + } +} + +void LibRaw::parseRicohMakernotes(int base, unsigned tag, unsigned type, + unsigned len, unsigned dng_writer) +{ + char buffer[17]; + if (tag == 0x0005) + { + int c; + int count = 0; + fread(buffer, 16, 1, ifp); + buffer[16] = 0; + FORC(16) + { + if ((isspace(buffer[c])) || (buffer[c] == 0x2D) || (isalnum(buffer[c]))) + count++; + else + break; + } + if (count == 16) + { + if (strncmp(model, "GXR", 3)) + { + sprintf(imgdata.shootinginfo.BodySerial, "%8s", buffer + 8); + } + buffer[8] = 0; + sprintf(imgdata.shootinginfo.InternalBodySerial, "%8s", buffer); + } + else + { + sprintf(imgdata.shootinginfo.BodySerial, "%02x%02x%02x%02x", buffer[4], + buffer[5], buffer[6], buffer[7]); + sprintf(imgdata.shootinginfo.InternalBodySerial, "%02x%02x%02x%02x", + buffer[8], buffer[9], buffer[10], buffer[11]); + } + } + else if ((tag == 0x1001) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT)) + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + ilm.LensID = LIBRAW_LENS_NOT_SET; + ilm.FocalType = LIBRAW_FT_PRIME_LENS; + imgdata.shootinginfo.ExposureProgram = get2(); + } + else if (tag == 0x1002) + { + imgdata.shootinginfo.DriveMode = get2(); + } + else if (tag == 0x1006) + { + imgdata.shootinginfo.FocusMode = get2(); + } + else if ((tag == 0x100b) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_SRATIONAL)) + { + imCommon.FlashEC = getreal(type); + } + else if ((tag == 0x1017) && (get2() == 2)) + { + strcpy(ilm.Attachment, "Wide-Angle Adapter"); + } + else if (tag == 0x1500) + { + ilm.CurFocal = getreal(type); + } + else if ((tag == 0x2001) && !strncmp(model, "GXR", 3)) + { + short cur_tag; + fseek(ifp, 20, SEEK_CUR); + /*ntags =*/ get2(); + cur_tag = get2(); + while (cur_tag != 0x002c) + { + fseek(ifp, 10, SEEK_CUR); + cur_tag = get2(); + } + fseek(ifp, 6, SEEK_CUR); + fseek(ifp, get4(), SEEK_SET); + for (int i=0; i<4; i++) { + stread(buffer, 16, ifp); + if ((buffer[0] == 'S') && (buffer[1] == 'I') && (buffer[2] == 'D')) + memcpy(imgdata.shootinginfo.BodySerial, buffer+4, 12); + else if ((buffer[0] == 'R') && (buffer[1] == 'L')) + ilm.LensID = buffer[2] - '0'; + else if ((buffer[0] == 'L') && (buffer[1] == 'I') && (buffer[2] == 'D')) + memcpy(imgdata.lens.LensSerial, buffer+4, 12); + } + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/samsung.cpp libkdcraw/libkdcraw/libraw/src/metadata/samsung.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/samsung.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/samsung.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,182 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::parseSamsungMakernotes(int base, unsigned tag, unsigned type, + unsigned len, unsigned dng_writer) +{ + int i, c; + if (tag == 0x0002) + { + imSamsung.DeviceType = get4(); + if (imSamsung.DeviceType == 0x2000) + { + ilm.CameraMount = LIBRAW_MOUNT_Samsung_NX; + ilm.CameraFormat = LIBRAW_FORMAT_APSC; + } + else if (!strncmp(model, "NX mini", 7)) + { // device type 0x1000: 'NX mini', EX2F, EX1, WB2000 + ilm.CameraMount = LIBRAW_MOUNT_Samsung_NX_M; + ilm.CameraFormat = LIBRAW_FORMAT_1INCH; + } + else + { + ilm.CameraMount = LIBRAW_MOUNT_FixedLens; + ilm.LensMount = LIBRAW_MOUNT_FixedLens; + } + } + else if (tag == 0x0003) + { + ilm.CamID = unique_id = get4(); + } + else if (tag == 0x0043) + { + if ((i = get4())) + { + imCommon.CameraTemperature = (float)i; + if (get4() == 10) + imCommon.CameraTemperature /= 10.0f; + } + } + else if ((tag == 0xa002) && (dng_writer != AdobeDNG)) + { + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + } + else if (tag == 0xa003) + { + ilm.LensID = get2(); + if (ilm.LensID) + ilm.LensMount = LIBRAW_MOUNT_Samsung_NX; + } + else if (tag == 0xa004) + { // LensFirmware + stmread(imSamsung.LensFirmware, len, ifp); + } + else if (tag == 0xa005) + { + stmread(imgdata.lens.InternalLensSerial, len, ifp); + } + else if (tag == 0xa010) + { + FORC4 imSamsung.ImageSizeFull[c] = get4(); + FORC4 imSamsung.ImageSizeCrop[c] = get4(); + } + else if ((tag == 0xa011) && ((len == 1) || (len == 2)) && tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT)) + { + imSamsung.ColorSpace[0] = (int)get2(); + switch (imSamsung.ColorSpace[0]) { + case 0: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + if (len == 2) + imSamsung.ColorSpace[1] = (int)get2(); + } + else if (tag == 0xa019) + { + ilm.CurAp = getreal(type); + } + else if ((tag == 0xa01a) && (unique_id != 0x5000000) && + (!imgdata.lens.FocalLengthIn35mmFormat)) + { + ilm.FocalLengthIn35mmFormat = get4(); + if (ilm.FocalLengthIn35mmFormat >= 160) + ilm.FocalLengthIn35mmFormat /= 10.0f; + if ((ilm.CameraMount == LIBRAW_MOUNT_Samsung_NX_M) && + (imSamsung.LensFirmware[10] < '6')) + ilm.FocalLengthIn35mmFormat *= 1.6f; + } + else if (tag == 0xa020) + { + FORC(11) imSamsung.key[c] = get4(); + } + else if ((tag == 0xa021) && (dng_writer == nonDNG)) + { + FORC4 cam_mul[RGGB_2_RGBG(c)] = get4() - imSamsung.key[c]; + } + else if (tag == 0xa022) + { + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = + get4() - imSamsung.key[c + 4]; + if (icWBC[LIBRAW_WBI_Auto][0] < + (icWBC[LIBRAW_WBI_Auto][1] >> 1)) + { + icWBC[LIBRAW_WBI_Auto][1] = + icWBC[LIBRAW_WBI_Auto][1] >> 4; + icWBC[LIBRAW_WBI_Auto][3] = + icWBC[LIBRAW_WBI_Auto][3] >> 4; + } + } + else if (tag == 0xa023) + { + ushort ki[4] = {8, 9, 10, 0}; + FORC4 icWBC[LIBRAW_WBI_Ill_A][RGGB_2_RGBG(c)] = + get4() - imSamsung.key[ki[c]]; + if (icWBC[LIBRAW_WBI_Ill_A][0] < + (icWBC[LIBRAW_WBI_Ill_A][1] >> 1)) + { + icWBC[LIBRAW_WBI_Ill_A][1] = + icWBC[LIBRAW_WBI_Ill_A][1] >> 4; + icWBC[LIBRAW_WBI_Ill_A][3] = + icWBC[LIBRAW_WBI_Ill_A][3] >> 4; + } + } + else if (tag == 0xa024) + { + FORC4 icWBC[LIBRAW_WBI_D65][RGGB_2_RGBG(c)] = + get4() - imSamsung.key[c + 1]; + if (icWBC[LIBRAW_WBI_D65][0] < + (icWBC[LIBRAW_WBI_D65][1] >> 1)) + { + icWBC[LIBRAW_WBI_D65][1] = + icWBC[LIBRAW_WBI_D65][1] >> 4; + icWBC[LIBRAW_WBI_D65][3] = + icWBC[LIBRAW_WBI_D65][3] >> 4; + } + } + else if (tag == 0xa025) + { + unsigned t = get4() + imSamsung.key[0]; + if (t == 4096) + imSamsung.DigitalGain = 1.0; + else + imSamsung.DigitalGain = ((double)t) / 4096.0; + } + else if ((tag == 0xa028) && (dng_writer == nonDNG)) + { + FORC4 cblack[RGGB_2_RGBG(c)] = get4() - imSamsung.key[c]; + } + else if ((tag == 0xa030) && (len == 9)) + { + for (i = 0; i < 3; i++) + FORC3 imgdata.color.ccm[i][c] = + (float)((short)((get4() + imSamsung.key[i * 3 + c]))) / 256.0; + } + else if ((tag == 0xa032) && (len == 9) && (dng_writer == nonDNG)) + { + double aRGB_cam[3][3]; + FORC(9) + ((double *)aRGB_cam)[c] = + ((double)((short)((get4() + imSamsung.key[c])))) / 256.0; + aRGB_coeff(aRGB_cam); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/sony.cpp libkdcraw/libkdcraw/libraw/src/metadata/sony.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/sony.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/sony.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,2102 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +static ushort saneSonyCameraInfo(uchar a, uchar b, uchar c, uchar d, uchar e, + uchar f) +{ + if ((a >> 4) > 9) + return 0; + else if ((a & 0x0f) > 9) + return 0; + else if ((b >> 4) > 9) + return 0; + else if ((b & 0x0f) > 9) + return 0; + else if ((c >> 4) > 9) + return 0; + else if ((c & 0x0f) > 9) + return 0; + else if ((d >> 4) > 9) + return 0; + else if ((d & 0x0f) > 9) + return 0; + else if ((e >> 4) > 9) + return 0; + else if ((e & 0x0f) > 9) + return 0; + else if ((f >> 4) > 9) + return 0; + else if ((f & 0x0f) > 9) + return 0; + return 1; +} +static float my_roundf(float x) +{ + float t; + if (x >= 0.0) + { + t = ceilf(x); + if (t - x > 0.5) + t -= 1.0; + return t; + } + else + { + t = ceilf(-x); + if (t + x > 0.5) + t -= 1.0; + return -t; + } +} + +static ushort bcd2dec(uchar data) +{ + if ((data >> 4) > 9) + return 0; + else if ((data & 0x0f) > 9) + return 0; + else + return (data >> 4) * 10 + (data & 0x0f); +} + +static uchar SonySubstitution[257] = + "\x00\x01\x32\xb1\x0a\x0e\x87\x28\x02\xcc\xca\xad\x1b\xdc\x08\xed\x64\x86" + "\xf0\x4f\x8c\x6c\xb8\xcb\x69\xc4\x2c\x03" + "\x97\xb6\x93\x7c\x14\xf3\xe2\x3e\x30\x8e\xd7\x60\x1c\xa1\xab\x37\xec\x75" + "\xbe\x23\x15\x6a\x59\x3f\xd0\xb9\x96\xb5" + "\x50\x27\x88\xe3\x81\x94\xe0\xc0\x04\x5c\xc6\xe8\x5f\x4b\x70\x38\x9f\x82" + "\x80\x51\x2b\xc5\x45\x49\x9b\x21\x52\x53" + "\x54\x85\x0b\x5d\x61\xda\x7b\x55\x26\x24\x07\x6e\x36\x5b\x47\xb7\xd9\x4a" + "\xa2\xdf\xbf\x12\x25\xbc\x1e\x7f\x56\xea" + "\x10\xe6\xcf\x67\x4d\x3c\x91\x83\xe1\x31\xb3\x6f\xf4\x05\x8a\x46\xc8\x18" + "\x76\x68\xbd\xac\x92\x2a\x13\xe9\x0f\xa3" + "\x7a\xdb\x3d\xd4\xe7\x3a\x1a\x57\xaf\x20\x42\xb2\x9e\xc3\x8b\xf2\xd5\xd3" + "\xa4\x7e\x1f\x98\x9c\xee\x74\xa5\xa6\xa7" + "\xd8\x5e\xb0\xb4\x34\xce\xa8\x79\x77\x5a\xc1\x89\xae\x9a\x11\x33\x9d\xf5" + "\x39\x19\x65\x78\x16\x71\xd2\xa9\x44\x63" + "\x40\x29\xba\xa0\x8f\xe4\xd6\x3b\x84\x0d\xc2\x4e\x58\xdd\x99\x22\x6b\xc9" + "\xbb\x17\x06\xe5\x7d\x66\x43\x62\xf6\xcd" + "\x35\x90\x2e\x41\x8d\x6d\xaa\x09\x73\x95\x0c\xf1\x1d\xde\x4c\x2f\x2d\xf7" + "\xd1\x72\xeb\xef\x48\xc7\xf8\xf9\xfa\xfb" + "\xfc\xfd\xfe\xff"; + +void LibRaw::sony_decrypt(unsigned *data, int len, int start, int key) +{ +#ifndef LIBRAW_NOTHREADS +#define pad tls->sony_decrypt.pad +#define p tls->sony_decrypt.p +#else + static unsigned pad[128], p; +#endif + if (start) + { + for (p = 0; p < 4; p++) + pad[p] = key = key * 48828125ULL + 1; + pad[3] = pad[3] << 1 | (pad[0] ^ pad[2]) >> 31; + for (p = 4; p < 127; p++) + pad[p] = (pad[p - 4] ^ pad[p - 2]) << 1 | (pad[p - 3] ^ pad[p - 1]) >> 31; + for (p = 0; p < 127; p++) + pad[p] = htonl(pad[p]); + } + while (len--) + { + *data++ ^= pad[p & 127] = pad[(p + 1) & 127] ^ pad[(p + 65) & 127]; + p++; + } +#ifndef LIBRAW_NOTHREADS +#undef pad +#undef p +#endif +} +void LibRaw::setSonyBodyFeatures(unsigned long long id) +{ + ushort idx; + static const struct + { + ushort scf[11]; + /* + scf[0] camera id + scf[1] camera format + scf[2] camera mount: Minolta A, Sony E, fixed, + scf[3] camera type: DSLR, NEX, SLT, ILCE, ILCA, DSC + scf[4] lens mount + scf[5] tag 0x2010 group (0 if not used) + scf[6] offset of Sony ISO in 0x2010 table, 0xffff if not valid + scf[7] offset of ShutterCount3 in 0x9050 table, 0xffff if not valid + scf[8] offset of MeteringMode in 0x2010 table, 0xffff if not valid + scf[9] offset of ExposureProgram in 0x2010 table, 0xffff if not valid + scf[10] offset of ReleaseMode2 in 0x2010 table, 0xffff if not valid + */ + } SonyCamFeatures[] = { + {SonyID_DSLR_A100, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A900, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A700, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A200, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A350, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A300, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A900, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A380, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A330, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A230, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A290, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x10b, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x10c, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A850, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A850, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x10f, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x110, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A550, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A500, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A450, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x114, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x115, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_NEX_5, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_NEX_3, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_SLT_A33, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_SLT_A55, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A560, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSLR_A580, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_DSLR, 0, + 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_NEX_C3, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_SLT_A35, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 0, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_SLT_A65, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 2, + 0x1218, 0x01bd, 0x1178, 0x1179, 0x112c}, + {SonyID_SLT_A77, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 2, + 0x1218, 0x01bd, 0x1178, 0x1179, 0x112c}, + {SonyID_NEX_5N, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 1, + 0x113e, 0x01bd, 0x1174, 0x1175, 0x112c}, + {SonyID_NEX_7, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 2, + 0x1218, 0x01bd, 0x1178, 0x1179, 0x112c}, + {SonyID_NEX_VG20, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 2, + 0x1218, 0x01bd, 0x1178, 0x1179, 0x112c}, + {SonyID_SLT_A37, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 3, + 0x11f4, 0x01bd, 0x1154, 0x1155, 0x1108}, + {SonyID_SLT_A57, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 3, + 0x11f4, 0x01bd, 0x1154, 0x1155, 0x1108}, + {SonyID_NEX_F3, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 3, + 0x11f4, 0x01bd, 0x1154, 0x1155, 0x1108}, + {SonyID_SLT_A99, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 5, + 0x1254, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {SonyID_NEX_6, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 5, + 0x1254, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {SonyID_NEX_5R, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 5, + 0x1254, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {SonyID_DSC_RX100, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 5, 0x1254, 0xffff, 0x11ac, 0x11ad, 0x1160}, + {SonyID_DSC_RX1, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 5, 0x1258, 0xffff, 0x11ac, 0x11ad, 0x1160}, + {SonyID_NEX_VG900, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 5, + 0x1254, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {SonyID_NEX_VG30, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 5, + 0x1254, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {0x12d, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_3000, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 5, + 0x1280, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {SonyID_SLT_A58, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_SLT, 0, 5, + 0x1280, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {0x130, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_NEX_3N, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 5, + 0x1280, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {SonyID_ILCE_7, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_NEX_5T, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_NEX, 0, 5, + 0x1254, 0x01aa, 0x11ac, 0x11ad, 0x1160}, + {SonyID_DSC_RX100M2, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 6, 0x113c, 0xffff, 0x1064, 0x1065, 0x1018}, + {SonyID_DSC_RX10, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 7, 0x0344, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_DSC_RX1R, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 5, 0x1258, 0xffff, 0x11ac, 0x11ad, 0x1160}, + {SonyID_ILCE_7R, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCE_6000, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCE_5000, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0x01aa, 0x025c, 0x025d, 0x0210}, + {0x13a, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x13b, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x13c, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSC_RX100M3, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 7, 0x0344, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCE_7S, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCA_77M2, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_ILCA, 0, + 7, 0x0344, 0x01a0, 0x025c, 0x025d, 0x0210}, + {0x140, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x141, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x142, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x143, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x144, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x145, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x146, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x147, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x148, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x149, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x14a, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x14b, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x14c, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x14d, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x14e, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x14f, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x150, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x151, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x152, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_5100, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0x01a0, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCE_7M2, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_DSC_RX100M4, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 8, 0x0346, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_DSC_RX10M2, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 8, 0x0346, 0xffff, 0x025c, 0x025d, 0x0210}, + {0x157, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSC_RX1RM2, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 8, 0x0346, 0xffff, 0x025c, 0x025d, 0x0210}, + {0x159, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_QX1, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 7, + 0x0344, 0x01a0, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCE_7RM2, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 8, + 0x0346, 0x01cb, 0x025c, 0x025d, 0x0210}, + {0x15c, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x15d, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_7SM2, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 8, + 0x0346, 0x01cb, 0x025c, 0x025d, 0x0210}, + {0x15f, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x160, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCA_68, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_ILCA, 0, + 7, 0x0344, 0x01a0, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCA_99M2, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Minolta_A, LIBRAW_SONY_ILCA, 0, 8, + 0x0346, 0x01cd, 0x025c, 0x025d, 0x0210}, + {SonyID_DSC_RX10M3, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 8, 0x0346, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_DSC_RX100M5, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 8, 0x0346, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCE_6300, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 8, + 0x0346, 0x01cd, 0x025c, 0x025d, 0x0210}, + {SonyID_ILCE_9, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + {0x167, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_6500, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 8, + 0x0346, 0x01cd, 0x025c, 0x025d, 0x0210}, + {0x169, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_7RM3, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + {SonyID_ILCE_7M3, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + {SonyID_DSC_RX0, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 8, 0x0346, 0xffff, 0x025c, 0x025d, 0x0210}, + {SonyID_DSC_RX10M4, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 9, 0x0320, 0xffff, 0x024b, 0x024c, 0x0208}, + {SonyID_DSC_RX100M6, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 9, 0x0320, 0xffff, 0x024b, 0x024c, 0x0208}, + {SonyID_DSC_HX99, LIBRAW_FORMAT_1div2p3INCH, LIBRAW_MOUNT_FixedLens, + LIBRAW_SONY_DSC, LIBRAW_MOUNT_FixedLens, 9, 0x0320, 0xffff, 0x024b, + 0x024c, 0x0208}, + {0x170, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSC_RX100M5A, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 9, 0x0320, 0xffff, 0x024b, 0x024c, 0x0208}, + {0x172, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_6400, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + {SonyID_DSC_RX0M2, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 9, 0x0320, 0xffff, 0x024b, 0x024c, 0x0208}, + {0x175, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_DSC_RX100M7, LIBRAW_FORMAT_1INCH, LIBRAW_MOUNT_FixedLens, LIBRAW_SONY_DSC, + LIBRAW_MOUNT_FixedLens, 9, 0x0320, 0xffff, 0x024b, 0x024c, 0x0208}, + {SonyID_ILCE_7RM4, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + {SonyID_ILCE_9M2, LIBRAW_FORMAT_FF, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + {0x179, 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_6600, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + {SonyID_ILCE_6100, LIBRAW_FORMAT_APSC, LIBRAW_MOUNT_Sony_E, LIBRAW_SONY_ILCE, 0, 9, + 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, + + }; + ilm.CamID = id; + + if (id == SonyID_DSC_R1) + { + ilm.CameraMount = ilm.LensMount = LIBRAW_MOUNT_FixedLens; + imSony.CameraType = LIBRAW_SONY_DSC; + imSony.group2010 = 0; + imSony.real_iso_offset = 0xffff; + imSony.ImageCount3_offset = 0xffff; + return; + } + else + idx = id - 0x100ULL; + + if ((idx >= 0) && (idx < sizeof SonyCamFeatures / sizeof *SonyCamFeatures)) + { + if (!SonyCamFeatures[idx].scf[2]) + return; + ilm.CameraFormat = SonyCamFeatures[idx].scf[1]; + ilm.CameraMount = SonyCamFeatures[idx].scf[2]; + imSony.CameraType = SonyCamFeatures[idx].scf[3]; + if (SonyCamFeatures[idx].scf[4]) + ilm.LensMount = SonyCamFeatures[idx].scf[4]; + imSony.group2010 = SonyCamFeatures[idx].scf[5]; + imSony.real_iso_offset = SonyCamFeatures[idx].scf[6]; + imSony.ImageCount3_offset = SonyCamFeatures[idx].scf[7]; + imSony.MeteringMode_offset = SonyCamFeatures[idx].scf[8]; + imSony.ExposureProgram_offset = SonyCamFeatures[idx].scf[9]; + imSony.ReleaseMode2_offset = SonyCamFeatures[idx].scf[10]; + } + + char *sbstr = strstr(software, " v"); + if (sbstr != NULL) + { + sbstr += 2; + imSony.firmware = atof(sbstr); + + if ((id == SonyID_ILCE_7) || + (id == SonyID_ILCE_7R)) + { + if (imSony.firmware < 1.2f) + imSony.ImageCount3_offset = 0x01aa; + else + imSony.ImageCount3_offset = 0x01c0; + } + else if (id == SonyID_ILCE_6000) + { + if (imSony.firmware < 2.0f) + imSony.ImageCount3_offset = 0x01aa; + else + imSony.ImageCount3_offset = 0x01c0; + } + else if ((id == SonyID_ILCE_7S) || + (id == SonyID_ILCE_7M2)) + { + if (imSony.firmware < 1.2f) + imSony.ImageCount3_offset = 0x01a0; + else + imSony.ImageCount3_offset = 0x01b6; + } + } +} + +void LibRaw::parseSonyLensType2(uchar a, uchar b) +{ + ushort lid2; + lid2 = (((ushort)a) << 8) | ((ushort)b); +// printf ("==>> 2: lid2 %d\n", lid2); + if (!lid2) + return; + if (lid2 < 0x100) + { + if ((ilm.AdapterID != 0x4900) && (ilm.AdapterID != 0xef00)) + { + ilm.AdapterID = lid2; + switch (lid2) + { + case 1: + case 2: + case 3: + case 6: + ilm.LensMount = LIBRAW_MOUNT_Minolta_A; + break; + case 44: + case 78: + case 184: + case 234: + case 239: + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + break; + } + } + } + else + ilm.LensID = lid2; + + if ((lid2 >= 50481) && + (lid2 < 50500)) { + strcpy(ilm.Adapter, "MC-11"); + ilm.AdapterID = 0x4900; + } else if ((lid2 > 0xef00) && + (lid2 < 0xffff) && + (lid2 != 0xff00)) { + ilm.AdapterID = 0xef00; + ilm.LensID -= ilm.AdapterID; + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + } + + return; +} + +void LibRaw::parseSonyLensFeatures(uchar a, uchar b) +{ + + ushort features; + features = (((ushort)a) << 8) | ((ushort)b); + + if ((ilm.LensMount == LIBRAW_MOUNT_Canon_EF) || + (ilm.LensMount != LIBRAW_MOUNT_Sigma_X3F) || !features) + return; + + ilm.LensFeatures_pre[0] = 0; + ilm.LensFeatures_suf[0] = 0; + if ((features & 0x0200) && (features & 0x0100)) + strcpy(ilm.LensFeatures_pre, "E"); + else if (features & 0x0200) + strcpy(ilm.LensFeatures_pre, "FE"); + else if (features & 0x0100) + strcpy(ilm.LensFeatures_pre, "DT"); + + if (!ilm.LensFormat && !ilm.LensMount) + { + ilm.LensFormat = LIBRAW_FORMAT_FF; + ilm.LensMount = LIBRAW_MOUNT_Minolta_A; + + if ((features & 0x0200) && (features & 0x0100)) + { + ilm.LensFormat = LIBRAW_FORMAT_APSC; + ilm.LensMount = LIBRAW_MOUNT_Sony_E; + } + else if (features & 0x0200) + { + ilm.LensMount = LIBRAW_MOUNT_Sony_E; + } + else if (features & 0x0100) + { + ilm.LensFormat = LIBRAW_FORMAT_APSC; + } + } + + if (features & 0x4000) + strnXcat(ilm.LensFeatures_pre, " PZ"); + + if (features & 0x0008) + strnXcat(ilm.LensFeatures_suf, " G"); + else if (features & 0x0004) + strnXcat(ilm.LensFeatures_suf, " ZA"); + + if ((features & 0x0020) && (features & 0x0040)) + strnXcat(ilm.LensFeatures_suf, " Macro"); + else if (features & 0x0020) + strnXcat(ilm.LensFeatures_suf, " STF"); + else if (features & 0x0040) + strnXcat(ilm.LensFeatures_suf, " Reflex"); + else if (features & 0x0080) + strnXcat(ilm.LensFeatures_suf, " Fisheye"); + + if (features & 0x0001) + strnXcat(ilm.LensFeatures_suf, " SSM"); + else if (features & 0x0002) + strnXcat(ilm.LensFeatures_suf, " SAM"); + + if (features & 0x8000) + strnXcat(ilm.LensFeatures_suf, " OSS"); + + if (features & 0x2000) + strnXcat(ilm.LensFeatures_suf, " LE"); + + if (features & 0x0800) + strnXcat(ilm.LensFeatures_suf, " II"); + + if (ilm.LensFeatures_suf[0] == ' ') + memmove(ilm.LensFeatures_suf, ilm.LensFeatures_suf + 1, + strbuflen(ilm.LensFeatures_suf) - 1); + + return; +} + +void LibRaw::process_Sony_0x0116(uchar *buf, ushort len, unsigned long long id) +{ + int i = 0; + + if (((id == SonyID_DSLR_A900) || + (id == SonyID_DSLR_A900_APSC) || + (id == SonyID_DSLR_A850) || + (id == SonyID_DSLR_A850_APSC)) && + (len >= 2)) + i = 1; + else if ((id >= SonyID_DSLR_A550) && (len >= 3)) + i = 2; + else + return; + + imCommon.BatteryTemperature = (float)(buf[i] - 32) / 1.8f; +} + +void LibRaw::process_Sony_0x2010(uchar *buf, ushort len) +{ + if (!imSony.group2010) + return; + + if ((imSony.real_iso_offset != 0xffff) && + (len >= (imSony.real_iso_offset + 2)) && (imCommon.real_ISO < 0.1f)) + { + uchar s[2]; + s[0] = SonySubstitution[buf[imSony.real_iso_offset]]; + s[1] = SonySubstitution[buf[imSony.real_iso_offset + 1]]; + imCommon.real_ISO = + 100.0f * libraw_powf64l(2.0f, (16 - ((float)sget2(s)) / 256.0f)); + } + + if (len >= (imSony.MeteringMode_offset + 2)) + { + imgdata.shootinginfo.MeteringMode = + SonySubstitution[buf[imSony.MeteringMode_offset]]; + imgdata.shootinginfo.ExposureProgram = + SonySubstitution[buf[imSony.ExposureProgram_offset]]; + } + + if (len >= (imSony.ReleaseMode2_offset + 2)) + { + imgdata.shootinginfo.DriveMode = + SonySubstitution[buf[imSony.ReleaseMode2_offset]]; + } +} + +void LibRaw::process_Sony_0x9050(uchar *buf, ushort len, unsigned long long id) +{ + ushort lid; + uchar s[4]; + int c; + + if ((ilm.CameraMount != LIBRAW_MOUNT_Sony_E) && + (ilm.CameraMount != LIBRAW_MOUNT_FixedLens)) + { + if (len < 2) + return; + if (buf[0]) + ilm.MaxAp4CurFocal = + my_roundf( + libraw_powf64l(2.0f, ((float)SonySubstitution[buf[0]] / 8.0 - 1.06f) / 2.0f) * + 10.0f) / 10.0f; + + if (buf[1]) + ilm.MinAp4CurFocal = + my_roundf( + libraw_powf64l(2.0f, ((float)SonySubstitution[buf[1]] / 8.0 - 1.06f) / 2.0f) * + 10.0f) / 10.0f; + } + + if (ilm.CameraMount != LIBRAW_MOUNT_FixedLens) + { + if (len <= 0x106) + return; + if (buf[0x3d] | buf[0x3c]) + { + lid = SonySubstitution[buf[0x3d]] << 8 | SonySubstitution[buf[0x3c]]; + ilm.CurAp = libraw_powf64l(2.0f, ((float)lid / 256.0f - 16.0f) / 2.0f); + } + if (buf[0x105] && + (ilm.LensMount != LIBRAW_MOUNT_Canon_EF) && + (ilm.LensMount != LIBRAW_MOUNT_Sigma_X3F)) { + switch (SonySubstitution[buf[0x105]]) { + case 1: + ilm.LensMount = LIBRAW_MOUNT_Minolta_A; + break; + case 2: + ilm.LensMount = LIBRAW_MOUNT_Sony_E; + break; + } + } + if (buf[0x106]) { + switch (SonySubstitution[buf[0x106]]) { + case 1: + ilm.LensFormat = LIBRAW_FORMAT_APSC; + break; + case 2: + ilm.LensFormat = LIBRAW_FORMAT_FF; + break; + } + } + } + + if (ilm.CameraMount == LIBRAW_MOUNT_Sony_E) + { + if (len <= 0x108) + return; + parseSonyLensType2( + SonySubstitution[buf[0x0108]], // LensType2 - Sony lens ids + SonySubstitution[buf[0x0107]]); + } + + if (len <= 0x10a) + return; + if ((ilm.LensID == LIBRAW_LENS_NOT_SET) && (ilm.CameraMount == LIBRAW_MOUNT_Minolta_A) && + (buf[0x010a] | buf[0x0109])) + { + ilm.LensID = // LensType - Minolta/Sony lens ids + SonySubstitution[buf[0x010a]] << 8 | SonySubstitution[buf[0x0109]]; + + if ((ilm.LensID > 0x4900) && (ilm.LensID <= 0x5900)) + { + ilm.AdapterID = 0x4900; + ilm.LensID -= ilm.AdapterID; + ilm.LensMount = LIBRAW_MOUNT_Sigma_X3F; + strcpy(ilm.Adapter, "MC-11"); + } + + else if ((ilm.LensID > 0xef00) && (ilm.LensID < 0xffff) && + (ilm.LensID != 0xff00)) + { + ilm.AdapterID = 0xef00; + ilm.LensID -= ilm.AdapterID; + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + } + } + + if ((id >= SonyID_SLT_A65) && (id <= SonyID_NEX_F3)) + { + if (len <= 0x116) + return; + // "SLT-A65", "SLT-A77", "NEX-7", "NEX-VG20", + // "SLT-A37", "SLT-A57", "NEX-F3", "Lunar" + parseSonyLensFeatures(SonySubstitution[buf[0x115]], + SonySubstitution[buf[0x116]]); + } + else if (ilm.CameraMount != LIBRAW_MOUNT_FixedLens) + { + if (len <= 0x117) + return; + parseSonyLensFeatures(SonySubstitution[buf[0x116]], + SonySubstitution[buf[0x117]]); + } + + if ((id == SonyID_ILCE_7RM2) || + (id == SonyID_ILCE_7SM2) || + (id == SonyID_ILCA_99M2) || + (id == SonyID_ILCE_6300) || + (id == SonyID_ILCE_9) || + (id == SonyID_ILCE_6500) || + (id == SonyID_ILCE_7RM3) || + (id == SonyID_ILCE_7M3) || + (id == SonyID_ILCE_6400) || + (id == SonyID_ILCE_7RM4) || + (id == SonyID_ILCE_9M2) || + (id == SonyID_ILCE_6600) || + (id == SonyID_ILCE_6100)) + { + if (len <= 0x8d) + return; + unsigned long long b88 = SonySubstitution[buf[0x88]]; + unsigned long long b89 = SonySubstitution[buf[0x89]]; + unsigned long long b8a = SonySubstitution[buf[0x8a]]; + unsigned long long b8b = SonySubstitution[buf[0x8b]]; + unsigned long long b8c = SonySubstitution[buf[0x8c]]; + unsigned long long b8d = SonySubstitution[buf[0x8d]]; + sprintf(imgdata.shootinginfo.InternalBodySerial, "%06llx", + (b88 << 40) + (b89 << 32) + (b8a << 24) + (b8b << 16) + (b8c << 8) + + b8d); + } + else if (ilm.CameraMount == LIBRAW_MOUNT_Minolta_A) + { + if (len <= 0xf4) + return; + unsigned long long bf0 = SonySubstitution[buf[0xf0]]; + unsigned long long bf1 = SonySubstitution[buf[0xf1]]; + unsigned long long bf2 = SonySubstitution[buf[0xf2]]; + unsigned long long bf3 = SonySubstitution[buf[0xf3]]; + unsigned long long bf4 = SonySubstitution[buf[0xf4]]; + sprintf(imgdata.shootinginfo.InternalBodySerial, "%05llx", + (bf0 << 32) + (bf1 << 24) + (bf2 << 16) + (bf3 << 8) + bf4); + } + else if ((ilm.CameraMount == LIBRAW_MOUNT_Sony_E) && + (id != SonyID_NEX_5N) && + (id != SonyID_NEX_7) && + (id != SonyID_NEX_VG20)) + { + if (len <= 0x7f) + return; + unsigned b7c = SonySubstitution[buf[0x7c]]; + unsigned b7d = SonySubstitution[buf[0x7d]]; + unsigned b7e = SonySubstitution[buf[0x7e]]; + unsigned b7f = SonySubstitution[buf[0x7f]]; + sprintf(imgdata.shootinginfo.InternalBodySerial, "%04x", + (b7c << 24) + (b7d << 16) + (b7e << 8) + b7f); + } + + if ((imSony.ImageCount3_offset != 0xffff) && + (len >= (imSony.ImageCount3_offset + 4))) + { + FORC4 s[c] = SonySubstitution[buf[imSony.ImageCount3_offset + c]]; + imSony.ImageCount3 = sget4(s); + } + + return; +} + +void LibRaw::process_Sony_0x9400(uchar *buf, ushort len, unsigned long long id) +{ + + uchar s[4]; + int c; + uchar bufx = buf[0]; + + if (((bufx == 0x23) || (bufx == 0x24) || (bufx == 0x26) || (bufx == 0x28)) && + (len >= 0x1f)) + { // 0x9400 'c' version + + if ((id == SonyID_ILCE_9) || + (id == SonyID_ILCE_7RM3) || + (id == SonyID_ILCE_7M3) || + (id == SonyID_DSC_RX10M4) || + (id == SonyID_DSC_RX100M6) || + (id == SonyID_DSC_HX99) || + (id == SonyID_DSC_RX100M5A) || + (id == SonyID_ILCE_6400) || + (id == SonyID_DSC_RX0M2) || + (id == SonyID_DSC_RX100M7) || + (id == SonyID_ILCE_7RM4) || + (id == SonyID_ILCE_9M2) || + (id == SonyID_ILCE_6600) || + (id == SonyID_ILCE_6100)) + { + imSony.ShotNumberSincePowerUp = SonySubstitution[buf[0x0a]]; + } + else + { + FORC4 s[c] = SonySubstitution[buf[0x0a + c]]; + imSony.ShotNumberSincePowerUp = sget4(s); + } + + imSony.Sony0x9400_version = 0xc; + + imSony.Sony0x9400_ReleaseMode2 = SonySubstitution[buf[0x09]]; + + FORC4 s[c] = SonySubstitution[buf[0x12 + c]]; + imSony.Sony0x9400_SequenceImageNumber = sget4(s); + + imSony.Sony0x9400_SequenceLength1 = SonySubstitution[buf[0x16]]; // shots + + FORC4 s[c] = SonySubstitution[buf[0x1a + c]]; + imSony.Sony0x9400_SequenceFileNumber = sget4(s); + + imSony.Sony0x9400_SequenceLength2 = SonySubstitution[buf[0x1e]]; // files + } + + else if ((bufx == 0x0c) && (len >= 0x1f)) + { // 0x9400 'b' version + imSony.Sony0x9400_version = 0xb; + + FORC4 s[c] = SonySubstitution[buf[0x08 + c]]; + imSony.Sony0x9400_SequenceImageNumber = sget4(s); + + FORC4 s[c] = SonySubstitution[buf[0x0c + c]]; + imSony.Sony0x9400_SequenceFileNumber = sget4(s); + + imSony.Sony0x9400_ReleaseMode2 = SonySubstitution[buf[0x10]]; + + imSony.Sony0x9400_SequenceLength1 = SonySubstitution[buf[0x1e]]; + } + + else if ((bufx == 0x0a) && (len >= 0x23)) + { // 0x9400 'a' version + imSony.Sony0x9400_version = 0xa; + + FORC4 s[c] = SonySubstitution[buf[0x08 + c]]; + imSony.Sony0x9400_SequenceImageNumber = sget4(s); + + FORC4 s[c] = SonySubstitution[buf[0x0c + c]]; + imSony.Sony0x9400_SequenceFileNumber = sget4(s); + + imSony.Sony0x9400_ReleaseMode2 = SonySubstitution[buf[0x10]]; + + imSony.Sony0x9400_SequenceLength1 = SonySubstitution[buf[0x22]]; + } + + else + return; +} + +void LibRaw::process_Sony_0x9402(uchar *buf, ushort len) +{ + + if (len < 23) + return; + + imgdata.shootinginfo.FocusMode = SonySubstitution[buf[0x16]]; + + if ((imSony.CameraType == LIBRAW_SONY_SLT) || + (imSony.CameraType == LIBRAW_SONY_ILCA)) + return; + + uchar bufx = buf[0x00]; + if ((bufx == 0x05) || (bufx == 0xff) || (buf[0x02] != 0xff)) + return; + + imCommon.AmbientTemperature = + (float)((short)SonySubstitution[buf[0x04]]); + + return; +} + +void LibRaw::process_Sony_0x9403(uchar *buf, ushort len) +{ + if (len < 6) + return; + uchar bufx = SonySubstitution[buf[4]]; + if ((bufx == 0x00) || (bufx == 0x94)) + return; + + imCommon.SensorTemperature = (float)((short)SonySubstitution[buf[5]]); + + return; +} + +void LibRaw::process_Sony_0x9406(uchar *buf, ushort len) +{ + if (len < 6) + return; + uchar bufx = buf[0]; + if ((bufx != 0x01) && (bufx != 0x08) && (bufx != 0x1b)) + return; + bufx = buf[2]; + if ((bufx != 0x08) && (bufx != 0x1b)) + return; + + imCommon.BatteryTemperature = + (float)(SonySubstitution[buf[5]] - 32) / 1.8f; + + return; +} + +void LibRaw::process_Sony_0x940c(uchar *buf, ushort len) +{ + if ((imSony.CameraType != LIBRAW_SONY_ILCE) && + (imSony.CameraType != LIBRAW_SONY_NEX)) + return; + if (len <= 0x000a) + return; + + ushort lid2; + if ((ilm.LensMount != LIBRAW_MOUNT_Canon_EF) && + (ilm.LensMount != LIBRAW_MOUNT_Sigma_X3F)) + { + switch (SonySubstitution[buf[0x0008]]) + { + case 1: + case 5: + ilm.LensMount = LIBRAW_MOUNT_Minolta_A; + break; + case 4: + ilm.LensMount = LIBRAW_MOUNT_Sony_E; + break; + } + } + lid2 = (((ushort)SonySubstitution[buf[0x000a]]) << 8) | + ((ushort)SonySubstitution[buf[0x0009]]); + if ((lid2 > 0) && + ((lid2 < 32784) || (ilm.LensID == 0x1999) || (ilm.LensID == 0xffff))) + parseSonyLensType2( + SonySubstitution[buf[0x000a]], // LensType2 - Sony lens ids + SonySubstitution[buf[0x0009]]); + if ((lid2 == 44) || (lid2 == 78) || (lid2 == 184) || (lid2 == 234) || + (lid2 == 239)) + ilm.AdapterID = lid2; + return; +} + +void LibRaw::process_Sony_0x940e(uchar *buf, ushort len, unsigned long long id) +{ + if (((imSony.CameraType != LIBRAW_SONY_SLT) && + (imSony.CameraType != LIBRAW_SONY_ILCA)) || + (id == SonyID_SLT_A33) || + (id == SonyID_SLT_A55) || + (id == SonyID_SLT_A35) || + (len < 3)) + return; + + imSony.AFType = SonySubstitution[buf[0x02]]; + + if (imSony.CameraType == LIBRAW_SONY_ILCA) + { + if (len >= 0x06) + { + imgdata.shootinginfo.FocusMode = SonySubstitution[buf[0x05]]; + } + if (len >= 0x0051) + { + imSony.AFMicroAdjValue = SonySubstitution[buf[0x0050]]; + } + } + else + { + if (len >= 0x0c) + { + imgdata.shootinginfo.FocusMode = SonySubstitution[buf[0x0b]]; + } + if (len >= 0x017e) + { + imSony.AFMicroAdjValue = SonySubstitution[buf[0x017d]]; + } + } + + if (imSony.AFMicroAdjValue != 0) + imSony.AFMicroAdjOn = 1; +} + +void LibRaw::parseSonyMakernotes( + int base, unsigned tag, unsigned type, unsigned len, unsigned dng_writer, + uchar *&table_buf_0x0116, ushort &table_buf_0x0116_len, + uchar *&table_buf_0x2010, ushort &table_buf_0x2010_len, + uchar *&table_buf_0x9050, ushort &table_buf_0x9050_len, + uchar *&table_buf_0x9400, ushort &table_buf_0x9400_len, + uchar *&table_buf_0x9402, ushort &table_buf_0x9402_len, + uchar *&table_buf_0x9403, ushort &table_buf_0x9403_len, + uchar *&table_buf_0x9406, ushort &table_buf_0x9406_len, + uchar *&table_buf_0x940c, ushort &table_buf_0x940c_len, + uchar *&table_buf_0x940e, ushort &table_buf_0x940e_len) +{ + + ushort lid, a, c, d; + uchar *table_buf; + uchar uc; + uchar s[2]; + int LensDataValid = 0; + unsigned uitemp; + + if (tag == 0xb001) + { // Sony ModelID + unique_id = get2(); + setSonyBodyFeatures(unique_id); + + if (table_buf_0x0116_len) + { + process_Sony_0x0116(table_buf_0x0116, table_buf_0x0116_len, unique_id); + free(table_buf_0x0116); + table_buf_0x0116_len = 0; + } + + if (table_buf_0x2010_len) + { + process_Sony_0x2010(table_buf_0x2010, table_buf_0x2010_len); + free(table_buf_0x2010); + table_buf_0x2010_len = 0; + } + + if (table_buf_0x9050_len) + { + process_Sony_0x9050(table_buf_0x9050, table_buf_0x9050_len, unique_id); + free(table_buf_0x9050); + table_buf_0x9050_len = 0; + } + + if (table_buf_0x9400_len) + { + process_Sony_0x9400(table_buf_0x9400, table_buf_0x9400_len, unique_id); + free(table_buf_0x9400); + table_buf_0x9400_len = 0; + } + + if (table_buf_0x9402_len) + { + process_Sony_0x9402(table_buf_0x9402, table_buf_0x9402_len); + free(table_buf_0x9402); + table_buf_0x9402_len = 0; + } + + if (table_buf_0x9403_len) + { + process_Sony_0x9403(table_buf_0x9403, table_buf_0x9403_len); + free(table_buf_0x9403); + table_buf_0x9403_len = 0; + } + + if (table_buf_0x9406_len) + { + process_Sony_0x9406(table_buf_0x9406, table_buf_0x9406_len); + free(table_buf_0x9406); + table_buf_0x9406_len = 0; + } + + if (table_buf_0x940c_len) + { + process_Sony_0x940c(table_buf_0x940c, table_buf_0x940c_len); + free(table_buf_0x940c); + table_buf_0x940c_len = 0; + } + + if (table_buf_0x940e_len) + { + process_Sony_0x940e(table_buf_0x940e, table_buf_0x940e_len, unique_id); + free(table_buf_0x940e); + table_buf_0x940e_len = 0; + } + } + else if (tag == 0xb000) + { + FORC4 imSony.FileFormat = imSony.FileFormat * 10 + fgetc(ifp); + } + else if (tag == 0xb026) + { + uitemp = get4(); + if (uitemp != 0xffffffff) + imgdata.shootinginfo.ImageStabilization = uitemp; + } + else if (((tag == 0x0001) || // Minolta CameraSettings, big endian + (tag == 0x0003)) && + (len >= 196)) + { + table_buf = (uchar *)malloc(len); + fread(table_buf, len, 1, ifp); + + lid = 0x01 << 2; + imgdata.shootinginfo.ExposureMode = + (unsigned)table_buf[lid] << 24 | (unsigned)table_buf[lid + 1] << 16 | + (unsigned)table_buf[lid + 2] << 8 | (unsigned)table_buf[lid + 3]; + + lid = 0x06 << 2; + imgdata.shootinginfo.DriveMode = + (unsigned)table_buf[lid] << 24 | (unsigned)table_buf[lid + 1] << 16 | + (unsigned)table_buf[lid + 2] << 8 | (unsigned)table_buf[lid + 3]; + + lid = 0x07 << 2; + imgdata.shootinginfo.MeteringMode = + (unsigned)table_buf[lid] << 24 | (unsigned)table_buf[lid + 1] << 16 | + (unsigned)table_buf[lid + 2] << 8 | (unsigned)table_buf[lid + 3]; + + lid = 0x25 << 2; + imSony.MinoltaCamID = + (unsigned)table_buf[lid] << 24 | (unsigned)table_buf[lid + 1] << 16 | + (unsigned)table_buf[lid + 2] << 8 | (unsigned)table_buf[lid + 3]; + if (imSony.MinoltaCamID != 0xffffffff) + ilm.CamID = imSony.MinoltaCamID; + + lid = 0x30 << 2; + imgdata.shootinginfo.FocusMode = + (unsigned)table_buf[lid] << 24 | (unsigned)table_buf[lid + 1] << 16 | + (unsigned)table_buf[lid + 2] << 8 | (unsigned)table_buf[lid + 3]; + + free(table_buf); + } + else if ((tag == 0x0004) && // Minolta CameraSettings7D, big endian + (len >= 227)) + { + table_buf = (uchar *)malloc(len); + fread(table_buf, len, 1, ifp); + + lid = 0x0; + imgdata.shootinginfo.ExposureMode = + (ushort)table_buf[lid] << 8 | (ushort)table_buf[lid + 1]; + + lid = 0x0e << 1; + imgdata.shootinginfo.FocusMode = + (ushort)table_buf[lid] << 8 | (ushort)table_buf[lid + 1]; + + lid = 0x10 << 1; + imgdata.shootinginfo.AFPoint = + (ushort)table_buf[lid] << 8 | (ushort)table_buf[lid + 1]; + + lid = 0x25 << 1; + switch ((ushort)table_buf[lid] << 8 | (ushort)table_buf[lid + 1]) { + case 0: + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 4: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + + lid = 0x71 << 1; + imgdata.shootinginfo.ImageStabilization = + (ushort)table_buf[lid] << 8 | (ushort)table_buf[lid + 1]; + + free(table_buf); + } + else if ((tag == 0x0010) && // CameraInfo + strncasecmp(model, "DSLR-A100", 9) && + !strncasecmp(make, "SONY", 4) && + ((len == 368) || // a700 : CameraInfo + (len == 5478) || // a850, a900 : CameraInfo + (len == 5506) || // a200, a300, a350 : CameraInfo2 + (len == 6118) || // a230, a290, a330, a380, a390 : CameraInfo2 + (len == 15360)) // a450, a500, a550, a560, a580 : CameraInfo3 + // a33, a35, a55 + // NEX-3, NEX-5, NEX-5C, NEX-C3, NEX-VG10E + + ) + { + table_buf = (uchar *)malloc(len); + fread(table_buf, len, 1, ifp); + if (memcmp(table_buf, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) && + memcmp(table_buf, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) + { + LensDataValid = 1; + } + switch (len) + { + case 368: // a700: CameraInfo + case 5478: // a850, a900: CameraInfo + if ((!dng_writer) || + (saneSonyCameraInfo(table_buf[0], table_buf[3], table_buf[2], + table_buf[5], table_buf[4], table_buf[7]))) + { + if (LensDataValid) + { + if (table_buf[0] | table_buf[3]) + ilm.MinFocal = bcd2dec(table_buf[0]) * 100 + bcd2dec(table_buf[3]); + if (table_buf[2] | table_buf[5]) + ilm.MaxFocal = bcd2dec(table_buf[2]) * 100 + bcd2dec(table_buf[5]); + if (table_buf[4]) + ilm.MaxAp4MinFocal = bcd2dec(table_buf[4]) / 10.0f; + if (table_buf[4]) + ilm.MaxAp4MaxFocal = bcd2dec(table_buf[7]) / 10.0f; + parseSonyLensFeatures(table_buf[1], table_buf[6]); + } + + imSony.AFPointSelected = table_buf[21]; + imgdata.shootinginfo.AFPoint = (ushort)table_buf[25]; + + if (len == 5478) + { + imSony.AFMicroAdjValue = table_buf[304] - 20; + imSony.AFMicroAdjOn = (((table_buf[305] & 0x80) == 0x80) ? 1 : 0); + imSony.AFMicroAdjRegisteredLenses = table_buf[305] & 0x7f; + } + } + break; + default: + // CameraInfo2 & 3 + if ((!dng_writer) || + (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], + table_buf[4], table_buf[5], table_buf[6]))) + { + if ((LensDataValid) && strncasecmp(model, "NEX-5C", 6)) + { + if (table_buf[1] | table_buf[2]) + ilm.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); + if (table_buf[3] | table_buf[4]) + ilm.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); + if (table_buf[5]) + ilm.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; + if (table_buf[6]) + ilm.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; + parseSonyLensFeatures(table_buf[0], table_buf[7]); + } + + if (!strncasecmp(model, "DSLR-A450", 9) || + !strncasecmp(model, "DSLR-A500", 9) || + !strncasecmp(model, "DSLR-A550", 9)) + { + imSony.AFPointSelected = table_buf[0x14]; + imgdata.shootinginfo.FocusMode = table_buf[0x15]; + imgdata.shootinginfo.AFPoint = (ushort)table_buf[0x18]; + } + else if (!strncasecmp(model, "SLT-", 4) || + !strncasecmp(model, "DSLR-A560", 9) || + !strncasecmp(model, "DSLR-A580", 9)) + { + imSony.AFPointSelected = table_buf[0x1c]; + imgdata.shootinginfo.FocusMode = table_buf[0x1d]; + imgdata.shootinginfo.AFPoint = (ushort)table_buf[0x20]; + } + } + } + free(table_buf); + } + else if ((!dng_writer) && ((tag == 0x0020) || (tag == 0xb0280020))) + { + if (!strncasecmp(model, "DSLR-A100", 9)) + { // WBInfoA100 + fseek(ifp, 0x49dc, SEEK_CUR); + stmread(imgdata.shootinginfo.InternalBodySerial, 13, ifp); + } + else if ((len == + 19154) || // a200 a230 a290 a300 a330 a350 a380 a390 : FocusInfo + (len == 19148)) + { // a700 a850 a900 : FocusInfo + table_buf = (uchar *)malloc(128); + fread(table_buf, 128, 1, ifp); + imgdata.shootinginfo.DriveMode = table_buf[14]; + imgdata.shootinginfo.ExposureProgram = table_buf[63]; + free(table_buf); + } + else if (len == 20480) // a450 a500 a550 a560 a580 a33 a35 a55 : MoreInfo + // NEX-3 NEX-5 NEX-C3 NEX-VG10E : MoreInfo + { + a = get2(); + /*b =*/ get2(); + c = get2(); + d = get2(); + if ((a) && (c == 1)) + { + fseek(ifp, d - 8, SEEK_CUR); + table_buf = (uchar *)malloc(256); + fread(table_buf, 256, 1, ifp); + imgdata.shootinginfo.DriveMode = table_buf[1]; + imgdata.shootinginfo.ExposureProgram = table_buf[2]; + imgdata.shootinginfo.MeteringMode = table_buf[3]; + switch (table_buf[6]) { + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + if (strncasecmp(model, "DSLR-A450", 9) && + strncasecmp(model, "DSLR-A500", 9) && + strncasecmp(model, "DSLR-A550", 9)) + imgdata.shootinginfo.FocusMode = table_buf[0x13]; + else + imgdata.shootinginfo.FocusMode = table_buf[0x2c]; + free(table_buf); + } + } + } + else if (tag == 0x0102) + { + imSony.Quality = get4(); + } + else if (tag == 0x0104) + { + imCommon.FlashEC = getreal(type); + } + else if (tag == 0x0105) + { // Teleconverter + ilm.TeleconverterID = get4(); + } + else if (tag == 0x0107) + { + uitemp = get4(); + if (uitemp == 1) + imgdata.shootinginfo.ImageStabilization = 0; + else if (uitemp == 5) + imgdata.shootinginfo.ImageStabilization = 1; + else + imgdata.shootinginfo.ImageStabilization = uitemp; + } + else if ((tag == 0xb0280088) && (dng_writer == nonDNG)) + { + thumb_offset = get4() + base; + } + else if ((tag == 0xb0280089) && (dng_writer == nonDNG)) + { + thumb_length = get4(); + } + else if (((tag == 0x0114) || // CameraSettings + (tag == 0xb0280114)) && + (len < 256000)) + { + table_buf = (uchar *)malloc(len); + fread(table_buf, len, 1, ifp); + switch (len) + { + case 260: // Sony a100, big endian + imgdata.shootinginfo.ExposureMode = + ((ushort)table_buf[0]) << 8 | ((ushort)table_buf[1]); + lid = 0x0a << 1; + imgdata.shootinginfo.DriveMode = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + lid = 0x0c << 1; + imgdata.shootinginfo.FocusMode = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + lid = 0x0d << 1; + imSony.AFPointSelected = table_buf[lid + 1]; + lid = 0x0e << 1; + imSony.AFAreaModeSetting = table_buf[lid + 1]; + lid = 0x12 << 1; + imgdata.shootinginfo.MeteringMode = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + + lid = 0x17 << 1; + switch ((ushort)table_buf[lid] << 8 | (ushort)table_buf[lid + 1]) { + case 0: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_MonochromeGamma; + break; + case 5: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + + break; + case 448: // Minolta "DYNAX 5D" and its aliases, big endian + lid = 0x0a << 1; + imgdata.shootinginfo.ExposureMode = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + lid = 0x25 << 1; + imgdata.shootinginfo.MeteringMode = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + + lid = 0x2f << 1; + switch ((ushort)table_buf[lid] << 8 | (ushort)table_buf[lid + 1]) { + case 0: + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_MonochromeGamma; + break; + case 4: + case 5: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + + lid = 0xbd << 1; + imgdata.shootinginfo.ImageStabilization = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + break; + case 280: // a200 a300 a350 a700 + case 364: // a850 a900 + // CameraSettings and CameraSettings2 are big endian + if (table_buf[2] | table_buf[3]) + { + lid = (((ushort)table_buf[2]) << 8) | ((ushort)table_buf[3]); + ilm.CurAp = libraw_powf64l(2.0f, ((float)lid / 8.0f - 1.0f) / 2.0f); + } + lid = 0x04 << 1; + imgdata.shootinginfo.DriveMode = table_buf[lid + 1]; + lid = 0x1b << 1; + switch (((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1])) { + case 0: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 1: + case 5: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + lid = 0x4d << 1; + imgdata.shootinginfo.FocusMode = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + if (!imCommon.ColorSpace || + (imCommon.ColorSpace == LIBRAW_COLORSPACE_Unknown)) { + lid = 0x83 << 1; + switch (((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1])) { + case 6: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 5: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + } + break; + case 332: // a230 a290 a330 a380 a390 + // CameraSettings and CameraSettings2 are big endian + if (table_buf[2] | table_buf[3]) + { + lid = (((ushort)table_buf[2]) << 8) | ((ushort)table_buf[3]); + ilm.CurAp = libraw_powf64l(2.0f, ((float)lid / 8.0f - 1.0f) / 2.0f); + } + lid = 0x4d << 1; + imgdata.shootinginfo.FocusMode = + ((ushort)table_buf[lid]) << 8 | ((ushort)table_buf[lid + 1]); + lid = 0x7e << 1; + imgdata.shootinginfo.DriveMode = table_buf[lid + 1]; + break; + case 1536: // a560 a580 a33 a35 a55 NEX-3 NEX-5 NEX-5C NEX-C3 NEX-VG10E + case 2048: // a450 a500 a550 + // CameraSettings3 are little endian + switch (table_buf[0x0e]) { + case 1: + imCommon.ColorSpace = LIBRAW_COLORSPACE_sRGB; + break; + case 2: + imCommon.ColorSpace = LIBRAW_COLORSPACE_AdobeRGB; + break; + default: + imCommon.ColorSpace = LIBRAW_COLORSPACE_Unknown; + break; + } + imgdata.shootinginfo.DriveMode = table_buf[0x34]; + parseSonyLensType2(table_buf[1016], table_buf[1015]); + if (ilm.LensMount != LIBRAW_MOUNT_Canon_EF) + { + switch (table_buf[153]) + { + case 16: + ilm.LensMount = LIBRAW_MOUNT_Minolta_A; + break; + case 17: + ilm.LensMount = LIBRAW_MOUNT_Sony_E; + break; + } + } + break; + } + free(table_buf); + } + else if ((tag == 0x3000) && (len < 256000)) + { + table_buf = (uchar *)malloc(len); + fread(table_buf, len, 1, ifp); + for (int i = 0; i < 20; i++) + imSony.SonyDateTime[i] = table_buf[6 + i]; + free(table_buf); + } + else if (tag == 0x0116 && len < 256000) + { + table_buf_0x0116 = (uchar *)malloc(len); + table_buf_0x0116_len = len; + fread(table_buf_0x0116, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x0116(table_buf_0x0116, table_buf_0x0116_len, ilm.CamID); + free(table_buf_0x0116); + table_buf_0x0116_len = 0; + } + } + else if (tag == 0x2008) + { + imSony.LongExposureNoiseReduction = get4(); + } + else if (tag == 0x2009) + { + imSony.HighISONoiseReduction = get2(); + } + else if (tag == 0x200a) + { + imSony.HDR[0] = get2(); + imSony.HDR[1] = get2(); + } + else if (tag == 0x2010 && len < 256000) + { + table_buf_0x2010 = (uchar *)malloc(len); + table_buf_0x2010_len = len; + fread(table_buf_0x2010, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x2010(table_buf_0x2010, table_buf_0x2010_len); + free(table_buf_0x2010); + table_buf_0x2010_len = 0; + } + } + else if (tag == 0x201a) + { + imSony.ElectronicFrontCurtainShutter = get4(); + } + else if (tag == 0x201b) + { + if ((imSony.CameraType != LIBRAW_SONY_DSC) || + (ilm.CamID == SonyID_DSC_RX10M4) || + (ilm.CamID == SonyID_DSC_RX100M6) || + (ilm.CamID == SonyID_DSC_RX100M5A) || + (ilm.CamID == SonyID_DSC_RX0M2) || + (ilm.CamID == SonyID_DSC_RX100M7)) + { + fread(&uc, 1, 1, ifp); + imgdata.shootinginfo.FocusMode = (short)uc; + } + } + else if (tag == 0x201c) + { + if ((imSony.CameraType != LIBRAW_SONY_DSC) || + (ilm.CamID == SonyID_DSC_RX10M4) || + (ilm.CamID == SonyID_DSC_RX100M6) || + (ilm.CamID == SonyID_DSC_RX100M5A) || + (ilm.CamID == SonyID_DSC_RX0M2) || + (ilm.CamID == SonyID_DSC_RX100M7)) + { + imSony.AFAreaModeSetting = fgetc(ifp); + } + } + else if (tag == 0x201d) + { + if (((imSony.AFAreaModeSetting == 3) && + ((imSony.CameraType == LIBRAW_SONY_ILCE) || + (imSony.CameraType == LIBRAW_SONY_NEX) || + (ilm.CamID == SonyID_DSC_RX10M4) || + (ilm.CamID == SonyID_DSC_RX100M6) || + (ilm.CamID == SonyID_DSC_RX100M5A) || + (ilm.CamID == SonyID_DSC_RX0M2) || + (ilm.CamID == SonyID_DSC_RX100M7))) || + ((imSony.AFAreaModeSetting == 4) && + (imSony.CameraType == LIBRAW_SONY_ILCA))) + { + imSony.FlexibleSpotPosition[0] = get2(); + imSony.FlexibleSpotPosition[1] = get2(); + } + } + else if (tag == 0x201e) + { + if (imSony.CameraType != LIBRAW_SONY_DSC) + { + imSony.AFPointSelected = fgetc(ifp); + } + } + else if (tag == 0x2020) + { + if (imSony.CameraType != LIBRAW_SONY_DSC) + { + fread(imSony.AFPointsUsed, 1, 10, ifp); + } + } + else if (tag == 0x2021) + { + if ((imSony.CameraType != LIBRAW_SONY_DSC) || + (ilm.CamID == SonyID_DSC_RX10M4) || + (ilm.CamID == SonyID_DSC_RX100M6) || + (ilm.CamID == SonyID_DSC_RX100M5A) || + (ilm.CamID == SonyID_DSC_RX0M2) || + (ilm.CamID == SonyID_DSC_RX100M7)) + { + imSony.AFTracking = fgetc(ifp); + } + } + else if (tag == 0x2027) + { + FORC4 imSony.FocusLocation[c] = get2(); + } + else if (tag == 0x2028) + { + if (get2()) + { + imSony.VariableLowPassFilter = get2(); + } + } + else if (tag == 0x2029) + { + imSony.RAWFileType = get2(); + } + else if (tag == 0x202c) + { + imSony.MeteringMode2 = get2(); + } + else if (tag == 0x202f) + { + imSony.PixelShiftGroupID = get4(); + imSony.PixelShiftGroupPrefix = imSony.PixelShiftGroupID >> 22; + imSony.PixelShiftGroupID = + ((imSony.PixelShiftGroupID >> 17) & (unsigned)0x1f) * + (unsigned)1000000 + + ((imSony.PixelShiftGroupID >> 12) & (unsigned)0x1f) * (unsigned)10000 + + ((imSony.PixelShiftGroupID >> 6) & (unsigned)0x3f) * (unsigned)100 + + (imSony.PixelShiftGroupID & (unsigned)0x3f); + + imSony.numInPixelShiftGroup = fgetc(ifp); + imSony.nShotsInPixelShiftGroup = fgetc(ifp); + } + else if (tag == 0x9050 && len < 256000) + { // little endian + table_buf_0x9050 = (uchar *)malloc(len); + table_buf_0x9050_len = len; + fread(table_buf_0x9050, len, 1, ifp); + + if (ilm.CamID) + { + process_Sony_0x9050(table_buf_0x9050, table_buf_0x9050_len, ilm.CamID); + free(table_buf_0x9050); + table_buf_0x9050_len = 0; + } + } + else if (tag == 0x9400 && len < 256000) + { + table_buf_0x9400 = (uchar *)malloc(len); + table_buf_0x9400_len = len; + fread(table_buf_0x9400, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x9400(table_buf_0x9400, table_buf_0x9400_len, unique_id); + free(table_buf_0x9400); + table_buf_0x9400_len = 0; + } + } + else if (tag == 0x9402 && len < 256000) + { + table_buf_0x9402 = (uchar *)malloc(len); + table_buf_0x9402_len = len; + fread(table_buf_0x9402, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x9402(table_buf_0x9402, table_buf_0x9402_len); + free(table_buf_0x9402); + table_buf_0x9402_len = 0; + } + } + else if (tag == 0x9403 && len < 256000) + { + table_buf_0x9403 = (uchar *)malloc(len); + table_buf_0x9403_len = len; + fread(table_buf_0x9403, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x9403(table_buf_0x9403, table_buf_0x9403_len); + free(table_buf_0x9403); + table_buf_0x9403_len = 0; + } + } + else if ((tag == 0x9405) && (len < 256000) && (len > 0x64)) + { + table_buf = (uchar *)malloc(len); + fread(table_buf, len, 1, ifp); + uc = table_buf[0x0]; + if (imCommon.real_ISO < 0.1f) + { + if ((uc == 0x25) || (uc == 0x3a) || (uc == 0x76) || (uc == 0x7e) || + (uc == 0x8b) || (uc == 0x9a) || (uc == 0xb3) || (uc == 0xe1)) + { + s[0] = SonySubstitution[table_buf[0x04]]; + s[1] = SonySubstitution[table_buf[0x05]]; + imCommon.real_ISO = + 100.0f * libraw_powf64l(2.0f, (16 - ((float)sget2(s)) / 256.0f)); + } + } + free(table_buf); + } + else if (tag == 0x9406 && len < 256000) + { + table_buf_0x9406 = (uchar *)malloc(len); + table_buf_0x9406_len = len; + fread(table_buf_0x9406, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x9406(table_buf_0x9406, table_buf_0x9406_len); + free(table_buf_0x9406); + table_buf_0x9406_len = 0; + } + } + else if (tag == 0x940c && len < 256000) + { + table_buf_0x940c = (uchar *)malloc(len); + table_buf_0x940c_len = len; + fread(table_buf_0x940c, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x940c(table_buf_0x940c, table_buf_0x940c_len); + free(table_buf_0x940c); + table_buf_0x940c_len = 0; + } + } + else if (tag == 0x940e && len < 256000) + { + table_buf_0x940e = (uchar *)malloc(len); + table_buf_0x940e_len = len; + fread(table_buf_0x940e, len, 1, ifp); + if (ilm.CamID) + { + process_Sony_0x940e(table_buf_0x940e, table_buf_0x940e_len, ilm.CamID); + free(table_buf_0x940e); + table_buf_0x940e_len = 0; + } + } + else if (((tag == 0xb027) || (tag == 0x010c)) && (ilm.LensID == LIBRAW_LENS_NOT_SET)) + { + ilm.LensID = get4(); +// printf ("==>> 1: ilm.LensID %lld\n", ilm.LensID); + if ((ilm.LensID > 0x4900) && (ilm.LensID <= 0x5900)) + { + ilm.AdapterID = 0x4900; + ilm.LensID -= ilm.AdapterID; + ilm.LensMount = LIBRAW_MOUNT_Sigma_X3F; + strcpy(ilm.Adapter, "MC-11"); + } + + else if ((ilm.LensID > 0xef00) && (ilm.LensID < 0xffff) && + (ilm.LensID != 0xff00)) + { + ilm.AdapterID = 0xef00; + ilm.LensID -= ilm.AdapterID; + ilm.LensMount = LIBRAW_MOUNT_Canon_EF; + } + + else if (((ilm.LensID != LIBRAW_LENS_NOT_SET) && (ilm.LensID < 0xef00)) || + (ilm.LensID == 0xff00)) + ilm.LensMount = LIBRAW_MOUNT_Minolta_A; + /* + if (tag == 0x010c) + ilm.CameraMount = LIBRAW_MOUNT_Minolta_A; + */ + } + else if (tag == 0xb02a && len < 256000) + { // Sony LensSpec + table_buf = (uchar *)malloc(len); + fread(table_buf, len, 1, ifp); + if ((!dng_writer) || + (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], + table_buf[4], table_buf[5], table_buf[6]))) + { + if (table_buf[1] | table_buf[2]) + ilm.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); + if (table_buf[3] | table_buf[4]) + ilm.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); + if (table_buf[5]) + ilm.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; + if (table_buf[6]) + ilm.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; + parseSonyLensFeatures(table_buf[0], table_buf[7]); + } + free(table_buf); + } + else if ((tag == 0xb02b) && !imgdata.sizes.raw_inset_crop.cwidth && + (len == 2)) + { + imgdata.sizes.raw_inset_crop.cheight = get4(); + imgdata.sizes.raw_inset_crop.cwidth = get4(); + } + else if (tag == 0xb041) + { + imgdata.shootinginfo.ExposureMode = get2(); + } + + // MetaVersion: (unique_id >= 286) +} + +void LibRaw::parseSonySR2(uchar *cbuf_SR2, unsigned SR2SubIFDOffset, + unsigned SR2SubIFDLength, unsigned dng_writer) +{ + unsigned c; + unsigned entries, tag_id, tag_type, tag_datalen; + INT64 tag_offset, tag_dataoffset; + int TagProcessed; + int tag_dataunitlen; + float num; + int i; + int WBCTC_count; +#define CHECKBUFFER_N(offset,N) \ + do \ + { \ + if ((((offset) + (N)) > SR2SubIFDLength) || ((offset) < 0)) \ + return; \ + } while (0) + + CHECKBUFFER_N(0, 2); + entries = sget2(cbuf_SR2); + if (entries > 1000) + return; + tag_offset = 2; + WBCTC_count = 0; + while (entries--) { + if (tiff_sget (SR2SubIFDOffset, cbuf_SR2, SR2SubIFDLength, + &tag_offset, &tag_id, &tag_type, &tag_dataoffset, + &tag_datalen, &tag_dataunitlen) == 0) { + TagProcessed = 0; + if (dng_writer == nonDNG) { + switch (tag_id) { + case 0x7300: + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 4,0); + FORC4 cblack[c] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + TagProcessed = 1; + break; + case 0x7303: + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 4, 0); + FORC4 cam_mul[GRBG_2_RGBG(c)] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + TagProcessed = 1; + break; + case 0x7310: + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 4, 0); + FORC4 cblack[RGGB_2_RGBG(c)] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + i = cblack[3]; + FORC3 if (i > (int)cblack[c]) i = cblack[c]; + FORC4 cblack[c] -= i; + black = i; + TagProcessed = 1; + break; + case 0x7313: + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 4, 0); + FORC4 cam_mul[RGGB_2_RGBG(c)] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + TagProcessed = 1; + break; + case 0x74a0: + CHECKBUFFER_N(tag_dataoffset, 4); + ilm.MaxAp4MaxFocal = sgetreal(tag_type, cbuf_SR2 + tag_dataoffset); + TagProcessed = 1; + break; + case 0x74a1: + CHECKBUFFER_N(tag_dataoffset, 4); + ilm.MaxAp4MinFocal = sgetreal(tag_type, cbuf_SR2 + tag_dataoffset); + TagProcessed = 1; + break; + case 0x74a2: + CHECKBUFFER_N(tag_dataoffset, 4); + ilm.MaxFocal = sgetreal(tag_type, cbuf_SR2 + tag_dataoffset); + TagProcessed = 1; + break; + case 0x74a3: + CHECKBUFFER_N(tag_dataoffset, 4); + ilm.MinFocal = sgetreal(tag_type, cbuf_SR2 + tag_dataoffset); + TagProcessed = 1; + break; + case 0x7800: + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 8, 2); + for (i = 0; i < 3; i++) + { + num = 0.0; + for (c = 0; c < 3; c++) + { + imgdata.color.ccm[i][c] = + (float)((short)sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * (i * 3 + c))); + num += imgdata.color.ccm[i][c]; + } + if (num > 0.01) + FORC3 imgdata.color.ccm[i][c] = imgdata.color.ccm[i][c] / num; + } + TagProcessed = 1; + break; + case 0x787f: + if (tag_datalen == 3) + { + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 2, 2); + FORC3 imgdata.color.linear_max[c] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + imgdata.color.linear_max[3] = imgdata.color.linear_max[1]; + } + else if (tag_datalen == 1) + { + CHECKBUFFER_N(tag_dataoffset, 2); + imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = + imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = + sget2(cbuf_SR2 + tag_dataoffset); + } + TagProcessed = 1; + break; + } + } + + if (!TagProcessed) { + if ((tag_id >= 0x7480) && (tag_id <= 0x7486)) { + i = tag_id - 0x7480; + if (Sony_SR2_wb_list[i] > 255) { + icWBCCTC[WBCTC_count][0] = Sony_SR2_wb_list[i]; + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 2, 2); + FORC3 icWBCCTC[WBCTC_count][c + 1] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + icWBCCTC[WBCTC_count][4] = icWBCCTC[WBCTC_count][2]; + WBCTC_count++; + } else { + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 2, 2); + FORC3 icWBC[Sony_SR2_wb_list[i]][c] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + icWBC[Sony_SR2_wb_list[i]][3] = icWBC[Sony_SR2_wb_list[i]][1]; + } + } else if ((tag_id >= 0x7820) && (tag_id <= 0x782d)) { + i = tag_id - 0x7820; + if (Sony_SR2_wb_list1[i] > 255) { + icWBCCTC[WBCTC_count][0] = Sony_SR2_wb_list1[i]; + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 2, 2); + FORC3 icWBCCTC[WBCTC_count][c + 1] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + icWBCCTC[WBCTC_count][4] = icWBCCTC[WBCTC_count][2]; + if (Sony_SR2_wb_list1[i] == 3200) { + FORC3 icWBC[LIBRAW_WBI_StudioTungsten][c] = icWBCCTC[WBCTC_count][c + 1]; + icWBC[LIBRAW_WBI_StudioTungsten][3] = icWBC[LIBRAW_WBI_StudioTungsten][1]; + } + WBCTC_count++; + } else { + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 2, 2); + FORC3 icWBC[Sony_SR2_wb_list1[i]][c] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + icWBC[Sony_SR2_wb_list1[i]][3] = icWBC[Sony_SR2_wb_list1[i]][1]; + } + } else if (tag_id == 0x7302) { + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 3, 2); + FORC4 icWBC[LIBRAW_WBI_Auto][GRBG_2_RGBG(c)] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + } else if (tag_id == 0x7312) { + CHECKBUFFER_N(tag_dataoffset + tag_dataunitlen * 3, 2); + FORC4 icWBC[LIBRAW_WBI_Auto][RGGB_2_RGBG(c)] = sget2(cbuf_SR2 + tag_dataoffset + tag_dataunitlen * c); + } + } + } + } +} +#undef CHECKBUFFER_N + +void LibRaw::parseSonySRF(unsigned len) +{ + + if ((len > 0xfffff) || (len == 0)) + return; + + INT64 save = ftell(ifp); + INT64 offset = + 0x0310c0 - save; /* for non-DNG this value normally is 0x8ddc */ + if (len < offset || offset < 0) + return; + INT64 decrypt_len = offset >> 2; /* master key offset value is the next + un-encrypted metadata field after SRF0 */ + + unsigned i, nWB; + unsigned MasterKey, SRF2Key; + INT64 srf_offset, tag_offset, tag_dataoffset; + int tag_dataunitlen; + uchar *srf_buf; + ushort entries; + unsigned tag_id, tag_type, tag_datalen; + + srf_buf = (uchar *)malloc(len+64); + fread(srf_buf, len, 1, ifp); + + offset += srf_buf[offset] << 2; + +#define CHECKBUFFER_SGET4(offset) \ + do \ + { \ + if ((((offset) + 4) > len) || ((offset) < 0)) \ + goto restore_after_parseSonySRF; \ + } while (0) + +#define CHECKBUFFER_SGET2(offset) \ + do \ + { \ + if ( ((offset + 2) > len) || ((offset) < 0)) \ + goto restore_after_parseSonySRF; \ + } while (0) + + CHECKBUFFER_SGET4(offset); + + /* master key is stored in big endian */ + MasterKey = ((unsigned)srf_buf[offset] << 24) | + ((unsigned)srf_buf[offset + 1] << 16) | + ((unsigned)srf_buf[offset + 2] << 8) | + (unsigned)srf_buf[offset + 3]; + + /* skip SRF0 */ + srf_offset = 0; + CHECKBUFFER_SGET2(srf_offset); + entries = sget2(srf_buf + srf_offset); + if (entries > 1000) + goto restore_after_parseSonySRF; + offset = srf_offset + 2; + CHECKBUFFER_SGET4(offset); + CHECKBUFFER_SGET4(offset + 12 * entries); + srf_offset = sget4(srf_buf + offset + 12 * entries) - + save; /* SRF0 ends with SRF1 abs. position */ + + /* get SRF1, it has fixed 40 bytes length and contains keys to decode metadata + * and raw data */ + if (srf_offset < 0 || decrypt_len < srf_offset / 4) + goto restore_after_parseSonySRF; + sony_decrypt((unsigned *)(srf_buf + srf_offset), decrypt_len - srf_offset / 4, + 1, MasterKey); + CHECKBUFFER_SGET2(srf_offset); + entries = sget2(srf_buf + srf_offset); + if (entries > 1000) + goto restore_after_parseSonySRF; + offset = srf_offset + 2; + tag_offset = offset; + + while (entries--) { + if (tiff_sget (save, srf_buf, len, + &tag_offset, &tag_id, &tag_type, &tag_dataoffset, + &tag_datalen, &tag_dataunitlen) == 0) { + if (tag_id == 0x0000) { + CHECKBUFFER_SGET4(tag_dataoffset); + SRF2Key = sget4(srf_buf + tag_dataoffset); + } else if (tag_id == 0x0001) { + CHECKBUFFER_SGET4(tag_dataoffset); + /*RawDataKey =*/ sget4(srf_buf + tag_dataoffset); + } + } else goto restore_after_parseSonySRF; + } + offset = tag_offset; + + /* get SRF2 */ + CHECKBUFFER_SGET4(offset); + srf_offset = + sget4(srf_buf + offset) - save; /* SRFn ends with SRFn+1 position */ + if (srf_offset < 0 || decrypt_len < srf_offset / 4) + goto restore_after_parseSonySRF; + sony_decrypt((unsigned *)(srf_buf + srf_offset), decrypt_len - srf_offset / 4, + 1, SRF2Key); + CHECKBUFFER_SGET2(srf_offset); + entries = sget2(srf_buf + srf_offset); + if (entries > 1000) + goto restore_after_parseSonySRF; + offset = srf_offset + 2; + tag_offset = offset; + + while (entries--) { + if (tiff_sget(save, srf_buf, len, + &tag_offset, &tag_id, &tag_type, &tag_dataoffset, + &tag_datalen, &tag_dataunitlen) == 0) { + if ((tag_id >= 0x00c0) && (tag_id <= 0x00ce)) { + i = (tag_id - 0x00c0) % 3; + nWB = (tag_id - 0x00c0) / 3; + CHECKBUFFER_SGET4(tag_dataoffset); + icWBC[Sony_SRF_wb_list[nWB]][i] = sget4(srf_buf + tag_dataoffset); + if (i == 1) { + icWBC[Sony_SRF_wb_list[nWB]][3] = + icWBC[Sony_SRF_wb_list[nWB]][i]; + } + } else if ((tag_id >= 0x00d0) && (tag_id <= 0x00d2)) { + i = (tag_id - 0x00d0) % 3; + CHECKBUFFER_SGET4(tag_dataoffset); + cam_mul[i] = sget4(srf_buf + tag_dataoffset); + if (i == 1) { + cam_mul[3] = cam_mul[i]; + } + } else switch (tag_id) { + /* + 0x0002 SRF6Offset + 0x0003 SRFDataOffset (?) + 0x0004 RawDataOffset + 0x0005 RawDataLength + */ + case 0x0043: + CHECKBUFFER_SGET4(tag_dataoffset); // need to add extra space + ilm.MaxAp4MaxFocal = sgetreal(tag_type, srf_buf + tag_dataoffset); + break; + case 0x0044: + CHECKBUFFER_SGET4(tag_dataoffset); + ilm.MaxAp4MinFocal = sgetreal(tag_type, srf_buf + tag_dataoffset); + break; + case 0x0045: + CHECKBUFFER_SGET4(tag_dataoffset); + ilm.MinFocal = sgetreal(tag_type, srf_buf + tag_dataoffset); + break; + case 0x0046: + CHECKBUFFER_SGET4(tag_dataoffset); + ilm.MaxFocal = sgetreal(tag_type, srf_buf + tag_dataoffset); + break; + } + } else goto restore_after_parseSonySRF; + } + offset = tag_offset; + +restore_after_parseSonySRF: + free(srf_buf); + fseek(ifp, save, SEEK_SET); +#undef CHECKBUFFER_SGET4 +#undef CHECKBUFFER_SGET2 +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/metadata/tiff.cpp libkdcraw/libkdcraw/libraw/src/metadata/tiff.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/metadata/tiff.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/metadata/tiff.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,2011 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" +#include "../../internal/libraw_cameraids.h" + +int LibRaw::parse_tiff_ifd(int base) +{ + unsigned entries, tag, type, len, plen = 16, save, utmp; + int ifd, use_cm = 0, cfa, i, j, c, ima_len = 0; + char *cbuf, *cp; + uchar cfa_pat[16], cfa_pc[] = {0, 1, 2, 3}, tab[256]; + double fm[3][4], cc[4][4], cm[4][3], cam_xyz[4][3], num; + double ab[] = {1, 1, 1, 1}, asn[] = {0, 0, 0, 0}, xyz[] = {1, 1, 1}; + unsigned sony_curve[] = {0, 0, 0, 0, 0, 4095}; + unsigned *buf, sony_offset = 0, sony_length = 0, sony_key = 0; + struct jhead jh; + + ushort *rafdata; + + if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) + return 1; + ifd = tiff_nifds++; + for (j = 0; j < 4; j++) + for (i = 0; i < 4; i++) + cc[j][i] = i == j; + entries = get2(); + if (entries > 512) + return 1; + + INT64 fsize = ifp->size(); + + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + INT64 savepos = ftell(ifp); + if (len > 8 && savepos + len > 2 * fsize) + { + fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! + continue; + } + if (callbacks.exif_cb) + { + callbacks.exif_cb(callbacks.exifparser_data, + tag | (is_pana_raw ? 0x30000 : ((ifd + 1) << 20)), type, + len, order, ifp, base); + fseek(ifp, savepos, SEEK_SET); + } + + if (!is_pana_raw) + { /* processing of EXIF tags that collide w/ PanasonicRaw tags */ + switch (tag) + { + case 0x0001: + if (len == 4) + is_pana_raw = get4(); + break; + case 0x000b: /* 11, Std. EXIF Software tag */ + fgets(software, 64, ifp); + if (!strncmp(software, "Adobe", 5) || !strncmp(software, "dcraw", 5) || + !strncmp(software, "UFRaw", 5) || !strncmp(software, "Bibble", 6) || + !strcmp(software, "Digital Photo Professional")) + is_raw = 0; + break; + case 0x001c: /* 28, safeguard, probably not needed */ + case 0x001d: /* 29, safeguard, probably not needed */ + case 0x001e: /* 30, safeguard, probably not needed */ + cblack[tag - 0x001c] = get2(); + cblack[3] = cblack[1]; + break; + + case 0x0111: /* 273, StripOffset */ + if (len > 1 && len < 16384) + { + off_t sav = ftell(ifp); + tiff_ifd[ifd].strip_offsets = (int *)calloc(len, sizeof(int)); + tiff_ifd[ifd].strip_offsets_count = len; + for (int i = 0; i < (int)len; i++) + tiff_ifd[ifd].strip_offsets[i] = get4() + base; + fseek(ifp, sav, SEEK_SET); // restore position + } + /* fallback */ + case 0x0201: /* 513, JpegIFOffset */ + case 0xf007: // 61447 + tiff_ifd[ifd].offset = get4() + base; + if (!tiff_ifd[ifd].bps && tiff_ifd[ifd].offset > 0) + { + fseek(ifp, tiff_ifd[ifd].offset, SEEK_SET); + if (ljpeg_start(&jh, 1)) + { + tiff_ifd[ifd].comp = 6; + tiff_ifd[ifd].t_width = jh.wide; + tiff_ifd[ifd].t_height = jh.high; + tiff_ifd[ifd].bps = jh.bits; + tiff_ifd[ifd].samples = jh.clrs; + if (!(jh.sraw || (jh.clrs & 1))) + tiff_ifd[ifd].t_width *= jh.clrs; + if ((tiff_ifd[ifd].t_width > 4 * tiff_ifd[ifd].t_height) & ~jh.clrs) + { + tiff_ifd[ifd].t_width /= 2; + tiff_ifd[ifd].t_height *= 2; + } + i = order; + parse_tiff(tiff_ifd[ifd].offset + 12); + order = i; + } + } + break; + } + } + else + { /* processing Panasonic-specific "PanasonicRaw" tags */ + switch (tag) + { + case 0x0004: /* 4, SensorTopBorder */ + imgdata.sizes.raw_inset_crop.ctop = get2(); + break; + case 0x000a: /* 10, BitsPerSample */ + pana_bpp = get2(); + break; + case 0x000b: /* 11, Compression */ + imPana.Compression = get2(); + break; + case 0x000e: /* 14, LinearityLimitRed */ + case 0x000f: /* 15, LinearityLimitGreen */ + case 0x0010: /* 16, LinearityLimitBlue */ + imgdata.color.linear_max[tag - 14] = get2(); + if (tag == 0x000f) // 15, LinearityLimitGreen + imgdata.color.linear_max[3] = imgdata.color.linear_max[1]; + break; + case 0x0013: /* 19, WBInfo */ + if ((i = get2()) > 0x100) + break; + for (c = 0; c < i; c++) + { + if ((j = get2()) < 0x100) + { + icWBC[j][0] = get2(); + icWBC[j][2] = get2(); + icWBC[j][1] = icWBC[j][3] = + 0x100; + } + else // light source out of EXIF numbers range + get4(); + } + break; + case 0x0018: /* 24, HighISOMultiplierRed */ + case 0x0019: /* 25, HighISOMultiplierGreen */ + case 0x001a: /* 26, HighISOMultiplierBlue */ + imPana.HighISOMultiplier[tag - 0x0018] = get2(); + break; + case 0x001c: /* 28, BlackLevelRed */ + case 0x001d: /* 29, BlackLevelGreen */ + case 0x001e: /* 30, BlackLevelBlue */ + pana_black[tag - 0x001c] = get2(); + break; + case 0x002d: /* 45, RawFormat */ + /* pana_encoding: tag 0x002d (45dec) + not used - DMC-LX1/FZ30/FZ50/L1/LX1/LX2 + 2 - RAW DMC-FZ8/FZ18 + 3 - RAW DMC-L10 + 4 - RW2 for most other models, including G9 in "pixel shift off" + mode and YUNEEC CGO4 (must add 15 to black levels for + RawFormat == 4) 5 - RW2 DC-GH5s; G9 in "pixel shift on" + mode 6 - RW2 DC-S1, DC-S1R in "pixel shift off" + mode 7 - RW2 DC-S1R (probably DC-S1 too) in + "pixel shift on" mode + */ + pana_encoding = get2(); + break; + case 0x002f: /* 47, CropTop */ + imgdata.sizes.raw_inset_crop.ctop = get2(); + break; + case 0x0030: /* 48, CropLeft */ + imgdata.sizes.raw_inset_crop.cleft = get2(); + break; + case 0x0031: /* 49, CropBottom */ + imgdata.sizes.raw_inset_crop.cheight = + get2() - imgdata.sizes.raw_inset_crop.ctop; + break; + case 0x0032: /* 50, CropRight */ + imgdata.sizes.raw_inset_crop.cwidth = + get2() - imgdata.sizes.raw_inset_crop.cleft; + break; + case 0x0037: /* 55, ISO if ISO in 0x8827 & ISO in 0x0017 == 65535 */ + if (iso_speed == 65535) + iso_speed = get4(); + break; + case 0x011c: /* 284, Gamma */ + { + int n = get2(); + if (n >= 1024) + imPana.gamma = (float)n / 1024.0f; + else if (n >= 256) + imPana.gamma = (float)n / 256.0f; + else + imPana.gamma = (float)n / 100.0f; + } + break; + case 0x0120: /* 288, CameraIFD, contains tags 0x1xxx, 0x2xxx, 0x3xxx */ + { + unsigned sorder = order; + unsigned long sbase = base; + base = ftell(ifp); + order = get2(); + fseek(ifp, 2, SEEK_CUR); + fseek(ifp, get4() - 8, SEEK_CUR); + parse_tiff_ifd(base); + base = sbase; + order = sorder; + } + break; + case 0x0121: /* 289, Multishot, 0 is Off, 65536 is Pixel Shift */ + imPana.Multishot = get4(); + break; + case 0x1201: + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT)) { + ilm.LensID = fgetc(ifp); + if (ilm.LensID && (ilm.LensID != 0xff)) ilm.LensID <<= 16; + } else if (type == 258) { + unsigned n = get4(); + if (n == 257) { + ilm.LensMount = LIBRAW_MOUNT_LPS_L; + ilm.LensFormat = LIBRAW_FORMAT_FF; + } + } + break; + case 0x1202: + if (ilm.LensID != 0xffffffffffffffff) { + utmp = (fgetc(ifp) << 8) | fgetc(ifp); + if (utmp) ilm.LensID += utmp; + else ilm.LensID = 0xffffffffffffffff; + } + break; + case 0x1203: /* 4611, FocalLengthIn35mmFormat, contained in 0x0120 + CameraIFD */ + if (imgdata.lens.FocalLengthIn35mmFormat < 0.65f) + imgdata.lens.FocalLengthIn35mmFormat = get2(); + break; + case 0x2009: /* 8201, contained in 0x0120 CameraIFD */ + if ((pana_encoding == 4) || (pana_encoding == 5)) + { + i = MIN(8, len); + int permut[8] = {3, 2, 1, 0, 3 + 4, 2 + 4, 1 + 4, 0 + 4}; + imPana.BlackLevelDim = len; + for (j = 0; j < i; j++) + { + imPana.BlackLevel[permut[j]] = + (float)(get2()) / (float)(powf(2.f, 14.f - pana_bpp)); + } + } + break; + case 0x3420: /* 13344, WB_RedLevelAuto, contained in 0x0120 CameraIFD */ + icWBC[LIBRAW_WBI_Auto][0] = get2(); + icWBC[LIBRAW_WBI_Auto][1] = icWBC[LIBRAW_WBI_Auto][3] = 1024.0f; + break; + case 0x3421: /* 13345, WB_BlueLevelAuto, contained in 0x0120 CameraIFD */ + icWBC[LIBRAW_WBI_Auto][2] = get2(); + break; + case 0x0002: /* 2, ImageWidth */ + tiff_ifd[ifd].t_width = getint(type); + break; + case 0x0003: /* 3, ImageHeight */ + tiff_ifd[ifd].t_height = getint(type); + break; + case 0x0005: /* 5, SensorLeftBorder */ + width = get2(); + imgdata.sizes.raw_inset_crop.cleft = width; + break; + case 0x0006: /* 6, SensorBottomBorder */ + height = get2(); + imgdata.sizes.raw_inset_crop.cheight = + height - imgdata.sizes.raw_inset_crop.ctop; + break; + case 0x0007: /* 7, SensorRightBorder */ + i = get2(); + width += i; + imgdata.sizes.raw_inset_crop.cwidth = + i - imgdata.sizes.raw_inset_crop.cleft; + break; + case 0x0009: /* 9, CFAPattern */ + if ((i = get2())) + filters = i; + break; + case 0x0011: /* 17, RedBalance */ + case 0x0012: /* 18, BlueBalance */ + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) && len == 1) + cam_mul[(tag - 0x0011) * 2] = get2() / 256.0; + break; + case 0x0017: /* 23, ISO */ + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT)) + iso_speed = get2(); + break; + case 0x0024: /* 36, WBRedLevel */ + case 0x0025: /* 37, WBGreenLevel */ + case 0x0026: /* 38, WBBlueLevel */ + cam_mul[tag - 0x0024] = get2(); + break; + case 0x0027: /* 39, WBInfo2 */ + if ((i = get2()) > 0x100) + break; + for (c = 0; c < i; c++) + { + if ((j = get2()) < 0x100) + { + icWBC[j][0] = get2(); + icWBC[j][1] = icWBC[j][3] = get2(); + icWBC[j][2] = get2(); + } + else + fseek(ifp, 6, SEEK_CUR); + } + break; + if (len < 50 || cam_mul[0] > 0.001f) + break; + fseek(ifp, 12, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + break; + case 0x002e: /* 46, JpgFromRaw */ + if ((type != LIBRAW_EXIFTAG_TYPE_UNDEFINED) || (fgetc(ifp) != 0xff) || (fgetc(ifp) != 0xd8)) + break; + thumb_offset = ftell(ifp) - 2; + thumb_length = len; + break; + + case 0x0118: /* 280, Panasonic RW2 offset */ + if (type != LIBRAW_EXIFTAG_TYPE_LONG) + break; + load_raw = &LibRaw::panasonic_load_raw; + load_flags = 0x2008; + case 0x0111: /* 273, StripOffset */ + if (len > 1 && len < 16384) + { + off_t sav = ftell(ifp); + tiff_ifd[ifd].strip_offsets = (int *)calloc(len, sizeof(int)); + tiff_ifd[ifd].strip_offsets_count = len; + for (int i = 0; i < (int)len; i++) + tiff_ifd[ifd].strip_offsets[i] = get4() + base; + fseek(ifp, sav, SEEK_SET); // restore position + } + /* fallthrough */ + tiff_ifd[ifd].offset = get4() + base; + if (!tiff_ifd[ifd].bps && tiff_ifd[ifd].offset > 0) + { + fseek(ifp, tiff_ifd[ifd].offset, SEEK_SET); + if (ljpeg_start(&jh, 1)) + { + tiff_ifd[ifd].comp = 6; + tiff_ifd[ifd].t_width = jh.wide; + tiff_ifd[ifd].t_height = jh.high; + tiff_ifd[ifd].bps = jh.bits; + tiff_ifd[ifd].samples = jh.clrs; + if (!(jh.sraw || (jh.clrs & 1))) + tiff_ifd[ifd].t_width *= jh.clrs; + if ((tiff_ifd[ifd].t_width > 4 * tiff_ifd[ifd].t_height) & ~jh.clrs) + { + tiff_ifd[ifd].t_width /= 2; + tiff_ifd[ifd].t_height *= 2; + } + i = order; + parse_tiff(tiff_ifd[ifd].offset + 12); + order = i; + } + } + break; + } + + } /* processing of Panasonic-specific tags finished */ + + switch (tag) + { /* processing of general EXIF tags */ + case 0xf000: /* 61440, Fuji HS10 table */ + fseek(ifp, get4() + base, SEEK_SET); + parse_tiff_ifd(base); + break; + case 0x00fe: /* NewSubfileType */ + tiff_ifd[ifd].newsubfiletype = getreal(type); + break; + case 0x0100: /* 256, ImageWidth */ + case 0xf001: /* 61441, Fuji RAF IFD 0xf001 RawImageFullWidth */ + tiff_ifd[ifd].t_width = getint(type); + break; + case 0x0101: /* 257, ImageHeight */ + case 0xf002: /* 61442, Fuji RAF IFD 0xf002 RawImageFullHeight */ + tiff_ifd[ifd].t_height = getint(type); + break; + case 0x0102: /* 258, BitsPerSample */ + case 0xf003: /* 61443, Fuji RAF IFD 0xf003 */ + tiff_ifd[ifd].samples = len & 7; + tiff_ifd[ifd].bps = getint(type); + if (tiff_bps < (unsigned)tiff_ifd[ifd].bps) + tiff_bps = tiff_ifd[ifd].bps; + break; + case 0xf006: /* 61446, Fuji RAF IFD 0xf006 */ + raw_height = 0; + if (tiff_ifd[ifd].bps > 12) + break; + load_raw = &LibRaw::packed_load_raw; + load_flags = get4() ? 24 : 80; + break; + case 0x0103: /* 259, Compression */ + /* + 262 = Kodak 262 + 32767 = Sony ARW Compressed + 32769 = Packed RAW + 32770 = Samsung SRW Compressed + 32772 = Samsung SRW Compressed 2 + 32867 = Kodak KDC Compressed + 34713 = Nikon NEF Compressed + 65000 = Kodak DCR Compressed + 65535 = Pentax PEF Compressed + */ + tiff_ifd[ifd].comp = getint(type); + break; + case 0x0106: /* 262, PhotometricInterpretation */ + tiff_ifd[ifd].phint = get2(); + break; + case 0x010e: /* 270, ImageDescription */ + fread(desc, 512, 1, ifp); + break; + case 0x010f: /* 271, Make */ + fgets(make, 64, ifp); + break; + case 0x0110: /* 272, Model */ + if (!strncmp(make, "Hasselblad", 10) && model[0] && + (imHassy.format != LIBRAW_HF_Imacon)) + break; + fgets(model, 64, ifp); + break; + case 0x0116: // 278 + tiff_ifd[ifd].rows_per_strip = getint(type); + break; + case 0x0112: /* 274, Orientation */ + tiff_ifd[ifd].t_flip = "50132467"[get2() & 7] - '0'; + break; + case 0x0115: /* 277, SamplesPerPixel */ + tiff_ifd[ifd].samples = getint(type) & 7; + break; + case 0x0152: /* Extrasamples */ + tiff_ifd[ifd].extrasamples = (getint(type) & 0xff) + 1024; + break; + case 0x0117: /* 279, StripByteCounts */ + if (len > 1 && len < 16384) + { + off_t sav = ftell(ifp); + tiff_ifd[ifd].strip_byte_counts = (int *)calloc(len, sizeof(int)); + tiff_ifd[ifd].strip_byte_counts_count = len; + for (int i = 0; i < (int)len; i++) + tiff_ifd[ifd].strip_byte_counts[i] = get4(); + fseek(ifp, sav, SEEK_SET); // restore position + } + /* fallback */ + case 0x0202: // 514 + case 0xf008: // 61448 + tiff_ifd[ifd].bytes = get4(); + break; + case 0xf00e: // 61454, FujiFilm "As Shot" + FORC3 cam_mul[(4 - c) % 3] = getint(type); + break; + case 0x0131: /* 305, Software */ + fgets(software, 64, ifp); + if (!strncmp(software, "Adobe", 5) || !strncmp(software, "dcraw", 5) || + !strncmp(software, "UFRaw", 5) || !strncmp(software, "Bibble", 6) || + !strcmp(software, "Digital Photo Professional")) + is_raw = 0; + break; + case 0x0132: /* 306, DateTime */ + get_timestamp(0); + break; + case 0x013b: /* 315, Artist */ + fread(artist, 64, 1, ifp); + break; + case 0x013d: // 317 + tiff_ifd[ifd].predictor = getint(type); + break; + case 0x0142: /* 322, TileWidth */ + tiff_ifd[ifd].t_tile_width = getint(type); + break; + case 0x0143: /* 323, TileLength */ + tiff_ifd[ifd].t_tile_length = getint(type); + break; + case 0x0144: /* 324, TileOffsets */ + tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); + if (len == 1) + tiff_ifd[ifd].t_tile_width = tiff_ifd[ifd].t_tile_length = 0; + if (len == 4) + { + load_raw = &LibRaw::sinar_4shot_load_raw; + is_raw = 5; + } + break; + case 0x0145: // 325 + tiff_ifd[ifd].bytes = len > 1 ? ftell(ifp) : get4(); + break; + case 0x014a: /* 330, SubIFDs */ + if (!strcmp(model, "DSLR-A100") && tiff_ifd[ifd].t_width == 3872) + { + load_raw = &LibRaw::sony_arw_load_raw; + data_offset = get4() + base; + ifd++; + if (ifd >= int(sizeof tiff_ifd / sizeof tiff_ifd[0])) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + break; + } + if (!strncmp(make, "Hasselblad", 10) && + libraw_internal_data.unpacker_data.hasselblad_parser_flag) + { + fseek(ifp, ftell(ifp) + 4, SEEK_SET); + fseek(ifp, get4() + base, SEEK_SET); + parse_tiff_ifd(base); + break; + } + if (len > 1000) + len = 1000; /* 1000 SubIFDs is enough */ + while (len--) + { + i = ftell(ifp); + fseek(ifp, get4() + base, SEEK_SET); + if (parse_tiff_ifd(base)) + break; + fseek(ifp, i + 4, SEEK_SET); + } + break; + case 0x0153: // 339 + tiff_ifd[ifd].sample_format = getint(type); + break; + case 0x0190: // 400 + strcpy(make, "Sarnoff"); + maximum = 0xfff; + break; + case 0x02bc: // 700 + if ((tagtypeIs(LIBRAW_EXIFTAG_TYPE_BYTE) || + tagtypeIs(LIBRAW_EXIFTAG_TYPE_ASCII) || + tagtypeIs(LIBRAW_EXIFTAG_TYPE_SBYTE) || + tagtypeIs(LIBRAW_EXIFTOOLTAGTYPE_binary)) && + (len > 1) && (len < 5100000)) + { + xmpdata = (char *)malloc(xmplen = len + 1); + fread(xmpdata, len, 1, ifp); + xmpdata[len] = 0; + } + break; + case 0x7000: + imSony.SonyRawFileType = get2(); + break; + case 0x7010: // 28688 + FORC4 sony_curve[c + 1] = get2() >> 2 & 0xfff; + for (i = 0; i < 5; i++) + for (j = sony_curve[i] + 1; j <= (int)sony_curve[i + 1]; j++) + curve[j] = curve[j - 1] + (1 << i); + break; + case 0x7200: // 29184, Sony SR2Private + sony_offset = get4(); + break; + case 0x7201: // 29185, Sony SR2Private + sony_length = get4(); + break; + case 0x7221: // 29217, Sony SR2Private + sony_key = get4(); + break; + case 0x7250: // 29264, Sony SR2Private + parse_minolta(ftell(ifp)); + raw_width = 0; + break; + case 0x7303: // 29443, Sony SR2SubIFD + FORC4 cam_mul[GRBG_2_RGBG(c)] = get2(); + break; + case 0x7313: // 29459, Sony SR2SubIFD + FORC4 cam_mul[RGGB_2_RGBG(c)] = get2(); + break; + case 0x7310: // 29456, Sony SR2SubIFD + FORC4 cblack[RGGB_2_RGBG(c)] = get2(); + i = cblack[3]; + FORC3 if (i > (int)cblack[c]) i = cblack[c]; + FORC4 cblack[c] -= i; + black = i; + break; + case 0x827d: /* 33405, Model2 */ + /* + for Kodak ProBack 645 PB645x-yyyy 'x' is: + 'M' for Mamiya 645 + 'C' for Contax 645 + 'H' for Hasselblad H-series + */ + fgets(model2, 64, ifp); + break; + case 0x828d: /* 33421, CFARepeatPatternDim */ + if (get2() == 6 && get2() == 6) + tiff_ifd[ifd].t_filters = filters = 9; + break; + case 0x828e: /* 33422, CFAPattern */ + if (filters == 9) + { + FORC(36)((char *)xtrans)[c] = fgetc(ifp) & 3; + break; + } + case 0xfd09: /* 64777, Kodak P-series */ + if (len == 36) + { + tiff_ifd[ifd].t_filters = filters = 9; + colors = 3; + FORC(36) xtrans[0][c] = fgetc(ifp) & 3; + } + else if (len > 0) + { + if ((plen = len) > 16) + plen = 16; + fread(cfa_pat, 1, plen, ifp); + for (colors = cfa = i = 0; i < (int)plen && colors < 4; i++) + { + if (cfa_pat[i] > 31) + continue; // Skip wrong data + colors += !(cfa & (1 << cfa_pat[i])); + cfa |= 1 << cfa_pat[i]; + } + if (cfa == 070) + memcpy(cfa_pc, "\003\004\005", 3); /* CMY */ + if (cfa == 072) + memcpy(cfa_pc, "\005\003\004\001", 4); /* GMCY */ + goto guess_cfa_pc; + } + break; + case 0x8290: // 33424 + case 0xfe00: // 65024 + fseek(ifp, get4() + base, SEEK_SET); + parse_kodak_ifd(base); + break; + case 0x829a: /* 33434, ExposureTime */ + tiff_ifd[ifd].t_shutter = shutter = getreal(type); + break; + case 0x829d: /* 33437, FNumber */ + aperture = getreal(type); + break; + case 0x9400: + imCommon.exifAmbientTemperature = getreal(type); + if ((imCommon.CameraTemperature > -273.15f) && + ((OlyID == OlyID_TG_5) || (OlyID == OlyID_TG_6))) + imCommon.CameraTemperature += + imCommon.exifAmbientTemperature; + break; + case 0x9401: + imCommon.exifHumidity = getreal(type); + break; + case 0x9402: + imCommon.exifPressure = getreal(type); + break; + case 0x9403: + imCommon.exifWaterDepth = getreal(type); + break; + case 0x9404: + imCommon.exifAcceleration = getreal(type); + break; + case 0x9405: + imCommon.exifCameraElevationAngle = getreal(type); + break; + case 0xa405: // FocalLengthIn35mmFormat + imgdata.lens.FocalLengthIn35mmFormat = get2(); + break; + case 0xa431: // BodySerialNumber + case 0xc62f: + stmread(imgdata.shootinginfo.BodySerial, len, ifp); + break; + case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard + imgdata.lens.MinFocal = getreal(type); + imgdata.lens.MaxFocal = getreal(type); + imgdata.lens.MaxAp4MinFocal = getreal(type); + imgdata.lens.MaxAp4MaxFocal = getreal(type); + break; + case 0xa435: // LensSerialNumber + stmread(imgdata.lens.LensSerial, len, ifp); + break; + case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard + imgdata.lens.MinFocal = getreal(type); + imgdata.lens.MaxFocal = getreal(type); + imgdata.lens.MaxAp4MinFocal = getreal(type); + imgdata.lens.MaxAp4MaxFocal = getreal(type); + break; + case 0xa420: /* 42016, ImageUniqueID */ + stmread(imgdata.color.ImageUniqueID, len, ifp); + break; + case 0xc65d: /* 50781, RawDataUniqueID */ + imgdata.color.RawDataUniqueID[16] = 0; + fread(imgdata.color.RawDataUniqueID, 1, 16, ifp); + break; + case 0xa433: // LensMake + stmread(imgdata.lens.LensMake, len, ifp); + break; + case 0xa434: // LensModel + stmread(imgdata.lens.Lens, len, ifp); + if (!strncmp(imgdata.lens.Lens, "----", 4)) + imgdata.lens.Lens[0] = 0; + break; + case 0x9205: + imgdata.lens.EXIF_MaxAp = libraw_powf64l(2.0f, (getreal(type) / 2.0f)); + break; + case 0x8602: /* 34306, Leaf white balance */ + FORC4 + { + int q = get2(); + if (q) + cam_mul[GRGB_2_RGBG(c)] = 4096.0 / q; + } + break; + case 0x8603: /* 34307, Leaf CatchLight color matrix */ + fread(software, 1, 7, ifp); + if (strncmp(software, "MATRIX", 6)) + break; + colors = 4; + for (raw_color = i = 0; i < 3; i++) + { + FORC4 fscanf(ifp, "%f", &rgb_cam[i][GRGB_2_RGBG(c)]); + if (!use_camera_wb) + continue; + num = 0; + FORC4 num += rgb_cam[i][c]; + FORC4 rgb_cam[i][c] /= MAX(1, num); + } + break; + case 0x8606: /* 34310, Leaf metadata */ + parse_mos(ftell(ifp)); + case 0x85ff: // 34303 + strcpy(make, "Leaf"); + break; + case 0x8769: /* 34665, EXIF tag */ + fseek(ifp, get4() + base, SEEK_SET); + parse_exif(base); + break; + case 0x8825: /* 34853, GPSInfo tag */ + { + unsigned pos; + fseek(ifp, pos = (get4() + base), SEEK_SET); + parse_gps(base); + fseek(ifp, pos, SEEK_SET); + parse_gps_libraw(base); + } + break; + case 0x8773: /* 34675, InterColorProfile */ + case 0xc68f: /* 50831, AsShotICCProfile */ + profile_offset = ftell(ifp); + profile_length = len; + break; + case 0x9102: /* 37122, CompressedBitsPerPixel */ + kodak_cbpp = get4(); + break; + case 0x920a: /* 37386, FocalLength */ + focal_len = getreal(type); + break; + case 0x9211: /* 37393, ImageNumber */ + shot_order = getint(type); + break; + case 0x9215: /* 37397, ExposureIndex */ + imCommon.exifExposureIndex = getreal(type); + break; + case 0x9218: /* 37400, old Kodak KDC tag */ + for (raw_color = i = 0; i < 3; i++) + { + getreal(type); + FORC3 rgb_cam[i][c] = getreal(type); + } + break; + case 0xa010: // 40976 + strip_offset = get4(); + switch (tiff_ifd[ifd].comp) + { + case 0x8002: // 32770 + load_raw = &LibRaw::samsung_load_raw; + break; + case 0x8004: // 32772 + load_raw = &LibRaw::samsung2_load_raw; + break; + case 0x8005: // 32773 + load_raw = &LibRaw::samsung3_load_raw; + break; + } + break; + case 0xb4c3: /* 46275, Imacon tags */ + imHassy.format = LIBRAW_HF_Imacon; + strcpy(make, "Imacon"); + data_offset = ftell(ifp); + ima_len = len; + break; + case 0xb4c7: // 46279 + if (!ima_len) + break; + fseek(ifp, 38, SEEK_CUR); + case 0xb4c2: // 46274 + fseek(ifp, 40, SEEK_CUR); + raw_width = get4(); + raw_height = get4(); + left_margin = get4() & 7; + width = raw_width - left_margin - (get4() & 7); + top_margin = get4() & 7; + height = raw_height - top_margin - (get4() & 7); + if (raw_width == 7262 && ima_len == 234317952) + { + height = 5412; + width = 7216; + left_margin = 7; + filters = 0; + } + else if (raw_width == 7262) + { + height = 5444; + width = 7244; + left_margin = 7; + } + fseek(ifp, 52, SEEK_CUR); + FORC3 cam_mul[c] = getreal(11); + fseek(ifp, 114, SEEK_CUR); + flip = (get2() >> 7) * 90; + if (width * (height * 6l) == ima_len) + { + if (flip % 180 == 90) + SWAP(width, height); + raw_width = width; + raw_height = height; + left_margin = top_margin = filters = flip = 0; + } + c = unsigned(height) * unsigned(width) / 1000000; + if (c == 32) + c--; + sprintf(model, "Ixpress %d-Mp", c); + load_raw = &LibRaw::imacon_full_load_raw; + if (filters) + { + if (left_margin & 1) + filters = 0x61616161; + load_raw = &LibRaw::unpacked_load_raw; + } + maximum = 0xffff; + break; + case 0xc516: /* 50454, Sinar tag */ + case 0xc517: // 50455 + if (len < 1 || len > 2560000 || !(cbuf = (char *)malloc(len))) + break; + if (fread(cbuf, 1, len, ifp) != (int)len) + throw LIBRAW_EXCEPTION_IO_CORRUPT; // cbuf to be free'ed in recycle + cbuf[len - 1] = 0; + for (cp = cbuf - 1; cp && cp < cbuf + len; cp = strchr(cp, '\n')) + if (!strncmp(++cp, "Neutral ", 8)) + sscanf(cp + 8, "%f %f %f", cam_mul, cam_mul + 1, cam_mul + 2); + free(cbuf); + break; + case 0xc51a: // 50458 + if (!make[0]) + strcpy(make, "Hasselblad"); + break; + case 0xc51b: /* 50459, Hasselblad tag */ + if (!libraw_internal_data.unpacker_data.hasselblad_parser_flag) + { + libraw_internal_data.unpacker_data.hasselblad_parser_flag = 1; + i = order; + j = ftell(ifp); + c = tiff_nifds; + order = get2(); + fseek(ifp, j + (get2(), get4()), SEEK_SET); + parse_tiff_ifd(j); + maximum = 0xffff; + tiff_nifds = c; + order = i; + break; + } + case 0xc612: /* 50706, DNGVersion */ + FORC4 dng_version = (dng_version << 8) + fgetc(ifp); + if (!make[0]) + strcpy(make, "DNG"); + is_raw = 1; + break; + case 0xc614: /* 50708, UniqueCameraModel */ + stmread(imgdata.color.UniqueCameraModel, len, ifp); + if (model[0]) + break; + strncpy(make, imgdata.color.UniqueCameraModel, + MIN(len, sizeof(imgdata.color.UniqueCameraModel))); + if ((cp = strchr(make, ' '))) + { + strcpy(model, cp + 1); + *cp = 0; + } + break; + case 0xc616: /* 50710, CFAPlaneColor */ + if (filters == 9) + break; + if (len > 4) + len = 4; + colors = len; + fread(cfa_pc, 1, colors, ifp); + guess_cfa_pc: + FORCC tab[cfa_pc[c]] = c; + cdesc[c] = 0; + for (i = 16; i--;) + filters = filters << 2 | tab[cfa_pat[i % plen]]; + filters -= !filters; + tiff_ifd[ifd].t_filters = filters; + break; + case 0xc617: /* 50711, CFALayout */ + if (get2() == 2) + tiff_ifd[ifd].t_fuji_width = fuji_width = 1; + break; + case 0x0123: // 291 + case 0xc618: /* 50712, LinearizationTable */ + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_LINTABLE; + tiff_ifd[ifd].lineartable_offset = ftell(ifp); + tiff_ifd[ifd].lineartable_len = len; + linear_table(len); + break; + case 0xc619: /* 50713, BlackLevelRepeatDim */ + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_BLACK; + tiff_ifd[ifd].dng_levels.dng_fcblack[4] = + tiff_ifd[ifd].dng_levels.dng_cblack[4] = cblack[4] = get2(); + tiff_ifd[ifd].dng_levels.dng_fcblack[5] = + tiff_ifd[ifd].dng_levels.dng_cblack[5] = cblack[5] = get2(); + if (cblack[4] * cblack[5] > + (LIBRAW_CBLACK_SIZE - + 7)) // Use last cblack item as DNG black level count + tiff_ifd[ifd].dng_levels.dng_fcblack[4] = + tiff_ifd[ifd].dng_levels.dng_fcblack[5] = + tiff_ifd[ifd].dng_levels.dng_cblack[4] = + tiff_ifd[ifd].dng_levels.dng_cblack[5] = cblack[4] = + cblack[5] = 1; + break; + + case 0xf00c: + if (!is_4K_RAFdata) + { + unsigned fwb[4]; + FORC4 fwb[c] = get4(); + if (fwb[3] < 0x100) + { + icWBC[fwb[3]][0] = fwb[1]; + icWBC[fwb[3]][1] = icWBC[fwb[3]][3] = fwb[0]; + icWBC[fwb[3]][2] = fwb[2]; + if ((fwb[3] == 17) && + (libraw_internal_data.unpacker_data.lenRAFData > 3) && + (libraw_internal_data.unpacker_data.lenRAFData < 10240000)) + { + INT64 f_save = ftell(ifp); + rafdata = (ushort *)malloc( + sizeof(ushort) * libraw_internal_data.unpacker_data.lenRAFData); + fseek(ifp, libraw_internal_data.unpacker_data.posRAFData, SEEK_SET); + fread(rafdata, sizeof(ushort), + libraw_internal_data.unpacker_data.lenRAFData, ifp); + fseek(ifp, f_save, SEEK_SET); + + uchar *PrivateMknBuf = (uchar *)rafdata; + int PrivateMknLength = libraw_internal_data.unpacker_data.lenRAFData + << 1; + for (int pos = 0; pos < PrivateMknLength - 16; pos++) + { + if (!memcmp(PrivateMknBuf + pos, "TSNERDTS", 8)) + { + imFuji.isTSNERDTS = 1; + break; + } + } + + /* 0xc000 tag version, second ushort; valid if the first ushort is 0 + */ + if (!rafdata[0]) + imFuji.RAFDataVersion = rafdata[1]; + int fj; + for (int fi = 0; + fi < int(libraw_internal_data.unpacker_data.lenRAFData - 3); fi++) + { // find Tungsten WB + if ((fwb[0] == rafdata[fi]) && (fwb[1] == rafdata[fi + 1]) && + (fwb[2] == rafdata[fi + 2])) + { + if (rafdata[fi - 15] != + fwb[0]) // 15 is offset of Tungsten WB from the first + // preset, Fine Weather WB + continue; + for (int wb_ind = 0, ofst = fi - 15; wb_ind < Fuji_wb_list1.size(); + wb_ind++, ofst += 3) + { + icWBC[Fuji_wb_list1[wb_ind]][1] = + icWBC[Fuji_wb_list1[wb_ind]][3] = rafdata[ofst]; + icWBC[Fuji_wb_list1[wb_ind]][0] = rafdata[ofst + 1]; + icWBC[Fuji_wb_list1[wb_ind]][2] = rafdata[ofst + 2]; + } + + if ((imFuji.RAFDataVersion == 0x0260) || // X-Pro3 + (imFuji.RAFDataVersion == 0x0261) || // X100V + (imFuji.RAFDataVersion == 0x0262)) // X-T4 + fi += 24; + fi += 96; + for (fj = fi; fj < (fi + 15); fj += 3) + { + if (rafdata[fj] != rafdata[fi]) + { + fj -= 93; +// X-Pro3 has 34 CCT values instead of 31, manual still clames 2500 to 10000 K +// aligned 3000 K to Incandescent, as it is usual w/ other Fujifilm cameras + if ((imFuji.RAFDataVersion == 0x0260) || // X-Pro3 + (imFuji.RAFDataVersion == 0x0261) || // X100V + (imFuji.RAFDataVersion == 0x0262)) // X-T4 + fj -= 9; + for (int iCCT = 0, ofst = fj; iCCT < 31; + iCCT++, ofst += 3) + { + icWBCCTC[iCCT][0] = FujiCCT_K[iCCT]; + icWBCCTC[iCCT][1] = rafdata[ofst + 1]; + icWBCCTC[iCCT][2] = icWBCCTC[iCCT][4] = rafdata[ofst]; + icWBCCTC[iCCT][3] = rafdata[ofst + 2]; + } + break; + } + } + free(rafdata); + break; + } + } + } + } + FORC4 fwb[c] = get4(); + if (fwb[3] < 0x100) + { + icWBC[fwb[3]][0] = fwb[1]; + icWBC[fwb[3]][1] = + icWBC[fwb[3]][3] = fwb[0]; + icWBC[fwb[3]][2] = fwb[2]; + } + } + break; + case 0xf00d: + if (!is_4K_RAFdata) + { + FORC3 icWBC[LIBRAW_WBI_Auto][(4 - c) % 3] = getint(type); + icWBC[LIBRAW_WBI_Auto][3] = icWBC[LIBRAW_WBI_Auto][1]; + // free(rafdata); + } + break; + case 0xc615: /* 50709, LocalizedCameraModel */ + stmread(imgdata.color.LocalizedCameraModel, len, ifp); + break; + case 0xf00a: // 61450 + cblack[4] = cblack[5] = MIN(sqrt((double)len), 64); + case 0xc61a: /* 50714, BlackLevel */ + if (tiff_ifd[ifd].samples > 1 && + tiff_ifd[ifd].samples == (int)len) // LinearDNG, per-channel black + { + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_BLACK; + for (i = 0; i < 4 && i < (int)len; i++) + { + tiff_ifd[ifd].dng_levels.dng_fcblack[i] = getreal(type); + tiff_ifd[ifd].dng_levels.dng_cblack[i] = cblack[i] = + tiff_ifd[ifd].dng_levels.dng_fcblack[i] + 0.5; + } + + tiff_ifd[ifd].dng_levels.dng_fblack = + tiff_ifd[ifd].dng_levels.dng_black = black = 0; + } + else if (tiff_ifd[ifd].samples > 1 // Linear DNG w repeat dim + && (tiff_ifd[ifd].samples * cblack[4] * cblack[5] == len)) + { + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_BLACK; + tiff_ifd[ifd].dng_levels.dng_cblack[LIBRAW_CBLACK_SIZE - 1] = + cblack[LIBRAW_CBLACK_SIZE - 1] = len; + for (i = 0; i < (int)len && i < LIBRAW_CBLACK_SIZE - 7; i++) + { + tiff_ifd[ifd].dng_levels.dng_fcblack[i + 6] = getreal(type); + tiff_ifd[ifd].dng_levels.dng_cblack[i + 6] = cblack[i + 6] = + tiff_ifd[ifd].dng_levels.dng_fcblack[i + 6] + 0.5; + } + } + else if ((cblack[4] * cblack[5] < 2) && len == 1) + { + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_BLACK; + tiff_ifd[ifd].dng_levels.dng_fblack = getreal(type); + black = tiff_ifd[ifd].dng_levels.dng_black = + tiff_ifd[ifd].dng_levels.dng_fblack; + } + else if (cblack[4] * cblack[5] <= len) + { + FORC(int(cblack[4] * cblack[5])) + { + tiff_ifd[ifd].dng_levels.dng_fcblack[6 + c] = getreal(type); + cblack[6 + c] = tiff_ifd[ifd].dng_levels.dng_fcblack[6 + c]; + } + black = 0; + FORC4 + cblack[c] = 0; + + if (tag == 0xc61a) + { + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_BLACK; + FORC(int(cblack[4] * cblack[5])) + tiff_ifd[ifd].dng_levels.dng_cblack[6 + c] = cblack[6 + c]; + tiff_ifd[ifd].dng_levels.dng_fblack = 0; + tiff_ifd[ifd].dng_levels.dng_black = 0; + FORC4 + tiff_ifd[ifd].dng_levels.dng_fcblack[c] = + tiff_ifd[ifd].dng_levels.dng_cblack[c] = 0; + } + } + break; + case 0xc61b: /* 50715, BlackLevelDeltaH */ + case 0xc61c: /* 50716, BlackLevelDeltaV */ + for (num = i = 0; i < (int)len && i < 65536; i++) + num += getreal(type); + if (len > 0) + { + black += num / len + 0.5; + tiff_ifd[ifd].dng_levels.dng_fblack += num / float(len); + tiff_ifd[ifd].dng_levels.dng_black += num / len + 0.5; + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_BLACK; + } + break; + case 0xc61d: /* 50717, WhiteLevel */ + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_WHITE; + tiff_ifd[ifd].dng_levels.dng_whitelevel[0] = maximum = getint(type); + if (tiff_ifd[ifd].samples > 1) // Linear DNG case + for (i = 1; i < 4 && i < (int)len; i++) + tiff_ifd[ifd].dng_levels.dng_whitelevel[i] = getint(type); + break; + case 0xc61e: /* DefaultScale */ + { + float q1 = getreal(type); + float q2 = getreal(type); + if (q1 > 0.00001f && q2 > 0.00001f) + { + pixel_aspect = q1 / q2; + if (pixel_aspect > 0.995 && pixel_aspect < 1.005) + pixel_aspect = 1.0; + } + } + break; + case 0xc61f: /* 50719, DefaultCropOrigin */ + if (len == 2) + { + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_CROPORIGIN; + tiff_ifd[ifd].dng_levels.default_crop[0] = getreal(type); + tiff_ifd[ifd].dng_levels.default_crop[1] = getreal(type); + if (!strncasecmp(make, "SONY", 4)) + { + imgdata.sizes.raw_inset_crop.cleft = + tiff_ifd[ifd].dng_levels.default_crop[0]; + imgdata.sizes.raw_inset_crop.ctop = + tiff_ifd[ifd].dng_levels.default_crop[1]; + } + } + break; + + case 0xc620: /* 50720, DefaultCropSize */ + if (len == 2) + { + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_CROPSIZE; + tiff_ifd[ifd].dng_levels.default_crop[2] = getreal(type); + tiff_ifd[ifd].dng_levels.default_crop[3] = getreal(type); + if (!strncasecmp(make, "SONY", 4)) + { + imgdata.sizes.raw_inset_crop.cwidth = + tiff_ifd[ifd].dng_levels.default_crop[2]; + imgdata.sizes.raw_inset_crop.cheight = + tiff_ifd[ifd].dng_levels.default_crop[3]; + } + } + break; + + case 0x74c7: + if ((len == 2) && !strncasecmp(make, "SONY", 4)) + { + imgdata.sizes.raw_inset_crop.cleft = get4(); + imgdata.sizes.raw_inset_crop.ctop = get4(); + } + break; + + case 0x74c8: + if ((len == 2) && !strncasecmp(make, "SONY", 4)) + { + imgdata.sizes.raw_inset_crop.cwidth = get4(); + imgdata.sizes.raw_inset_crop.cheight = get4(); + } + break; + + case 0xc65a: // 50778 + tiff_ifd[ifd].dng_color[0].illuminant = get2(); + tiff_ifd[ifd].dng_color[0].parsedfields |= LIBRAW_DNGFM_ILLUMINANT; + break; + case 0xc65b: // 50779 + tiff_ifd[ifd].dng_color[1].illuminant = get2(); + tiff_ifd[ifd].dng_color[1].parsedfields |= LIBRAW_DNGFM_ILLUMINANT; + break; + + case 0xc621: /* 50721, ColorMatrix1 */ + case 0xc622: /* 50722, ColorMatrix2 */ + { + int chan = (len == 9) ? 3 : (len == 12 ? 4 : 0); + i = tag == 0xc621 ? 0 : 1; + if (chan) + { + tiff_ifd[ifd].dng_color[i].parsedfields |= LIBRAW_DNGFM_COLORMATRIX; + imHassy.nIFD_CM[i] = ifd; + } + FORC(chan) for (j = 0; j < 3; j++) + { + tiff_ifd[ifd].dng_color[i].colormatrix[c][j] = cm[c][j] = getreal(type); + } + use_cm = 1; + } + break; + + case 0xc714: /* ForwardMatrix1 */ + case 0xc715: /* ForwardMatrix2 */ + { + int chan = (len == 9) ? 3 : (len == 12 ? 4 : 0); + i = tag == 0xc714 ? 0 : 1; + if (chan) + tiff_ifd[ifd].dng_color[i].parsedfields |= LIBRAW_DNGFM_FORWARDMATRIX; + for (j = 0; j < 3; j++) + FORC(chan) + { + tiff_ifd[ifd].dng_color[i].forwardmatrix[j][c] = fm[j][c] = + getreal(type); + } + } + break; + + case 0xc623: /* 50723, CameraCalibration1 */ + case 0xc624: /* 50724, CameraCalibration2 */ + { + int chan = (len == 9) ? 3 : (len == 16 ? 4 : 0); + j = tag == 0xc623 ? 0 : 1; + if (chan) + tiff_ifd[ifd].dng_color[j].parsedfields |= LIBRAW_DNGFM_CALIBRATION; + for (i = 0; i < chan; i++) + FORC(chan) + { + tiff_ifd[ifd].dng_color[j].calibration[i][c] = cc[i][c] = + getreal(type); + } + } + break; + case 0xc627: /* 50727, AnalogBalance */ + if (len >= 3) + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_ANALOGBALANCE; + for (c = 0; c < (int)len && c < 4; c++) + { + tiff_ifd[ifd].dng_levels.analogbalance[c] = ab[c] = getreal(type); + } + break; + case 0xc628: /* 50728, AsShotNeutral */ + if (len >= 3) + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_ASSHOTNEUTRAL; + for (c = 0; c < (int)len && c < 4; c++) + tiff_ifd[ifd].dng_levels.asshotneutral[c] = asn[c] = getreal(type); + break; + case 0xc629: /* 50729, AsShotWhiteXY */ + xyz[0] = getreal(type); + xyz[1] = getreal(type); + xyz[2] = 1 - xyz[0] - xyz[1]; + FORC3 xyz[c] /= LibRaw_constants::d65_white[c]; + break; + case 0xc62a: /* DNG: 50730 BaselineExposure */ + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_BASELINEEXPOSURE; + tiff_ifd[ifd].dng_levels.baseline_exposure = getreal(type); + break; + case 0xc62e: /* DNG: 50734 LinearResponseLimit */ + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_LINEARRESPONSELIMIT; + tiff_ifd[ifd].dng_levels.LinearResponseLimit = getreal(type); + break; + + case 0xc634: /* 50740 : DNG Adobe, DNG Pentax, Sony SR2, DNG Private */ + if (!(imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_SKIP_MAKERNOTES)) + { + char mbuf[64]; + INT64 curr_pos, start_pos = ftell(ifp); + unsigned MakN_order, m_sorder = order; + unsigned MakN_length; + unsigned pos_in_original_raw; + fread(mbuf, 1, 6, ifp); + + if (!strcmp(mbuf, "Adobe")) + { + order = 0x4d4d; // Adobe header is always in "MM" / big endian + curr_pos = start_pos + 6; + while (curr_pos + 8 - start_pos <= len) + { + fread(mbuf, 1, 4, ifp); + curr_pos += 8; + + if (!strncmp(mbuf, "Pano", 4)) + { // PanasonicRaw, yes, they use "Pano" as signature + parseAdobePanoMakernote(); + } + + if (!strncmp(mbuf, "MakN", 4)) + { + MakN_length = get4(); + MakN_order = get2(); + pos_in_original_raw = get4(); + order = MakN_order; + + INT64 save_pos = ifp->tell(); + parse_makernote_0xc634(curr_pos + 6 - pos_in_original_raw, 0, + AdobeDNG); + + curr_pos = save_pos + MakN_length - 6; + fseek(ifp, curr_pos, SEEK_SET); + + fread(mbuf, 1, 4, ifp); + curr_pos += 8; + + if (!strncmp(mbuf, "Pano ", 4)) + { + parseAdobePanoMakernote(); + } + + if (!strncmp(mbuf, "RAF ", 4)) + { // Fujifilm Raw, AdobeRAF + parseAdobeRAFMakernote(); + } + + if (!strncmp(mbuf, "SR2 ", 4)) + { + order = 0x4d4d; + MakN_length = get4(); + MakN_order = get2(); + pos_in_original_raw = get4(); + order = MakN_order; + + unsigned *buf_SR2; + unsigned entries, tag, type, len, save; + unsigned SR2SubIFDOffset = 0; + unsigned SR2SubIFDLength = 0; + unsigned SR2SubIFDKey = 0; + int base = curr_pos + 6 - pos_in_original_raw; + entries = get2(); + while (entries--) + { + tiff_get(base, &tag, &type, &len, &save); + + if (tag == 0x7200) + { + SR2SubIFDOffset = get4(); + } + else if (tag == 0x7201) + { + SR2SubIFDLength = get4(); + } + else if (tag == 0x7221) + { + SR2SubIFDKey = get4(); + } + fseek(ifp, save, SEEK_SET); + } + + if (SR2SubIFDLength && (SR2SubIFDLength < 10240000) && + (buf_SR2 = (unsigned *)malloc(SR2SubIFDLength + 1024))) + { // 1024b for safety + fseek(ifp, SR2SubIFDOffset + base, SEEK_SET); + fread(buf_SR2, SR2SubIFDLength, 1, ifp); + sony_decrypt(buf_SR2, SR2SubIFDLength / 4, 1, SR2SubIFDKey); + parseSonySR2((uchar *)buf_SR2, SR2SubIFDOffset, + SR2SubIFDLength, AdobeDNG); + + free(buf_SR2); + } + + } /* SR2 processed */ + break; + } + } + } + else + { + fread(mbuf + 6, 1, 2, ifp); + if (!strcmp(mbuf, "RICOH") && ((sget2((uchar *)mbuf + 6) == 0x4949) || + (sget2((uchar *)mbuf + 6) == 0x4d4d))) + { + is_PentaxRicohMakernotes = 1; + } + if (!strcmp(mbuf, "PENTAX ") || !strcmp(mbuf, "SAMSUNG") || + is_PentaxRicohMakernotes) + { + fseek(ifp, start_pos, SEEK_SET); + parse_makernote_0xc634(base, 0, CameraDNG); + } + } + fseek(ifp, start_pos, SEEK_SET); + order = m_sorder; + } + if (dng_version) + { + break; + } + parse_minolta(j = get4() + base); + fseek(ifp, j, SEEK_SET); + parse_tiff_ifd(base); + break; + case 0xc640: // 50752 + read_shorts(cr2_slice, 3); + break; + case 0xc68b: /* 50827, OriginalRawFileName */ + stmread(imgdata.color.OriginalRawFileName, len, ifp); + break; + case 0xc68d: /* 50829 ActiveArea */ + tiff_ifd[ifd].t_tm = top_margin = getint(type); + tiff_ifd[ifd].t_lm = left_margin = getint(type); + tiff_ifd[ifd].t_vheight = height = getint(type) - top_margin; + tiff_ifd[ifd].t_vwidth = width = getint(type) - left_margin; + break; + case 0xc68e: /* 50830 MaskedAreas */ + for (i = 0; i < (int)len && i < 32; i++) + ((int *)mask)[i] = getint(type); + black = 0; + break; + case 0xc71a: /* 50970, PreviewColorSpace */ + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_PREVIEWCS; + tiff_ifd[ifd].dng_levels.preview_colorspace = getint(type); + break; + case 0xc741: /* 51009, OpcodeList2 */ + tiff_ifd[ifd].dng_levels.parsedfields |= LIBRAW_DNGFM_OPCODE2; + tiff_ifd[ifd].opcode2_offset = meta_offset = ftell(ifp); + break; + case 0xfd04: /* 64772, Kodak P-series */ + if (len < 13) + break; + fseek(ifp, 16, SEEK_CUR); + data_offset = get4(); + fseek(ifp, 28, SEEK_CUR); + data_offset += get4(); + load_raw = &LibRaw::packed_load_raw; + break; + case 0xfe02: // 65026 + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_ASCII)) + fgets(model2, 64, ifp); + } + fseek(ifp, save, SEEK_SET); + } + if (sony_length && sony_length < 10240000 && + (buf = (unsigned *)malloc(sony_length))) + { + fseek(ifp, sony_offset, SEEK_SET); + fread(buf, sony_length, 1, ifp); + sony_decrypt(buf, sony_length / 4, 1, sony_key); + parseSonySR2((uchar *)buf, sony_offset, sony_length, nonDNG); + free(buf); + } + for (i = 0; i < colors && i < 4; i++) + FORCC cc[i][c] *= ab[i]; + if (use_cm) + { + FORCC for (i = 0; i < 3; i++) for (cam_xyz[c][i] = j = 0; j < colors; j++) + cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; + cam_xyz_coeff(cmatrix, cam_xyz); + } + if (asn[0]) + { + cam_mul[3] = 0; + FORCC + if (fabs(asn[c]) > 0.0001) + cam_mul[c] = 1 / asn[c]; + } + if (!use_cm) + FORCC if (fabs(cc[c][c]) > 0.0001) pre_mul[c] /= cc[c][c]; + return 0; +} + +int LibRaw::parse_tiff(int base) +{ + int doff; + fseek(ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) + return 0; + get2(); + while ((doff = get4())) + { + fseek(ifp, doff + base, SEEK_SET); + if (parse_tiff_ifd(base)) + break; + } + return 1; +} + +struct ifd_size_t +{ + int ifdi; + INT64 databits; +}; + +int ifd_size_t_cmp(const void *a, const void *b) +{ + if (!a || !b) + return 0; + const ifd_size_t *ai = (ifd_size_t *)a; + const ifd_size_t *bi = (ifd_size_t *)b; + return bi->databits > ai->databits ? 1 + : (bi->databits < ai->databits ? -1 : 0); +} + +void LibRaw::apply_tiff() +{ + int max_samp = 0, ties = 0, raw = -1, thm = -1, i; + unsigned long long ns, os; + struct jhead jh; + + thumb_misc = 16; + if (thumb_offset) + { + fseek(ifp, thumb_offset, SEEK_SET); + if (ljpeg_start(&jh, 1)) + { + if ((unsigned)jh.bits < 17 && (unsigned)jh.wide < 0x10000 && + (unsigned)jh.high < 0x10000) + { + thumb_misc = jh.bits; + thumb_width = jh.wide; + thumb_height = jh.high; + } + } + } + for (i = tiff_nifds; i--;) + { + if (tiff_ifd[i].t_shutter) + shutter = tiff_ifd[i].t_shutter; + tiff_ifd[i].t_shutter = shutter; + } + + if (dng_version) + { + int ifdc = 0; + for (i = 0; i < (int)tiff_nifds; i++) + { + if (tiff_ifd[i].t_width < 1 || tiff_ifd[i].t_width > 65535 || + tiff_ifd[i].t_height < 1 || tiff_ifd[i].t_height > 65535) + continue; /* wrong image dimensions */ + + int samp = tiff_ifd[i].samples; + if (samp == 2) + samp = 1; // Fuji 2-frame + max_samp = LIM(MAX(max_samp, samp), 1, + 3); // max_samp is needed for thumbnail selection below + + if (tiff_ifd[i].phint != 32803 && tiff_ifd[i].phint != 34892) + continue; + + if ((tiff_ifd[i].newsubfiletype == 0) // main image + // Enhanced demosaiced: + || (tiff_ifd[i].newsubfiletype == 16 && + (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_DNG_ADD_ENHANCED)) + // Preview: 0x1 or 0x10001 + || ((tiff_ifd[i].newsubfiletype & 0xffff) == 1 && + (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_DNG_ADD_PREVIEWS))) + { + // Add this IFD to dng_frames + libraw_internal_data.unpacker_data.dng_frames[ifdc] = + ((tiff_ifd[i].newsubfiletype & 0xffff) << 16) | ((i << 8) & 0xff00); + ifdc++; + // Fuji SuperCCD: second frame: + if ((tiff_ifd[i].newsubfiletype == 0) && tiff_ifd[i].samples == 2) + { + libraw_internal_data.unpacker_data.dng_frames[ifdc] = + ((tiff_ifd[i].newsubfiletype & 0xffff) << 16) | + ((i << 8) & 0xff00) | 1; + ifdc++; + } + } + } + if (ifdc) + { + if (ifdc > 1 && (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_DNG_PREFER_LARGEST_IMAGE)) + { + ifd_size_t arr[LIBRAW_IFD_MAXCOUNT * 2]; + memset(arr, 0, sizeof(arr)); + for (int i = 0; i < ifdc && i < LIBRAW_IFD_MAXCOUNT * 2; i++) + { + int ifdidx = + (libraw_internal_data.unpacker_data.dng_frames[i] >> 8) & 0xff; + arr[i].ifdi = libraw_internal_data.unpacker_data.dng_frames[i]; + arr[i].databits = + tiff_ifd[ifdidx].t_width * tiff_ifd[ifdidx].t_height * + tiff_ifd[ifdidx].samples * tiff_ifd[ifdidx].bps + + (0x100 - + (arr[i].ifdi & 0xff)); // add inverted frame # to ensure same + // sort order for similar sized frames. + } + qsort(arr, MIN(ifdc, LIBRAW_IFD_MAXCOUNT * 2), sizeof(arr[0]), + ifd_size_t_cmp); + for (int i = 0; i < ifdc && i < LIBRAW_IFD_MAXCOUNT * 2; i++) + libraw_internal_data.unpacker_data.dng_frames[i] = arr[i].ifdi; + } + + int idx = LIM((int)shot_select, 0, ifdc - 1); + i = (libraw_internal_data.unpacker_data.dng_frames[idx] >> 8) & + 0xff; // extract frame# back + + raw_width = tiff_ifd[i].t_width; + raw_height = tiff_ifd[i].t_height; + tiff_bps = tiff_ifd[i].bps; + tiff_compress = tiff_ifd[i].comp; + tiff_sampleformat = tiff_ifd[i].sample_format; + data_offset = tiff_ifd[i].offset; + data_size = tiff_ifd[i].bytes; + tiff_flip = tiff_ifd[i].t_flip; + tiff_samples = tiff_ifd[i].samples; + tile_width = tiff_ifd[i].t_tile_width; + tile_length = tiff_ifd[i].t_tile_length; + fuji_width = tiff_ifd[i].t_fuji_width; + if (tiff_samples != 2) /* special case: Fuji SuperCCD */ + { + if (tiff_ifd[i].phint == 34892) + filters = 0; + else if (i > 0 && tiff_ifd[i].phint == 32803 && + tiff_ifd[0].phint == 32803 && !tiff_ifd[i].t_filters && + tiff_ifd[0].t_filters) + filters = tiff_ifd[0].t_filters; + else + filters = tiff_ifd[i].t_filters; + width = tiff_ifd[i].t_vwidth; + height = tiff_ifd[i].t_vheight; + top_margin = tiff_ifd[i].t_tm; + left_margin = tiff_ifd[i].t_lm; + shutter = tiff_ifd[i].t_shutter; + if (tiff_ifd[i].dng_levels.dng_whitelevel[0]) + maximum = tiff_ifd[i].dng_levels.dng_whitelevel[0]; + else if (tiff_ifd[i].sample_format <= 2 && tiff_bps > 0 && + tiff_bps < 32) // SampleFormat: 0-default(1), 1 - Uint, 2 - Int + maximum = (1 << tiff_bps) - 1; + else if (tiff_ifd[i].sample_format == 3) + maximum = 1; // Defaults for FP + } + raw = i; + is_raw = ifdc; + } + else + is_raw = 0; + } + else + { + for (i = 0; i < (int)tiff_nifds; i++) + { + if (tiff_ifd[i].t_width < 1 || tiff_ifd[i].t_width > 65535 || + tiff_ifd[i].t_height < 1 || tiff_ifd[i].t_height > 65535) + continue; /* wrong image dimensions */ + if (max_samp < tiff_ifd[i].samples) + max_samp = tiff_ifd[i].samples; + if (max_samp > 3) + max_samp = 3; + + os = unsigned(raw_width) * unsigned(raw_height); + ns = unsigned(tiff_ifd[i].t_width) * unsigned(tiff_ifd[i].t_height); + if (tiff_bps) + { + os *= tiff_bps; + ns *= tiff_ifd[i].bps; + } + /* too complex if below, so separate if to skip RGB+Alpha TIFFs*/ + if (tiff_ifd[i].phint == 2 && tiff_ifd[i].extrasamples > 0 && tiff_ifd[i].samples > 3) + continue; // SKIP RGB+Alpha IFDs + + if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && + unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 && + (unsigned)tiff_ifd[i].bps < 33 && + (unsigned)tiff_ifd[i].samples < 13 && ns && + ((ns > os && (ties = 1)) || (ns == os && (int)shot_select == ties++))) + { + raw_width = tiff_ifd[i].t_width; + raw_height = tiff_ifd[i].t_height; + tiff_bps = tiff_ifd[i].bps; + tiff_compress = tiff_ifd[i].comp; + tiff_sampleformat = tiff_ifd[i].sample_format; + data_offset = tiff_ifd[i].offset; + data_size = tiff_ifd[i].bytes; + tiff_flip = tiff_ifd[i].t_flip; + tiff_samples = tiff_ifd[i].samples; + tile_width = tiff_ifd[i].t_tile_width; + tile_length = tiff_ifd[i].t_tile_length; + shutter = tiff_ifd[i].t_shutter; + raw = i; + } + } + if (is_raw == 1 && ties) + is_raw = ties; + } + if (is_NikonTransfer && raw >= 0) + { + if (tiff_ifd[raw].bps == 16) + { + if (tiff_compress == 1) + { + if ((raw_width * raw_height * 3) == (tiff_ifd[raw].bytes << 1)) + { + tiff_bps = tiff_ifd[raw].bps = 12; + } + else + { + tiff_bps = tiff_ifd[raw].bps = 14; + } + } + } + else if (tiff_ifd[raw].bps == 8) + { + if (tiff_compress == 1) + { + is_NikonTransfer = 2; // 8-bit debayered TIFF, like CoolScan NEFs + imgdata.params.coolscan_nef_gamma = 2.2f; + } + } + } + + if (!tile_width) + tile_width = INT_MAX; + if (!tile_length) + tile_length = INT_MAX; + for (i = tiff_nifds; i--;) + if (tiff_ifd[i].t_flip) + tiff_flip = tiff_ifd[i].t_flip; + +#if 0 + if (raw < 0 && is_raw) + is_raw = 0; +#endif + + if (raw >= 0 && !load_raw) + switch (tiff_compress) + { + case 32767: + if (!dng_version && + INT64(tiff_ifd[raw].bytes) == INT64(raw_width) * INT64(raw_height)) + { + tiff_bps = 14; + load_raw = &LibRaw::sony_arw2_load_raw; + break; + } + if (!dng_version && !strncasecmp(make, "Sony", 4) && + INT64(tiff_ifd[raw].bytes) == + INT64(raw_width) * INT64(raw_height) * 2LL) + { + tiff_bps = 14; + load_raw = &LibRaw::unpacked_load_raw; + break; + } + if (INT64(tiff_ifd[raw].bytes) * 8ULL != + INT64(raw_width) * INT64(raw_height) * INT64(tiff_bps)) + { + raw_height += 8; + load_raw = &LibRaw::sony_arw_load_raw; + break; + } + load_flags = 79; + case 32769: + load_flags++; + case 32770: + case 32773: + goto slr; + case 0: + case 1: +#ifdef USE_DNGSDK + if (dng_version && tiff_sampleformat == 3 && + (tiff_bps > 8 && (tiff_bps % 8 == 0))) // 16,24,32,48... + { + load_raw = &LibRaw::float_dng_load_raw_placeholder; + break; + } +#endif + // Sony 14-bit uncompressed + if (!dng_version && !strncasecmp(make, "Sony", 4) && + INT64(tiff_ifd[raw].bytes) == + INT64(raw_width) * INT64(raw_height) * 2LL) + { + tiff_bps = 14; + load_raw = &LibRaw::unpacked_load_raw; + break; + } + if (!dng_version && !strncasecmp(make, "Sony", 4) && + tiff_ifd[raw].samples == 4 && + INT64(tiff_ifd[raw].bytes) == + INT64(raw_width) * INT64(raw_height) * 8LL) // Sony ARQ + { + // maybe to detect ARQ with the following: + // if (tiff_ifd[raw].phint == 32892) + tiff_bps = 14; + tiff_samples = 4; + load_raw = &LibRaw::sony_arq_load_raw; + filters = 0; + strcpy(cdesc, "RGBG"); + break; + } + if (!strncasecmp(make, "Nikon", 5) && + (!strncmp(software, "Nikon Scan", 10) || (is_NikonTransfer == 2) || + strcasestr(model, "COOLSCAN"))) + { + load_raw = &LibRaw::nikon_coolscan_load_raw; + raw_color = 1; + filters = 0; + break; + } + if ((!strncmp(make, "OLYMPUS", 7) || + (!strncasecmp(make, "CLAUSS", 6) && + !strncasecmp(model, "piX 5oo", 7))) && // 0x5330303539 works here + (INT64(tiff_ifd[raw].bytes) * 2ULL == + INT64(raw_width) * INT64(raw_height) * 3ULL)) + load_flags = 24; + if (!dng_version && INT64(tiff_ifd[raw].bytes) * 5ULL == + INT64(raw_width) * INT64(raw_height) * 8ULL) + { + load_flags = 81; + tiff_bps = 12; + } + slr: + switch (tiff_bps) + { + case 8: + load_raw = &LibRaw::eight_bit_load_raw; + break; + case 12: + if (tiff_ifd[raw].phint == 2) + load_flags = 6; + if (!strncasecmp(make, "NIKON", 5) && + !strncasecmp(model, "COOLPIX A1000", 13) && + data_size == raw_width * raw_height * 2) + load_raw = &LibRaw::unpacked_load_raw; + else + load_raw = &LibRaw::packed_load_raw; + break; + case 14: + load_flags = 0; + case 16: + load_raw = &LibRaw::unpacked_load_raw; + if ((!strncmp(make, "OLYMPUS", 7) || + (!strncasecmp(make, "CLAUSS", 6) && + !strncasecmp(model, "piX 5oo", 7))) && // 0x5330303539 works here + (INT64(tiff_ifd[raw].bytes) * 7ULL > + INT64(raw_width) * INT64(raw_height))) + load_raw = &LibRaw::olympus_load_raw; + } + break; + case 6: + case 7: + case 99: + load_raw = &LibRaw::lossless_jpeg_load_raw; + break; + case 262: + load_raw = &LibRaw::kodak_262_load_raw; + break; + case 34713: + if ((INT64(raw_width) + 9LL) / 10LL * 16LL * INT64(raw_height) == + INT64(tiff_ifd[raw].bytes)) + { + load_raw = &LibRaw::packed_load_raw; + load_flags = 1; + } + else if (INT64(raw_width) * INT64(raw_height) * 3LL == + INT64(tiff_ifd[raw].bytes) * 2LL) + { + load_raw = &LibRaw::packed_load_raw; + if (model[0] == 'N') + load_flags = 80; + } + else if (INT64(raw_width) * INT64(raw_height) * 3LL == + INT64(tiff_ifd[raw].bytes)) + { + load_raw = &LibRaw::nikon_yuv_load_raw; + gamma_curve(1 / 2.4, 12.92, 1, 4095); + memset(cblack, 0, sizeof cblack); + filters = 0; + } + else if (INT64(raw_width) * INT64(raw_height) * 2LL == + INT64(tiff_ifd[raw].bytes)) + { + load_raw = &LibRaw::unpacked_load_raw; + load_flags = 4; + order = 0x4d4d; + } + else if (INT64(raw_width) * INT64(raw_height) * 3LL == + INT64(tiff_ifd[raw].bytes) * 2LL) + { + load_raw = &LibRaw::packed_load_raw; + load_flags = 80; + } + else if (tiff_ifd[raw].rows_per_strip && + tiff_ifd[raw].strip_offsets_count && + tiff_ifd[raw].strip_offsets_count == + tiff_ifd[raw].strip_byte_counts_count) + { + int fit = 1; + for (int i = 0; i < tiff_ifd[raw].strip_byte_counts_count - 1; + i++) // all but last + if (INT64(tiff_ifd[raw].strip_byte_counts[i]) * 2LL != + INT64(tiff_ifd[raw].rows_per_strip) * INT64(raw_width) * 3LL) + { + fit = 0; + break; + } + if (fit) + load_raw = &LibRaw::nikon_load_striped_packed_raw; + else + load_raw = &LibRaw::nikon_load_raw; // fallback + } + else if ((((INT64(raw_width) * 3LL / 2LL) + 15LL) / 16LL) * 16LL * + INT64(raw_height) == + INT64(tiff_ifd[raw].bytes)) + { + load_raw = &LibRaw::nikon_load_padded_packed_raw; + load_flags = (((INT64(raw_width) * 3ULL / 2ULL) + 15ULL) / 16ULL) * + 16ULL; // bytes per row + } + else + load_raw = &LibRaw::nikon_load_raw; + break; + case 65535: + load_raw = &LibRaw::pentax_load_raw; + break; + case 65000: + switch (tiff_ifd[raw].phint) + { + case 2: + load_raw = &LibRaw::kodak_rgb_load_raw; + filters = 0; + break; + case 6: + load_raw = &LibRaw::kodak_ycbcr_load_raw; + filters = 0; + break; + case 32803: + load_raw = &LibRaw::kodak_65000_load_raw; + } + case 32867: + case 34892: + break; + case 8: + break; +#ifdef USE_GPRSDK + case 9: + if (dng_version) + break; /* Compression=9 supported for dng if we compiled with GPR SDK */ + /* Else: fallthrough */ +#endif + default: + is_raw = 0; + } + if (!dng_version) + { + if (((tiff_samples == 3 && tiff_ifd[raw].bytes && + !(tiff_bps == 16 && + !strncmp(make, "Leaf", 4)) && // Allow Leaf/16bit/3color files + tiff_bps != 14 && + (tiff_compress & -16) != 32768) || + (tiff_bps == 8 && strncmp(make, "Phase", 5) && + strncmp(make, "Leaf", 4) && !strcasestr(make, "Kodak") && + !strstr(model2, "DEBUG RAW"))) && + !strcasestr(model, "COOLSCAN") && strncmp(software, "Nikon Scan", 10) && + is_NikonTransfer != 2) + is_raw = 0; + + if (is_raw && raw >= 0 && tiff_ifd[raw].phint == 2 && tiff_ifd[raw].extrasamples > 0 && tiff_ifd[raw].samples > 3) + is_raw = 0; // SKIP RGB+Alpha IFDs + } + + for (i = 0; i < (int)tiff_nifds; i++) + if (i != raw && + (tiff_ifd[i].samples == max_samp || + (tiff_ifd[i].comp == 7 && + tiff_ifd[i].samples == 1)) /* Allow 1-bps JPEGs */ + && tiff_ifd[i].bps > 0 && tiff_ifd[i].bps < 33 && + tiff_ifd[i].phint != 32803 && tiff_ifd[i].phint != 34892 && + unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 && + unsigned(tiff_ifd[i].t_width * tiff_ifd[i].t_height / + (SQR(tiff_ifd[i].bps) + 1)) > + unsigned(thumb_width * thumb_height / (SQR(thumb_misc) + 1)) && + tiff_ifd[i].comp != 34892) + { + thumb_width = tiff_ifd[i].t_width; + thumb_height = tiff_ifd[i].t_height; + thumb_offset = tiff_ifd[i].offset; + thumb_length = tiff_ifd[i].bytes; + thumb_misc = tiff_ifd[i].bps; + thm = i; + } + if (thm >= 0) + { + thumb_misc |= tiff_ifd[thm].samples << 5; + switch (tiff_ifd[thm].comp) + { + case 0: + write_thumb = &LibRaw::layer_thumb; + break; + case 1: + if (tiff_ifd[thm].bps <= 8) + write_thumb = &LibRaw::ppm_thumb; + else if (!strncmp(make, "Imacon", 6)) + write_thumb = &LibRaw::ppm16_thumb; + else + thumb_load_raw = &LibRaw::kodak_thumb_load_raw; + break; + case 65000: + thumb_load_raw = tiff_ifd[thm].phint == 6 ? &LibRaw::kodak_ycbcr_load_raw + : &LibRaw::kodak_rgb_load_raw; + } + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/aspect_ratio.cpp libkdcraw/libkdcraw/libraw/src/postprocessing/aspect_ratio.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/aspect_ratio.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/postprocessing/aspect_ratio.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,110 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::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; + 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()"); + + RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE, 0, 2); + + 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 > (unsigned)height - 2 || uc > (unsigned)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; + RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE, 1, 2); +} + +void LibRaw::stretch() +{ + ushort newdim, (*img)[4], *pix0, *pix1; + int row, col, c; + double rc, frac; + + if (pixel_aspect == 1) + return; + RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH, 0, 2); + 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; + RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH, 1, 2); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/dcraw_process.cpp libkdcraw/libkdcraw/libraw/src/postprocessing/dcraw_process.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/dcraw_process.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/postprocessing/dcraw_process.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,254 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +int LibRaw::dcraw_process(void) +{ + int quality, i; + + int iterations = -1, dcb_enhance = 1, noiserd = 0; + float preser = 0; + float expos = 1.0; + + CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); + // CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE); + + try + { + + int no_crop = 1; + + if (~O.cropbox[2] && ~O.cropbox[3]) + no_crop = 0; + + libraw_decoder_info_t di; + get_decoder_info(&di); + + bool is_bayer = (imgdata.idata.filters || P1.colors == 1); + int subtract_inline = + !O.bad_pixels && !O.dark_frame && is_bayer && !IO.zero_is_bad; + + raw2image_ex(subtract_inline); // allocate imgdata.image and copy data! + + // Adjust sizes + + int save_4color = O.four_color_rgb; + + if (IO.zero_is_bad) + { + remove_zeroes(); + SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES); + } + + if (O.bad_pixels && no_crop) + { + bad_pixels(O.bad_pixels); + SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS); + } + + if (O.dark_frame && no_crop) + { + subtract(O.dark_frame); + SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME); + } + /* pre subtract black callback: check for it above to disable subtract + * inline */ + + if (callbacks.pre_subtractblack_cb) + (callbacks.pre_subtractblack_cb)(this); + + quality = 2 + !IO.fuji_width; + + if (O.user_qual >= 0) + quality = O.user_qual; + + if (!subtract_inline || !C.data_maximum) + { + adjust_bl(); + subtract_black_internal(); + } + + if (!(di.decoder_flags & LIBRAW_DECODER_FIXEDMAXC)) + adjust_maximum(); + + if (O.user_sat > 0) + C.maximum = O.user_sat; + + if (P1.is_foveon) + { + if (load_raw == &LibRaw::x3f_load_raw) + { + // Filter out zeroes + for (int i = 0; i < S.height * S.width; i++) + { + for (int c = 0; c < 4; c++) + if ((short)imgdata.image[i][c] < 0) + imgdata.image[i][c] = 0; + } + } + SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE); + } + + if (O.green_matching && !O.half_size) + { + green_matching(); + } + + if (callbacks.pre_scalecolors_cb) + (callbacks.pre_scalecolors_cb)(this); + + if (!O.no_auto_scale) + { + scale_colors(); + SET_PROC_FLAG(LIBRAW_PROGRESS_SCALE_COLORS); + } + + if (callbacks.pre_preinterpolate_cb) + (callbacks.pre_preinterpolate_cb)(this); + + pre_interpolate(); + + SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE); + + if (O.dcb_iterations >= 0) + iterations = O.dcb_iterations; + if (O.dcb_enhance_fl >= 0) + dcb_enhance = O.dcb_enhance_fl; + if (O.fbdd_noiserd >= 0) + noiserd = O.fbdd_noiserd; + + /* pre-exposure correction callback */ + + if (O.exp_correc > 0) + { + expos = O.exp_shift; + preser = O.exp_preser; + exp_bef(expos, preser); + } + + if (callbacks.pre_interpolate_cb) + (callbacks.pre_interpolate_cb)(this); + + /* post-exposure correction fallback */ + if (P1.filters && !O.no_interpolation) + { + if (noiserd > 0 && P1.colors == 3 && P1.filters) + fbdd(noiserd); + + if (P1.filters > 1000 && callbacks.interpolate_bayer_cb) + (callbacks.interpolate_bayer_cb)(this); + else if (P1.filters == 9 && callbacks.interpolate_xtrans_cb) + (callbacks.interpolate_xtrans_cb)(this); + else if (quality == 0) + lin_interpolate(); + else if (quality == 1 || P1.colors > 3) + vng_interpolate(); + else if (quality == 2 && P1.filters > 1000) + ppg_interpolate(); + else if (P1.filters == LIBRAW_XTRANS) + { + // Fuji X-Trans + xtrans_interpolate(quality > 2 ? 3 : 1); + } + else if (quality == 3) + ahd_interpolate(); // really don't need it here due to fallback op + else if (quality == 4) + dcb(iterations, dcb_enhance); + + else if (quality == 11) + dht_interpolate(); + else if (quality == 12) + aahd_interpolate(); + // fallback to AHD + else + { + ahd_interpolate(); + imgdata.process_warnings |= LIBRAW_WARN_FALLBACK_TO_AHD; + } + + SET_PROC_FLAG(LIBRAW_PROGRESS_INTERPOLATE); + } + if (IO.mix_green) + { + for (P1.colors = 3, i = 0; i < S.height * S.width; i++) + imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1; + SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN); + } + + if (callbacks.post_interpolate_cb) + (callbacks.post_interpolate_cb)(this); + else if (!P1.is_foveon && P1.colors == 3 && O.med_passes > 0) + { + median_filter(); + SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER); + } + + if (O.highlight == 2) + { + blend_highlights(); + SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); + } + + if (O.highlight > 2) + { + recover_highlights(); + SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); + } + + if (O.use_fuji_rotate) + { + fuji_rotate(); + SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); + } + + if (!libraw_internal_data.output_data.histogram) + { + libraw_internal_data.output_data.histogram = + (int(*)[LIBRAW_HISTOGRAM_SIZE])malloc( + sizeof(*libraw_internal_data.output_data.histogram) * 4); + merror(libraw_internal_data.output_data.histogram, + "LibRaw::dcraw_process()"); + } +#ifndef NO_LCMS + if (O.camera_profile) + { + apply_profile(O.camera_profile, O.output_profile); + SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE); + } +#endif + + if (callbacks.pre_converttorgb_cb) + (callbacks.pre_converttorgb_cb)(this); + + convert_to_rgb(); + SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB); + + if (callbacks.post_converttorgb_cb) + (callbacks.post_converttorgb_cb)(this); + + if (O.use_fuji_rotate) + { + stretch(); + SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH); + } + O.four_color_rgb = save_4color; // also, restore + + return 0; + } + catch (LibRaw_exceptions err) + { + EXCEPTION_HANDLER(err); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/mem_image.cpp libkdcraw/libkdcraw/libraw/src/postprocessing/mem_image.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/mem_image.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/postprocessing/mem_image.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,289 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *errcode) +{ + if (!T.thumb) + { + if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && + load_raw == &LibRaw::broadcom_load_raw) // RPi + ) + { + if (errcode) + *errcode = LIBRAW_NO_THUMBNAIL; + } + else + { + if (errcode) + *errcode = LIBRAW_OUT_OF_ORDER_CALL; + } + return NULL; + } + + if (T.tlength < 64u) + { + if (errcode) + *errcode = EINVAL; + return NULL; + } + + if (INT64(T.tlength) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) + { + if (errcode) + *errcode = LIBRAW_TOO_BIG; + return NULL; + } + + if (T.tformat == LIBRAW_THUMBNAIL_BITMAP) + { + libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc( + sizeof(libraw_processed_image_t) + T.tlength); + + if (!ret) + { + if (errcode) + *errcode = ENOMEM; + return NULL; + } + + memset(ret, 0, sizeof(libraw_processed_image_t)); + ret->type = LIBRAW_IMAGE_BITMAP; + ret->height = T.theight; + ret->width = T.twidth; + ret->colors = 3; + ret->bits = 8; + ret->data_size = T.tlength; + memmove(ret->data, T.thumb, T.tlength); + if (errcode) + *errcode = 0; + return ret; + } + else if (T.tformat == LIBRAW_THUMBNAIL_JPEG) + { + ushort exif[5]; + int mk_exif = 0; + if (strcmp(T.thumb + 6, "Exif")) + mk_exif = 1; + + int dsize = T.tlength + mk_exif * (sizeof(exif) + sizeof(tiff_hdr)); + + libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc( + sizeof(libraw_processed_image_t) + dsize); + + if (!ret) + { + if (errcode) + *errcode = ENOMEM; + return NULL; + } + + memset(ret, 0, sizeof(libraw_processed_image_t)); + + ret->type = LIBRAW_IMAGE_JPEG; + ret->data_size = dsize; + + ret->data[0] = 0xff; + ret->data[1] = 0xd8; + if (mk_exif) + { + struct tiff_hdr th; + memcpy(exif, "\xff\xe1 Exif\0\0", 10); + exif[1] = htons(8 + sizeof th); + memmove(ret->data + 2, exif, sizeof(exif)); + tiff_head(&th, 0); + memmove(ret->data + (2 + sizeof(exif)), &th, sizeof(th)); + memmove(ret->data + (2 + sizeof(exif) + sizeof(th)), T.thumb + 2, + T.tlength - 2); + } + else + { + memmove(ret->data + 2, T.thumb + 2, T.tlength - 2); + } + if (errcode) + *errcode = 0; + return ret; + } + else + { + if (errcode) + *errcode = LIBRAW_UNSUPPORTED_THUMBNAIL; + return NULL; + } +} + +// jlb +// macros for copying pixels to either BGR or RGB formats +#define FORBGR for (c = P1.colors - 1; c >= 0; c--) +#define FORRGB for (c = 0; c < P1.colors; c++) + +void LibRaw::get_mem_image_format(int *width, int *height, int *colors, + int *bps) const + +{ + *width = S.width; + *height = S.height; + if (imgdata.progress_flags < LIBRAW_PROGRESS_FUJI_ROTATE) + { + if (O.use_fuji_rotate) + { + if (IO.fuji_width) + { + int fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink; + *width = (ushort)(fuji_width / sqrt(0.5)); + *height = (ushort)((*height - fuji_width) / sqrt(0.5)); + } + else + { + if (S.pixel_aspect < 0.995) + *height = (ushort)(*height / S.pixel_aspect + 0.5); + if (S.pixel_aspect > 1.005) + *width = (ushort)(*width * S.pixel_aspect + 0.5); + } + } + } + if (S.flip & 4) + { + std::swap(*width, *height); + } + *colors = P1.colors; + *bps = O.output_bps; +} + +int LibRaw::copy_mem_image(void *scan0, int stride, int bgr) + +{ + // the image memory pointed to by scan0 is assumed to be in the format + // returned by get_mem_image_format + if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) < + LIBRAW_PROGRESS_PRE_INTERPOLATE) + return LIBRAW_OUT_OF_ORDER_CALL; + + if (libraw_internal_data.output_data.histogram) + { + int perc, val, total, t_white = 0x2000, c; + perc = S.width * S.height * O.auto_bright_thr; + if (IO.fuji_width) + perc /= 2; + if (!((O.highlight & ~2) || O.no_auto_bright)) + for (t_white = c = 0; c < P1.colors; c++) + { + for (val = 0x2000, total = 0; --val > 32;) + if ((total += libraw_internal_data.output_data.histogram[c][val]) > + perc) + break; + if (t_white < val) + t_white = val; + } + gamma_curve(O.gamm[0], O.gamm[1], 2, (t_white << 3) / O.bright); + } + + int s_iheight = S.iheight; + int s_iwidth = S.iwidth; + int s_width = S.width; + int s_hwight = S.height; + + S.iheight = S.height; + S.iwidth = S.width; + + if (S.flip & 4) + SWAP(S.height, S.width); + uchar *ppm; + ushort *ppm2; + int c, row, col, soff, rstep, cstep; + + soff = flip_index(0, 0); + cstep = flip_index(0, 1) - soff; + rstep = flip_index(1, 0) - flip_index(0, S.width); + + for (row = 0; row < S.height; row++, soff += rstep) + { + uchar *bufp = ((uchar *)scan0) + row * stride; + ppm2 = (ushort *)(ppm = bufp); + // keep trivial decisions in the outer loop for speed + if (bgr) + { + if (O.output_bps == 8) + { + for (col = 0; col < S.width; col++, soff += cstep) + FORBGR *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8; + } + else + { + for (col = 0; col < S.width; col++, soff += cstep) + FORBGR *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]]; + } + } + else + { + if (O.output_bps == 8) + { + for (col = 0; col < S.width; col++, soff += cstep) + FORRGB *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8; + } + else + { + for (col = 0; col < S.width; col++, soff += cstep) + FORRGB *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]]; + } + } + + // bufp += stride; // go to the next line + } + + S.iheight = s_iheight; + S.iwidth = s_iwidth; + S.width = s_width; + S.height = s_hwight; + + return 0; +} +#undef FORBGR +#undef FORRGB + +libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode) + +{ + int width, height, colors, bps; + get_mem_image_format(&width, &height, &colors, &bps); + int stride = width * (bps / 8) * colors; + unsigned ds = height * stride; + libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc( + sizeof(libraw_processed_image_t) + ds); + if (!ret) + { + if (errcode) + *errcode = ENOMEM; + return NULL; + } + memset(ret, 0, sizeof(libraw_processed_image_t)); + + // metadata init + ret->type = LIBRAW_IMAGE_BITMAP; + ret->height = height; + ret->width = width; + ret->colors = colors; + ret->bits = bps; + ret->data_size = ds; + copy_mem_image(ret->data, stride, 0); + + return ret; +} + +void LibRaw::dcraw_clear_mem(libraw_processed_image_t *p) +{ + if (p) + ::free(p); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_aux.cpp libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_aux.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_aux.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_aux.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,410 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::hat_transform(float *temp, float *base, int st, int size, int sc) +{ + int i; + for (i = 0; i < sc; i++) + temp[i] = 2 * base[st * i] + base[st * (sc - i)] + base[st * (i + sc)]; + for (; i + sc < size; i++) + temp[i] = 2 * base[st * i] + base[st * (i - sc)] + base[st * (i + sc)]; + for (; i < size; i++) + temp[i] = 2 * base[st * i] + base[st * (i - sc)] + + base[st * (2 * size - 2 - (i + sc))]; +} + +#if !defined(LIBRAW_USE_OPENMP) +void LibRaw::wavelet_denoise() +{ + float *fimg = 0, *temp, thold, mul[2], avg, diff; + int scale = 1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; + ushort *window[4]; + static const float noise[] = {0.8002, 0.2735, 0.1202, 0.0585, + 0.0291, 0.0152, 0.0080, 0.0044}; + + while (maximum << scale < 0x10000) + scale++; + maximum <<= --scale; + black <<= scale; + FORC4 cblack[c] <<= scale; + if ((size = iheight * iwidth) < 0x15550000) + fimg = (float *)malloc((size * 3 + iheight + iwidth) * sizeof *fimg); + merror(fimg, "wavelet_denoise()"); + temp = fimg + size * 3; + if ((nc = colors) == 3 && filters) + nc++; + FORC(nc) + { /* denoise R,G1,B,G3 individually */ + for (i = 0; i < size; i++) + fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); + for (hpass = lev = 0; lev < 5; lev++) + { + lpass = size * ((lev & 1) + 1); + for (row = 0; row < iheight; row++) + { + hat_transform(temp, fimg + hpass + row * iwidth, 1, iwidth, 1 << lev); + for (col = 0; col < iwidth; col++) + fimg[lpass + row * iwidth + col] = temp[col] * 0.25; + } + for (col = 0; col < iwidth; col++) + { + hat_transform(temp, fimg + lpass + col, iwidth, iheight, 1 << lev); + for (row = 0; row < iheight; row++) + fimg[lpass + row * iwidth + col] = temp[row] * 0.25; + } + thold = threshold * noise[lev]; + for (i = 0; i < size; i++) + { + fimg[hpass + i] -= fimg[lpass + i]; + if (fimg[hpass + i] < -thold) + fimg[hpass + i] += thold; + else if (fimg[hpass + i] > thold) + fimg[hpass + i] -= thold; + else + fimg[hpass + i] = 0; + if (hpass) + fimg[i] += fimg[hpass + i]; + } + hpass = lpass; + } + for (i = 0; i < size; i++) + image[i][c] = CLIP(SQR(fimg[i] + fimg[lpass + i]) / 0x10000); + } + if (filters && colors == 3) + { /* pull G1 and G3 closer together */ + for (row = 0; row < 2; row++) + { + mul[row] = 0.125 * pre_mul[FC(row + 1, 0) | 1] / pre_mul[FC(row, 0) | 1]; + blk[row] = cblack[FC(row, 0) | 1]; + } + for (i = 0; i < 4; i++) + window[i] = (ushort *)fimg + width * i; + for (wlast = -1, row = 1; row < height - 1; row++) + { + while (wlast < row + 1) + { + for (wlast++, i = 0; i < 4; i++) + window[(i + 3) & 3] = window[i]; + for (col = FC(wlast, 1) & 1; col < width; col += 2) + window[2][col] = BAYER(wlast, col); + } + thold = threshold / 512; + for (col = (FC(row, 0) & 1) + 1; col < width - 1; col += 2) + { + avg = (window[0][col - 1] + window[0][col + 1] + window[2][col - 1] + + window[2][col + 1] - blk[~row & 1] * 4) * + mul[row & 1] + + (window[1][col] + blk[row & 1]) * 0.5; + avg = avg < 0 ? 0 : sqrt(avg); + diff = sqrt((double)BAYER(row, col)) - avg; + if (diff < -thold) + diff += thold; + else if (diff > thold) + diff -= thold; + else + diff = 0; + BAYER(row, col) = CLIP(SQR(avg + diff) + 0.5); + } + } + } + free(fimg); +} +#else /* LIBRAW_USE_OPENMP */ +void LibRaw::wavelet_denoise() +{ + float *fimg = 0, *temp, thold, mul[2], avg, diff; + int scale = 1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; + ushort *window[4]; + static const float noise[] = {0.8002, 0.2735, 0.1202, 0.0585, + 0.0291, 0.0152, 0.0080, 0.0044}; + + while (maximum << scale < 0x10000) + scale++; + maximum <<= --scale; + black <<= scale; + FORC4 cblack[c] <<= scale; + if ((size = iheight * iwidth) < 0x15550000) + fimg = (float *)malloc((size * 3 + iheight + iwidth) * sizeof *fimg); + merror(fimg, "wavelet_denoise()"); + temp = fimg + size * 3; + if ((nc = colors) == 3 && filters) + nc++; +#pragma omp parallel default(shared) private( \ + i, col, row, thold, lev, lpass, hpass, temp, c) firstprivate(scale, size) + { +#pragma omp critical /* LibRaw's malloc is not local thread-safe */ + temp = (float *)malloc((iheight + iwidth) * sizeof *fimg); + FORC(nc) + { /* denoise R,G1,B,G3 individually */ +#pragma omp for + for (i = 0; i < size; i++) + fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); + for (hpass = lev = 0; lev < 5; lev++) + { + lpass = size * ((lev & 1) + 1); +#pragma omp for + for (row = 0; row < iheight; row++) + { + hat_transform(temp, fimg + hpass + row * iwidth, 1, iwidth, 1 << lev); + for (col = 0; col < iwidth; col++) + fimg[lpass + row * iwidth + col] = temp[col] * 0.25; + } +#pragma omp for + for (col = 0; col < iwidth; col++) + { + hat_transform(temp, fimg + lpass + col, iwidth, iheight, 1 << lev); + for (row = 0; row < iheight; row++) + fimg[lpass + row * iwidth + col] = temp[row] * 0.25; + } + thold = threshold * noise[lev]; +#pragma omp for + for (i = 0; i < size; i++) + { + fimg[hpass + i] -= fimg[lpass + i]; + if (fimg[hpass + i] < -thold) + fimg[hpass + i] += thold; + else if (fimg[hpass + i] > thold) + fimg[hpass + i] -= thold; + else + fimg[hpass + i] = 0; + if (hpass) + fimg[i] += fimg[hpass + i]; + } + hpass = lpass; + } +#pragma omp for + for (i = 0; i < size; i++) + image[i][c] = CLIP(SQR(fimg[i] + fimg[lpass + i]) / 0x10000); + } +#pragma omp critical + free(temp); + } /* end omp parallel */ + /* the following loops are hard to parallize, no idea yes, + * problem is wlast which is carrying dependency + * second part should be easyer, but did not yet get it right. + */ + if (filters && colors == 3) + { /* pull G1 and G3 closer together */ + for (row = 0; row < 2; row++) + { + mul[row] = 0.125 * pre_mul[FC(row + 1, 0) | 1] / pre_mul[FC(row, 0) | 1]; + blk[row] = cblack[FC(row, 0) | 1]; + } + for (i = 0; i < 4; i++) + window[i] = (ushort *)fimg + width * i; + for (wlast = -1, row = 1; row < height - 1; row++) + { + while (wlast < row + 1) + { + for (wlast++, i = 0; i < 4; i++) + window[(i + 3) & 3] = window[i]; + for (col = FC(wlast, 1) & 1; col < width; col += 2) + window[2][col] = BAYER(wlast, col); + } + thold = threshold / 512; + for (col = (FC(row, 0) & 1) + 1; col < width - 1; col += 2) + { + avg = (window[0][col - 1] + window[0][col + 1] + window[2][col - 1] + + window[2][col + 1] - blk[~row & 1] * 4) * + mul[row & 1] + + (window[1][col] + blk[row & 1]) * 0.5; + avg = avg < 0 ? 0 : sqrt(avg); + diff = sqrt((double)BAYER(row, col)) - avg; + if (diff < -thold) + diff += thold; + else if (diff > thold) + diff -= thold; + else + diff = 0; + BAYER(row, col) = CLIP(SQR(avg + diff) + 0.5); + } + } + } + free(fimg); +} + +#endif +void LibRaw::median_filter() +{ + ushort(*pix)[4]; + int pass, c, i, j, k, med[9]; + static const uchar opt[] = /* Optimal 9-element median search */ + {1, 2, 4, 5, 7, 8, 0, 1, 3, 4, 6, 7, 1, 2, 4, 5, 7, 8, 0, + 3, 5, 8, 4, 7, 3, 6, 1, 4, 2, 5, 4, 7, 4, 2, 6, 4, 4, 2}; + + for (pass = 1; pass <= med_passes; pass++) + { + RUN_CALLBACK(LIBRAW_PROGRESS_MEDIAN_FILTER, pass - 1, med_passes); + for (c = 0; c < 3; c += 2) + { + for (pix = image; pix < image + width * height; pix++) + pix[0][3] = pix[0][c]; + for (pix = image + width; pix < image + width * (height - 1); pix++) + { + if ((pix - image + 1) % width < 2) + continue; + for (k = 0, i = -width; i <= width; i += width) + for (j = i - 1; j <= i + 1; j++) + med[k++] = pix[j][3] - pix[j][1]; + for (i = 0; i < int(sizeof opt); i += 2) + if (med[opt[i]] > med[opt[i + 1]]) + SWAP(med[opt[i]], med[opt[i + 1]]); + pix[0][c] = CLIP(med[4] + pix[0][1]); + } + } + } +} + +void LibRaw::blend_highlights() +{ + int clip = INT_MAX, row, col, c, i, j; + static const float trans[2][4][4] = { + {{1, 1, 1}, {1.7320508, -1.7320508, 0}, {-1, -1, 2}}, + {{1, 1, 1, 1}, {1, -1, 1, -1}, {1, 1, -1, -1}, {1, -1, -1, 1}}}; + static const float itrans[2][4][4] = { + {{1, 0.8660254, -0.5}, {1, -0.8660254, -0.5}, {1, 0, 1}}, + {{1, 1, 1, 1}, {1, -1, 1, -1}, {1, 1, -1, -1}, {1, -1, -1, 1}}}; + float cam[2][4], lab[2][4], sum[2], chratio; + + if ((unsigned)(colors - 3) > 1) + return; + RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, 0, 2); + FORCC if (clip > (i = 65535 * pre_mul[c])) clip = i; + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) + { + FORCC if (image[row * width + col][c] > clip) break; + if (c == colors) + continue; + FORCC + { + cam[0][c] = image[row * width + col][c]; + cam[1][c] = MIN(cam[0][c], clip); + } + for (i = 0; i < 2; i++) + { + FORCC for (lab[i][c] = j = 0; j < colors; j++) lab[i][c] += + trans[colors - 3][c][j] * cam[i][j]; + for (sum[i] = 0, c = 1; c < colors; c++) + sum[i] += SQR(lab[i][c]); + } + chratio = sqrt(sum[1] / sum[0]); + for (c = 1; c < colors; c++) + lab[0][c] *= chratio; + FORCC for (cam[0][c] = j = 0; j < colors; j++) cam[0][c] += + itrans[colors - 3][c][j] * lab[0][j]; + FORCC image[row * width + col][c] = cam[0][c] / colors; + } + RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, 1, 2); +} + +#define SCALE (4 >> shrink) +void LibRaw::recover_highlights() +{ + float *map, sum, wgt, grow; + int hsat[4], count, spread, change, val, i; + unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; + ushort *pixel; + static const signed char dir[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, + {1, 1}, {1, 0}, {1, -1}, {0, -1}}; + + grow = pow(2.0, 4 - highlight); + FORC(unsigned(colors)) hsat[c] = 32000 * pre_mul[c]; + for (kc = 0, c = 1; c < (unsigned)colors; c++) + if (pre_mul[kc] < pre_mul[c]) + kc = c; + high = height / SCALE; + wide = width / SCALE; + map = (float *)calloc(high, wide * sizeof *map); + merror(map, "recover_highlights()"); + FORC(unsigned(colors)) if (c != kc) + { + RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, c - 1, colors - 1); + memset(map, 0, high * wide * sizeof *map); + for (mrow = 0; mrow < high; mrow++) + for (mcol = 0; mcol < wide; mcol++) + { + sum = wgt = count = 0; + for (row = mrow * SCALE; row < (mrow + 1) * SCALE; row++) + for (col = mcol * SCALE; col < (mcol + 1) * SCALE; col++) + { + pixel = image[row * width + col]; + if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) + { + sum += pixel[c]; + wgt += pixel[kc]; + count++; + } + } + if (count == SCALE * SCALE) + map[mrow * wide + mcol] = sum / wgt; + } + for (spread = 32 / grow; spread--;) + { + for (mrow = 0; mrow < high; mrow++) + for (mcol = 0; mcol < wide; mcol++) + { + if (map[mrow * wide + mcol]) + continue; + sum = count = 0; + for (d = 0; d < 8; d++) + { + y = mrow + dir[d][0]; + x = mcol + dir[d][1]; + if (y < high && x < wide && map[y * wide + x] > 0) + { + sum += (1 + (d & 1)) * map[y * wide + x]; + count += 1 + (d & 1); + } + } + if (count > 3) + map[mrow * wide + mcol] = -(sum + grow) / (count + grow); + } + for (change = i = 0; i < int(high * wide); i++) + if (map[i] < 0) + { + map[i] = -map[i]; + change = 1; + } + if (!change) + break; + } + for (i = 0; i < int(high * wide); i++) + if (map[i] == 0) + map[i] = 1; + for (mrow = 0; mrow < high; mrow++) + for (mcol = 0; mcol < wide; mcol++) + { + for (row = mrow * SCALE; row < (mrow + 1) * SCALE; row++) + for (col = mcol * SCALE; col < (mcol + 1) * SCALE; col++) + { + pixel = image[row * width + col]; + if (pixel[c] / hsat[c] > 1) + { + val = pixel[kc] * map[mrow * wide + mcol]; + if (pixel[c] < val) + pixel[c] = CLIP(val); + } + } + } + } + free(map); +} +#undef SCALE diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_ph.cpp libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_ph.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_ph.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_ph.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,31 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + Placehoder functions to build LibRaw w/o postprocessing tools + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +int LibRaw::dcraw_process(void) +{ + return LIBRAW_NOT_IMPLEMENTED; +} + +void LibRaw::fuji_rotate() {} +void LibRaw::convert_to_rgb_loop(float out_cam[3][4]) {} +libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *) { + return NULL; +} +libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *){ return NULL;} +void LibRaw::lin_interpolate_loop(int *code, int size) {} +void LibRaw::scale_colors_loop(float scale_mul[4]) {} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_utils.cpp libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_utils.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_utils.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_utils.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,190 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#define TBLN 65535 + +void LibRaw::exp_bef(float shift, float smooth) +{ + // params limits + if (shift > 8) + shift = 8; + if (shift < 0.25) + shift = 0.25; + if (smooth < 0.0) + smooth = 0.0; + if (smooth > 1.0) + smooth = 1.0; + + unsigned short *lut = (ushort *)malloc((TBLN + 1) * sizeof(unsigned short)); + + if (shift <= 1.0) + { + for (int i = 0; i <= TBLN; i++) + lut[i] = (unsigned short)((float)i * shift); + } + else + { + float x1, x2, y1, y2; + + float cstops = log(shift) / log(2.0f); + float room = cstops * 2; + float roomlin = powf(2.0f, room); + x2 = (float)TBLN; + x1 = (x2 + 1) / roomlin - 1; + y1 = x1 * shift; + y2 = x2 * (1 + (1 - smooth) * (shift - 1)); + float sq3x = powf(x1 * x1 * x2, 1.0f / 3.0f); + float B = (y2 - y1 + shift * (3 * x1 - 3.0f * sq3x)) / + (x2 + 2.0f * x1 - 3.0f * sq3x); + float A = (shift - B) * 3.0f * powf(x1 * x1, 1.0f / 3.0f); + float CC = y2 - A * powf(x2, 1.0f / 3.0f) - B * x2; + for (int i = 0; i <= TBLN; i++) + { + float X = (float)i; + float Y = A * powf(X, 1.0f / 3.0f) + B * X + CC; + if (i < x1) + lut[i] = (unsigned short)((float)i * shift); + else + lut[i] = Y < 0 ? 0 : (Y > TBLN ? TBLN : (unsigned short)(Y)); + } + } + for (int i = 0; i < S.height * S.width; i++) + { + imgdata.image[i][0] = lut[imgdata.image[i][0]]; + imgdata.image[i][1] = lut[imgdata.image[i][1]]; + imgdata.image[i][2] = lut[imgdata.image[i][2]]; + imgdata.image[i][3] = lut[imgdata.image[i][3]]; + } + + if (C.data_maximum <= TBLN) + C.data_maximum = lut[C.data_maximum]; + if (C.maximum <= TBLN) + C.maximum = lut[C.maximum]; + free(lut); +} + +void LibRaw::convert_to_rgb_loop(float out_cam[3][4]) +{ + int row, col, c; + float out[3]; + ushort *img; + memset(libraw_internal_data.output_data.histogram, 0, + sizeof(int) * LIBRAW_HISTOGRAM_SIZE * 4); + if (libraw_internal_data.internal_output_params.raw_color) + { + for (img = imgdata.image[0], row = 0; row < S.height; row++) + { + for (col = 0; col < S.width; col++, img += 4) + { + for (c = 0; c < imgdata.idata.colors; c++) + { + libraw_internal_data.output_data.histogram[c][img[c] >> 3]++; + } + } + } + } + else if (imgdata.idata.colors == 3) + { + for (img = imgdata.image[0], row = 0; row < S.height; row++) + { + for (col = 0; col < S.width; col++, img += 4) + { + out[0] = out_cam[0][0] * img[0] + out_cam[0][1] * img[1] + + out_cam[0][2] * img[2]; + out[1] = out_cam[1][0] * img[0] + out_cam[1][1] * img[1] + + out_cam[1][2] * img[2]; + out[2] = out_cam[2][0] * img[0] + out_cam[2][1] * img[1] + + out_cam[2][2] * img[2]; + img[0] = CLIP((int)out[0]); + img[1] = CLIP((int)out[1]); + img[2] = CLIP((int)out[2]); + libraw_internal_data.output_data.histogram[0][img[0] >> 3]++; + libraw_internal_data.output_data.histogram[1][img[1] >> 3]++; + libraw_internal_data.output_data.histogram[2][img[2] >> 3]++; + } + } + } + else if (imgdata.idata.colors == 4) + { + for (img = imgdata.image[0], row = 0; row < S.height; row++) + { + for (col = 0; col < S.width; col++, img += 4) + { + out[0] = out_cam[0][0] * img[0] + out_cam[0][1] * img[1] + + out_cam[0][2] * img[2] + out_cam[0][3] * img[3]; + out[1] = out_cam[1][0] * img[0] + out_cam[1][1] * img[1] + + out_cam[1][2] * img[2] + out_cam[1][3] * img[3]; + out[2] = out_cam[2][0] * img[0] + out_cam[2][1] * img[1] + + out_cam[2][2] * img[2] + out_cam[2][3] * img[3]; + img[0] = CLIP((int)out[0]); + img[1] = CLIP((int)out[1]); + img[2] = CLIP((int)out[2]); + libraw_internal_data.output_data.histogram[0][img[0] >> 3]++; + libraw_internal_data.output_data.histogram[1][img[1] >> 3]++; + libraw_internal_data.output_data.histogram[2][img[2] >> 3]++; + libraw_internal_data.output_data.histogram[3][img[3] >> 3]++; + } + } + } +} + +void LibRaw::scale_colors_loop(float scale_mul[4]) +{ + unsigned size = S.iheight * S.iwidth; + + if (C.cblack[4] && C.cblack[5]) + { + int val; + for (unsigned i = 0; i < size; i++) + { + for (unsigned c = 0; c < 4; c++) + { + if (!(val = imgdata.image[i][c])) continue; + val -= C.cblack[6 + i / S.iwidth % C.cblack[4] * C.cblack[5] + + i % S.iwidth % C.cblack[5]]; + val -= C.cblack[c]; + val *= scale_mul[c]; + imgdata.image[i][c] = CLIP(val); + } + } + } + else if (C.cblack[0] || C.cblack[1] || C.cblack[2] || C.cblack[3]) + { + for (unsigned i = 0; i < size; i++) + { + for (unsigned c = 0; c < 4; c++) + { + int val = imgdata.image[i][c]; + if (!val) continue; + val -= C.cblack[c]; + val *= scale_mul[c]; + imgdata.image[i][c] = CLIP(val); + } + } + } + else // BL is zero + { + for (unsigned i = 0; i < size; i++) + { + for (unsigned c = 0; c < 4; c++) + { + int val = imgdata.image[i][c]; + val *= scale_mul[c]; + imgdata.image[i][c] = CLIP(val); + } + } + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_utils_dcrdefs.cpp libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_utils_dcrdefs.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/postprocessing/postprocessing_utils_dcrdefs.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/postprocessing/postprocessing_utils_dcrdefs.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,305 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::convert_to_rgb() +{ + int i, j, k; + size_t prof_desc_len; + char *prof_desc; + float out_cam[3][4]; + double num, inverse[3][3]; + static const double(*out_rgb[])[3] = { + LibRaw_constants::rgb_rgb, LibRaw_constants::adobe_rgb, + LibRaw_constants::wide_rgb, LibRaw_constants::prophoto_rgb, + LibRaw_constants::xyz_rgb, LibRaw_constants::aces_rgb}; + static const char *name[] = {"sRGB", "Adobe RGB (1998)", + "WideGamut D65", "ProPhoto D65", + "XYZ", "ACES"}; + 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, 60, /* desc, len is strlen(longest_string) + 12 */ + 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}; + + RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 0, 2); + + prof_desc_len = snprintf(NULL, 0, "%s gamma %g toe slope %g", name[output_color - 1], floorf(1000.f/gamm[0]+.5f)/1000.f, floorf(gamm[1]*1000.0f+.5f)/1000.f) + 1; + prof_desc = (char *)malloc(prof_desc_len); + sprintf(prof_desc, "%s gamma %g toe slope %g", name[output_color - 1], floorf(1000.f/gamm[0]+.5f)/1000.f, floorf(gamm[1]*1000.0f+.5f)/1000.f); + + gamma_curve(gamm[0], gamm[1], 0, 0); + memcpy(out_cam, rgb_cam, sizeof out_cam); + raw_color |= colors == 1 || output_color < 1 || output_color > 6; + 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 < (int)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] = prof_desc_len + 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 += LibRaw_constants::xyzd50_srgb[i][k] * inverse[j][k]; + oprof[pbody[j * 3 + 23] / 4 + i + 2] = num * 0x10000 + 0.5; + } + for (i = 0; i < (int)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, prof_desc); + 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]; + } + convert_to_rgb_loop(out_cam); + + if (colors == 4 && output_color) + colors = 3; + + RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 1, 2); +} + +void LibRaw::scale_colors() +{ + unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; + int val; + double dsum[8], dmin, dmax; + float scale_mul[4], fr, fc; + ushort *img = 0, *pix; + + RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 0, 2); + + if (user_mul[0]) + memcpy(pre_mul, user_mul, sizeof pre_mul); + if (use_auto_wb || (use_camera_wb && + (cam_mul[0] < -0.5 // LibRaw 0.19 and older: fallback to auto only if cam_mul[0] is set to -1 + || (cam_mul[0] <= 0.00001f // New default: fallback to auto if no cam_mul parsed from metadata + && !(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_CAMERAWB_FALLBACK_TO_DAYLIGHT)) + ))) + { + memset(dsum, 0, sizeof dsum); + bottom = MIN(greybox[1] + greybox[3], height); + right = MIN(greybox[0] + greybox[2], width); + for (row = greybox[1]; row < bottom; row += 8) + for (col = greybox[0]; col < right; col += 8) + { + memset(sum, 0, sizeof sum); + for (y = row; y < row + 8 && y < bottom; y++) + for (x = col; x < col + 8 && x < right; x++) + FORC4 + { + if (filters) + { + c = fcol(y, x); + val = BAYER2(y, x); + } + else + val = image[y * width + x][c]; + if (val > (int)maximum - 25) + goto skip_block; + if ((val -= cblack[c]) < 0) + val = 0; + sum[c] += val; + sum[c + 4]++; + if (filters) + break; + } + FORC(8) dsum[c] += sum[c]; + skip_block:; + } + FORC4 if (dsum[c]) pre_mul[c] = dsum[c + 4] / dsum[c]; + } + if (use_camera_wb && cam_mul[0] > 0.00001f) + { + memset(sum, 0, sizeof sum); + for (row = 0; row < 8; row++) + for (col = 0; col < 8; col++) + { + c = FC(row, col); + if ((val = white[row][col] - cblack[c]) > 0) + sum[c] += val; + sum[c + 4]++; + } + if (imgdata.color.as_shot_wb_applied) + { + // Nikon sRAW: camera WB already applied: + pre_mul[0] = pre_mul[1] = pre_mul[2] = pre_mul[3] = 1.0; + } + else if (sum[0] && sum[1] && sum[2] && sum[3]) + FORC4 pre_mul[c] = (float)sum[c + 4] / sum[c]; + else if (cam_mul[0] > 0.00001f && cam_mul[2] > 0.00001f) + memcpy(pre_mul, cam_mul, sizeof pre_mul); + else + { + imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB; + } + } + // Nikon sRAW, daylight + if (imgdata.color.as_shot_wb_applied && !use_camera_wb && !use_auto_wb && + cam_mul[0] > 0.00001f && cam_mul[1] > 0.00001f && cam_mul[2] > 0.00001f) + { + for (c = 0; c < 3; c++) + pre_mul[c] /= cam_mul[c]; + } + if (pre_mul[1] == 0) + pre_mul[1] = 1; + if (pre_mul[3] == 0) + pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + if (threshold) + wavelet_denoise(); + maximum -= black; + for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++) + { + if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + if (dmax < pre_mul[c]) + dmax = pre_mul[c]; + } + if (!highlight) + dmax = dmin; + if (dmax > 0.00001 && maximum > 0) + FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; + else + FORC4 scale_mul[c] = 1.0; + + if (filters > 1000 && (cblack[4] + 1) / 2 == 1 && (cblack[5] + 1) / 2 == 1) + { + FORC4 cblack[FC(c / 2, c % 2)] += + cblack[6 + c / 2 % cblack[4] * cblack[5] + c % 2 % cblack[5]]; + cblack[4] = cblack[5] = 0; + } + size = iheight * iwidth; + scale_colors_loop(scale_mul); + if ((aber[0] != 1 || aber[2] != 1) && colors == 3) + { + for (c = 0; c < 4; c += 2) + { + if (aber[c] == 1) + continue; + img = (ushort *)malloc(size * sizeof *img); + merror(img, "scale_colors()"); + for (i = 0; i < size; i++) + img[i] = image[i][c]; + for (row = 0; row < iheight; row++) + { + ur = fr = (row - iheight * 0.5) * aber[c] + iheight * 0.5; + if (ur > (unsigned)iheight - 2) + continue; + fr -= ur; + for (col = 0; col < iwidth; col++) + { + uc = fc = (col - iwidth * 0.5) * aber[c] + iwidth * 0.5; + if (uc > (unsigned)iwidth - 2) + continue; + fc -= uc; + pix = img + ur * iwidth + uc; + image[row * iwidth + col][c] = + (pix[0] * (1 - fc) + pix[1] * fc) * (1 - fr) + + (pix[iwidth] * (1 - fc) + pix[iwidth + 1] * fc) * fr; + } + } + free(img); + } + } + RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 1, 2); +} + +// green equilibration +void LibRaw::green_matching() +{ + int i, j; + double m1, m2, c1, c2; + int o1_1, o1_2, o1_3, o1_4; + int o2_1, o2_2, o2_3, o2_4; + ushort(*img)[4]; + const int margin = 3; + int oj = 2, oi = 2; + float f; + const float thr = 0.01f; + if (half_size || shrink) + return; + if (FC(oj, oi) != 3) + oj++; + if (FC(oj, oi) != 3) + oi++; + if (FC(oj, oi) != 3) + oj--; + + img = (ushort(*)[4])calloc(height * width, sizeof *image); + merror(img, "green_matching()"); + memcpy(img, image, height * width * sizeof *image); + + for (j = oj; j < height - margin; j += 2) + for (i = oi; i < width - margin; i += 2) + { + o1_1 = img[(j - 1) * width + i - 1][1]; + o1_2 = img[(j - 1) * width + i + 1][1]; + o1_3 = img[(j + 1) * width + i - 1][1]; + o1_4 = img[(j + 1) * width + i + 1][1]; + o2_1 = img[(j - 2) * width + i][3]; + o2_2 = img[(j + 2) * width + i][3]; + o2_3 = img[j * width + i - 2][3]; + o2_4 = img[j * width + i + 2][3]; + + m1 = (o1_1 + o1_2 + o1_3 + o1_4) / 4.0; + m2 = (o2_1 + o2_2 + o2_3 + o2_4) / 4.0; + + c1 = (abs(o1_1 - o1_2) + abs(o1_1 - o1_3) + abs(o1_1 - o1_4) + + abs(o1_2 - o1_3) + abs(o1_3 - o1_4) + abs(o1_2 - o1_4)) / + 6.0; + c2 = (abs(o2_1 - o2_2) + abs(o2_1 - o2_3) + abs(o2_1 - o2_4) + + abs(o2_2 - o2_3) + abs(o2_3 - o2_4) + abs(o2_2 - o2_4)) / + 6.0; + if ((img[j * width + i][3] < maximum * 0.95) && (c1 < maximum * thr) && + (c2 < maximum * thr)) + { + f = image[j * width + i][3] * m1 / m2; + image[j * width + i][3] = f > 0xffff ? 0xffff : f; + } + } + free(img); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/ext_preprocess.cpp libkdcraw/libkdcraw/libraw/src/preprocessing/ext_preprocess.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/ext_preprocess.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/preprocessing/ext_preprocess.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,130 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_fileio_defs.h" + +/* + Search from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. + */ +void LibRaw::bad_pixels(const char *cfname) +{ + FILE *fp = NULL; + char *cp, line[128]; + int time, row, col, r, c, rad, tot, n; + + if (!filters) + return; + RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS, 0, 2); + if (cfname) + fp = fopen(cfname, "r"); + if (!fp) + { + imgdata.process_warnings |= LIBRAW_WARN_NO_BADPIXELMAP; + 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) && fcol(r, c) == fcol(row, col)) + { + tot += BAYER2(r, c); + n++; + } + if (n > 0) + BAYER2(row, col) = tot / n; + } + fclose(fp); + RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS, 1, 2); +} + +void LibRaw::subtract(const char *fname) +{ + FILE *fp; + int dim[3] = {0, 0, 0}, comment = 0, number = 0, error = 0, nd = 0, c, row, + col; + ushort *pixel; + RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME, 0, 2); + + if (!(fp = fopen(fname, "rb"))) + { + imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_FILE; + return; + } + if (fgetc(fp) != 'P' || fgetc(fp) != '5') + error = 1; + while (!error && nd < 3 && (c = fgetc(fp)) != EOF) + { + if (c == '#') + comment = 1; + if (c == '\n') + comment = 0; + if (comment) + continue; + if (isdigit(c)) + number = 1; + if (number) + { + if (isdigit(c)) + dim[nd] = dim[nd] * 10 + c - '0'; + else if (isspace(c)) + { + number = 0; + nd++; + } + else + error = 1; + } + } + if (error || nd < 3) + { + fclose(fp); + return; + } + else if (dim[0] != width || dim[1] != height || dim[2] != 65535) + { + imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_DIM; + fclose(fp); + return; + } + pixel = (ushort *)calloc(width, sizeof *pixel); + merror(pixel, "subtract()"); + for (row = 0; row < height; row++) + { + fread(pixel, 2, width, fp); + for (col = 0; col < width; col++) + BAYER(row, col) = MAX(BAYER(row, col) - ntohs(pixel[col]), 0); + } + free(pixel); + fclose(fp); + memset(cblack, 0, sizeof cblack); + black = 0; + RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME, 1, 2); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/preprocessing_ph.cpp libkdcraw/libkdcraw/libraw/src/preprocessing/preprocessing_ph.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/preprocessing_ph.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/preprocessing/preprocessing_ph.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,23 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + Placehoder functions to build LibRaw w/o postprocessing + and preprocessing calls + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +void LibRaw::copy_fuji_uncropped(unsigned short cblack[4], + unsigned short *dmaxp) {} +void LibRaw::copy_bayer(unsigned short cblack[4], unsigned short *dmaxp){} +void LibRaw::raw2image_start(){} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/raw2image.cpp libkdcraw/libkdcraw/libraw/src/preprocessing/raw2image.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/raw2image.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/preprocessing/raw2image.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,558 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +void LibRaw::raw2image_start() +{ + // restore color,sizes and internal data into raw_image fields + memmove(&imgdata.color, &imgdata.rawdata.color, sizeof(imgdata.color)); + memmove(&imgdata.sizes, &imgdata.rawdata.sizes, sizeof(imgdata.sizes)); + memmove(&imgdata.idata, &imgdata.rawdata.iparams, sizeof(imgdata.idata)); + memmove(&libraw_internal_data.internal_output_params, + &imgdata.rawdata.ioparams, + sizeof(libraw_internal_data.internal_output_params)); + + if (O.user_flip >= 0) + S.flip = O.user_flip; + + switch ((S.flip + 3600) % 360) + { + case 270: + S.flip = 5; + break; + case 180: + S.flip = 3; + break; + case 90: + S.flip = 6; + break; + } + + // adjust for half mode! + IO.shrink = + P1.filters && + (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1))); + + S.iheight = (S.height + IO.shrink) >> IO.shrink; + S.iwidth = (S.width + IO.shrink) >> IO.shrink; +} + +int LibRaw::raw2image(void) +{ + + CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); + + try + { + raw2image_start(); + + if (is_phaseone_compressed() && imgdata.rawdata.raw_alloc) + { + phase_one_allocate_tempbuffer(); + int rc = phase_one_subtract_black((ushort *)imgdata.rawdata.raw_alloc, + imgdata.rawdata.raw_image); + if (rc == 0) + rc = phase_one_correct(); + if (rc != 0) + { + phase_one_free_tempbuffer(); + return rc; + } + } + + // free and re-allocate image bitmap + if (imgdata.image) + { + imgdata.image = (ushort(*)[4])realloc( + imgdata.image, S.iheight * S.iwidth * sizeof(*imgdata.image)); + memset(imgdata.image, 0, S.iheight * S.iwidth * sizeof(*imgdata.image)); + } + else + imgdata.image = + (ushort(*)[4])calloc(S.iheight * S.iwidth, sizeof(*imgdata.image)); + + merror(imgdata.image, "raw2image()"); + + libraw_decoder_info_t decoder_info; + get_decoder_info(&decoder_info); + + // Move saved bitmap to imgdata.image + if ((imgdata.idata.filters || P1.colors == 1) && imgdata.rawdata.raw_image) + { + if (IO.fuji_width) + { + unsigned r, c; + int row, col; + for (row = 0; row < S.raw_height - S.top_margin * 2; row++) + { + for (col = 0; + col < IO.fuji_width + << !libraw_internal_data.unpacker_data.fuji_layout; + col++) + { + if (libraw_internal_data.unpacker_data.fuji_layout) + { + r = IO.fuji_width - 1 - col + (row >> 1); + c = col + ((row + 1) >> 1); + } + else + { + r = IO.fuji_width - 1 + row - (col >> 1); + c = row + ((col + 1) >> 1); + } + if (r < S.height && c < S.width) + imgdata.image[((r) >> IO.shrink) * S.iwidth + ((c) >> IO.shrink)] + [FC(r, c)] = + imgdata.rawdata + .raw_image[(row + S.top_margin) * S.raw_pitch / 2 + + (col + S.left_margin)]; + } + } + } + else + { + int row, col; + for (row = 0; row < S.height; row++) + for (col = 0; col < S.width; col++) + imgdata.image[((row) >> IO.shrink) * S.iwidth + + ((col) >> IO.shrink)][fcol(row, col)] = + imgdata.rawdata + .raw_image[(row + S.top_margin) * S.raw_pitch / 2 + + (col + S.left_margin)]; + } + } + else // if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY) + { + if (imgdata.rawdata.color4_image) + { + if (S.width * 8 == S.raw_pitch) + memmove(imgdata.image, imgdata.rawdata.color4_image, + S.width * S.height * sizeof(*imgdata.image)); + else + { + for (int row = 0; row < S.height; row++) + memmove(&imgdata.image[row * S.width], + &imgdata.rawdata + .color4_image[(row + S.top_margin) * S.raw_pitch / 8 + + S.left_margin], + S.width * sizeof(*imgdata.image)); + } + } + else if (imgdata.rawdata.color3_image) + { + unsigned char *c3image = (unsigned char *)imgdata.rawdata.color3_image; + for (int row = 0; row < S.height; row++) + { + ushort(*srcrow)[3] = + (ushort(*)[3]) & c3image[(row + S.top_margin) * S.raw_pitch]; + ushort(*dstrow)[4] = (ushort(*)[4]) & imgdata.image[row * S.width]; + for (int col = 0; col < S.width; col++) + { + for (int c = 0; c < 3; c++) + dstrow[col][c] = srcrow[S.left_margin + col][c]; + dstrow[col][3] = 0; + } + } + } + else + { + // legacy decoder, but no data? + throw LIBRAW_EXCEPTION_DECODE_RAW; + } + } + + // Free PhaseOne separate copy allocated at function start + if (is_phaseone_compressed()) + { + phase_one_free_tempbuffer(); + } + // hack - clear later flags! + + if (load_raw == &LibRaw::canon_600_load_raw && S.width < S.raw_width) + { + canon_600_correct(); + } + + imgdata.progress_flags = + LIBRAW_PROGRESS_START | LIBRAW_PROGRESS_OPEN | + LIBRAW_PROGRESS_RAW2_IMAGE | LIBRAW_PROGRESS_IDENTIFY | + LIBRAW_PROGRESS_SIZE_ADJUST | LIBRAW_PROGRESS_LOAD_RAW; + return 0; + } + catch (LibRaw_exceptions err) + { + EXCEPTION_HANDLER(err); + } +} + +void LibRaw::copy_fuji_uncropped(unsigned short cblack[4], + unsigned short *dmaxp) +{ + int row; +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for default(shared) +#endif + for (row = 0; row < int(S.raw_height) - int(S.top_margin) * 2; row++) + { + int col; + unsigned short ldmax = 0; + for (col = 0; + col < IO.fuji_width << !libraw_internal_data.unpacker_data.fuji_layout + && col + int(S.left_margin) < int(S.raw_width); + col++) + { + unsigned r, c; + if (libraw_internal_data.unpacker_data.fuji_layout) + { + r = IO.fuji_width - 1 - col + (row >> 1); + c = col + ((row + 1) >> 1); + } + else + { + r = IO.fuji_width - 1 + row - (col >> 1); + c = row + ((col + 1) >> 1); + } + if (r < S.height && c < S.width) + { + unsigned short val = + imgdata.rawdata.raw_image[(row + S.top_margin) * S.raw_pitch / 2 + + (col + S.left_margin)]; + int cc = FC(r, c); + if (val > cblack[cc]) + { + val -= cblack[cc]; + if (val > ldmax) + ldmax = val; + } + else + val = 0; + imgdata.image[((r) >> IO.shrink) * S.iwidth + ((c) >> IO.shrink)][cc] = + val; + } + } +#if defined(LIBRAW_USE_OPENMP) +#pragma omp critical(dataupdate) +#endif + { + if (*dmaxp < ldmax) + *dmaxp = ldmax; + } + } +} + +void LibRaw::copy_bayer(unsigned short cblack[4], unsigned short *dmaxp) +{ + // Both cropped and uncropped + int row; + int maxHeight = MIN(S.height,S.raw_height-S.top_margin); +#if defined(LIBRAW_USE_OPENMP) +#pragma omp parallel for default(shared) +#endif + for (row = 0; row < maxHeight ; row++) + { + int col; + unsigned short ldmax = 0; + for (col = 0; col < S.width && col + S.left_margin < S.raw_width; col++) + { + unsigned short val = + imgdata.rawdata.raw_image[(row + S.top_margin) * S.raw_pitch / 2 + + (col + S.left_margin)]; + int cc = fcol(row, col); + if (val > cblack[cc]) + { + val -= cblack[cc]; + if (val > ldmax) + ldmax = val; + } + else + val = 0; + imgdata + .image[((row) >> IO.shrink) * S.iwidth + ((col) >> IO.shrink)][cc] = + val; + } +#if defined(LIBRAW_USE_OPENMP) +#pragma omp critical(dataupdate) +#endif + { + if (*dmaxp < ldmax) + *dmaxp = ldmax; + } + } +} + +int LibRaw::raw2image_ex(int do_subtract_black) +{ + + CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); + + try + { + raw2image_start(); + + // Compressed P1 files with bl data! + if (is_phaseone_compressed() && imgdata.rawdata.raw_alloc) + { + phase_one_allocate_tempbuffer(); + int rc = phase_one_subtract_black((ushort *)imgdata.rawdata.raw_alloc, + imgdata.rawdata.raw_image); + if (rc == 0) + rc = phase_one_correct(); + if (rc != 0) + { + phase_one_free_tempbuffer(); + return rc; + } + } + + // process cropping + int do_crop = 0; + if (~O.cropbox[2] && ~O.cropbox[3]) + { + int crop[4], c, filt; + for (int c = 0; c < 4; c++) + { + crop[c] = O.cropbox[c]; + if (crop[c] < 0) + crop[c] = 0; + } + + if (IO.fuji_width && imgdata.idata.filters >= 1000) + { + crop[0] = (crop[0] / 4) * 4; + crop[1] = (crop[1] / 4) * 4; + if (!libraw_internal_data.unpacker_data.fuji_layout) + { + crop[2] *= sqrt(2.0); + crop[3] /= sqrt(2.0); + } + crop[2] = (crop[2] / 4 + 1) * 4; + crop[3] = (crop[3] / 4 + 1) * 4; + } + else if (imgdata.idata.filters == 1) + { + crop[0] = (crop[0] / 16) * 16; + crop[1] = (crop[1] / 16) * 16; + } + else if (imgdata.idata.filters == LIBRAW_XTRANS) + { + crop[0] = (crop[0] / 6) * 6; + crop[1] = (crop[1] / 6) * 6; + } + do_crop = 1; + + crop[2] = MIN(crop[2], (signed)S.width - crop[0]); + crop[3] = MIN(crop[3], (signed)S.height - crop[1]); + if (crop[2] <= 0 || crop[3] <= 0) + throw LIBRAW_EXCEPTION_BAD_CROP; + + // adjust sizes! + S.left_margin += crop[0]; + S.top_margin += crop[1]; + S.width = crop[2]; + S.height = crop[3]; + + S.iheight = (S.height + IO.shrink) >> IO.shrink; + S.iwidth = (S.width + IO.shrink) >> IO.shrink; + if (!IO.fuji_width && imgdata.idata.filters && + imgdata.idata.filters >= 1000) + { + for (filt = c = 0; c < 16; c++) + filt |= FC((c >> 1) + (crop[1]), (c & 1) + (crop[0])) << c * 2; + imgdata.idata.filters = filt; + } + } + + int alloc_width = S.iwidth; + int alloc_height = S.iheight; + + if (IO.fuji_width && do_crop) + { + int IO_fw = S.width >> !libraw_internal_data.unpacker_data.fuji_layout; + int t_alloc_width = + (S.height >> libraw_internal_data.unpacker_data.fuji_layout) + IO_fw; + int t_alloc_height = t_alloc_width - 1; + alloc_height = (t_alloc_height + IO.shrink) >> IO.shrink; + alloc_width = (t_alloc_width + IO.shrink) >> IO.shrink; + } + int alloc_sz = alloc_width * alloc_height; + + if (imgdata.image) + { + imgdata.image = (ushort(*)[4])realloc(imgdata.image, + alloc_sz * sizeof(*imgdata.image)); + memset(imgdata.image, 0, alloc_sz * sizeof(*imgdata.image)); + } + else + imgdata.image = (ushort(*)[4])calloc(alloc_sz, sizeof(*imgdata.image)); + merror(imgdata.image, "raw2image_ex()"); + + libraw_decoder_info_t decoder_info; + get_decoder_info(&decoder_info); + + // Adjust black levels + unsigned short cblack[4] = {0, 0, 0, 0}; + unsigned short dmax = 0; + if (do_subtract_black) + { + adjust_bl(); + for (int i = 0; i < 4; i++) + cblack[i] = (unsigned short)C.cblack[i]; + } + + // Move saved bitmap to imgdata.image + if ((imgdata.idata.filters || P1.colors == 1) && imgdata.rawdata.raw_image) + { + if (IO.fuji_width) + { + if (do_crop) + { + IO.fuji_width = + S.width >> !libraw_internal_data.unpacker_data.fuji_layout; + int IO_fwidth = + (S.height >> libraw_internal_data.unpacker_data.fuji_layout) + + IO.fuji_width; + int IO_fheight = IO_fwidth - 1; + + int row, col; + for (row = 0; row < S.height; row++) + { + for (col = 0; col < S.width; col++) + { + int r, c; + if (libraw_internal_data.unpacker_data.fuji_layout) + { + r = IO.fuji_width - 1 - col + (row >> 1); + c = col + ((row + 1) >> 1); + } + else + { + r = IO.fuji_width - 1 + row - (col >> 1); + c = row + ((col + 1) >> 1); + } + + unsigned short val = + imgdata.rawdata + .raw_image[(row + S.top_margin) * S.raw_pitch / 2 + + (col + S.left_margin)]; + int cc = FCF(row, col); + if (val > cblack[cc]) + { + val -= cblack[cc]; + if (dmax < val) + dmax = val; + } + else + val = 0; + imgdata.image[((r) >> IO.shrink) * alloc_width + + ((c) >> IO.shrink)][cc] = val; + } + } + S.height = IO_fheight; + S.width = IO_fwidth; + S.iheight = (S.height + IO.shrink) >> IO.shrink; + S.iwidth = (S.width + IO.shrink) >> IO.shrink; + S.raw_height -= 2 * S.top_margin; + } + else + { + copy_fuji_uncropped(cblack, &dmax); + } + } // end Fuji + else + { + copy_bayer(cblack, &dmax); + } + } + else // if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY) + { + if (imgdata.rawdata.color4_image) + { + if (S.raw_pitch != S.width * 8) + { + for (int row = 0; row < S.height && row + S.top_margin < S.raw_height; + row++) + memmove(&imgdata.image[row * S.width], + &imgdata.rawdata + .color4_image[(row + S.top_margin) * S.raw_pitch / 8 + + S.left_margin], + MIN(S.width, S.raw_width - S.left_margin) * + sizeof(*imgdata.image)); + } + else + { + // legacy is always 4channel and not shrinked! + memmove(imgdata.image, imgdata.rawdata.color4_image, + MAX(0,MIN(S.raw_width - S.left_margin, S.width)) * + MAX(0,MIN(S.raw_height - S.top_margin, S.height)) * + sizeof(*imgdata.image)); + } + } + else if (imgdata.rawdata.color3_image) + { + unsigned char *c3image = (unsigned char *)imgdata.rawdata.color3_image; + for (int row = 0; row < S.height && row + S.top_margin < S.raw_height; + row++) + { + ushort(*srcrow)[3] = + (ushort(*)[3]) & c3image[(row + S.top_margin) * S.raw_pitch]; + ushort(*dstrow)[4] = (ushort(*)[4]) & imgdata.image[row * S.width]; + for (int col = 0; col < S.width && col + S.left_margin < S.raw_width; + col++) + { + for (int c = 0; c < 3; c++) + dstrow[col][c] = srcrow[S.left_margin + col][c]; + dstrow[col][3] = 0; + } + } + } + else + { + // legacy decoder, but no data? + throw LIBRAW_EXCEPTION_DECODE_RAW; + } + } + + // Free PhaseOne separate copy allocated at function start + if (is_phaseone_compressed()) + { + phase_one_free_tempbuffer(); + } + if (load_raw == &LibRaw::canon_600_load_raw && S.width < S.raw_width) + { + canon_600_correct(); + } + + if (do_subtract_black) + { + C.data_maximum = (int)dmax; + C.maximum -= C.black; + // ZERO(C.cblack); + C.cblack[0] = C.cblack[1] = C.cblack[2] = C.cblack[3] = 0; + C.black = 0; + } + + // hack - clear later flags! + imgdata.progress_flags = + LIBRAW_PROGRESS_START | LIBRAW_PROGRESS_OPEN | + LIBRAW_PROGRESS_RAW2_IMAGE | LIBRAW_PROGRESS_IDENTIFY | + LIBRAW_PROGRESS_SIZE_ADJUST | LIBRAW_PROGRESS_LOAD_RAW; + return 0; + } + catch (LibRaw_exceptions err) + { + EXCEPTION_HANDLER(err); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/subtract_black.cpp libkdcraw/libkdcraw/libraw/src/preprocessing/subtract_black.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/preprocessing/subtract_black.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/preprocessing/subtract_black.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,91 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +int LibRaw::subtract_black() +{ + adjust_bl(); + return subtract_black_internal(); +} + +int LibRaw::subtract_black_internal() +{ + CHECK_ORDER_LOW(LIBRAW_PROGRESS_RAW2_IMAGE); + + try + { + if (!is_phaseone_compressed() && + (C.cblack[0] || C.cblack[1] || C.cblack[2] || C.cblack[3] || + (C.cblack[4] && C.cblack[5]))) + { + int cblk[4], i; + for (i = 0; i < 4; i++) + cblk[i] = C.cblack[i]; + + int size = S.iheight * S.iwidth; + int dmax = 0; + if (C.cblack[4] && C.cblack[5]) + { + for (unsigned i = 0; i < (unsigned)size; i++) + { + for (unsigned c = 0; c < 4; c++) + { + int val = imgdata.image[i][c]; + val -= C.cblack[6 + i / S.iwidth % C.cblack[4] * C.cblack[5] + + i % S.iwidth % C.cblack[5]]; + val -= cblk[c]; + imgdata.image[i][c] = CLIP(val); + if (dmax < val) dmax = val; + } + } + } + else + { + for (unsigned i = 0; i < (unsigned)size; i++) + { + for (unsigned c = 0; c < 4; c++) + { + int val = imgdata.image[i][c]; + val -= cblk[c]; + imgdata.image[i][c] = CLIP(val); + if (dmax < val) dmax = val; + } + } + } + C.data_maximum = dmax & 0xffff; + C.maximum -= C.black; + ZERO(C.cblack); // Yeah, we used cblack[6+] values too! + C.black = 0; + } + else + { + // Nothing to Do, maximum is already calculated, black level is 0, so no + // change only calculate channel maximum; + int idx; + ushort *p = (ushort *)imgdata.image; + int dmax = 0; + for (idx = 0; idx < S.iheight * S.iwidth * 4; idx++) + if (dmax < p[idx]) + dmax = p[idx]; + C.data_maximum = dmax; + } + return 0; + } + catch (LibRaw_exceptions err) + { + EXCEPTION_HANDLER(err); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/tables/cameralist.cpp libkdcraw/libkdcraw/libraw/src/tables/cameralist.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/tables/cameralist.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/tables/cameralist.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,1187 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" +#ifdef USE_RAWSPEED +/* we need separate file for that */ +#include "../../RawSpeed/rawspeed_xmldata.cpp" +const int RAWSPEED_DATA_COUNT = + (sizeof(_rawspeed_data_xml) / sizeof(_rawspeed_data_xml[0])); +#endif +// clang-format off +// Supported cameras: +static const char *static_camera_list[] = { + "Adobe Digital Negative (DNG)", + "AgfaPhoto DC-833m", + "Alcatel 5035D", + "Apple iPad Pro", + "Apple iPhone SE", + "Apple iPhone 6s", + "Apple iPhone 6 plus", + "Apple iPhone 7", + "Apple iPhone 7 plus", + "Apple iPhone 8", + "Apple iPhone 8 plus", + "Apple iPhone X", + "Apple QuickTake 100", + "Apple QuickTake 150", + "Apple QuickTake 200", + "ARRI ALEXA", + "ARRI ALEXA65", + "ARRI ALEXA LF", + "ARRI ALEXA XT", + "ARRI ALEXA SXT", + "ASUS ZenPhone4", + "ASUS ZenPhone6", + "AVT F-080C", + "AVT F-145C", + "AVT F-201C", + "AVT F-510C", + "AVT F-810C", + "Baumer TXG14", + "BlackMagic Cinema Camera", + "BlackMagic Micro Cinema Camera", + "BlackMagic Pocket Cinema Camera", + "BlackMagic Production Camera 4k", + "BlackMagic URSA", + "BlackMagic URSA Mini 4k", + "BlackMagic URSA Mini 4.6k", + "BlackMagic URSA Mini Pro 4.6k", + "BQ Aquarius U", + "Canon PowerShot 600", + "Canon PowerShot A5", + "Canon PowerShot A5 Zoom", + "Canon PowerShot A50", + "Canon PowerShot A410 (CHDK hack)", + "Canon PowerShot A460 (CHDK hack)", + "Canon PowerShot A470 (CHDK hack)", + "Canon PowerShot A480 (CHDK hack)", + "Canon PowerShot A530 (CHDK hack)", + "Canon PowerShot A540 (CHDK hack)", + "Canon PowerShot A550 (CHDK hack)", + "Canon PowerShot A560 (CHDK hack)", + "Canon PowerShot A570 (CHDK hack)", + "Canon PowerShot A590 (CHDK hack)", + "Canon PowerShot A610 (CHDK hack)", + "Canon PowerShot A620 (CHDK hack)", + "Canon PowerShot A630 (CHDK hack)", + "Canon PowerShot A640 (CHDK hack)", + "Canon PowerShot A650 (CHDK hack)", + "Canon PowerShot A710 IS (CHDK hack)", + "Canon PowerShot A720 IS (CHDK hack)", + "Canon PowerShot A3300 IS (CHDK hack)", + "Canon PowerShot D10 (CHDK hack)", + "Canon PowerShot ELPH 130 IS (CHDK hack)", + "Canon PowerShot ELPH 160 IS (CHDK hack)", + "Canon PowerShot Pro70", + "Canon PowerShot Pro90 IS", + "Canon PowerShot Pro1", + "Canon PowerShot G1", + "Canon PowerShot G1 X", + "Canon PowerShot G1 X Mark II", + "Canon PowerShot G1 X Mark III", + "Canon PowerShot G2", + "Canon PowerShot G3", + "Canon PowerShot G3 X", + "Canon PowerShot G5", + "Canon PowerShot G5 X", + "Canon PowerShot G5 X Mark II", + "Canon PowerShot G6", + "Canon PowerShot G7 (CHDK hack)", + "Canon PowerShot G7 X", + "Canon PowerShot G7 X Mark II", + "Canon PowerShot G7 X Mark III", + "Canon PowerShot G9", + "Canon PowerShot G9 X", + "Canon PowerShot G9 X Mark II", + "Canon PowerShot G10", + "Canon PowerShot G11", + "Canon PowerShot G12", + "Canon PowerShot G15", + "Canon PowerShot G16", + "Canon PowerShot S2 IS (CHDK hack)", + "Canon PowerShot S3 IS (CHDK hack)", + "Canon PowerShot S5 IS (CHDK hack)", + "Canon PowerShot SD300 (CHDK hack)", + "Canon PowerShot SD750 (CHDK hack)", + "Canon PowerShot SD950 (CHDK hack)", + "Canon PowerShot S30", + "Canon PowerShot S40", + "Canon PowerShot S45", + "Canon PowerShot S50", + "Canon PowerShot S60", + "Canon PowerShot S70", + "Canon PowerShot S90", + "Canon PowerShot S95", + "Canon PowerShot S100", + "Canon PowerShot S110", + "Canon PowerShot S120", + "Canon PowerShot SX1 IS", + "Canon PowerShot SX50 HS", + "Canon PowerShot SX60 HS", + "Canon PowerShot SX70 HS", + "Canon PowerShot SX100 IS (CHDK hack)", + "Canon PowerShot SX110 IS (CHDK hack)", + "Canon PowerShot SX120 IS (CHDK hack)", + "Canon PowerShot SX130 IS (CHDK hack)", + "Canon PowerShot SX160 IS (CHDK hack)", + "Canon PowerShot SX220 HS (CHDK hack)", + "Canon PowerShot SX510 HS (CHDK hack)", + "Canon PowerShot SX10 IS (CHDK hack)", + "Canon PowerShot SX20 IS (CHDK hack)", + "Canon PowerShot SX30 IS (CHDK hack)", + "Canon PowerShot IXUS 95 (CHDK hack)", + "Canon PowerShot IXUS 160 (CHDK hack)", + "Canon PowerShot IXUS 900Ti (CHDK hack)", + "Canon EOS R", + "Canon EOS RP", + "Canon EOS D30", + "Canon EOS D60", + "Canon EOS 5DS", + "Canon EOS 5DS R", + "Canon EOS 5D", + "Canon EOS 5D Mark II", + "Canon EOS 5D Mark III", + "Canon EOS 5D Mark IV", + "Canon EOS 6D", + "Canon EOS 6D Mark II", + "Canon EOS 7D", + "Canon EOS 7D Mark II", + "Canon EOS 10D", + "Canon EOS 20D", + "Canon EOS 20Da", + "Canon EOS 30D", + "Canon EOS 40D", + "Canon EOS 50D", + "Canon EOS 60D", + "Canon EOS 60Da", + "Canon EOS 70D", + "Canon EOS 77D / 9000D", + "Canon EOS 80D", + "Canon EOS 90D", + "Canon EOS 100D / Rebel SL1 / Kiss X7", + "Canon EOS 200D / Rebel SL2 / Kiss X9", + "Canon EOS 250D / 200D II / Rebel SL3 / Kiss X10", + "Canon EOS 300D / Digital Rebel / Kiss Digital", + "Canon EOS 350D / Digital Rebel XT / Kiss Digital N", + "Canon EOS 400D / Digital Rebel XTi / Kiss Digital X", + "Canon EOS 450D / Digital Rebel XSi / Kiss X2", + "Canon EOS 500D / Rebel T1i / Kiss X3", + "Canon EOS 550D / Rebel T2i / Kiss X4", + "Canon EOS 600D / Rebel T3i / Kiss X5", + "Canon EOS 650D / Rebel T4i / Kiss X6i", + "Canon EOS 700D / Rebel T5i / Kiss X7i", + "Canon EOS 750D / Rebel T6i / Kiss X8i", + "Canon EOS 760D / Rebel T6S / 8000D", + "Canon EOS 800D / Rebel T7i / Kiss X9i", + "Canon EOS 1000D / Digital Rebel XS / Kiss F", + "Canon EOS 1100D / Rebel T3 / Kiss X50", + "Canon EOS 1200D / Kiss X70 / REBEL T5 / Hi", + "Canon EOS 1300D / Rebel T6 / Kiss X80", + "Canon EOS 1500D / 2000D / Rebel T7 / Kiss X90", + "Canon EOS 3000D / 4000D / Rebel T100", + "Canon EOS C500", + "Canon EOS D2000", + "Canon EOS M", + "Canon EOS M2", + "Canon EOS M3", + "Canon EOS M5", + "Canon EOS M6", + "Canon EOS M6 Mark II", + "Canon EOS M10", + "Canon EOS M50 / Kiss M", + "Canon EOS M100", + "Canon EOS M200", + "Canon EOS-1D C", + "Canon EOS-1D X", + "Canon EOS-1D X Mark II", + "Canon EOS-1D X Mark III (lossless compressed only)", + "Canon EOS-1D", + "Canon EOS-1D Mark II", + "Canon EOS-1D Mark II N", + "Canon EOS-1D Mark III", + "Canon EOS-1D Mark IV", + "Canon EOS-1DS", + "Canon EOS-1Ds Mark II", + "Canon EOS-1Ds Mark III", + "Casio QV-2000UX (secret menu hack)", + "Casio QV-3000EX (secret menu hack)", + "Casio QV-3500EX (secret menu hack)", + "Casio QV-4000 (secret menu hack)", + "Casio QV-5700 (secret menu hack)", + "Casio QV-R41", + "Casio QV-R51", + "Casio QV-R61", + "Casio EX-F1", + "Casio EX-FC300S", + "Casio EX-FC400S", + "Casio EX-FH20", + "Casio EX-FH25", + "Casio EX-FH100", + "Casio EX-S20 / M20", + "Casio EX-S100", + "Casio EX-Z4", + "Casio EX-Z50", + "Casio EX-Z500", + "Casio EX-Z55", + "Casio EX-Z60", + "Casio EX-Z75", + "Casio EX-Z750", + "Casio EX-Z8", + "Casio EX-Z850", + "Casio EX-Z1050", + "Casio EX-ZR100", + "Casio EX-Z1080", + "Casio EX-ZR700", + "Casio EX-ZR710", + "Casio EX-ZR750", + "Casio EX-ZR800", + "Casio EX-ZR850", + "Casio EX-ZR1000", + "Casio EX-ZR1100", + "Casio EX-ZR1200", + "Casio EX-ZR1300", + "Casio EX-ZR1500", + "Casio EX-ZR3000", + "Casio EX-ZR3100", + "Casio EX-ZR3200", + "Casio EX-ZR3500", + "Casio EX-ZR3600", + "Casio EX-ZR3700", + "Casio EX-ZR4000 / 5000", + "Casio EX-ZR4100 / 5100", + "Casio EX-100", + "Casio EX-100F", + "Casio EX-100PRO", + "Casio EX-10", + "Casio EX-P505 (secret menu hack)", + "Casio EX-P600 (secret menu hack)", + "Casio EX-P700 (secret menu hack)", + "CLAUSS pix500", + "Contax N Digital", + "Creative PC-CAM 600", + "Digital Bolex D16", + "Digital Bolex D16M", + "DJI 4384x3288", + "DJI Mavic Air", + "DJI Mavic Air2", + "DJI Osmo Action", + "DJI Phantom4 Pro/Pro+", + "DJI Zenmuse X5", + "DJI Zenmuse X5R", + "DXO One", + "Epson R-D1", + "Epson R-D1s", + "Epson R-D1x", + "Eyedeas E1", + "Foculus 531C", + "FujiFilm DBP for GX680 / DX-2000", + "FujiFilm E550", + "FujiFilm E900", + "FujiFilm F500EXR / F505EXR", + "FujiFilm F550EXR", + "FujiFilm F600EXR / F605EXR", + "FujiFilm F700", + "FujiFilm F710", + "FujiFilm F770EXR / F775EXR", + "FujiFilm F800EXR", + "FujiFilm F810", + "FujiFilm F900EXR", + "FujiFilm S2Pro", + "FujiFilm S3Pro", + "FujiFilm S5Pro", + "FujiFilm S20Pro", + "FujiFilm S1", + "FujiFilm S100FS", + "FujiFilm S5000", + "FujiFilm S5100 / S5500", + "FujiFilm S5200 / S5600", + "FujiFilm S6000fd / S6500fd", + "FujiFilm S7000", + "FujiFilm S9000 / S9500", + "FujiFilm S9100 / S9600", + "FujiFilm S200EXR / S205EXR", + "FujiFilm SL1000", + "FujiFilm HS10/HS11", + "FujiFilm HS20EXR / HS22EXR", + "FujiFilm HS30EXR / HS33EXR / HS35EXR", + "FujiFilm HS50EXR", + "FujiFilm GFX 50S", + "FujiFilm GFX 50R", + "FujiFilm GFX 100", + "FujiFilm X-Pro1", + "FujiFilm X-Pro2", + "FujiFilm X-Pro3", + "FujiFilm X-S1", + "FujiFilm XQ1", + "FujiFilm XQ2", + "FujiFilm X100", + "FujiFilm X100f", + "FujiFilm X100S", + "FujiFilm X100T", + "FujiFilm X100V", + "FujiFilm X10", + "FujiFilm X20", + "FujiFilm X30", + "FujiFilm X70", + "FujiFilm X-A1", + "FujiFilm X-A2", + "FujiFilm X-A3", + "FujiFilm X-A5", + "FujiFilm X-A7", + "FujiFilm X-A10", + "FujiFilm X-A20", + "FujiFilm X-E1", + "FujiFilm X-E2", + "FujiFilm X-E2S", + "FujiFilm X-E3", + "FujiFilm X-M1", + "FujiFilm XF1", + "FujiFilm XF10", + "FujiFilm X-H1", + "FujiFilm X-T1", + "FujiFilm X-T1 Graphite Silver", + "FujiFilm X-T2", + "FujiFilm X-T3", + "FujiFilm X-T4 (uncompressed and lossless compressed only)", + "FujiFilm X-T10", + "FujiFilm X-T20", + "FujiFilm X-T30", + "FujiFilm X-T100", + "FujiFilm X-T200", + "FujiFilm IS-1", + "Gione E7", + "GITUP GIT2", + "GITUP GIT2P", + "GITUP G3 DUO (16:9 mode only)", + "Google Pixel", + "Google Pixel XL", + "Google Pixel 3a", + "Google Pixel 4 XL", +#ifdef USE_GPRSDK + "GoPro Fusion", + "GoPro HERO5", + "GoPro HERO6", + "GoPro HERO7", + "GoPro HERO8", +#endif + "Hasselblad H2D-22", + "Hasselblad H2D-39", + "Hasselblad H3DII-22", + "Hasselblad H3DII-31", + "Hasselblad H3DII-39", + "Hasselblad H3DII-50", + "Hasselblad H3D-22", + "Hasselblad H3D-31", + "Hasselblad H3D-39", + "Hasselblad H4D-60", + "Hasselblad H4D-50", + "Hasselblad H4D-40", + "Hasselblad H4D-31", + "Hasselblad H5D-60", + "Hasselblad H5D-50", + "Hasselblad H5D-50c", + "Hasselblad H5D-40", + "Hasselblad H6D-100c", + "Hasselblad A6D-100c", // Aerial camera + "Hasselblad CFV", + "Hasselblad CFV-50", + "Hasselblad CFH", + "Hasselblad CF-22", + "Hasselblad CF-31", + "Hasselblad CF-39", + "Hasselblad V96C", + "Hasselblad L1D-20c (DJI Mavic 2 Pro)", + "Hasselblad Lusso", + "Hasselblad Lunar", + "Hasselblad True Zoom", + "Hasselblad Stellar", + "Hasselblad Stellar II", + "Hasselblad HV", + "Hasselblad X1D", + "Hasselblad X1D II 50C", + "HTC UltraPixel", + "HTC MyTouch 4G", + "HTC One (A9)", + "HTC One (M9)", + "HTC 10", + "HTC U12", + "Huawei P8 Lite (PRA-LX1)", + "Huawei P9 (EVA-L09/AL00)", + "Huawei P10 (VTR-L09)", + "Huawei P10+ (VKY-L09)", + "Huawei P10 Lite (WAS-LX1A)", + "Huawei P20 (EML-L09)", + "Huawei P20 Pro (CLT-L29/L09)", + "Huawei P30 Pro (VOG-L29)", + "Huawei Honor6a", + "Huawei Honor7a pro", + "Huawei Honor8 (FRD-L09)", + "Huawei Honor9", + "Huawei Honor10", + "Huawei Honor20", + "Huawei Honor View 10 (BKL-L09)", + "Huawei Honor View 20 (PCT-L29)", + "Huawei Mate8 (NXT-L29)", + "Huawei Mate10 (BLA-L29)", + "Huawei Mate20 Pro (LYA-L29)", + "Imacon Ixpress 96, 96C", + "Imacon Ixpress 384, 384C (single shot only)", + "Imacon Ixpress 132C", + "Imacon Ixpress 528C (single shot only)", + "ISG 2020x1520", + "Ikonoskop A-Cam dII Panchromatic", + "Ikonoskop A-Cam dII", + "Kinefinity KineMINI", + "Kinefinity KineRAW Mini", + "Kinefinity KineRAW S35", + "Kodak DC20", + "Kodak DC25", + "Kodak DC40", + "Kodak DC50", + "Kodak DC120", + "Kodak DCS200", + "Kodak DCS315C", + "Kodak DCS330C", + "Kodak DCS420", + "Kodak DCS460", + "Kodak DCS460M", + "Kodak DCS460", + "Kodak DCS520C", + "Kodak DCS560C", + "Kodak DCS620C", + "Kodak DCS620X", + "Kodak DCS660C", + "Kodak DCS660M", + "Kodak DCS720X", + "Kodak DCS760C", + "Kodak DCS760M", + "Kodak EOSDCS1", + "Kodak EOSDCS3", + "Kodak NC2000", + "Kodak ProBack", + "Kodak PB645C", + "Kodak PB645H", + "Kodak PB645M", + "Kodak DCS Pro 14n", + "Kodak DCS Pro 14nx", + "Kodak DCS Pro SLR/c", + "Kodak DCS Pro SLR/n", + "Kodak C330", + "Kodak C603", + "Kodak P850", + "Kodak P880", + "Kodak PIXPRO AZ901", + "Kodak PIXPRO S-1", + "Kodak Z980", + "Kodak Z981", + "Kodak Z990", + "Kodak Z1015", + "Kodak KAI-0340", + "Konica KD-400Z", + "Konica KD-510Z", + "Leaf AFi 5", + "Leaf AFi 6", + "Leaf AFi 7", + "Leaf AFi-II 6", + "Leaf AFi-II 7", + "Leaf AFi-II 10", + "Leaf AFi-II 10R", + "Leaf Aptus-II 5", + "Leaf Aptus-II 6", + "Leaf Aptus-II 7", + "Leaf Aptus-II 8", + "Leaf Aptus-II 10", + "Leaf Aptus-II 12", + "Leaf Aptus-II 12R", + "Leaf Aptus 17", + "Leaf Aptus 22", + "Leaf Aptus 54S", + "Leaf Aptus 65", + "Leaf Aptus 65S", + "Leaf Aptus 75", + "Leaf Aptus 75S", + "Leaf Cantare", + "Leaf Cantare XY", + "Leaf CatchLight", + "Leaf CMost", + "Leaf Credo 40", + "Leaf Credo 50", + "Leaf Credo 60", + "Leaf Credo 80 (low compression mode only)", + "Leaf DCB-II", + "Leaf Valeo 6", + "Leaf Valeo 11", + "Leaf Valeo 17", + "Leaf Valeo 17wi", + "Leaf Valeo 22", + "Leaf Valeo 22wi", + "Leaf Volare", + "Lenovo a820", + "Leica C (Typ 112)", + "Leica CL", + "Leica C-Lux / CAM-DC25", + "Leica Digilux 2", + "Leica Digilux 3", + "Leica Digital-Modul-R", + "Leica D-LUX2", + "Leica D-LUX3", + "Leica D-LUX4", + "Leica D-LUX5", + "Leica D-LUX6", + "Leica D-LUX7", + "Leica D-Lux (Typ 109)", + "Leica M8", + "Leica M8.2", + "Leica M9", + "Leica M10", + "Leica M10-D", + "Leica M10-P", + "Leica M10 Monochrom", + "Leica M (Typ 240)", + "Leica M (Typ 262)", + "Leica Monochrom (Typ 240)", + "Leica Monochrom (Typ 246)", + "Leica M-D (Typ 262)", + "Leica M-E", + "Leica M-P", + "Leica R8", + "Leica Q (Typ 116)", + "Leica Q-P", + "Leica Q2", + "Leica S", + "Leica S2", + "Leica S (Typ 007)", + "Leica SL (Typ 601)", + "Leica SL2", + "Leica T (Typ 701)", + "Leica TL", + "Leica TL2", + "Leica X1", + "Leica X (Typ 113)", + "Leica X2", + "Leica X-E (Typ 102)", + "Leica X-U (Typ 113)", + "Leica V-LUX1", + "Leica V-LUX2", + "Leica V-LUX3", + "Leica V-LUX4", + "Leica V-LUX5", + "Leica V-Lux (Typ 114)", + "Leica X VARIO (Typ 107)", + "LG G3", + "LG G4", + "LG G6", + "LG V20 (F800K)", + "LG VS995", + "Logitech Fotoman Pixtura", + "Mamiya ZD", + "Matrix 4608x3288", + "Meizy MX4", + "Micron 2010", + "Minolta RD175 / Agfa ActionCam", + "Minolta DiMAGE 5", + "Minolta DiMAGE 7", + "Minolta DiMAGE 7i", + "Minolta DiMAGE 7Hi", + "Minolta DiMAGE A1", + "Minolta DiMAGE A2", + "Minolta DiMAGE A200", + "Minolta DiMAGE G400", + "Minolta DiMAGE G500", + "Minolta DiMAGE G530", + "Minolta DiMAGE G600", + "Minolta DiMAGE Z2", + "Minolta Alpha/Dynax/Maxxum 5D", + "Minolta Alpha/Dynax/Maxxum 7D", + "Motorola PIXL", + "Motorola Moto G (5S)", + "Motorola Moto G7 Play", + "Nikon D1", + "Nikon D1H", + "Nikon D1X", + "Nikon D2H", + "Nikon D2Hs", + "Nikon D2X", + "Nikon D2Xs", + "Nikon D3", + "Nikon D3s", + "Nikon D3X", + "Nikon D4", + "Nikon D4s", + "Nikon D40", + "Nikon D40X", + "Nikon D5", + "Nikon D50", + "Nikon D5", + "Nikon D60", + "Nikon D70", + "Nikon D70s", + "Nikon D80", + "Nikon D90", + "Nikon D100", + "Nikon D200", + "Nikon D300", + "Nikon D300s", + "Nikon D500", + "Nikon D600", + "Nikon D610", + "Nikon D700", + "Nikon D750", + "Nikon D780", + "Nikon D800", + "Nikon D800E", + "Nikon D810", + "Nikon D810A", + "Nikon D850", + "Nikon D3000", + "Nikon D3100", + "Nikon D3200", + "Nikon D3300", + "Nikon D3400", + "Nikon D3500", + "Nikon D5000", + "Nikon D5100", + "Nikon D5200", + "Nikon D5300", + "Nikon D5500", + "Nikon D5600", + "Nikon D7000", + "Nikon D7100", + "Nikon D7200", + "Nikon D7500", + "Nikon Df", + "Nikon Z 6", + "Nikon Z 7", + "Nikon Z 50", + "Nikon 1 AW1", + "Nikon 1 J1", + "Nikon 1 J2", + "Nikon 1 J3", + "Nikon 1 J4", + "Nikon 1 J5", + "Nikon 1 S1", + "Nikon 1 S2", + "Nikon 1 V1", + "Nikon 1 V2", + "Nikon 1 V3", + "Nikon Coolpix 700 (\"DIAG RAW\" hack)", + "Nikon Coolpix 800 (\"DIAG RAW\" hack)", + "Nikon Coolpix 880 (\"DIAG RAW\" hack)", + "Nikon Coolpix 900 (\"DIAG RAW\" hack)", + "Nikon Coolpix 950 (\"DIAG RAW\" hack)", + "Nikon Coolpix 990 (\"DIAG RAW\" hack)", + "Nikon Coolpix 995 (\"DIAG RAW\" hack)", + "Nikon Coolpix 2100 (\"DIAG RAW\" hack)", + "Nikon Coolpix 2500 (\"DIAG RAW\" hack)", + "Nikon Coolpix 3200 (\"DIAG RAW\" hack)", + "Nikon Coolpix 3700 (\"DIAG RAW\" hack)", + "Nikon Coolpix 4300 (\"DIAG RAW\" hack)", + "Nikon Coolpix 4500 (\"DIAG RAW\" hack)", + "Nikon Coolpix 5000", + "Nikon Coolpix 5400", + "Nikon Coolpix 5700", + "Nikon Coolpix 8400", + "Nikon Coolpix 8700", + "Nikon Coolpix 8800", + "Nikon Coolpix A", + "Nikon Coolpix A1000", + "Nikon Coolpix B700", + "Nikon Coolpix P330", + "Nikon Coolpix P340", + "Nikon Coolpix P950", + "Nikon Coolpix P6000", + "Nikon Coolpix P1000", + "Nikon Coolpix P7000", + "Nikon Coolpix P7100", + "Nikon Coolpix P7700", + "Nikon Coolpix P7800", + "Nikon Coolpix S6 (\"DIAG RAW\" hack)", + "Nikon Coolscan NEF", + "Nokia 7 Plus", + "Nokia N95", + "Nokia X2", + "Nokia 1200x1600", + "Nokia Lumia 930", + "Nokia Lumia 950 XL", + "Nokia Lumia 1020", + "Nokia Lumia 1520", + "Olympus AIR A01", + "Olympus C-3030Z", + "Olympus C-5050Z", + "Olympus C-5060WZ", + "Olympus C-7070WZ", + "Olympus C-70Z / C-7000Z", + "Olympus C-740UZ", + "Olympus C-770UZ", + "Olympus C-8080WZ", + "Olympus X200 / D-560Z / C-350Z", + "Olympus E-1", + "Olympus E-3", + "Olympus E-5", + "Olympus E-10", + "Olympus E-20 / E-20N / E-20P", + "Olympus E-30", + "Olympus E-300", + "Olympus E-330", + "Olympus E-400", + "Olympus E-410", + "Olympus E-420", + "Olympus E-450", + "Olympus E-500", + "Olympus E-510", + "Olympus E-520", + "Olympus E-600", + "Olympus E-620", + "Olympus E-P1", + "Olympus E-P2", + "Olympus E-P3", + "Olympus E-P5", + "Olympus E-PL1", + "Olympus E-PL1s", + "Olympus E-PL2", + "Olympus E-PL3", + "Olympus E-PL5", + "Olympus E-PL6", + "Olympus E-PL7", + "Olympus E-PL8", + "Olympus E-PL9", + "Olympus E-PL10", + "Olympus E-PM1", + "Olympus E-PM2", + "Olympus E-M1", + "Olympus E-M1 Mark II", + "Olympus E-M1 Mark III", + "Olympus E-M1X", + "Olympus E-M10", + "Olympus E-M10 Mark II", + "Olympus E-M10 Mark III", + "Olympus E-M5", + "Olympus E-M5 Mark II", + "Olympus E-M5 Mark III", + "Olympus Pen-F", + "Olympus SP-310", + "Olympus SP-320", + "Olympus SP-350", + "Olympus SP-500UZ", + "Olympus SP-510UZ", + "Olympus SP-550UZ", + "Olympus SP-560UZ", + "Olympus SP-565UZ", + "Olympus SP-570UZ", + "Olympus Stylus 1", + "Olympus Stylus 1s", + "Olympus SH-2", + "Olympus SH-3", + "Olympus TG-4", + "Olympus TG-5", + "Olympus TG-6", + "Olympus XZ-1", + "Olympus XZ-2", + "Olympus XZ-10", + "OmniVision 4688", + "OmniVision OV5647", + "OmniVision OV5648", + "OmniVision OV8850", + "OmniVision 13860", + "OnePlus 6T", + "OnePlus One", + "OnePlus A3303", + "OnePlus A5000", + "Panasonic DMC-CM1", + "Panasonic DMC-FZ8", + "Panasonic DMC-FZ18", + "Panasonic DMC-FZ28", + "Panasonic DMC-FZ30", + "Panasonic DMC-FZ35 / FZ38", + "Panasonic DMC-FZ40 / FZ42 / FZ45", + "Panasonic DMC-FZ50", + "Panasonic DMC-FZ70 / FZ72", + "Panasonic DC-FZ80 / FZ81 / FZ82 / FZ83 / FZ85", + "Panasonic DMC-FZ100", + "Panasonic DMC-FZ150", + "Panasonic DMC-FZ200", + "Panasonic DMC-FZ300 / FZ330", + "Panasonic DMC-FZ1000", + "Panasonic DC-FZ1000 II / FZ1000M2 / DC-FZ10002", + "Panasonic DMC-FZ2000 / FZ2500 / FZH1", + "Panasonic DMC-FX150 / FX180", + "Panasonic DMC-G1", + "Panasonic DMC-G10", + "Panasonic DMC-G2", + "Panasonic DMC-G3", + "Panasonic DMC-G5", + "Panasonic DMC-G6", + "Panasonic DMC-G7 / G70", + "Panasonic DMC-G8 / G80 / G81 / G85", + "Panasonic DC-G9", + "Panasonic DC-G90 / G95 / G91 / G99", + "Panasonic DMC-GF1", + "Panasonic DMC-GF2", + "Panasonic DMC-GF3", + "Panasonic DMC-GF5", + "Panasonic DMC-GF6", + "Panasonic DMC-GF7", + "Panasonic DC-GF10 / GF90", + "Panasonic DMC-GH1", + "Panasonic DMC-GH2", + "Panasonic DMC-GH3", + "Panasonic DMC-GH4", + "Panasonic AG-GH4", + "Panasonic DC-GH5", + "Panasonic DC-GH5S", + "Panasonic DMC-GM1", + "Panasonic DMC-GM1s", + "Panasonic DMC-GM5", + "Panasonic DMC-GX1", + "Panasonic DMC-GX7", + "Panasonic DMC-GX8", + "Panasonic DC-GX9 / GX7mkIII", + "Panasonic DMC-GX80 / GX85, DMC-GX7mkII", + "Panasonic DC-GX800 / GX850, DC-GF9", + "Panasonic DMC-L1", + "Panasonic DMC-L10", + "Panasonic DMC-LC1", + "Panasonic DMC-LF1", + "Panasonic DMC-LX1", + "Panasonic DMC-LX2", + "Panasonic DMC-LX3", + "Panasonic DMC-LX5", + "Panasonic DMC-LX7", + "Panasonic DMC-LX9 / LX10 / LX15", + "Panasonic DMC-LX100", + "Panasonic DC-LX100M2", + "Panasonic DC-S1", + "Panasonic DC-S1H", + "Panasonic DC-S1R", + "Panasonic DMC-ZS40, DMC-TZ60 / TZ61", + "Panasonic DMC-ZS50, DMC-TZ70 / TZ71", + "Panasonic DMC-ZS60, DMC-TZ80 / TZ81 / TZ82 / TZ85", + "Panasonic DC-ZS70, DC-TZ90 / TZ91 / TZ92 / TZ93", + "Panasonic DC-ZS80, DC-TZ95 / TZ96 / TZ97", + "Panasonic DMC-ZS100 / ZS110, DMC-TZ100 / TZ101 / TZ110, DMC-TX1", + "Panasonic DC-ZS200 / ZS220, DC-TZ200 / TZ202 / TZ220, DC-TX2", + "PARROT Anafi", + "PARROT Bebop 2", + "PARROT Bebop Drone", + "Pentax *ist D", + "Pentax *ist DL", + "Pentax *ist DL2", + "Pentax *ist DS", + "Pentax *ist DS2", + "Pentax K10D", + "Pentax K20D", + "Pentax K100D", + "Pentax K100D Super", + "Pentax K110D", + "Pentax K200D", + "Pentax K2000/K-m", + "Pentax KP", + "Pentax K-x", + "Pentax K-r", + "Pentax K-01", + "Pentax K-1", + "Pentax K-1 Mark II", + "Pentax K-3", + "Pentax K-3 II", + "Pentax K-30", + "Pentax K-5", + "Pentax K-5 II", + "Pentax K-5 IIs", + "Pentax K-50", + "Pentax K-500", + "Pentax K-7", + "Pentax K-70", + "Pentax K-S1", + "Pentax K-S2", + "Pentax MX-1", + "Pentax Q", + "Pentax Q7", + "Pentax Q10", + "Pentax QS-1", + "Pentax Optio S (secret menu or hack)", + "Pentax Optio S4 (secret menu or hack)", + "Pentax Optio 33WR (secret menu or hack)", + "Pentax Optio 750Z (secret menu or hack)", + "Pentax 645D", + "Pentax 645Z", + "PhaseOne IQ140", + "PhaseOne IQ150", + "PhaseOne IQ160", + "PhaseOne IQ180", + "PhaseOne IQ180 IR", + "PhaseOne IQ250", + "PhaseOne IQ260", + "PhaseOne IQ260 Achromatic", + "PhaseOne IQ280", + "PhaseOne IQ3 50MP", + "PhaseOne IQ3 60MP", + "PhaseOne IQ3 80MP", + "PhaseOne IQ3 100MP", + "PhaseOne IQ3 100MP Trichromatic", + "PhaseOne IQ4 150MP", + "PhaseOne LightPhase", + "PhaseOne Achromatic+", + "PhaseOne H 10", + "PhaseOne H 20", + "PhaseOne H 25", + "PhaseOne P 20", + "PhaseOne P 20+", + "PhaseOne P 21", + "PhaseOne P 25", + "PhaseOne P 25+", + "PhaseOne P 30", + "PhaseOne P 30+", + "PhaseOne P 40+", + "PhaseOne P 45", + "PhaseOne P 45+", + "PhaseOne P 65", + "PhaseOne P 65+", + "Photron BC2-HD", + "Pixelink A782", +#ifdef USE_X3FTOOLS + "Polaroid x530", +#endif + "RaspberryPi Camera", + "RaspberryPi Camera V2", + "Ricoh GR", + "Realme 3 Pro", + "Ricoh GR II", + "Ricoh GR III", + "Ricoh GR Digital", + "Ricoh GR Digital II", + "Ricoh GR Digital III", + "Ricoh GR Digital IV", + "Ricoh Caplio GX100", + "Ricoh Caplio GX200", + "Ricoh GXR Mount A12", + "Ricoh GXR GR Lens A12 50mm F2.5 Macro", + "Ricoh GXR GR Lens A12 28mm F2.5", + "Ricoh GXR Ricoh Lens A16 24-85mm F3.5-5.5", + "Ricoh GXR Ricoh Lens S10 24-72mm F2.5-4.4 VC", + "Ricoh GXR Ricoh Lens P10 28-300 mm F3.5-5.6 VC", +#ifndef NO_JASPER + "Redcode R3D format", +#endif + "Rollei d530flex", + "RoverShot 3320af", + "Samsung EX1 / TL500", + "Samsung EX2F", + "Samsung GX-1L", + "Samsung GX-1S", + "Samsung GX10", + "Samsung GX20", + "Samsung Galaxy Nexus", + "Samsung Galaxy Note 9", + "Samsung Galaxy NX (EK-GN120)", + "Samsung Galaxy S3", + "Samsung Galaxy S6 (SM-G920F)", + "Samsung Galaxy S7", + "Samsung Galaxy S7 Edge", + "Samsung Galaxy S8 (SM-G950U)", + "Samsung Galaxy S9 (SM-G960F)", + "Samsung Galaxy S9+ (SM-G965U / 965F)", + "Samsung Galaxy S10 (SM-G973F)", + "Samsung Galaxy S10+ (SM-G975U)", + "Samsung NX1", + "Samsung NX5", + "Samsung NX10", + "Samsung NX11", + "Samsung NX100", + "Samsung NX1000", + "Samsung NX1100", + "Samsung NX20", + "Samsung NX200", + "Samsung NX210", + "Samsung NX2000", + "Samsung NX30", + "Samsung NX300", + "Samsung NX300M", + "Samsung NX3000", + "Samsung NX500", + "Samsung NX mini / NXF1", + "Samsung Pro815", + "Samsung WB550 / WB560 / HZ15W", + "Samsung WB2000 / TL350", + "Samsung WB5000 / HZ25W", + "Samsung S85 (hacked)", + "Samsung S850 (hacked)", + "Sarnoff 4096x5440", + "Seitz 6x17", + "Seitz Roundshot D3", + "Seitz Roundshot D2X", + "Seitz Roundshot D2Xs", + "Sigma fp", +#ifdef USE_X3FTOOLS + "Sigma SD9 (raw decode only)", + "Sigma SD10 (raw decode only)", + "Sigma SD14 (raw decode only)", + "Sigma SD15 (raw decode only)", + "Sigma SD1", + "Sigma SD1 Merrill", + "Sigma DP1", + "Sigma DP1 Merrill", + "Sigma DP1S", + "Sigma DP1X", + "Sigma DP2", + "Sigma DP2 Merrill", + "Sigma DP2S", + "Sigma DP2X", + "Sigma DP3 Merrill", + "Sigma dp0 Quattro", + "Sigma dp1 Quattro", + "Sigma dp2 Quattro", + "Sigma dp3 Quattro", + "Sigma sd Quattro", + "Sigma sd Quattro H", +#else + "Sigma dp0 Quattro (DNG only)", + "Sigma dp1 Quattro (DNG only)", + "Sigma dp2 Quattro (DNG only)", + "Sigma dp3 Quattro (DNG only)", + "Sigma sd Quattro (DNG only)", + "Sigma sd Quattro H (DNG only)", +#endif + "Sinar eMotion 22", + "Sinar eMotion 54", + "Sinar eSpirit 65", + "Sinar eMotion 75", + "Sinar eVolution 75", + "Sinar 3072x2048 (Sinarback 23)", + "Sinar 4080x4080 (Sinarback 44)", + "Sinar 4080x5440", + "Sinar STI format", + "Sinar Sinarback 54", + "SMaL Ultra-Pocket 3", + "SMaL Ultra-Pocket 4", + "SMaL Ultra-Pocket 5", + "Sony ILCE-7 (A7)", + "Sony ILCE-7M2 (A7 II)", + "Sony ILCE-7M3 (A7 III)", + "Sony ILCE-7R (A7R", + "Sony ILCE-7RM2 (A7R II)", + "Sony ILCE-7RM3 (A7R III)", + "Sony ILCE-7RM4 (A7R IV)", + "Sony ILCE-7S (A7S)", + "Sony ILCE-7S2 (A7S II)", + "Sony ILCE-9 (A9)", + "Sony ILCE-9M2 (A9 II)", + "Sony ILCA-68 (A68)", + "Sony ILCA-77M2 (A77-II)", + "Sony ILCA-99M2 (A99-II)", + "Sony ILCE-3000 / 3500", + "Sony ILCE-5000", + "Sony ILCE-5100", + "Sony ILCE-6000", + "Sony ILCE-6100", + "Sony ILCE-6300", + "Sony ILCE-6400", + "Sony ILCE-6500", + "Sony ILCE-6600", + "Sony ILCE-QX1", + "Sony DSC-F828", + "Sony DSC-HX95", + "Sony DSC-HX99", + "Sony DSC-R1", + "Sony DSC-RX0", + "Sony DSC-RX0 II", + "Sony DSC-RX1", + "Sony DSC-RX1R", + "Sony DSC-RX1R II", + "Sony DSC-RX10", + "Sony DSC-RX10 II", + "Sony DSC-RX10 III", + "Sony DSC-RX10 IV", + "Sony DSC-RX100", + "Sony DSC-RX100 II", + "Sony DSC-RX100 III", + "Sony DSC-RX100 IV", + "Sony DSC-RX100 V", + "Sony DSC-RX100 VA", + "Sony DSC-RX100 VI", + "Sony DSC-RX100 VII", + "Sony DSC-V3", + "Sony DSLR-A100", + "Sony DSLR-A200", + "Sony DSLR-A230", + "Sony DSLR-A290", + "Sony DSLR-A300", + "Sony DSLR-A330", + "Sony DSLR-A350", + "Sony DSLR-A380 / A390", + "Sony DSLR-A450", + "Sony DSLR-A500", + "Sony DSLR-A550", + "Sony DSLR-A560", + "Sony DSLR-A580", + "Sony DSLR-A700", + "Sony DSLR-A850", + "Sony DSLR-A900", + "Sony NEX-3", + "Sony NEX-3N", + "Sony NEX-5", + "Sony NEX-5N", + "Sony NEX-5R", + "Sony NEX-5T", + "Sony NEX-6", + "Sony NEX-7", + "Sony NEX-C3", + "Sony NEX-F3", + "Sony NEX-VG20", + "Sony NEX-VG30", + "Sony NEX-VG900", + "Sony SLT-A33", + "Sony SLT-A35", + "Sony SLT-A37", + "Sony SLT-A55(V)", + "Sony SLT-A57", + "Sony SLT-A58", + "Sony SLT-A65(V)", + "Sony SLT-A77(V)", + "Sony SLT-A99(V)", + "Sony XCD-SX910CR", + "Sony IMX135-mipi 13mp", + "Sony IMX135-QCOM", + "Sony IMX072-mipi", + "Sony IMX214", + "Sony IMX219", + "Sony IMX230", + "Sony IMX298-mipi 16mp", + "Sony IMX219-mipi 8mp", + "Sony Xperia L", + "STV680 VGA", + "PtGrey GRAS-50S5C", + "JaiPulnix BB-500CL", + "JaiPulnix BB-500GE", + "SVS SVS625CL", + "Yi M1", + "YUNEEC CGO3", + "YUNEEC CGO3P", + "YUNEEC CGO4", + "Xiaomi MI3", + "Xiaomi MI 9 Lite", + "Xiaomi RedMi Note3 Pro", + "Xiaomi RedMi Note7", + "Xiaomi FIMI X8SE", + "Xiaoyi YIAC3 (YI 4k)", + "Zenit M", + NULL +}; +// clang-format on + +const char **LibRaw::cameraList() { return static_camera_list; } +int LibRaw::cameraCount() +{ + return (sizeof(static_camera_list) / sizeof(static_camera_list[0])) - 1; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/tables/colorconst.cpp libkdcraw/libkdcraw/libraw/src/tables/colorconst.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/tables/colorconst.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/tables/colorconst.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,45 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +const double LibRaw_constants::xyz_rgb[3][3] = { + {0.4124564, 0.3575761, 0.1804375}, + {0.2126729, 0.7151522, 0.0721750}, + {0.0193339, 0.1191920, 0.9503041}}; + +const float LibRaw_constants::d65_white[3] = {0.95047f, 1.0f, 1.08883f}; + +const double LibRaw_constants::xyzd50_srgb[3][3] = { + {0.436083, 0.385083, 0.143055}, + {0.222507, 0.716888, 0.060608}, + {0.013930, 0.097097, 0.714022}}; +const double LibRaw_constants::rgb_rgb[3][3] = { + {1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; +const double LibRaw_constants::adobe_rgb[3][3] = { + {0.715146, 0.284856, 0.000000}, + {0.000000, 1.000000, 0.000000}, + {0.000000, 0.041166, 0.958839}}; +const double LibRaw_constants::wide_rgb[3][3] = { + {0.593087, 0.404710, 0.002206}, + {0.095413, 0.843149, 0.061439}, + {0.011621, 0.069091, 0.919288}}; +const double LibRaw_constants::prophoto_rgb[3][3] = { + {0.529317, 0.330092, 0.140588}, + {0.098368, 0.873465, 0.028169}, + {0.016879, 0.117663, 0.865457}}; +const double LibRaw_constants::aces_rgb[3][3] = { + {0.432996, 0.375380, 0.189317}, + {0.089427, 0.816523, 0.102989}, + {0.019165, 0.118150, 0.941914}}; diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/tables/colordata.cpp libkdcraw/libkdcraw/libraw/src/tables/colordata.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/tables/colordata.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/tables/colordata.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,1757 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +/* + All matrices are from Adobe DNG Converter unless otherwise noted. + */ +int LibRaw::adobe_coeff(unsigned make_idx, const char *t_model, + int internal_only) +{ + // clang-format off + static const struct + { + unsigned m_idx; + const char *prefix; + int t_black, t_maximum, trans[12]; + } table[] = { + { LIBRAW_CAMERAMAKER_Agfa, "DC-833m", 0, 0, + { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Apple, "QuickTake", 0, 0, + { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Broadcom, "RPi IMX219", 66, 0x3ff, + { 5302,1083,-728,-5320,14112,1699,-863,2371,5136 } }, /* LibRaw */ + { LIBRAW_CAMERAMAKER_Broadcom, "RPi OV5647", 16, 0x3ff, + { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Broadcom, "Pi", 16, 0x3ff, + { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Canon, "EOS D30", 0, 0, + { 9900,-2771,-1324,-7072,14229,3140,-2790,3344,8861 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS D60", 0, 0xfa0, + { 6211,-1358,-896,-8557,15766,3012,-3001,3507,8567 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 5DS", 0, 0x3c96, // same CMs: 5DS, "5DS R" */ + { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, // v.2 + { LIBRAW_CAMERAMAKER_Canon, "EOS 5D Mark IV", 0, 0, + { 6446,-366,-864,-4436,12204,2513,-952,2496,6348 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 5D Mark III", 0, 0x3c80, + { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 5D Mark II", 0, 0x3cf0, + { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 5D", 0, 0xe6c, + { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 6D Mark II", 0, 0x38de, + { 6875,-970,-932,-4691,12459,2501,-874,1953,5809 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 6D", 0, 0x3c82, + { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 77D", 0, 0, + { 7377,-742,-998,-4235,11981,2549,-673,1918,5538 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 7D Mark II", 0, 0x3510, + { 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 7D", 0, 0x3510, + { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 850D", 0, 0, + { 9079,-1923,-1236,-4677,12454,2492,-922,2319,5565}}, + { LIBRAW_CAMERAMAKER_Canon, "EOS 800D", 0, 0, + { 6970,-512,-968,-4425,12161,2553,-739,1982,5601 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 80D", 0, 0, + { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 10D", 0, 0xfa0, + { 8250,-2044,-1127,-8092,15606,2664,-2893,3453,8348 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 250D", 0, 0, + { 9079,-1923,-1236,-4677,12454,2492,-922,2319,5565 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 200D", 0, 0, + { 7377,-742,-998,-4235,11981,2549,-673,1918,5538 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 20Da", 0, 0, + { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 20D", 0, 0xfff, + { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 30D", 0, 0, + { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 40D", 0, 0x3f60, + { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 50D", 0, 0x3d93, + { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 60Da", 0, 0x2ff7, + { 17492,-7240,-2023,-1791,10323,1701,-186,1329,5406 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 60D", 0, 0x2ff7, + { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 70D", 0, 0x3bc7, + { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 100D", 0, 0x350f, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 300D", 0, 0xfa0, + { 8250,-2044,-1127,-8092,15606,2664,-2893,3453,8348 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 350D", 0, 0xfff, + { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 3000D", 0, 0, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 400D", 0, 0xe8e, + { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 450D", 0, 0x390d, + { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 500D", 0, 0x3479, + { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 550D", 0, 0x3dd7, + { 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 600D", 0, 0x3510, + { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 650D", 0, 0x354d, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 750D", 0, 0x3c00, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 760D", 0, 0x3c00, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 700D", 0, 0x3c00, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + + { LIBRAW_CAMERAMAKER_Canon, "EOS 90D", 0, 0, + { 11498, -3759, -1516, -5073, 12954, 2349, -892, 1867, 6118}}, /* temp */ + + { LIBRAW_CAMERAMAKER_Canon, "EOS 1000D", 0, 0xe43, + { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 1100D", 0, 0x3510, + { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 1200D", 0, 0x37c2, + { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 1300D", 0, 0x37c2, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS 1500D", 0, 0, + { 8300,-2110,-1120,-4917,12694,2482,-938,2141,5666 } }, // v.2 + + { LIBRAW_CAMERAMAKER_Canon, "EOS RP", 0, 0, + { 8608,-2097,-1178,-5425,13265,2383,-1149,2238,5680 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS R", 0, 0, + { 8293,-1789,-1094,-5025,12925,2327,-1199,2769,6108 } }, // v.2 + + { LIBRAW_CAMERAMAKER_Canon, "EOS M6 Mark II", 0, 0, + { 11498, -3759, -1516, -5073, 12954, 2349, -892, 1867, 6118}}, /* temp */ + + { LIBRAW_CAMERAMAKER_Canon, "EOS M6", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS M50", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS M5", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS M3", 0, 0, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + + { LIBRAW_CAMERAMAKER_Canon, "EOS M200", 0, 0, /* temp */ + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + + { LIBRAW_CAMERAMAKER_Canon, "EOS M2", 0, 0, + { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS M100", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS M10", 0, 0, + { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS M", 0, 0, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + + { LIBRAW_CAMERAMAKER_Canon, "EOS-1Ds Mark III", 0, 0x3bb0, + { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1Ds Mark II", 0, 0xe80, + { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D Mark IV", 0, 0x3bb0, + { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D Mark III", 0, 0x3bb0, + { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D Mark II N", 0, 0xe80, + { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D Mark II", 0, 0xe80, + { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1DS", 0, 0xe20, + { 3925,4060,-1739,-8973,16552,2545,-3287,3945,8243 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D C", 0, 0x3c4e, + { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D X Mark III", 0, 0, + { 8971, -2022, -1242, -5405, 13249, 2380, -1280, 2483, 6072}}, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D X Mark II", 0, 0x3c4e, + { 7596,-978,-967,-4808,12571,2503,-1398,2567,5752 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D X", 0, 0x3c4e, + { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS-1D", 0, 0xe20, + { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, + { LIBRAW_CAMERAMAKER_Canon, "EOS C500", 853, 0, + { 17851,-10604,922,-7425,16662,763,-3660,3636,22278 } }, /* DJC */ + {LIBRAW_CAMERAMAKER_Canon, "PowerShot 600", 0, 0, + { -3822,10019,1311,4085,-157,3386,-5341,10829,4812,-1969,10969,1126 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A530", 0, 0, + { 0 } }, /* don't want the A5 matrix */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A50", 0, 0, + { -6233,10706,1825,3260,821,3980,-6512,10745,6287,-2539,12232,262 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A5", 0, 0, + { -5707,10308,2002,2662,1829,4139,-6265,11063,6033,-2659,11911,593 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G10", 0, 0, + { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G11", 0, 0, + { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G12", 0, 0, + { 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G15", 0, 0, + { 7474,-2301,-567,-4056,11456,2975,-222,716,4181 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G16", 0, 0, + { 8020,-2687,-682,-3704,11879,2052,-965,1921,5556 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G1 X Mark III", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G1 X Mark II", 0, 0, + { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G1 X", 0, 0, + { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G1", 0, 0, + { -5686,10300,2223,4725,-1157,4383,-6128,10783,6163,-2688,12093,604 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G2", 0, 0, + { 9194,-2787,-1059,-8098,15657,2608,-2610,3064,7867 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G3 X", 0, 0, + { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G3", 0, 0, + { 9326,-2882,-1084,-7940,15447,2677,-2620,3090,7740 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G5 X Mark II",0, 0, + { 11629, -5713, -914, -2706, 11090, 1842, -206, 1225, 5515 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G5 X",0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G5", 0, 0, + { 9869,-2972,-942,-7314,15098,2369,-1898,2536,7282 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G6", 0, 0, + { 9876,-3774,-871,-7613,14807,3071,-1448,1305,7485 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G7 X Mark III", 0, 0, + { 11629, -5713, -914, -2706, 11090, 1842, -206, 1225, 5515 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G7 X Mark II", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G7 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G9 X Mark II", 0, 0, + { 10056,-4131,-944,-2576,11143,1625,-238,1294,5179 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G9 X",0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot G9", 0, 0, + { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot Pro1", 0, 0, + { 10062,-3522,-1000,-7643,15117,2730,-765,817,7322 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot Pro70", 34, 0, + { -5106,10695,1576,3820,53,4566,-6497,10736,6701,-3336,11887,1394 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot Pro90", 0, 0, + { -5912,10768,2288,4612,-989,4333,-6153,10897,5944,-2907,12288,624 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S30", 0, 0, + { 10744,-3813,-1142,-7962,15966,2075,-2492,2805,7744 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S40", 0, 0, + { 8606,-2573,-949,-8237,15489,2974,-2649,3076,9100 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S45", 0, 0, // + + { 8251,-2410,-964,-8047,15430,2823,-2380,2824,8119 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S50", 0, 0, + { 8979,-2658,-871,-7721,15500,2357,-1773,2366,6634 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S60", 0, 0, + { 8794,-2482,-797,-7804,15403,2572,-1422,1996,7083 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S70", 0, 0, + { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S90", 0, 0, + { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S95", 0, 0, + { 13440,-5896,-1279,-1236,9598,1931,-180,1001,4651 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S120", 0, 0, + { 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S110", 0, 0, + { 8039,-2643,-654,-3783,11230,2930,-206,690,4194 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S100", 0, 0, + { 7968,-2565,-636,-2873,10697,2513,180,667,4211 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot SX1 IS", 0, 0, + { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot SX50 HS", 0, 0, + { 12432,-4753,-1247,-2110,10691,1629,-412,1623,4926 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot SX60 HS", 0, 0, + { 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot SX70 HS", 0, 0, + { 18285,-8907,-1951,-1845,10688,1323,364,1101,5139 } }, + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A3300", 0, 0, + { 10826,-3654,-1023,-3215,11310,1906,0,999,4960 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A470", 0, 0, + { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A610", 0, 0, + { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A620", 0, 0, + { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A630", 0, 0, + { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A640", 0, 0, + { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A650", 0, 0, + { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot A720", 0, 0, + { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot D10", 127, 0, + { 14052,-5229,-1156,-1325,9420,2252,-498,1957,4116 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot S3 IS", 0, 0, + { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot SX110 IS", 0, 0, + { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "PowerShot SX220", 0, 0, + { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Canon, "IXUS 160", 0, 0, // same CamID: "IXUS 160", "ELPH 160" + { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Casio, "EX-F1", 0, 0, + { 9084,-2016,-848,-6711,14351,2570,-1059,1725,6135 } }, + { LIBRAW_CAMERAMAKER_Casio, "EX-FH100", 0, 0, + { 12771,-4179,-1558,-2149,10938,1375,-453,1751,4494 } }, + { LIBRAW_CAMERAMAKER_Casio, "EX-S20", 0, 0, + { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Casio, "EX-Z750", 0, 0, + { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Casio, "EX-Z10", 128, 0xfff, + { 9790,-3338,-603,-2321,10222,2099,-344,1273,4799 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_CINE, "650", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { LIBRAW_CAMERAMAKER_CINE, "660", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { LIBRAW_CAMERAMAKER_CINE, "", 0, 0, /* empty camera name*/ + { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, + + { LIBRAW_CAMERAMAKER_Contax, "N Digital", 0, 0xf1e, + { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + + { LIBRAW_CAMERAMAKER_DXO, "ONE", 0, 0, + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, + + { LIBRAW_CAMERAMAKER_Epson, "R-D1", 0, 0, // same CMs: R-D1, R-D1s, R-D1x + { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "DBP for GX680", 128, 0x0fff, + { 12741,-4916,-1420,-8510,16791,1715,-1767,2302,7771 } }, /* temp, copy from S2Pro */ + + { LIBRAW_CAMERAMAKER_Fujifilm, "E550", 0, 0, + { 11044,-3888,-1120,-7248,15167,2208,-1531,2276,8069 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "E900", 0, 0, + { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "F5", 0, 0, // same CamID: F500EXR, F505EXR; different CamID: F550EXR + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "F6", 0, 0, // same CamID: F600EXR, F605EXR; different CamID: F660EXR + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "F77", 0, 0xfe9, // same CamID: F770EXR, F775EXR + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "F7", 0, 0, // same CMs: F700, F710EXR + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "F810", 0, 0, + { 11044,-3888,-1120,-7248,15167,2208,-1531,2276,8069 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "F8", 0, 0, // F800EXR + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "F900EXR", 0, 0, + { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "GFX 100", 0, 0, + { 16212,-8423,-1583,-4336,12583,1937,-195,726,6199 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "GFX 50", 0, 0, // same CMs: "GFX 50S", "GFX 50R" + { 11756,-4754,-874,-3056,11045,2305,-381,1457,6006 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "HS10 HS11", 0, 0xf68, + { 12440,-3954,-1183,-1123,9674,1708,-83,1614,4086 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "HS2", 0, 0, // same CamID: HS20EXR, HS22EXR + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "HS3", 0, 0, // same CamID: HS30EXR, HS33EXR, HS35EXR + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "HS50EXR", 0, 0, + { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "IS-1", 0, 0, + { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "IS Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "S5000", 0, 0, + { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S5100", 0, 0, + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S5200", 0, 0, // same CamID: S5200, S5600 + { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S6", 0, 0, // same CamID: S6000fd, S6500fd + { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S7000", 0, 0, + { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S9000", 0, 0, // same CamID: S9000, S9500 + { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S9100", 0, 0, // same CamID: S9100, S9600 + { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "S100FS", 514, 0, + { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "S20Pro", 0, 0, + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S20", 512, 0x3fff, // same CamID: S200EXR, S205EXR + { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "SL1000", 0, 0, + { 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "S1", 0, 0, + { 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S2Pro", 128, 0, + { 12741,-4916,-1420,-8510,16791,1715,-1767,2302,7771 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S3Pro", 0, 0, + { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "S5Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "X100F", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X100S", 0, 0, + { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X100T", 0, 0, + { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X100V", 0, 0, + { 13426,-6334,-1177,-4244,12136,2371,580,1303,5980 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X100", 0, 0, + { 12161,-4457,-1069,-5034,12874,2400,-795,1724,6904 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "X10", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X20", 0, 0, + { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X30", 0, 0, + { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X70", 0, 0, + { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "XF10", 0, 0, + { 11673,-4760,-1041,-3988,12058,2166,-771,1417,5569 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "XF1", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "XQ", 0, 0, // same CMs: XQ1, XQ2 + { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "X-Pro1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-Pro2", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-Pro3", 0, 0, + { 13426,-6334,-1177,-4244,12136,2371,580,1303,5980 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "X-A10", 0, 0, + { 11540,-4999,-991,-2949,10963,2278,-382,1049,5605} }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-A20", 0, 0, + { 11540,-4999,-991,-2949,10963,2278,-382,1049,5605} }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-A1", 0, 0, + { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-A2", 0, 0, + { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-A3", 0, 0, + { 12407,-5222,-1086,-2971,11116,2120,-294,1029,5284 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-A5", 0, 0, + { 11673,-4760,-1041,-3988,12058,2166,-771,1417,5569 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-A7", 0, 0, + { 15055,-7391,-1274,-4062,12071,2238,-610,1217,6147 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-E1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-E2S", 0, 0, + { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-E2", 0, 0, + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-E3", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-H1", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-M1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-S1", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + + { LIBRAW_CAMERAMAKER_Fujifilm, "X-T100", 0, 0, + { 11673,-4760,-1041,-3988,12058,2166,-771,1417,5569 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-T1", 0, 0, /* same CMs: X-T1, "X-T1IR", "X-T1 IR", X-T10 */ + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-T200", 0, 0, + { 15055,-7391,-1274,-4062,12071,2238,-610,1217,6147 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-T2", 0, 0, // same CMs: X-T2, X-T20 + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { LIBRAW_CAMERAMAKER_Fujifilm, "X-T3", 0, 0, // same CMs: X-T3, X-T30 + { 13426,-6334,-1177,-4244,12136,2371,580,1303,5980 } }, // v.2 + { LIBRAW_CAMERAMAKER_Fujifilm, "X-T4", 0, 0, + { 13426,-6334,-1177,-4244,12136,2371,580,1303,5980 } }, + + { LIBRAW_CAMERAMAKER_GITUP, "G3DUO", 130, 62000, + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + + { LIBRAW_CAMERAMAKER_GITUP, "GIT2P", 4160, 0, + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + { LIBRAW_CAMERAMAKER_GITUP, "GIT2", 3200, 0, + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + + { LIBRAW_CAMERAMAKER_GoPro, "HERO5 Black", 0, 0, + { 10344,-4210,-620,-2315,10625,1948,93,1058,5541 } }, + + {LIBRAW_CAMERAMAKER_Hasselblad, "L1D-20c", 0, 0, + { 7310, -2746, -646, -2991, 10847, 2469, 163, 585, 6324}}, + + { LIBRAW_CAMERAMAKER_Hasselblad, "16-Uncoated-3FR", 0, 0, + { 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "16-Uncoated-FFF", 0, 0, + { 8068, -2959, -108, -5788, 13608, 2389, -1002, 2237, 8162}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "16-Uncoated", 0, 0, + { 8519,-3260,-280,-5081,13459,1738,-1449,2960,7809 } }, + + { LIBRAW_CAMERAMAKER_Hasselblad, "22-Uncoated-3FR", 0, 0, + { 8523, -3257, -280, -5078, 13458, 1743, -1449, 2961, 7809}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "22-Uncoated-FFF", 0, 0, + { 8068, -2959, -108, -5788, 13608, 2389, -1002, 2237, 8162}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "22-Uncoated", 0, 0, + { 8519,-3260,-280,-5081,13459,1738,-1449,2960,7809 } }, + + {LIBRAW_CAMERAMAKER_Hasselblad, "31-Uncoated-FFF", 0, 0, + { 5155, -1201, 200, -5841, 13197, 2950, -1101, 2317, 6988}}, + {LIBRAW_CAMERAMAKER_Hasselblad, "31-Uncoated", 0, 0, + { 5458, -1448, 145, -4479, 12338, 2401, -1659, 3086, 6710}}, + + {LIBRAW_CAMERAMAKER_Hasselblad, "39-Uncoated-3FR", 0, 0, + { 3904, -100, 262, -4318, 12407, 2128, -1598, 3594, 6233}}, + {LIBRAW_CAMERAMAKER_Hasselblad, "39-Uncoated-FFF", 0, 0, + { 4739, -932, 295, -4829, 12220, 2952, -1027, 2341, 7083}}, + {LIBRAW_CAMERAMAKER_Hasselblad, "39-Uncoated", 0, 0, + { 3894, -110, 287, -4672, 12610, 2295, -2092, 4100, 6196}}, + + { LIBRAW_CAMERAMAKER_Hasselblad, "39-Coated-3FR", 0, 0, + { 5427, -1147, 173, -3834, 12073, 1969, -1444, 3320, 5621}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "39-Coated-FFF", 0, 0, + { 5323, -1233, 399, -4926, 12362, 2894, -856, 2471, 5961}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "39-Coated", 0, 0, + { 3857,452,-46,-6008,14477,1596,-2627,4481,5718 } }, + + {LIBRAW_CAMERAMAKER_Hasselblad, "40-Coated5-3FR", 0, 0, + { 7014, -2067, -540, -4821, 13016, 1980, -1663, 3089, 6940}}, + {LIBRAW_CAMERAMAKER_Hasselblad, "40-Coated5-FFF", 0, 0, + { 5963, -1357, -172, -5439, 12762, 3007, -964, 2222, 7172}}, + {LIBRAW_CAMERAMAKER_Hasselblad, "40-Coated5", 0, 0, + { 6159, -1402, -177, -5439, 12762, 3007, -955, 2200, 7104}}, + + { LIBRAW_CAMERAMAKER_Hasselblad, "40-Coated-3FR", 0, 0, + { 6550, -1681, -399, -4626, 12598, 2257, -1807, 3354, 6486}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "40-Coated-FFF", 0, 0, + { 6041, -1375, -174, -5439, 10000, 3007, -930, 2145, 6923}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "40-Coated", 0, 0, + { 6159,-1402,-177,-5439,12762,3007,-955,2200,7104 } }, + + { LIBRAW_CAMERAMAKER_Hasselblad, "50-Coated5-3FR", 0, 0, + { 5707, -693, -382, -4285, 12669, 1773, -1615, 3519, 5410}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "50-Coated5-FFF", 0, 0, + { 5263, -612, 39, -4950, 12426, 2843, -935, 2423, 5941}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "50-Coated5", 0, 0, + { 5656, -659, -346, -3923, 12306, 1791, -1602, 3509, 5442}}, + + { LIBRAW_CAMERAMAKER_Hasselblad, "50-Coated-3FR", 0, 0, + { 5656, -659, -346, -3923, 12305, 1790, -1602, 3509, 5442}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "50-Coated-FFF", 0, 0, + { 5280, -614, 39, -4950, 12426, 2843, -939, 2434, 5968}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "50-Coated", 0, 0, + { 5656,-659,-346,-3923,12306,1791,-1602,3509,5442 } }, + + { LIBRAW_CAMERAMAKER_Hasselblad, "50-15-Coated5-II-3FR", 0, 0, + { 10887, -6152, 1034, -3564, 12412, 4224, 63, 626, 10123}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "50-15-Coated5-II-FFF", 0, 0, + { 4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "50-15-Coated5-II", 0, 0, + { 8737, -4937, 830, -2860, 9961, 3390, 51, 502, 8124}}, + + { LIBRAW_CAMERAMAKER_Hasselblad, "50-15-Coated5", 0, 0, + { 4932,-835,141,-4878,11868,3437,-1138,1961,7067 } }, + + { LIBRAW_CAMERAMAKER_Hasselblad, "60-Coated-3FR", 0, 0, + { 9296, 336, -1088, -6442, 14323, 2289, -1433, 2942, 5756}}, + { LIBRAW_CAMERAMAKER_Hasselblad, "60-Coated", 0, 0, + { 9662,-684,-279,-4903,12293,2950,-344,1669,6024 } }, + + { LIBRAW_CAMERAMAKER_Hasselblad, "100-17-Coated5", 0, 0, + { 5110, -1357, -308, -5573, 12835, 3077, -1279, 2025, 7010}}, + + { LIBRAW_CAMERAMAKER_HTC, "One A9", 64, 1023, + { 101,-20,-2,-11,145,41,-24,1,56 } }, /* this is FM1 transposed */ + + { LIBRAW_CAMERAMAKER_Imacon, "Ixpress", 0, 0, + { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Kodak, "NC2000", 0, 0, // AP Nikon + { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS315C", -8, 0, + { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS330C", -8, 0, + { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS420", 0, 0, + { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS46", 0, 0, // same CM as EOSDCS1 and DCS465 DB + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS520C", -178, 0, // same CamID: DCS520C, "EOS D2000C" + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS560C", -177, 0, // same CamID: DCS560C, "EOS D6000C" + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS620C", -177, 0, + { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS620X", -176, 0, + { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS660C", -173, 0, + { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS720X", 0, 0, + { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS760C", 0, 0, + { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS Pro SLR", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS Pro 14nx", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { LIBRAW_CAMERAMAKER_Kodak, "DCS Pro 14", 0, 0, // same CamID: "DCS Pro 14N", "Photo Control Camerz ZDS 14" + { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, + { LIBRAW_CAMERAMAKER_Kodak, "EOSDCS1", 0, 0, + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { LIBRAW_CAMERAMAKER_Kodak, "EOSDCS3", 0, 0, + { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, + { LIBRAW_CAMERAMAKER_Kodak, "ProBack645", 0, 0, + { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, + { LIBRAW_CAMERAMAKER_Kodak, "ProBack", 0, 0, + { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, + + {LIBRAW_CAMERAMAKER_Kodak, "PIXPRO AZ901", 0, 0, // dng + { 21875, -8006, -2558, 634, 8194, 1104, 1535, 951, 6969}}, + { LIBRAW_CAMERAMAKER_Kodak, "P712", 0, 3963, + { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, + { LIBRAW_CAMERAMAKER_Kodak, "P850", 0, 3964, + { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, + { LIBRAW_CAMERAMAKER_Kodak, "P880", 0, 3963, + { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, + { LIBRAW_CAMERAMAKER_Kodak, "Z980", 0, 0, + { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, + { LIBRAW_CAMERAMAKER_Kodak, "Z981", 0, 0, + { 12729,-4717,-1188,-1367,9187,2582,274,860,4411 } }, + { LIBRAW_CAMERAMAKER_Kodak, "Z990", 0, 0xfed, + { 11749,-4048,-1309,-1867,10572,1489,-138,1449,4522 } }, + { LIBRAW_CAMERAMAKER_Kodak, "Z1015", 0, 0xef1, + { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, + + {LIBRAW_CAMERAMAKER_Leaf, "AFi 54S", 0, 0, + { 8236, 1746, -1313, -8251, 15953, 2428, -3672, 5786, 5771}}, + {LIBRAW_CAMERAMAKER_Leaf, "AFi 65S", 0, 0, + { 7914, 1414, -1190, -8776, 16582, 2280, -2811, 4605, 5562}}, + {LIBRAW_CAMERAMAKER_Leaf, "AFi 75S", 0, 0, + { 7914, 1414, -1190, -8776, 16582, 2280, -2811, 4605, 5562}}, + {LIBRAW_CAMERAMAKER_Leaf, "Aptus 17", 0, 0, + { 8236, 1746, -1313, -8251, 15953, 2428, -3672, 5786, 5771}}, + {LIBRAW_CAMERAMAKER_Leaf, "Aptus 22", 0, 0, + { 8236, 1746, -1313, -8251, 15953, 2428, -3672, 5786, 5771}}, + {LIBRAW_CAMERAMAKER_Leaf, "Aptus 54S", 0, 0, + { 8236, 1746, -1313, -8251, 15953, 2428, -3672, 5786, 5771}}, + {LIBRAW_CAMERAMAKER_Leaf, "Aptus 65S", 0, 0, + { 7914, 1414, -1190, -8776, 16582, 2280, -2811, 4605, 5562}}, + {LIBRAW_CAMERAMAKER_Leaf, "Aptus 65", 0, 0, + { 7914, 1414, -1190, -8776, 16582, 2280, -2811, 4605, 5562}}, + {LIBRAW_CAMERAMAKER_Leaf, "Aptus 75S", 0, 0, + { 7914, 1414, -1190, -8776, 16582, 2280, -2811, 4605, 5562}}, + {LIBRAW_CAMERAMAKER_Leaf, "Aptus 75", 0, 0, + { 7914, 1414, -1190, -8776, 16582, 2280, -2811, 4605, 5562}}, + {LIBRAW_CAMERAMAKER_Leaf, "C-Most", 0, 0, + { 3952, 2188, 449, -6701, 14584, 2275, -4536, 7349, 6535}}, + {LIBRAW_CAMERAMAKER_Leaf, "Credo 40", 0, 0, + { 8035, 435, -962, -6001, 13872, 2320, -1159, 3065, 5434}}, + {LIBRAW_CAMERAMAKER_Leaf, "Credo 50", 0, 0, // emb + { 10325, 845, -604, -4113, 13385, 481, -1791, 4163, 6924}}, + {LIBRAW_CAMERAMAKER_Leaf, "Credo 60", 0, 0, + { 8035, 435, -962, -6001, 13872, 2320, -1159, 3065, 5434}}, + {LIBRAW_CAMERAMAKER_Leaf, "Credo 80", 0, 0, + { 6294, 686, -712, -5435, 13417, 2211, -1006, 2435, 5042}}, + {LIBRAW_CAMERAMAKER_Leaf, "Valeo 11", 0, 0, + { 8236, 1746, -1313, -8251, 15953, 2428, -3672, 5786, 5771}}, + {LIBRAW_CAMERAMAKER_Leaf, "Valeo 17", 0, 0, + { 8236, 1746, -1313, -8251, 15953, 2428, -3672, 5786, 5771}}, + {LIBRAW_CAMERAMAKER_Leaf, "Valeo 22", 0, 0, + { 8236, 1746, -1313, -8251, 15953, 2428, -3672, 5786, 5771}}, + {LIBRAW_CAMERAMAKER_Leaf, "Valeo 6", 0, 0, + { 3952, 2188, 449, -6701, 14584, 2275, -4536, 7349, 6535}}, + +// { LIBRAW_CAMERAMAKER_Leaf, "AFi-II 6", 0, 0, + { LIBRAW_CAMERAMAKER_Leaf, "AFi-II 7", 0, 0, + { 7691,-108,-339,-6185,13627,2833,-2046,3899,5952 } }, + { LIBRAW_CAMERAMAKER_Leaf, "AFi-II 10", 0, 0, + { 6719,1147,-148,-6929,14061,3176,-1781,3343,5424 } }, + + { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 5", 0, 0, + { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, + { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 6", 0, 0, + { 7989,-113,-352,-6185,13627,2833,-2028,3866,5901 } }, + { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 7", 0, 0, + { 8209,-116,-362,-6185,13627,2833,-1962,3740,5709 } }, + { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 8", 0, 0, + { 7361,1257,-163,-6929,14061,3176,-1839,3454,5603 } }, + { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 10R", 0, 0, + { 7167,1224,-158,-6929,14061,3176,-1826,3429,5562 } }, + { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 10", 0, 0, + { 7527,1285,-166,-6929,14061,3176,-1995,3747,6077 } }, +// { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 12R", 0, 0, + { LIBRAW_CAMERAMAKER_Leaf, "Aptus-II 12", 0, 0, + { 7361,1257,-163,-6929,14061,3176,-1695,3182,5162 } }, + + { LIBRAW_CAMERAMAKER_Leica, "CL", 0, 0, + { 7743,-2896,-921,-4211,12271,2169,-697,1562,5491 } }, + + { LIBRAW_CAMERAMAKER_Leica, "M8", 0, 0, + { 7675,-2196,-305,-5860,14119,1856,-2425,4006,6578 } }, + { LIBRAW_CAMERAMAKER_Leica, "M9", 0, 0, + { 6687,-1751,-291,-3556,11373,2492,-548,2204,7146 } }, + { LIBRAW_CAMERAMAKER_Leica, "M10", 0, 0, // same CMs: M10, M10-D, M10-P + { 9090,-3342,-740,-4006,13456,493,-569,2266,6871 } }, + { LIBRAW_CAMERAMAKER_Leica, "M (Typ 2", 0, 0, // same CMs: "M (Typ 240)", "M (Typ 262)", "M-D (Typ 262)" + { 7199,-2140,-712,-4005,13327,649,-810,2521,6673 } }, + + { LIBRAW_CAMERAMAKER_Leica, "Q (Typ 116)", 0, 0, + { 10068,-4043,-1068,-5319,14268,1044,-765,1701,6522 } }, + { LIBRAW_CAMERAMAKER_Leica, "Q2", 0, 0, + { 12312,-5440,-1307,-6408,15499,824,-1075,1677,7220 } }, + + { LIBRAW_CAMERAMAKER_Leica, "SL (Typ 601)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, + { LIBRAW_CAMERAMAKER_Leica, "S (Typ 007)", 0, 0, + { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } }, + { LIBRAW_CAMERAMAKER_Leica, "S2", 0, 0, + { 5627,-721,-447,-4423,12456,2192,-1048,2948,7379 } }, + { LIBRAW_CAMERAMAKER_Leica, "S3", 0, 0, +// { 5147,-1464,-318,-5374,13263,2325,-1425,2918,6450 } }, + { 5092,-1630,-470,-6313,14297,2170,-1603,3135,5982 } }, + {LIBRAW_CAMERAMAKER_Leica, "S", 0, 0, // same CMs: "S-E (Typ 006)", "S (Typ 006)" + { 5749,-1072,-382,-4274,12432,2048,-1166,3104,7105 } }, + + { LIBRAW_CAMERAMAKER_Leica, "TL2", 0, 0, + { 6375,-2062,-732,-4878,12838,2262,-877,1705,6204 } }, + { LIBRAW_CAMERAMAKER_Leica, "T", 0, 0, // same CMs: TL, "T (Typ 701)" + { 6295,-1679,-475,-5586,13046,2837,-1410,1889,7075 } }, + + { LIBRAW_CAMERAMAKER_Leica, "X2", 0, 0, + { 8336,-2853,-699,-4425,11989,2760,-954,1625,6396 } }, + { LIBRAW_CAMERAMAKER_Leica, "X1", 0, 0, + { 9055,-2611,-666,-4906,12652,2519,-555,1384,7417 } }, + { LIBRAW_CAMERAMAKER_Leica, "X", 0, 0, /* same CMs: "X (Typ 113)", "X-U (Typ 113)", XV, "X Vario (Typ 107)" */ + { 9062,-3198,-828,-4065,11772,2603,-761,1468,6458 } }, + + { LIBRAW_CAMERAMAKER_Mamiya,"ZD", 0, 0, + { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, + + { LIBRAW_CAMERAMAKER_Micron, "2010", 110, 0, + { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE 5", 0, 0xf7d, + { 9117,-3063,-973,-7949,15763,2306,-2752,3136,8093 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE 7Hi", 0, 0xf7d, + { 11555,-4064,-1256,-7903,15633,2409,-2811,3320,7358 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE 7i", 0, 0xf7d, + { 11050,-3791,-1199,-7875,15585,2434,-2797,3359,7560 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE 7", 0, 0xf7d, + { 9258,-2879,-1008,-8076,15847,2351,-2806,3280,7821 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE A1", 0, 0xf8b, + { 9274,-2548,-1167,-8220,16324,1943,-2273,2721,8340 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE A200", 0, 0, + { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE A2", 0, 0xf8f, + { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DiMAGE Z2", 0, 0, + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Minolta, "DG-5D", 0, 0xffb, // same CamID: "ALPHA 5D", "DYNAX 5D", "MAXXUM 5D", "Alpha Sweet Digital" + { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, + { LIBRAW_CAMERAMAKER_Minolta, "DG-7D", 0, 0xffb, // same CamID: "ALPHA 7D", "DYNAX 7D", "MAXXUM 7D" + { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, + + { LIBRAW_CAMERAMAKER_Motorola, "PIXL", 0, 0, + { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Nikon, "1 AW1", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { LIBRAW_CAMERAMAKER_Nikon, "1 J3", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { LIBRAW_CAMERAMAKER_Nikon, "1 J4", 0, 0, + { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, + { LIBRAW_CAMERAMAKER_Nikon, "1 J5", 0, 0, + { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } }, + { LIBRAW_CAMERAMAKER_Nikon, "1 S2", -200, 0, + { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, + { LIBRAW_CAMERAMAKER_Nikon, "1 V2", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { LIBRAW_CAMERAMAKER_Nikon, "1 V3", -200, 0, + { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, + { LIBRAW_CAMERAMAKER_Nikon, "1 ", 0, 0, /* same CMs: "1 J1", "1 J2", "1 S1", "1 V1" */ + { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, + + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 2100", 0, 0, // a.k.a. E2100 + { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711 } }, /* DJC, copied from Z2, new white balance */ + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 2500", 0, 0, // a.k.a. E2500, possibly same CM as for E5000 + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 3200", 0, 0, // a.k.a. E3200 + { 9846,-2085,-1019,-3278,11109,2170,-774,2134,5745 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 4300", 0, 0, // a.k.a. E4300 + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, /* DJC, copied from Minolta DiMAGE Z2 */ + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 4500", 0, 0, // a.k.a. E4500, possibly same CM as for E5000 + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 5000", 0, 0, // a.k.a. E5000 + { -6678,12805,2248,5725,-499,3375,-5903,10713,6034,-270,9976,134 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 5400", 0, 0, // a.k.a. E5400 + { 9349,-2988,-1001,-7918,15766,2266,-2097,2680,6839 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 5700", 0, 0, // a.k.a. E5700 + { -6475,12496,2428,5409,-16,3180,-5965,10912,5866,-177,9918,248 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 8400", 0, 0, // a.k.a. E8400 + { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 8700", 0, 0, // a.k.a. E8700 + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 8800", 0, 0, // a.k.a. E8800 + { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, + + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 700", 0, 0x3dd, // a.k.a. E700 + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 800", 0, 0x3dd, // a.k.a. E800 + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 950", 0, 0x3dd, // a.k.a. E950 + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, /* DJC */ + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX 995", 0, 0, // a.k.a. E995 + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, /* DJC, copied from E5000 */ + + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX A1000", 0, 0, + { 10601,-3487,-1127,-2931,11443,1676,-587,1740,5278 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX B700", 0, 0, + { 14387,-6014,-1299,-1357,9975,1616,467,1047,4744 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX A", 0, 0, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P1000", 0, 0, + { 14294,-6116,-1333,-1628,10219,1637,-14,1158,5022 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P6000", 0, 0, + { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P7000", 0, 0, + { 11432,-3679,-1111,-3169,11239,2202,-791,1380,4455 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P7100", 0, 0, + { 11053,-4269,-1024,-1976,10182,2088,-526,1263,4469 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P7700", -3200, 0, // same CamID: "COOLPIX P7700", "COOLPIX Deneb" + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P7800", -3200, 0, // same CamID: "COOLPIX P7800", "COOLPIX Kalon" + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P330", -200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { LIBRAW_CAMERAMAKER_Nikon, "COOLPIX P340", -200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { LIBRAW_CAMERAMAKER_Nikon, "Coolpix P950", 0, 0, + { 13307, -5641, -1290, -2048, 10581, 1689, -64, 1222, 5176}}, + + { LIBRAW_CAMERAMAKER_Nikon, "D3000", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3100", 0, 0, + { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3200", 0, 0xfb9, + { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3300", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3400", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3500", 0, 0, + { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D5000", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D5100", 0, 0x3de6, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D5200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D5300", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D5500", 0, 0, + { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D5600", 0, 0, + { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D7000", 0, 0, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D7100", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D7200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D7500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, + + { LIBRAW_CAMERAMAKER_Nikon, "D100", 0, 0, + { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D200", 0, 0xfbc, + { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D300", 0, 0, // same CMs: D300, D300s + { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D600", 0, 0x3e07, + { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D610",0, 0, + { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D700", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D750", -600, 0, + { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D780", -600, 0, + { 9943,-3269,-839,-5323,13269,2259,-1198,2083,7557 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D800", 0, 0, // same CMs: D800, D800E + { 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D810A", 0, 0, + { 11973,-5685,-888,-1965,10326,1901,-115,1123,7169 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D810", 0, 0, + { 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D850", 0, 0, + { 10405,-3755,-1270,-5461,13787,1793,-1040,2015,6785 } }, + + { LIBRAW_CAMERAMAKER_Nikon, "D40X", 0, 0, + { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D40", 0, 0, + { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D50", 0, 0, + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D60", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D70", 0, 0, // same CMs: D70, D70s + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D80", 0, 0, + { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D90", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, + + { LIBRAW_CAMERAMAKER_Nikon, "D1H", 0, 0, + { 7659,-2238,-935,-8942,16969,2004,-2701,3051,8690 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D1X", 0, 0, + { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D1", 0, 0, +// { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, /* multiplied by 2.218750, 1.0, 1.148438 */ + { 7637,-2199,-974,-9109,17099,2043,-2822,3306,8372 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D2H", 0, 0, // same CMs: D2H, D2Hs + { 5733,-911,-629,-7967,15987,2055,-3050,4013,7048 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D2X", 0, 0, // same CMs: D2X, D2Xs + { 10231,-2768,-1254,-8302,15900,2551,-797,681,7148 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3S", 0, 0, + { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3X", 0, 0, + { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D3", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D4", 0, 0, // same CMs: D4, D4S (and Df) + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D5", 0, 0, + { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } }, + { LIBRAW_CAMERAMAKER_Nikon, "D6", 0, 0, + { 9028,-3423,-1035,-6321,14265,2217,-1013,1683,6928}}, + { LIBRAW_CAMERAMAKER_Nikon, "Df", 0, 0, + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + + { LIBRAW_CAMERAMAKER_Nikon, "Z 50", 0, 0, + { 11640,-4829,-1079,-5107,13006,2325,-972,1711,7380}}, + { LIBRAW_CAMERAMAKER_Nikon, "Z 6", 0, 0, + { 9943,-3269,-839,-5323,13269,2259,-1198,2083,7557 } }, // v.2 + { LIBRAW_CAMERAMAKER_Nikon, "Z 7", 0, 0, + { 10405,-3755,-1270,-5461,13787,1793,-1040,2015,6785 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "AIR A01", 0, 0xfe1, + { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "C-5050Z", 0, 0, + { 10633,-3234,-1285,-7460,15570,1967,-1917,2510,6299 } }, + { LIBRAW_CAMERAMAKER_Olympus, "C-5060WZ", 0, 0, + { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, + { LIBRAW_CAMERAMAKER_Olympus, "C-7070WZ", 0, 0, + { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, + { LIBRAW_CAMERAMAKER_Olympus, "C-7000Z", 0, 0, + { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, + { LIBRAW_CAMERAMAKER_Olympus, "C-8080WZ", 0, 0, + { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-300", 0, 0, + { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-330", 0, 0, + { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-400", 0, 0, + { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-410", 0, 0xf6a, + { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-420", 0, 0xfd7, + { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-450", 0, 0xfd2, + { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-500", 0, 0, + { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-510", 0, 0xf6a, + { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-520", 0, 0xfd2, + { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-600", 0, 0xfaf, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-620", 0, 0xfaf, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-10", 0, 0xffc, + { 12970,-4703,-1433,-7466,15843,1644,-2191,2451,6668 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-20", 0, 0xffc, // model is "E-20,E-20N,E-20P" + { 13414,-4950,-1517,-7166,15293,1960,-2325,2664,7212 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-30", 0, 0xfbc, + { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-1", 0, 0, + { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-3", 0, 0xf99, + { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-5", 0, 0xeec, + { 11200,-3783,-1325,-4576,12593,2206,-695,1742,7504 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-P1", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-P2", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-P3", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-P5", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-PL10", 0, 0, + { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL1s", 0, 0, + { 11409,-3872,-1393,-4572,12757,2003,-709,1810,7415 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL1", 0, 0, + { 11408,-4289,-1215,-4286,12385,2118,-387,1467,7787 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL2", 0, 0xcf3, + { 15030,-5552,-1806,-3987,12387,1767,-592,1670,7023 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL3", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL5", 0, 0xfcb, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL6", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL7", 0, 0, + { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL8", 0, 0, + { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PL9", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-PM1", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-PM2", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-M10", 0, 0, // Same CMs: E-M10, E-M10 Mark II, E-M10 Mark III; "CLAUSS piX 5oo" + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-M1X", 0, 0, + { 11896,-5110,-1076,-3181,11378,2048,-519,1224,5166 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-M1 Mark III", 0, 0, + { 11896,-5110,-1076,-3181,11378,2048,-519,1224,5166 } }, /* preliminary */ + + { LIBRAW_CAMERAMAKER_Olympus, "E-M1 Mark II", 0, 0, + { 9383,-3170,-763,-2457,10702,2020,-384,1236,5552 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-M1", 0, 0, + { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "E-M5 Mark III", 0, 0, + { 11896,-5110,-1076,-3181,11378,2048,-519,1224,5166 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-M5 Mark II", 0, 0, + { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } }, + { LIBRAW_CAMERAMAKER_Olympus, "E-M5", 0, 0xfe1, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "PEN-F",0, 0, + { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "SH-2", 0, 0, // same CamID: SH-2, SH-3 + { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "SP-350", 0, 0, + { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, + { LIBRAW_CAMERAMAKER_Olympus, "SP-3", 0, 0, // Same CMs: SP310, SP320 + { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, + { LIBRAW_CAMERAMAKER_Olympus, "SP-500UZ", 0, 0xfff, + { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, + { LIBRAW_CAMERAMAKER_Olympus, "SP-510UZ", 0, 0xffe, + { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, + { LIBRAW_CAMERAMAKER_Olympus, "SP-550UZ", 0, 0xffe, + { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, + { LIBRAW_CAMERAMAKER_Olympus, "SP-560UZ", 0, 0xff9, + { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, + { LIBRAW_CAMERAMAKER_Olympus, "SP-565UZ", 0, 0, + { 11856,-4469,-1159,-4814,12368,2756,-993,1779,5589 } }, + { LIBRAW_CAMERAMAKER_Olympus, "SP-570UZ", 0, 0, + { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "STYLUS 1",0, 0, // Olympus "STYLUS 1 and STYLUS 1s have the same CamID, cameras are slightly different + { 8360,-2420,-880,-3928,12353,1739,-1381,2416,5173 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "TG-4", 0, 0, + { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } }, + { LIBRAW_CAMERAMAKER_Olympus, "TG-", 0, 0, // same CMs: TG-5, TG-6 + { 10899,-3833,-1082,-2112,10736,1575,-267,1452,5269 } }, + + { LIBRAW_CAMERAMAKER_Olympus, "XZ-10", 0, 0, + { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + { LIBRAW_CAMERAMAKER_Olympus, "XZ-1", 0, 0, + { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, + { LIBRAW_CAMERAMAKER_Olympus, "XZ-2", 0, 0, + { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + + { LIBRAW_CAMERAMAKER_OmniVison, "", 16, 0x3ff, + { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Pentax, "*istDL2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { LIBRAW_CAMERAMAKER_Pentax, "*istDL", 0, 0, + { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, + { LIBRAW_CAMERAMAKER_Pentax, "*istDS2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { LIBRAW_CAMERAMAKER_Pentax, "*istDS", 0, 0, + { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, + { LIBRAW_CAMERAMAKER_Pentax, "*istD", 0, 0, + { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, + + { LIBRAW_CAMERAMAKER_Pentax, "K-01", 0, 0, + { 8134,-2728,-645,-4365,11987,2694,-838,1509,6498 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K10D", 0, 0, + { 9679,-2965,-811,-8622,16514,2182,-975,883,9793 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K1", 0, 0, // same CMs: K100D, "K100D Super", K110D + { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K20D", 0, 0, + { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K200D", 0, 0, + { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-m", 0, 0, + { 9730,-2989,-970,-8527,16258,2381,-1060,970,8362 } }, + { LIBRAW_CAMERAMAKER_Pentax, "KP", 0, 0, + { 7825,-2160,-1403,-4841,13555,1349,-1559,2449,5814 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-x", 0, 0, + { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-r", 0, 0, + { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-1", 0, 0, // same CMs: K-1, "K-1 Mark II" + { 8596,-2981,-639,-4202,12046,2431,-685,1424,6122 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-30", 0, 0, + { 8134,-2728,-645,-4365,11987,2694,-838,1509,6498 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-3", 0, 0, // same CMs: K-3, "K-3 II" + { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-500", 0, 0, + { 8109,-2740,-608,-4593,12175,2731,-1006,1515,6545 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-50", 0, 0, + { 8109,-2740,-608,-4593,12175,2731,-1006,1515,6545 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-5 II", 0, 0, // same CMs: "K-5 II" and "K-5 IIs" + { 8170,-2725,-639,-4440,12017,2744,-771,1465,6599 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-5", 0, 0, + { 8713,-2833,-743,-4342,11900,2772,-722,1543,6247 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-70", 0, 0, + { 8766,-3149,-747,-3976,11943,2292,-517,1259,5552 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-7", 0, 0, + { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, + { LIBRAW_CAMERAMAKER_Pentax, "KP", 0, 0, + { 8617,-3228,-1034,-4674,12821,2044,-803,1577,5728 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-S1", 0, 0, + { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } }, + { LIBRAW_CAMERAMAKER_Pentax, "K-S2", 0, 0, + { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } }, + + { LIBRAW_CAMERAMAKER_Pentax, "Q-S1", 0, 0, + { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, + { LIBRAW_CAMERAMAKER_Pentax, "Q7", 0, 0, + { 10901,-3938,-1025,-2743,11210,1738,-823,1805,5344 } }, + { LIBRAW_CAMERAMAKER_Pentax, "Q10", 0, 0, + { 11562,-4183,-1172,-2357,10919,1641,-582,1726,5112 } }, + { LIBRAW_CAMERAMAKER_Pentax, "Q", 0, 0, + { 11731,-4169,-1267,-2015,10727,1473,-217,1492,4870 } }, + + { LIBRAW_CAMERAMAKER_Pentax, "MX-1", 0, 0, + { 9296,-3146,-888,-2860,11287,1783,-618,1698,5151 } }, + + { LIBRAW_CAMERAMAKER_Pentax, "645D", 0, 0x3e00, + { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, + { LIBRAW_CAMERAMAKER_Pentax, "645Z", 0, 0, + { 9519,-3591,-664,-4074,11725,2671,-624,1501,6653 } }, + + + {LIBRAW_CAMERAMAKER_Panasonic, "DC-S1R", 0, 0, + { 11822,-5321,-1249,-5958,15114,766,-614,1264,7043 } }, + {LIBRAW_CAMERAMAKER_Panasonic, "DC-S1H", 0, 0, + { 9397, -3719, -805, -5425, 13326, 2309, -972, 1715, 6034}}, + {LIBRAW_CAMERAMAKER_Panasonic, "DC-S1", 0, 0, + { 9744,-3905,-779,-4899,12807,2324,-798,1630,5827 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-CM1", -15, 0, // same CMs: DMC-CM1, DMC-CM10 + { 8770,-3194,-820,-2871,11281,1803,-513,1552,4434 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DC-FZ1000M2", -15, 0, + { 9803,-4185,-992,-4066,12578,1628,-838,1824,5288 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ1000", -15, 0, + { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ2500", -15, 0, + { 7386,-2443,-743,-3437,11864,1757,-608,1660,4766 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ100", -15, 0xfff, + { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ150", -15, 0xfff, + { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ200", -15, 0xfff, + { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ300", -15, 0xfff, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ18", 0, 0, + { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ28", -15, 0xf96, + { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ30", 0, 0xf94, + { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ35", -15, 0, + { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ40", -15, 0, + { 13639,-5535,-1371,-1698,9633,2430,316,1152,4108 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ50", 0, 0, + { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ70", -15, 0, + { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-FZ80", -15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FZ8", 0, 0xf7f, + { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, + + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-L10", -15, 0xf96, + { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-L1", 0, 0xf7f, + { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LC1", 0, 0, + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LF1", -15, 0, + { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DC-LX100M2", -15, 0, + { 8585,-3127,-833,-4005,12250,1953,-650,1494,4862 } }, // v.2 + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LX100", -15, 0, + { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LX1", 0, 0xf7f, + { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LX2", 0, 0, + { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LX3", -15, 0, + { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LX5", -15, 0, + { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LX7", -15, 0, + { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-LX9", -15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-FX150", -15, 0xfff, + { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DC-G99", -15, 0, + { 9657,-3963,-748,-3361,11378,2258,-568,1415,5158 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G10", 0, 0, + { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G1", -15, 0xf94, + { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G2", -15, 0xf3c, + { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G3", -15, 0xfff, + { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G5", -15, 0xfff, + { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G6", -15, 0xfff, + { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G7", -15, 0xfff, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-G8", -15, 0xfff, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-G9", -15, 0, + { 7685,-2375,-634,-3687,11700,2249,-748,1546,5111 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GH1", -15, 0xf92, + { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GH2", -15, 0xf95, + { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GH3", -15, 0, + { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GH4", -15, 0, + { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-GH5s", -15, 0, + { 6929,-2355,-708,-4192,12534,1828,-1097,1989,5195 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-GH5", -15, 0, + { 7641,-2336,-605,-3218,11299,2187,-485,1338,5121 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GM1", -15, 0, + { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GM5", -15, 0, + { 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DC-GF10", -15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GF1", -15, 0xf92, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GF2", -15, 0xfff, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GF3", -15, 0xfff, + { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GF5", -15, 0xfff, + { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GF6", -15, 0, + { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GF7", -15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GF8", -15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-GF9", -15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GX85", -15, 0, + { 7771,-3020,-629,-4029,11950,2345,-821,1977,6119 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GX1", -15, 0, + { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GX7", -15,0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-GX8", -15,0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-GX9", -15, 0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-ZS100", -15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-ZS200", -15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-ZS40", -15, 0, + { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-ZS50", -15, 0, + { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DMC-ZS60", -15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-ZS70", -15, 0, + { 9052,-3117,-883,-3045,11346,1927,-205,1520,4730 } }, + { LIBRAW_CAMERAMAKER_Panasonic, "DC-ZS80", -15, 0, + { 12194,-5340,-1329,-3035,11394,1858,-50,1418,5219 } }, + + { LIBRAW_CAMERAMAKER_PhaseOne, "H20", 0, 0, + { 3906,1422,-467,-9953,18472,1365,-3307,4496,6406 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "H25", 0, 0, + { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ4 150MP", 0, 0, + { 6644, -2257, -804, -6459, 14562, 2019, -1221, 1876, 6411}}, + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ140", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ150", 0, 0, + {10325,845,-604,-4113,13385,481,-1791,4163,6924}}, /* temp */ /* emb */ +// { 3984,0,0,0,10000,0,0,0,7666 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ160", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ180", 0, 0, + { 6294,686,-712,-5435,13417,2211,-1006,2435,5042 } }, + + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ250",0, 0, +// {3984,0,0,0,10000,0,0,0,7666}}, + {10325,845,-604,-4113,13385,481,-1791,4163,6924}}, /* emb */ + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ260", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ280", 0, 0, + { 6294,686,-712,-5435,13417,2211,-1006,2435,5042 } }, + + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ3 100MP", 0, 0, +// {2423,0,0,0,9901,0,0,0,7989}}, + { 10999,354,-742,-4590,13342,937,-1060,2166,8120} }, /* emb */ + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ3 50MP", 0, 0, +// { 3984,0,0,0,10000,0,0,0,7666 } }, + {10058,1079,-587,-4135,12903,944,-916,2726,7480}}, /* emb */ + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ3 60MP", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "IQ3 80MP", 0, 0, + { 6294,686,-712,-5435,13417,2211,-1006,2435,5042 } }, + + { LIBRAW_CAMERAMAKER_PhaseOne, "P21", 0, 0, + { 6516,-2050,-507,-8217,16703,1479,-3492,4741,8489 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "P30", 0, 0, + { 4516,-244,-36,-7020,14976,2174,-3206,4670,7087 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "P40", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "P45", 0, 0, + { 5053,-24,-117,-5685,14077,1703,-2619,4491,5850 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "P65", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { LIBRAW_CAMERAMAKER_PhaseOne, "P2", 0, 0, + { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, + + { LIBRAW_CAMERAMAKER_Photron, "BC2-HD", 0, 0, + { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Polaroid, "x530", 0, 0, + { 13458,-2556,-510,-5444,15081,205,0,0,12120 } }, + + { LIBRAW_CAMERAMAKER_RED, "One", 704, 0xffff, + { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Ricoh, "S10 24-72mm F2.5-4.4 VC", 0, 0, + { 10531,-4043,-878,-2038,10270,2052,-107,895,4577 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GR A12 50mm F2.5 MACRO", 0, 0, + { 8849,-2560,-689,-5092,12831,2520,-507,1280,7104 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GR DIGITAL 2", 0, 0, + { 8846,-2704,-729,-5265,12708,2871,-1471,1955,6218 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GR DIGITAL 3", 0, 0, + { 8170,-2496,-655,-5147,13056,2312,-1367,1859,5265 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GR DIGITAL 4", 0, 0, + { 8771,-3151,-837,-3097,11015,2389,-703,1343,4924 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GR III", 0, 0, + { 6127,-1777,-585,-5913,13699,2428,-1088,1780,6017 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GR II", 0, 0, + { 5329,-1459,-390,-5407,12930,2768,-1119,1772,6046 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GR", 0, 0, + { 5329,-1459,-390,-5407,12930,2768,-1119,1772,6046 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GX200", 0, 0, + { 8040,-2368,-626,-4659,12543,2363,-1125,1581,5660 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GXR Mount A12", 0, 0, + { 7834,-2182,-739,-5453,13409,2241,-952,2005,6620 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GXR A12 50mm", 0, 0, + { 8849,-2560,-689,-5092,12831,2520,-507,1280,7104 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GXR A12 28mm", 0, 0, + { 10228,-3159,-933,-5304,13158,2371,-943,1873,6685 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GXR A16", 0, 0, + { 7837,-2538,-730,-4370,12184,2461,-868,1648,5830 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GXR P10", 0, 0, + { 13168,-5128,-1663,-3006,11569,1611,-373,1244,4907 } }, + { LIBRAW_CAMERAMAKER_Ricoh, "GXR S10", 0, 0, + { 8963,-2926,-754,-4881,12921,2164,-1464,1944,4901 } }, + + { LIBRAW_CAMERAMAKER_Samsung, "EX1", 0, 0x3e00, + { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, + { LIBRAW_CAMERAMAKER_Samsung, "EX2F", 0, 0x7ff, + { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, +// { LIBRAW_CAMERAMAKER_Samsung, "GX20", 0, 0, +// { 23213,-14575,-4840,-7077,16564,316,385,-1656,9398 } }, // Adobe DNG +// { 27717,-17403,-5779,-8450,19778,377,459,1978,11221 } }, // Samsung DNG +// { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, // Adobe DCP + +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S6 Edge Rear Camera", 0, 0, +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S6 Rear Camera", 0, 0, + { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S6", 0, 0, // same CMs: "Galaxy S6", "Galaxy S6 Edge" + { 13699,-5767,-1384,-4449,13879,499,-467,1691,5892 } }, + +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S7 Edge Rear Camera", 0, 0, +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S7 Rear Camera", 0, 0, + { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S7", 0, 0, // same CMs: "Galaxy S7", "Galaxy S7 Edge" + { 9927,-3704,-1024,-3935,12758,1257,-389,1512,4993 } }, + +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S8+ Rear Camera", 0, 0, +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S8 Rear Camera", 0, 0, + { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S8", 0, 0, // same CMs: "Galaxy S8", "Galaxy S8+" + { 9927,-3704,-1024,-3935,12758,1257,-389,1512,4993 } }, + +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S9+ Rear Camera", 0, 0, +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S9 Rear Camera", 0, 0, + { LIBRAW_CAMERAMAKER_Samsung, "Galaxy S9", 0, 0, // same CMs: "Galaxy S9", "Galaxy S9+" + { 13292,-6142,-1268,-4095,12890,1283,-557,1930,5163 } }, +// { LIBRAW_CAMERAMAKER_Samsung, "Galaxy Note 9 Rear Telephoto Camera", 0, 0, + { LIBRAW_CAMERAMAKER_Samsung, "Galaxy Note 9 Rear Camera", 0, 0, + { 13292,-6142,-1268,-4095,12890,1283,-557,1930,5163 } }, + + { LIBRAW_CAMERAMAKER_Samsung, "NX U", 0, 0, + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX3300", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX3000", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX30", 0, 0, // same CMs: NX30, NX300, NX300M + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX2000", 0, 0, + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX2", 0, 0xfff, // same CMs: NX20, NX200, NX210 + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX1000", 0, 0, + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX1100", 0, 0, + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX11", 0, 0, + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX10", 0, 0, // same CMs: NX10, NX100 + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX500", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX5", 0, 0, + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX1", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { LIBRAW_CAMERAMAKER_Samsung, "NX mini", 0, 0, + { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, + + { LIBRAW_CAMERAMAKER_Samsung, "WB2000", 0, 0xfff, + { 12093,-3557,-1155,-1000,9534,1733,-22,1787,4576 } }, + { LIBRAW_CAMERAMAKER_Samsung, "WB5000", 0, 0, + { 7675, -2195, -305, -5860, 14118, 1857, -2425, 4007, 6578}}, + { LIBRAW_CAMERAMAKER_Samsung, "S85", 0, 0, + { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, /* DJC */ + +// Foveon: LibRaw color data + { LIBRAW_CAMERAMAKER_Sigma, "dp0 Quattro", 2047, 0, + { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, + { LIBRAW_CAMERAMAKER_Sigma, "dp1 Quattro", 2047, 0, + { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, + { LIBRAW_CAMERAMAKER_Sigma, "dp2 Quattro", 2047, 0, + { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, + { LIBRAW_CAMERAMAKER_Sigma, "dp3 Quattro", 2047, 0, + { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, + { LIBRAW_CAMERAMAKER_Sigma, "sd Quattro H", 256, 0, + { 1295,108,-311,256,828,-65,-28,750,254 } }, /* temp */ + { LIBRAW_CAMERAMAKER_Sigma, "sd Quattro", 2047, 0, + { 1295,108,-311,256,828,-65,-28,750,254 } }, /* temp */ + { LIBRAW_CAMERAMAKER_Sigma, "SD9", 15, 4095, + { 13564,-2537,-751,-5465,15154,194,-67,116,10425 } }, + { LIBRAW_CAMERAMAKER_Sigma, "SD10", 15, 16383, + { 6787,-1682,575,-3091,8357,160,217,-369,12314 } }, + { LIBRAW_CAMERAMAKER_Sigma, "SD14", 15, 16383, + { 13589,-2509,-739,-5440,15104,193,-61,105,10554 } }, + { LIBRAW_CAMERAMAKER_Sigma, "SD15", 15, 4095, + { 13556,-2537,-730,-5462,15144,195,-61,106,10577 } }, +// Merrills + SD1 + { LIBRAW_CAMERAMAKER_Sigma, "SD1", 31, 4095, + { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, /* LibRaw */ + { LIBRAW_CAMERAMAKER_Sigma, "DP1 Merrill", 31, 4095, + { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, /* LibRaw */ + { LIBRAW_CAMERAMAKER_Sigma, "DP2 Merrill", 31, 4095, + { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, /* LibRaw */ + { LIBRAW_CAMERAMAKER_Sigma, "DP3 Merrill", 31, 4095, + { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, /* LibRaw */ +// Sigma DP (non-Merrill Versions) + { LIBRAW_CAMERAMAKER_Sigma, "DP1X", 0, 4095, + { 13704,-2452,-857,-5413,15073,186,-89,151,9820 } }, + { LIBRAW_CAMERAMAKER_Sigma, "DP1", 0, 4095, + { 12774,-2591,-394,-5333,14676,207,15,-21,12127 } }, + { LIBRAW_CAMERAMAKER_Sigma, "DP", 0, 4095, + // { 7401,-1169,-567,2059,3769,1510,664,3367,5328 } }, + { 13100,-3638,-847,6855,2369,580,2723,3218,3251 } }, /* LibRaw */ + + { LIBRAW_CAMERAMAKER_Sinar, "", 0, 0, + { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, /* DJC */ + + { LIBRAW_CAMERAMAKER_Sony, "DSC-F828", 0, 0, + { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-R1", 0, 0, + { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-V3", 0, 0, + { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, + + { LIBRAW_CAMERAMAKER_Sony, "DSC-HX9", -800, 0, // same CMs: DSC-HX95, DSC-HX99 + { 13076,-5686,-1481,-4027,12851,1251,-167,725,4937 } }, + + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX100M7", -800, 0, + {10315, -4390, -937, -4859, 12734, 2365, -734, 1537, 5997 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX100M6", -800, 0, + { 7325,-2321,-596,-3494,11674,2055,-668,1562,5031 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX100M5A", -800, 0, + { 11176,-4700,-965,-4004,12184,2032,-763,1726,5876 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX100M", -800, 0, // same CMs: DSC-RX100M2, DSC-RX100M3, DSC-RX100M4, DSC-RX100M5 + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX100", 0, 0, + { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX10M4", -800, 0, + { 7699,-2566,-629,-2967,11270,1928,-378,1286,4807 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX10",0, 0, // same CMs: DSC-RX10, DSC-RX10M2, DSC-RX10M3 + { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX1RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX1R", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX1", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + + { LIBRAW_CAMERAMAKER_Sony, "DSC-RX0", -800, 0, // same CMs: DSC-RX0, DSC-RX0M2 + { 9396,-3507,-843,-2497,11111,1572,-343,1355,5089 } }, + + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A100", 0, 0xfeb, + { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A290", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A2", 0, 0, // same CMs: DSLR-A200, DSLR-A230 + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A300", 0, 0, + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A330", 0, 0, + { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A3", 0, 0, // same CMs: DSLR-A350, DSLR-A380, DSLR-A390 + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A450", 0, 0, // close to 16596 if arw is 14-bit + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A580", 0, 16596, + { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A500", 0, 16596, + { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A5", 0, 16596, // same CMs: DSLR-A550, DSLR-A560 + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A700", 0, 0, + { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A850", 0, 0, + { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, + { LIBRAW_CAMERAMAKER_Sony, "DSLR-A900", 0, 0, + { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, + + { LIBRAW_CAMERAMAKER_Sony, "ILCA-68", 0, 0, + { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCA-77M2", 0, 0, + { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCA-99M2", 0, 0, + { 6660,-1918,-471,-4613,12398,2485,-649,1433,6447 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-9", 0, 0, + { 6389,-1703,-378,-4562,12265,2587,-670,1489,6550 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7S", 0, 0, // same CMs: ILCE-7S, ILCE-7SM2 + { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, + + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7RM4", 0, 0, + {7662, -2686,-660,-5240, 12965,2530, -796, 1508, 6167 }}, + + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7RM3", 0, 0, + { 6640,-1847,-503,-5238,13010,2474,-993,1673,6527 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7R", 0, 0, + { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7M3", 0, 0, + { 7374,-2389,-551,-5435,13162,2519,-1006,1795,6552 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7", 0, 0, // same CMs: ILCE-7, ILCE-7M2 + { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, + + { LIBRAW_CAMERAMAKER_Sony, "ILCE-6100", 0, 0, + { 7657,-2847,-607,-4083,11966,2389,-684,1418,5844 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-6300", 0, 0, + { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-6400", 0, 0, + { 7657,-2847,-607,-4083,11966,2389,-684,1418,5844 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-6500", 0, 0, + { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-6600", 0, 0, + { 7657,-2847,-607,-4083,11966,2389,-684,1418,5844 } }, + + { LIBRAW_CAMERAMAKER_Sony, "ILCE", 0, 0, // same CMs: ILCE-3000, ILCE-5000, ILCE-5100, ILCE-6000, ILCE-QX1 + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { LIBRAW_CAMERAMAKER_Sony, "MODEL-NAME", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-5N", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-5R", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-5T", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-5", 0, 0, + { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-3N", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-3", 0, 0, + { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-6", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-7", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-VG30", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX-VG900", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { LIBRAW_CAMERAMAKER_Sony, "NEX", 0, 0, // same CMs: NEX-C3, NEX-F3, NEX-VG20 + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A33", 0, 0, + { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A35", 0, 0, + { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A37", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A55", 0, 0, + { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A5", 0, 0, // same CMs: SLT-A57, SLT-A58 + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A65", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A77", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { LIBRAW_CAMERAMAKER_Sony, "SLT-A99", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { LIBRAW_CAMERAMAKER_YI, "M1", 0, 0, + { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, + }; + // clang-format on + + double cam_xyz[4][3]; + //char name[130]; + int i, j; + + if (colors > 4 || colors < 1) + return 1; + + int bl4 = (cblack[0] + cblack[1] + cblack[2] + cblack[3]) / 4, bl64 = 0; + if (cblack[4] * cblack[5] > 0) + { + for (unsigned c = 0; c < 4096 && c < cblack[4] * cblack[5]; c++) + bl64 += cblack[c + 6]; + bl64 /= cblack[4] * cblack[5]; + } + int rblack = black + bl4 + bl64; + + for (i = 0; i < int(sizeof table / sizeof *table); i++) + { + if (table[i].m_idx == make_idx) + { + unsigned l = strlen(table[i].prefix); + if (!l || !strncasecmp(t_model, table[i].prefix, l)) + { + if (!dng_version) + { + if (table[i].t_black > 0) + { + black = (ushort)table[i].t_black; + memset(cblack, 0, sizeof(cblack)); + } + else if (table[i].t_black < 0 && rblack == 0) + { + black = (ushort)(-table[i].t_black); + memset(cblack, 0, sizeof(cblack)); + } + if (table[i].t_maximum) + maximum = (ushort)table[i].t_maximum; + } + if (table[i].trans[0]) + { + for (raw_color = j = 0; j < 12; j++) + if (internal_only) + imgdata.color.cam_xyz[j / 3][j % 3] = table[i].trans[j] / 10000.0; + else + imgdata.color.cam_xyz[j / 3][j % 3] = ((double *)cam_xyz)[j] = + table[i].trans[j] / 10000.0; + if (!internal_only) + cam_xyz_coeff(rgb_cam, cam_xyz); + } + return 1; // CM found + } + } + } + return 0; // CM not found +} +void LibRaw::simple_coeff(int index) +{ + static const float table[][12] = { + /* index 0 -- all Foveon cameras */ + {1.4032, -0.2231, -0.1016, -0.5263, 1.4816, 0.017, -0.0112, 0.0183, + 0.9113}, + /* index 1 -- Kodak DC20 and DC25 */ + {2.25, 0.75, -1.75, -0.25, -0.25, 0.75, 0.75, -0.25, -0.25, -1.75, 0.75, + 2.25}, + /* index 2 -- Logitech Fotoman Pixtura */ + {1.893, -0.418, -0.476, -0.495, 1.773, -0.278, -1.017, -0.655, 2.672}, + /* index 3 -- Nikon E880, E900, and E990 */ + {-1.936280, 1.800443, -1.448486, 2.584324, 1.405365, -0.524955, -0.289090, + 0.408680, -1.204965, 1.082304, 2.941367, -1.818705}}; + int i, c; + + for (raw_color = i = 0; i < 3; i++) + FORCC rgb_cam[i][c] = table[index][i * MIN(colors,4) + c]; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/tables/wblists.cpp libkdcraw/libkdcraw/libraw/src/tables/wblists.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/tables/wblists.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/tables/wblists.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,210 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + + +#define _ARR_SZ(a) (sizeof(a)/sizeof(a[0])) + +static const int _tagtype_dataunit_bytes [19] = { + 1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4, 2, 8, 8, 8, 8 +}; + +libraw_static_table_t LibRaw::tagtype_dataunit_bytes(_tagtype_dataunit_bytes, _ARR_SZ(_tagtype_dataunit_bytes)); + +static const int _Canon_wbi2std[] = { // Canon WB index to standard indexes +// std. number wbi - Canon number + LIBRAW_WBI_Auto, // 0 + LIBRAW_WBI_Daylight, // 1 + LIBRAW_WBI_Cloudy, // 2 + LIBRAW_WBI_Tungsten, // 3 + LIBRAW_WBI_Fluorescent, // 4 + LIBRAW_WBI_Flash, // 5 + LIBRAW_WBI_Custom, // 6 + LIBRAW_WBI_BW, // 7 + LIBRAW_WBI_Shade, // 8 + LIBRAW_WBI_Kelvin, // 9 + LIBRAW_WBI_PC_Set1, // 10 + LIBRAW_WBI_PC_Set2, // 11 + LIBRAW_WBI_PC_Set3, // 12 + LIBRAW_WBI_Unknown, // 13, unlucky number "13", not used + LIBRAW_WBI_FluorescentHigh, // 14 + LIBRAW_WBI_Custom1, // 15 + LIBRAW_WBI_Custom2, // 16 + LIBRAW_WBI_Underwater, // 17, last one for older PowerShot models + LIBRAW_WBI_Custom3, // 18 + LIBRAW_WBI_Custom4, // 19 + LIBRAW_WBI_PC_Set4, // 20 + LIBRAW_WBI_PC_Set5, // 21 + LIBRAW_WBI_Unknown, // 22 + LIBRAW_WBI_Auto1 // 23 +}; + +libraw_static_table_t LibRaw::Canon_wbi2std(_Canon_wbi2std, _ARR_SZ(_Canon_wbi2std)); + +static const int _Canon_KeyIsZero_Len2048_linenums_2_StdWBi[] = { // Appendix A: G2, S30, S40; G3, G5, S45, S50 + LIBRAW_WBI_Custom1, + LIBRAW_WBI_Custom2, + LIBRAW_WBI_Daylight, + LIBRAW_WBI_Cloudy, + LIBRAW_WBI_Tungsten, + LIBRAW_WBI_Fluorescent, + LIBRAW_WBI_Unknown, // ? FluorescentHigh, Shade, Custom, Kelvin + LIBRAW_WBI_Flash +}; + +libraw_static_table_t LibRaw::Canon_KeyIsZero_Len2048_linenums_2_StdWBi(_Canon_KeyIsZero_Len2048_linenums_2_StdWBi, + _ARR_SZ(_Canon_KeyIsZero_Len2048_linenums_2_StdWBi)); + +static const int _Canon_KeyIs0x0410_Len3072_linenums_2_StdWBi[] = { // G6, S60, S70; offset +16 + LIBRAW_WBI_Custom1, + LIBRAW_WBI_Custom2, + LIBRAW_WBI_Daylight, + LIBRAW_WBI_Cloudy, + LIBRAW_WBI_Tungsten, + LIBRAW_WBI_Fluorescent, + LIBRAW_WBI_FluorescentHigh, // LIBRAW_WBI_Unknown, // ? FluorescentHigh, Shade, Custom, Kelvin + LIBRAW_WBI_Unknown, + LIBRAW_WBI_Underwater, // LIBRAW_WBI_Unknown, + LIBRAW_WBI_Unknown, + LIBRAW_WBI_Flash +}; + +libraw_static_table_t LibRaw::Canon_KeyIs0x0410_Len3072_linenums_2_StdWBi(_Canon_KeyIs0x0410_Len3072_linenums_2_StdWBi, + _ARR_SZ(_Canon_KeyIs0x0410_Len3072_linenums_2_StdWBi)); + +static const int _Canon_KeyIs0x0410_Len2048_linenums_2_StdWBi[] = { // Pro1; offset +8 + LIBRAW_WBI_Custom1, + LIBRAW_WBI_Custom2, + LIBRAW_WBI_Daylight, + LIBRAW_WBI_Cloudy, + LIBRAW_WBI_Tungsten, + LIBRAW_WBI_Fluorescent, + LIBRAW_WBI_Unknown, + LIBRAW_WBI_Flash, // LIBRAW_WBI_Unknown, + LIBRAW_WBI_Unknown, + LIBRAW_WBI_Unknown, + LIBRAW_WBI_Unknown // LIBRAW_WBI_Flash +}; + +libraw_static_table_t LibRaw::Canon_KeyIs0x0410_Len2048_linenums_2_StdWBi(_Canon_KeyIs0x0410_Len2048_linenums_2_StdWBi, + _ARR_SZ(_Canon_KeyIs0x0410_Len2048_linenums_2_StdWBi)); + +static const int _Canon_G9_linenums_2_StdWBi[] = { + LIBRAW_WBI_Auto, + LIBRAW_WBI_Daylight, + LIBRAW_WBI_Cloudy, + LIBRAW_WBI_Tungsten, + LIBRAW_WBI_Fluorescent, + LIBRAW_WBI_FluorescentHigh, + LIBRAW_WBI_Flash, + LIBRAW_WBI_Underwater, + LIBRAW_WBI_Custom1, + LIBRAW_WBI_Custom2 +}; +libraw_static_table_t LibRaw::Canon_G9_linenums_2_StdWBi(_Canon_G9_linenums_2_StdWBi, _ARR_SZ(_Canon_G9_linenums_2_StdWBi)); + +static const int _Canon_D30_linenums_2_StdWBi[] = { + LIBRAW_WBI_Daylight, + LIBRAW_WBI_Cloudy, + LIBRAW_WBI_Tungsten, + LIBRAW_WBI_Fluorescent, + LIBRAW_WBI_Flash, + LIBRAW_WBI_Custom +}; +libraw_static_table_t LibRaw::Canon_D30_linenums_2_StdWBi(_Canon_D30_linenums_2_StdWBi, _ARR_SZ(_Canon_D30_linenums_2_StdWBi)); + +static const int _Fuji_wb_list1[] = { + LIBRAW_WBI_FineWeather, LIBRAW_WBI_Shade, LIBRAW_WBI_FL_D, + LIBRAW_WBI_FL_L, LIBRAW_WBI_FL_W, LIBRAW_WBI_Tungsten +}; +libraw_static_table_t LibRaw::Fuji_wb_list1(_Fuji_wb_list1, _ARR_SZ(_Fuji_wb_list1)); + +static const int _FujiCCT_K[31] = { + 2500, 2550, 2650, 2700, 2800, 2850, 2950, 3000, 3100, 3200, 3300, + 3400, 3600, 3700, 3800, 4000, 4200, 4300, 4500, 4800, 5000, 5300, + 5600, 5900, 6300, 6700, 7100, 7700, 8300, 9100, 10000 +}; +libraw_static_table_t LibRaw::FujiCCT_K(_FujiCCT_K, _ARR_SZ(_FujiCCT_K)); + +static const int _Fuji_wb_list2[] = { + LIBRAW_WBI_Auto, 0, LIBRAW_WBI_Custom, 6, LIBRAW_WBI_FineWeather, 1, + LIBRAW_WBI_Shade, 8, LIBRAW_WBI_FL_D, 10, LIBRAW_WBI_FL_L, 11, + LIBRAW_WBI_FL_W, 12, LIBRAW_WBI_Tungsten, 2, LIBRAW_WBI_Underwater, 35, + LIBRAW_WBI_Ill_A, 82, LIBRAW_WBI_D65, 83 +}; +libraw_static_table_t LibRaw::Fuji_wb_list2(_Fuji_wb_list2, _ARR_SZ(_Fuji_wb_list2)); + +static const int _Pentax_wb_list1[] = { + LIBRAW_WBI_Daylight, LIBRAW_WBI_Shade, + LIBRAW_WBI_Cloudy, LIBRAW_WBI_Tungsten, + LIBRAW_WBI_FL_D, LIBRAW_WBI_FL_N, + LIBRAW_WBI_FL_W, LIBRAW_WBI_Flash +}; +libraw_static_table_t LibRaw::Pentax_wb_list1(_Pentax_wb_list1, _ARR_SZ(_Pentax_wb_list1)); + +static const int _Pentax_wb_list2[] = { + LIBRAW_WBI_Daylight, LIBRAW_WBI_Shade, LIBRAW_WBI_Cloudy, + LIBRAW_WBI_Tungsten, LIBRAW_WBI_FL_D, LIBRAW_WBI_FL_N, + LIBRAW_WBI_FL_W, LIBRAW_WBI_Flash, LIBRAW_WBI_FL_L +}; +libraw_static_table_t LibRaw::Pentax_wb_list2(_Pentax_wb_list2, _ARR_SZ(_Pentax_wb_list2)); + + +static const int _Oly_wb_list1[] = { + LIBRAW_WBI_Shade, LIBRAW_WBI_Cloudy, LIBRAW_WBI_FineWeather, + LIBRAW_WBI_Tungsten, LIBRAW_WBI_Sunset, LIBRAW_WBI_FL_D, + LIBRAW_WBI_FL_N, LIBRAW_WBI_FL_W, LIBRAW_WBI_FL_WW +}; +libraw_static_table_t LibRaw::Oly_wb_list1(_Oly_wb_list1, _ARR_SZ(_Oly_wb_list1)); + +static const int _Oly_wb_list2[] = { + LIBRAW_WBI_Auto, 0, + LIBRAW_WBI_Tungsten, 3000, + 0x100, 3300, + 0x100, 3600, + 0x100, 3900, + LIBRAW_WBI_FL_W, 4000, + 0x100, 4300, + LIBRAW_WBI_FL_D, 4500, + 0x100, 4800, + LIBRAW_WBI_FineWeather, 5300, + LIBRAW_WBI_Cloudy, 6000, + LIBRAW_WBI_FL_N, 6600, + LIBRAW_WBI_Shade, 7500, + LIBRAW_WBI_Custom1, 0, + LIBRAW_WBI_Custom2, 0, + LIBRAW_WBI_Custom3, 0, + LIBRAW_WBI_Custom4, 0 +}; +libraw_static_table_t LibRaw::Oly_wb_list2(_Oly_wb_list2, _ARR_SZ(_Oly_wb_list2)); + +static const int _Sony_SRF_wb_list[] = { + LIBRAW_WBI_Daylight, LIBRAW_WBI_Cloudy, LIBRAW_WBI_Fluorescent, + LIBRAW_WBI_Tungsten, LIBRAW_WBI_Flash +}; +libraw_static_table_t LibRaw::Sony_SRF_wb_list(_Sony_SRF_wb_list, _ARR_SZ(_Sony_SRF_wb_list)); + +static const int _Sony_SR2_wb_list[] = { + LIBRAW_WBI_Daylight, LIBRAW_WBI_Cloudy, LIBRAW_WBI_Tungsten, LIBRAW_WBI_Flash, + 4500, LIBRAW_WBI_Unknown, LIBRAW_WBI_Fluorescent +}; +libraw_static_table_t LibRaw::Sony_SR2_wb_list(_Sony_SR2_wb_list, _ARR_SZ(_Sony_SR2_wb_list)); + +static const int _Sony_SR2_wb_list1[] = { + LIBRAW_WBI_Daylight, LIBRAW_WBI_Cloudy, LIBRAW_WBI_Tungsten, LIBRAW_WBI_Flash, + 4500, LIBRAW_WBI_Shade, LIBRAW_WBI_FL_W, LIBRAW_WBI_FL_N, LIBRAW_WBI_FL_D, + LIBRAW_WBI_FL_L, 8500, 6000, 3200, 2500 +}; +libraw_static_table_t LibRaw::Sony_SR2_wb_list1(_Sony_SR2_wb_list1, _ARR_SZ(_Sony_SR2_wb_list1)); \ No newline at end of file diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/curves.cpp libkdcraw/libkdcraw/libraw/src/utils/curves.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/curves.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/curves.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,151 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +void LibRaw::cubic_spline(const int *x_, const int *y_, const int len) +{ + float **A, *b, *c, *d, *x, *y; + int i, j; + + A = (float **)calloc(((2 * len + 4) * sizeof **A + sizeof *A), 2 * len); + if (!A) + return; + A[0] = (float *)(A + 2 * len); + for (i = 1; i < 2 * len; i++) + A[i] = A[0] + 2 * len * i; + y = len + (x = i + (d = i + (c = i + (b = A[0] + i * i)))); + 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)(y_out * 65535.0 + 0.5)); + } + free(A); +} +void LibRaw::gamma_curve(double pwr, double ts, int mode, int imax) +{ + int i; + double g[6], bnd[2] = {0, 0}, r; + + g[0] = pwr; + g[1] = ts; + g[2] = g[3] = g[4] = 0; + bnd[g[1] >= 1] = 1; + if (g[1] && (g[1] - 1) * (g[0] - 1) <= 0) + { + for (i = 0; i < 48; i++) + { + g[2] = (bnd[0] + bnd[1]) / 2; + if (g[0]) + bnd[(pow(g[2] / g[1], -g[0]) - 1) / g[0] - 1 / g[2] > -1] = g[2]; + else + bnd[g[2] / exp(1 - 1 / g[2]) < g[1]] = g[2]; + } + g[3] = g[2] / g[1]; + if (g[0]) + g[4] = g[2] * (1 / g[0] - 1); + } + if (g[0]) + g[5] = 1 / (g[1] * SQR(g[3]) / 2 - g[4] * (1 - g[3]) + + (1 - pow(g[3], 1 + g[0])) * (1 + g[4]) / (1 + g[0])) - + 1; + else + g[5] = 1 / (g[1] * SQR(g[3]) / 2 + 1 - g[2] - g[3] - + g[2] * g[3] * (log(g[3]) - 1)) - + 1; + if (!mode--) + { + memcpy(gamm, g, sizeof gamm); + return; + } + for (i = 0; i < 0x10000; i++) + { + curve[i] = 0xffff; + if ((r = (double)i / imax) < 1) + curve[i] = + 0x10000 * + (mode ? (r < g[3] ? r * g[1] + : (g[0] ? pow(r, g[0]) * (1 + g[4]) - g[4] + : log(r) * g[2] + 1)) + : (r < g[2] ? r / g[1] + : (g[0] ? pow((r + g[4]) / (1 + g[4]), 1 / g[0]) + : exp((r - 1) / g[2])))); + } +} + +void LibRaw::linear_table(unsigned len) +{ + int i; + if (len > 0x10000) + len = 0x10000; + else if (len < 1) + return; + read_shorts(curve, len); + for (i = len; i < 0x10000; i++) + curve[i] = curve[i - 1]; + maximum = curve[len < 0x1000 ? 0xfff : len - 1]; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/decoder_info.cpp libkdcraw/libkdcraw/libraw/src/utils/decoder_info.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/decoder_info.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/decoder_info.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,389 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ +#include "../../internal/libraw_cxx_defs.h" + +const char *LibRaw::unpack_function_name() +{ + libraw_decoder_info_t decoder_info; + get_decoder_info(&decoder_info); + return decoder_info.decoder_name; +} + +int LibRaw::get_decoder_info(libraw_decoder_info_t *d_info) +{ + if (!d_info) + return LIBRAW_UNSPECIFIED_ERROR; + d_info->decoder_name = 0; + d_info->decoder_flags = 0; + if (!load_raw) + return LIBRAW_OUT_OF_ORDER_CALL; + + // dcraw.c names order + if (load_raw == &LibRaw::android_tight_load_raw) + { + d_info->decoder_name = "android_tight_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::android_loose_load_raw) + { + d_info->decoder_name = "android_loose_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::float_dng_load_raw_placeholder) + { + d_info->decoder_name = "float_dng_load_raw_placeholder()"; + } + else if (load_raw == &LibRaw::vc5_dng_load_raw_placeholder) + { + d_info->decoder_name = "vc5_dng_load_raw_placeholder()"; + } + else if (load_raw == &LibRaw::canon_600_load_raw) + { + d_info->decoder_name = "canon_600_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::fuji_compressed_load_raw) + { + d_info->decoder_name = "fuji_compressed_load_raw()"; + } + else if (load_raw == &LibRaw::fuji_14bit_load_raw) + { + d_info->decoder_name = "fuji_14bit_load_raw()"; + } + else if (load_raw == &LibRaw::canon_load_raw) + { + d_info->decoder_name = "canon_load_raw()"; + } + else if (load_raw == &LibRaw::lossless_jpeg_load_raw) + { + d_info->decoder_name = "lossless_jpeg_load_raw()"; + d_info->decoder_flags = + LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::canon_sraw_load_raw) + { + d_info->decoder_name = "canon_sraw_load_raw()"; + // d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::crxLoadRaw) + { + d_info->decoder_name = "crxLoadRaw()"; + } + else if (load_raw == &LibRaw::lossless_dng_load_raw) + { + d_info->decoder_name = "lossless_dng_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | + LIBRAW_DECODER_TRYRAWSPEED | + LIBRAW_DECODER_ADOBECOPYPIXEL; + } + else if (load_raw == &LibRaw::packed_dng_load_raw) + { + d_info->decoder_name = "packed_dng_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | + LIBRAW_DECODER_TRYRAWSPEED | + LIBRAW_DECODER_ADOBECOPYPIXEL; + } + else if (load_raw == &LibRaw::pentax_load_raw) + { + d_info->decoder_name = "pentax_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::nikon_load_raw) + { + d_info->decoder_name = "nikon_load_raw()"; + d_info->decoder_flags = + LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_HASCURVE; + } + else if (load_raw == &LibRaw::nikon_coolscan_load_raw) + { + d_info->decoder_name = "nikon_coolscan_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::nikon_load_sraw) + { + d_info->decoder_name = "nikon_load_sraw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::nikon_yuv_load_raw) + { + d_info->decoder_name = "nikon_load_yuv_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::rollei_load_raw) + { + // UNTESTED + d_info->decoder_name = "rollei_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::phase_one_load_raw) + { + d_info->decoder_name = "phase_one_load_raw()"; + } + else if (load_raw == &LibRaw::phase_one_load_raw_c) + { + d_info->decoder_name = "phase_one_load_raw_c()"; + } + else if (load_raw == &LibRaw::hasselblad_load_raw) + { + d_info->decoder_name = "hasselblad_load_raw()"; + } + else if (load_raw == &LibRaw::leaf_hdr_load_raw) + { + d_info->decoder_name = "leaf_hdr_load_raw()"; + } + else if (load_raw == &LibRaw::unpacked_load_raw) + { + d_info->decoder_name = "unpacked_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FLATDATA; + } + else if (load_raw == &LibRaw::unpacked_load_raw_reversed) + { + d_info->decoder_name = "unpacked_load_raw_reversed()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::sinar_4shot_load_raw) + { + // UNTESTED + d_info->decoder_name = "sinar_4shot_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_SINAR4SHOT; + } + else if (load_raw == &LibRaw::imacon_full_load_raw) + { + d_info->decoder_name = "imacon_full_load_raw()"; + } + else if (load_raw == &LibRaw::hasselblad_full_load_raw) + { + d_info->decoder_name = "hasselblad_full_load_raw()"; + } + else if (load_raw == &LibRaw::packed_load_raw) + { + d_info->decoder_name = "packed_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::broadcom_load_raw) + { + // UNTESTED + d_info->decoder_name = "broadcom_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::nokia_load_raw) + { + // UNTESTED + d_info->decoder_name = "nokia_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::canon_rmf_load_raw) + { + // UNTESTED + d_info->decoder_name = "canon_rmf_load_raw()"; + } + else if (load_raw == &LibRaw::panasonic_load_raw) + { + d_info->decoder_name = "panasonic_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::panasonicC6_load_raw) + { + d_info->decoder_name = "panasonicC6_load_raw()"; + } + else if (load_raw == &LibRaw::panasonicC7_load_raw) + { + d_info->decoder_name = "panasonicC7_load_raw()"; + } + else if (load_raw == &LibRaw::olympus_load_raw) + { + d_info->decoder_name = "olympus_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::minolta_rd175_load_raw) + { + // UNTESTED + d_info->decoder_name = "minolta_rd175_load_raw()"; + } + else if (load_raw == &LibRaw::quicktake_100_load_raw) + { + // UNTESTED + d_info->decoder_name = "quicktake_100_load_raw()"; + } + else if (load_raw == &LibRaw::kodak_radc_load_raw) + { + d_info->decoder_name = "kodak_radc_load_raw()"; + } + else if (load_raw == &LibRaw::kodak_jpeg_load_raw) + { + // UNTESTED + RBAYER + d_info->decoder_name = "kodak_jpeg_load_raw()"; + } + else if (load_raw == &LibRaw::lossy_dng_load_raw) + { + // Check rbayer + d_info->decoder_name = "lossy_dng_load_raw()"; + d_info->decoder_flags = + LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_HASCURVE; + } + else if (load_raw == &LibRaw::kodak_dc120_load_raw) + { + d_info->decoder_name = "kodak_dc120_load_raw()"; + } + else if (load_raw == &LibRaw::eight_bit_load_raw) + { + d_info->decoder_name = "eight_bit_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::kodak_c330_load_raw) + { + d_info->decoder_name = "kodak_yrgb_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::kodak_c603_load_raw) + { + d_info->decoder_name = "kodak_yrgb_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::kodak_262_load_raw) + { + d_info->decoder_name = "kodak_262_load_raw()"; // UNTESTED! + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::kodak_65000_load_raw) + { + d_info->decoder_name = "kodak_65000_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE; + } + else if (load_raw == &LibRaw::kodak_ycbcr_load_raw) + { + // UNTESTED + d_info->decoder_name = "kodak_ycbcr_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::kodak_rgb_load_raw) + { + // UNTESTED + d_info->decoder_name = "kodak_rgb_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::sony_load_raw) + { + d_info->decoder_name = "sony_load_raw()"; + } + else if (load_raw == &LibRaw::sony_arw_load_raw) + { + d_info->decoder_name = "sony_arw_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::sony_arw2_load_raw) + { + d_info->decoder_name = "sony_arw2_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | + LIBRAW_DECODER_TRYRAWSPEED | + LIBRAW_DECODER_SONYARW2; + } + else if (load_raw == &LibRaw::sony_arq_load_raw) + { + d_info->decoder_name = "sony_arq_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_LEGACY_WITH_MARGINS | LIBRAW_DECODER_FLATDATA | LIBRAW_DECODER_FLAT_BG2_SWAPPED; + } + else if (load_raw == &LibRaw::samsung_load_raw) + { + d_info->decoder_name = "samsung_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; + } + else if (load_raw == &LibRaw::samsung2_load_raw) + { + d_info->decoder_name = "samsung2_load_raw()"; + } + else if (load_raw == &LibRaw::samsung3_load_raw) + { + d_info->decoder_name = "samsung3_load_raw()"; + } + else if (load_raw == &LibRaw::smal_v6_load_raw) + { + // UNTESTED + d_info->decoder_name = "smal_v6_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::smal_v9_load_raw) + { + // UNTESTED + d_info->decoder_name = "smal_v9_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; + } + else if (load_raw == &LibRaw::redcine_load_raw) + { + d_info->decoder_name = "redcine_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_HASCURVE; + } + else if (load_raw == &LibRaw::x3f_load_raw) + { + d_info->decoder_name = "x3f_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC | LIBRAW_DECODER_FIXEDMAXC | + LIBRAW_DECODER_LEGACY_WITH_MARGINS; + } + else if (load_raw == &LibRaw::pentax_4shot_load_raw) + { + d_info->decoder_name = "pentax_4shot_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC; + } + else if (load_raw == &LibRaw::deflate_dng_load_raw) + { + d_info->decoder_name = "deflate_dng_load_raw()"; + d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC; + } + else if (load_raw == &LibRaw::nikon_load_striped_packed_raw) + { + d_info->decoder_name = "nikon_load_striped_packed_raw()"; + } + else if (load_raw == &LibRaw::nikon_load_padded_packed_raw) + { + d_info->decoder_name = "nikon_load_padded_packed_raw()"; + } + else if (load_raw == &LibRaw::nikon_14bit_load_raw) + { + d_info->decoder_name = "nikon_14bit_load_raw()"; + } + /* -- added 07/02/18 -- */ + else if (load_raw == &LibRaw::unpacked_load_raw_fuji_f700s20) + { + d_info->decoder_name = "unpacked_load_raw_fuji_f700s20()"; + } + else if (load_raw == &LibRaw::unpacked_load_raw_FujiDBP) + { + d_info->decoder_name = "unpacked_load_raw_FujiDBP()"; + } +#ifdef USE_6BY9RPI + else if (load_raw == &LibRaw::rpi_load_raw8) + { + d_info->decoder_name = "rpi_load_raw8"; + } + else if (load_raw == &LibRaw::rpi_load_raw12) + { + d_info->decoder_name = "rpi_load_raw12"; + } + else if (load_raw == &LibRaw::rpi_load_raw14) + { + d_info->decoder_name = "rpi_load_raw14"; + } + else if (load_raw == &LibRaw::rpi_load_raw16) + { + d_info->decoder_name = "rpi_load_raw16"; + } +#endif + else + { + d_info->decoder_name = "Unknown unpack function"; + d_info->decoder_flags = LIBRAW_DECODER_NOTSET; + } + return LIBRAW_SUCCESS; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/init_close_utils.cpp libkdcraw/libkdcraw/libraw/src/utils/init_close_utils.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/init_close_utils.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/init_close_utils.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,269 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +static void cleargps(libraw_gps_info_t *q) +{ + for (int i = 0; i < 3; i++) + q->latitude[i] = q->longitude[i] = q->gpstimestamp[i] = 0.f; + q->altitude = 0.f; + q->altref = q->latref = q->longref = q->gpsstatus = q->gpsparsed = 0; +} + +LibRaw::LibRaw(unsigned int flags) : memmgr(1024) +{ + double aber[4] = {1, 1, 1, 1}; + double gamm[6] = {0.45, 4.5, 0, 0, 0, 0}; + unsigned greybox[4] = {0, 0, UINT_MAX, UINT_MAX}; + unsigned cropbox[4] = {0, 0, UINT_MAX, UINT_MAX}; + ZERO(imgdata); + + cleargps(&imgdata.other.parsed_gps); + ZERO(libraw_internal_data); + ZERO(callbacks); + + _rawspeed_camerameta = _rawspeed_decoder = NULL; + dnghost = NULL; + dngnegative = NULL; + dngimage = NULL; + _x3f_data = NULL; + +#ifdef USE_RAWSPEED + CameraMetaDataLR *camerameta = + make_camera_metadata(); // May be NULL in case of exception in + // make_camera_metadata() + _rawspeed_camerameta = static_cast<void *>(camerameta); +#endif + callbacks.mem_cb = (flags & LIBRAW_OPIONS_NO_MEMERR_CALLBACK) + ? NULL + : &default_memory_callback; + callbacks.data_cb = (flags & LIBRAW_OPIONS_NO_DATAERR_CALLBACK) + ? NULL + : &default_data_callback; + callbacks.exif_cb = NULL; // no default callback + callbacks.pre_identify_cb = NULL; + callbacks.post_identify_cb = NULL; + callbacks.pre_subtractblack_cb = callbacks.pre_scalecolors_cb = + callbacks.pre_preinterpolate_cb = callbacks.pre_interpolate_cb = + callbacks.interpolate_bayer_cb = callbacks.interpolate_xtrans_cb = + callbacks.post_interpolate_cb = callbacks.pre_converttorgb_cb = + callbacks.post_converttorgb_cb = NULL; + + memmove(&imgdata.params.aber, &aber, sizeof(aber)); + memmove(&imgdata.params.gamm, &gamm, sizeof(gamm)); + memmove(&imgdata.params.greybox, &greybox, sizeof(greybox)); + memmove(&imgdata.params.cropbox, &cropbox, sizeof(cropbox)); + + imgdata.params.bright = 1; + imgdata.params.use_camera_matrix = 1; + imgdata.params.user_flip = -1; + imgdata.params.user_black = -1; + imgdata.params.user_cblack[0] = imgdata.params.user_cblack[1] = + imgdata.params.user_cblack[2] = imgdata.params.user_cblack[3] = -1000001; + imgdata.params.user_sat = -1; + imgdata.params.user_qual = -1; + imgdata.params.output_color = 1; + imgdata.params.output_bps = 8; + imgdata.params.use_fuji_rotate = 1; + imgdata.params.exp_shift = 1.0; + imgdata.params.auto_bright_thr = LIBRAW_DEFAULT_AUTO_BRIGHTNESS_THRESHOLD; + imgdata.params.adjust_maximum_thr = LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD; + imgdata.params.use_rawspeed = 1; + imgdata.params.use_dngsdk = LIBRAW_DNG_DEFAULT; + imgdata.params.no_auto_scale = 0; + imgdata.params.no_interpolation = 0; + imgdata.params.raw_processing_options = LIBRAW_PROCESSING_DP2Q_INTERPOLATERG | + LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF | + LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT; + imgdata.params.sony_arw2_posterization_thr = 0; + imgdata.params.max_raw_memory_mb = LIBRAW_MAX_ALLOC_MB_DEFAULT; + imgdata.params.green_matching = 0; + imgdata.params.custom_camera_strings = 0; + imgdata.params.coolscan_nef_gamma = 1.0f; + imgdata.parent_class = this; + imgdata.progress_flags = 0; + imgdata.color.dng_levels.baseline_exposure = -999.f; + imgdata.color.dng_levels.LinearResponseLimit = 1.0f; + MN.hasselblad.nIFD_CM[0] = + MN.hasselblad.nIFD_CM[1] = -1; + MN.kodak.ISOCalibrationGain = 1.0f; + _exitflag = 0; + tls = new LibRaw_TLS; + tls->init(); +} + +LibRaw::~LibRaw() +{ + recycle(); + delete tls; +#ifdef USE_RAWSPEED + if (_rawspeed_camerameta) + { + CameraMetaDataLR *cmeta = + static_cast<CameraMetaDataLR *>(_rawspeed_camerameta); + delete cmeta; + _rawspeed_camerameta = NULL; + } +#endif +} + +void x3f_clear(void *); + +void LibRaw::recycle() +{ + recycle_datastream(); +#define FREE(a) \ + do \ + { \ + if (a) \ + { \ + free(a); \ + a = NULL; \ + } \ + } while (0) + + FREE(imgdata.image); + + FREE(imgdata.thumbnail.thumb); + FREE(libraw_internal_data.internal_data.meta_data); + FREE(libraw_internal_data.output_data.histogram); + FREE(libraw_internal_data.output_data.oprof); + FREE(imgdata.color.profile); + FREE(imgdata.rawdata.ph1_cblack); + FREE(imgdata.rawdata.ph1_rblack); + FREE(imgdata.rawdata.raw_alloc); + FREE(imgdata.idata.xmpdata); + +#undef FREE + + ZERO(imgdata.sizes); + imgdata.sizes.raw_inset_crop.cleft = 0xffff; + imgdata.sizes.raw_inset_crop.ctop = 0xffff; + + ZERO(imgdata.idata); + ZERO(MN); + ZERO(imgdata.color); + ZERO(imgdata.other); + ZERO(imgdata.thumbnail); + ZERO(imgdata.rawdata); + cleargps(&imgdata.other.parsed_gps); + imgdata.color.dng_levels.baseline_exposure = -999.f; + imgdata.color.dng_levels.LinearResponseLimit = 1.f; + + MN.canon.SensorLeftBorder = -1; + MN.canon.SensorTopBorder = -1; + + MN.nikon.SensorHighSpeedCrop.cleft = 0xffff; + MN.nikon.SensorHighSpeedCrop.ctop = 0xffff; + + MN.fuji.WB_Preset = 0xffff; + MN.fuji.ExpoMidPointShift = -999.f; + MN.fuji.DynamicRange = 0xffff; + MN.fuji.FilmMode = 0xffff; + MN.fuji.DynamicRangeSetting = 0xffff; + MN.fuji.DevelopmentDynamicRange = 0xffff; + MN.fuji.AutoDynamicRange = 0xffff; + MN.fuji.DRangePriority = 0xffff; + MN.fuji.FocusMode = 0xffff; + MN.fuji.DriveMode = -1; + MN.fuji.AFMode = 0xffff; + MN.fuji.FocusPixel[0] = MN.fuji.FocusPixel[1] = 0xffff; + MN.fuji.ImageStabilization[0] = + MN.fuji.ImageStabilization[1] = + MN.fuji.ImageStabilization[2] = 0xffff; + + MN.samsung.ColorSpace[0] = MN.samsung.ColorSpace[1] = -1; + + MN.sony.CameraType = 0xffff; + MN.sony.real_iso_offset = 0xffff; + MN.sony.ImageCount3_offset = 0xffff; + MN.sony.ElectronicFrontCurtainShutter = 0xffff; + MN.sony.MinoltaCamID = 0xffffffff; + MN.sony.RAWFileType = 0xffff; + MN.sony.AFAreaModeSetting = 0xff; + MN.sony.FlexibleSpotPosition[0] = + MN.sony.FlexibleSpotPosition[1] = 0xffff; + MN.sony.AFPointSelected = 0xff; + MN.sony.LongExposureNoiseReduction = 0xffffffff; + MN.sony.Quality = 0xffffffff; + MN.sony.HighISONoiseReduction = 0xffff; + MN.sony.SonyRawFileType = 0xffff; + + MN.kodak.BlackLevelTop = 0xffff; + MN.kodak.BlackLevelBottom = 0xffff; + MN.kodak.ISOCalibrationGain = 1.0f; + + MN.hasselblad.nIFD_CM[0] = MN.hasselblad.nIFD_CM[1] = -1; + + imgdata.color.dng_color[0].illuminant = + imgdata.color.dng_color[1].illuminant = LIBRAW_WBI_None; + + for (int i = 0; i < 4; i++) + imgdata.color.dng_levels.analogbalance[i] = 1.0f; + + ZERO(libraw_internal_data); + ZERO(imgdata.lens); + imgdata.lens.makernotes.FocalUnits = 1; + imgdata.lens.makernotes.LensID = LIBRAW_LENS_NOT_SET; + ZERO(imgdata.shootinginfo); + imgdata.shootinginfo.DriveMode = -1; + imgdata.shootinginfo.FocusMode = -1; + imgdata.shootinginfo.MeteringMode = -1; + imgdata.shootinginfo.AFPoint = -1; + imgdata.shootinginfo.ExposureMode = -1; + imgdata.shootinginfo.ExposureProgram = -1; + imgdata.shootinginfo.ImageStabilization = -1; + + _exitflag = 0; +#ifdef USE_RAWSPEED + if (_rawspeed_decoder) + { + RawSpeed::RawDecoder *d = + static_cast<RawSpeed::RawDecoder *>(_rawspeed_decoder); + delete d; + } + _rawspeed_decoder = 0; +#endif +#ifdef USE_DNGSDK + if (dngnegative) + { + dng_negative *ng = (dng_negative *)dngnegative; + delete ng; + dngnegative = 0; + } + if(dngimage) + { + dng_image *dimage = (dng_image*)dngimage; + delete dimage; + dngimage = 0; + } +#endif +#ifdef USE_X3FTOOLS + if (_x3f_data) + { + x3f_clear(_x3f_data); + _x3f_data = 0; + } +#endif + memmgr.cleanup(); + + imgdata.thumbnail.tformat = LIBRAW_THUMBNAIL_UNKNOWN; + imgdata.progress_flags = 0; + + load_raw = thumb_load_raw = 0; + + tls->init(); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/open.cpp libkdcraw/libkdcraw/libraw/src/utils/open.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/open.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/open.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,1032 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" +#include "../../internal/libraw_cameraids.h" + +int LibRaw::open_file(const char *fname, INT64 max_buf_size) +{ + int big = 0; + if (max_buf_size == LIBRAW_OPEN_BIGFILE) + big = 1; + else if (max_buf_size == LIBRAW_OPEN_FILE) + big = 0; + else + { +#ifndef LIBRAW_WIN32_CALLS + struct stat st; + if (stat(fname, &st)) + return LIBRAW_IO_ERROR; + big = (st.st_size > max_buf_size) ? 1 : 0; +#else + struct _stati64 st; + if (_stati64(fname, &st)) + return LIBRAW_IO_ERROR; + big = (st.st_size > max_buf_size) ? 1 : 0; +#endif + } + + LibRaw_abstract_datastream *stream; + try + { + if (big) + stream = new LibRaw_bigfile_datastream(fname); + else + stream = new LibRaw_file_datastream(fname); + } + + catch (const std::bad_alloc& ) + { + recycle(); + return LIBRAW_UNSUFFICIENT_MEMORY; + } + if (!stream->valid()) + { + delete stream; + return LIBRAW_IO_ERROR; + } + ID.input_internal = 0; // preserve from deletion on error + int ret = open_datastream(stream); + if (ret == LIBRAW_SUCCESS) + { + ID.input_internal = 1; // flag to delete datastream on recycle + } + else + { + delete stream; + ID.input_internal = 0; + } + return ret; +} + +#if defined(WIN32) || defined(_WIN32) +#ifndef LIBRAW_WIN32_UNICODEPATHS +int LibRaw::open_file(const wchar_t *, INT64) +{ + return LIBRAW_NOT_IMPLEMENTED; +} +#else +int LibRaw::open_file(const wchar_t *fname, INT64 max_buf_size) +{ + int big = 0; + if (max_buf_size == LIBRAW_OPEN_BIGFILE) + big = 1; + else if (max_buf_size == LIBRAW_OPEN_FILE) + big = 0; + else + { + struct _stati64 st; + if (_wstati64(fname, &st)) + return LIBRAW_IO_ERROR; + big = (st.st_size > max_buf_size) ? 1 : 0; + } + + LibRaw_abstract_datastream *stream; + try + { + if (big) + stream = new LibRaw_bigfile_datastream(fname); + else + stream = new LibRaw_file_datastream(fname); + } + + catch (std::bad_alloc) + { + recycle(); + return LIBRAW_UNSUFFICIENT_MEMORY; + } + if (!stream->valid()) + { + delete stream; + return LIBRAW_IO_ERROR; + } + ID.input_internal = 0; // preserve from deletion on error + int ret = open_datastream(stream); + if (ret == LIBRAW_SUCCESS) + { + ID.input_internal = 1; // flag to delete datastream on recycle + } + else + { + delete stream; + ID.input_internal = 0; + } + return ret; +} +#endif +#endif + +int LibRaw::open_buffer(void *buffer, size_t size) +{ + // this stream will close on recycle() + if (!buffer || buffer == (void *)-1) + return LIBRAW_IO_ERROR; + + LibRaw_buffer_datastream *stream; + try + { + stream = new LibRaw_buffer_datastream(buffer, size); + } + catch (const std::bad_alloc& ) + { + recycle(); + return LIBRAW_UNSUFFICIENT_MEMORY; + } + if (!stream->valid()) + { + delete stream; + return LIBRAW_IO_ERROR; + } + ID.input_internal = 0; // preserve from deletion on error + int ret = open_datastream(stream); + if (ret == LIBRAW_SUCCESS) + { + ID.input_internal = 1; // flag to delete datastream on recycle + } + else + { + delete stream; + ID.input_internal = 0; + } + return ret; +} + +int LibRaw::open_bayer(unsigned char *buffer, unsigned datalen, + ushort _raw_width, ushort _raw_height, + ushort _left_margin, ushort _top_margin, + ushort _right_margin, ushort _bottom_margin, + unsigned char procflags, unsigned char bayer_pattern, + unsigned unused_bits, unsigned otherflags, + unsigned black_level) +{ + // this stream will close on recycle() + if (!buffer || buffer == (void *)-1) + return LIBRAW_IO_ERROR; + + LibRaw_buffer_datastream *stream; + try + { + stream = new LibRaw_buffer_datastream(buffer, datalen); + } + catch (const std::bad_alloc& ) + { + recycle(); + return LIBRAW_UNSUFFICIENT_MEMORY; + } + if (!stream->valid()) + { + delete stream; + return LIBRAW_IO_ERROR; + } + ID.input = stream; + SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN); + // From identify + initdata(); + strcpy(imgdata.idata.make, "BayerDump"); + snprintf(imgdata.idata.model, sizeof(imgdata.idata.model) - 1, + "%u x %u pixels", _raw_width, _raw_height); + S.flip = procflags >> 2; + libraw_internal_data.internal_output_params.zero_is_bad = procflags & 2; + libraw_internal_data.unpacker_data.data_offset = 0; + S.raw_width = _raw_width; + S.raw_height = _raw_height; + S.left_margin = _left_margin; + S.top_margin = _top_margin; + S.width = S.raw_width - S.left_margin - _right_margin; + S.height = S.raw_height - S.top_margin - _bottom_margin; + + imgdata.idata.filters = 0x1010101 * bayer_pattern; + imgdata.idata.colors = + 4 - !((imgdata.idata.filters & imgdata.idata.filters >> 1) & 0x5555); + libraw_internal_data.unpacker_data.load_flags = otherflags; + switch (libraw_internal_data.unpacker_data.tiff_bps = + (datalen)*8 / (S.raw_width * S.raw_height)) + { + case 8: + load_raw = &LibRaw::eight_bit_load_raw; + break; + case 10: + if ((datalen) / S.raw_height * 3 >= S.raw_width * 4) + { + load_raw = &LibRaw::android_loose_load_raw; + break; + } + else if (libraw_internal_data.unpacker_data.load_flags & 1) + { + load_raw = &LibRaw::android_tight_load_raw; + break; + } + case 12: + libraw_internal_data.unpacker_data.load_flags |= 128; + load_raw = &LibRaw::packed_load_raw; + break; + case 16: + libraw_internal_data.unpacker_data.order = + 0x4949 | 0x404 * (libraw_internal_data.unpacker_data.load_flags & 1); + libraw_internal_data.unpacker_data.tiff_bps -= + libraw_internal_data.unpacker_data.load_flags >> 4; + libraw_internal_data.unpacker_data.tiff_bps -= + libraw_internal_data.unpacker_data.load_flags = + libraw_internal_data.unpacker_data.load_flags >> 1 & 7; + load_raw = &LibRaw::unpacked_load_raw; + } + C.maximum = + (1 << libraw_internal_data.unpacker_data.tiff_bps) - (1 << unused_bits); + C.black = black_level; + S.iwidth = S.width; + S.iheight = S.height; + imgdata.idata.colors = 3; + imgdata.idata.filters |= ((imgdata.idata.filters >> 2 & 0x22222222) | + (imgdata.idata.filters << 2 & 0x88888888)) & + imgdata.idata.filters << 1; + + imgdata.idata.raw_count = 1; + for (int i = 0; i < 4; i++) + imgdata.color.pre_mul[i] = 1.0; + + strcpy(imgdata.idata.cdesc, "RGBG"); + + ID.input_internal = 1; + SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY); + return LIBRAW_SUCCESS; +} + +struct foveon_data_t +{ + const char *make; + const char *model; + const int raw_width, raw_height; + const int white; + const int left_margin, top_margin; + const int width, height; +} foveon_data[] = { + {"Sigma", "SD9", 2304, 1531, 12000, 20, 8, 2266, 1510}, + {"Sigma", "SD9", 1152, 763, 12000, 10, 2, 1132, 755}, + {"Sigma", "SD10", 2304, 1531, 12000, 20, 8, 2266, 1510}, + {"Sigma", "SD10", 1152, 763, 12000, 10, 2, 1132, 755}, + {"Sigma", "SD14", 2688, 1792, 14000, 18, 12, 2651, 1767}, + {"Sigma", "SD14", 2688, 896, 14000, 18, 6, 2651, 883}, // 2/3 + {"Sigma", "SD14", 1344, 896, 14000, 9, 6, 1326, 883}, // 1/2 + {"Sigma", "SD15", 2688, 1792, 2900, 18, 12, 2651, 1767}, + {"Sigma", "SD15", 2688, 896, 2900, 18, 6, 2651, 883}, // 2/3 ? + {"Sigma", "SD15", 1344, 896, 2900, 9, 6, 1326, 883}, // 1/2 ? + {"Sigma", "DP1", 2688, 1792, 2100, 18, 12, 2651, 1767}, + {"Sigma", "DP1", 2688, 896, 2100, 18, 6, 2651, 883}, // 2/3 ? + {"Sigma", "DP1", 1344, 896, 2100, 9, 6, 1326, 883}, // 1/2 ? + {"Sigma", "DP1S", 2688, 1792, 2200, 18, 12, 2651, 1767}, + {"Sigma", "DP1S", 2688, 896, 2200, 18, 6, 2651, 883}, // 2/3 + {"Sigma", "DP1S", 1344, 896, 2200, 9, 6, 1326, 883}, // 1/2 + {"Sigma", "DP1X", 2688, 1792, 3560, 18, 12, 2651, 1767}, + {"Sigma", "DP1X", 2688, 896, 3560, 18, 6, 2651, 883}, // 2/3 + {"Sigma", "DP1X", 1344, 896, 3560, 9, 6, 1326, 883}, // 1/2 + {"Sigma", "DP2", 2688, 1792, 2326, 13, 16, 2651, 1767}, + {"Sigma", "DP2", 2688, 896, 2326, 13, 8, 2651, 883}, // 2/3 ?? + {"Sigma", "DP2", 1344, 896, 2326, 7, 8, 1325, 883}, // 1/2 ?? + {"Sigma", "DP2S", 2688, 1792, 2300, 18, 12, 2651, 1767}, + {"Sigma", "DP2S", 2688, 896, 2300, 18, 6, 2651, 883}, // 2/3 + {"Sigma", "DP2S", 1344, 896, 2300, 9, 6, 1326, 883}, // 1/2 + {"Sigma", "DP2X", 2688, 1792, 2300, 18, 12, 2651, 1767}, + {"Sigma", "DP2X", 2688, 896, 2300, 18, 6, 2651, 883}, // 2/3 + {"Sigma", "DP2X", 1344, 896, 2300, 9, 6, 1325, 883}, // 1/2 + {"Sigma", "SD1", 4928, 3264, 3900, 12, 52, 4807, 3205}, // Full size + {"Sigma", "SD1", 4928, 1632, 3900, 12, 26, 4807, 1603}, // 2/3 size + {"Sigma", "SD1", 2464, 1632, 3900, 6, 26, 2403, 1603}, // 1/2 size + {"Sigma", "SD1 Merrill", 4928, 3264, 3900, 12, 52, 4807, 3205}, // Full size + {"Sigma", "SD1 Merrill", 4928, 1632, 3900, 12, 26, 4807, 1603}, // 2/3 size + {"Sigma", "SD1 Merrill", 2464, 1632, 3900, 6, 26, 2403, 1603}, // 1/2 size + {"Sigma", "DP1 Merrill", 4928, 3264, 3900, 12, 0, 4807, 3205}, + {"Sigma", "DP1 Merrill", 2464, 1632, 3900, 12, 0, 2403, 1603}, // 1/2 size + {"Sigma", "DP1 Merrill", 4928, 1632, 3900, 12, 0, 4807, 1603}, // 2/3 size + {"Sigma", "DP2 Merrill", 4928, 3264, 3900, 12, 0, 4807, 3205}, + {"Sigma", "DP2 Merrill", 2464, 1632, 3900, 12, 0, 2403, 1603}, // 1/2 size + {"Sigma", "DP2 Merrill", 4928, 1632, 3900, 12, 0, 4807, 1603}, // 2/3 size + {"Sigma", "DP3 Merrill", 4928, 3264, 3900, 12, 0, 4807, 3205}, + {"Sigma", "DP3 Merrill", 2464, 1632, 3900, 12, 0, 2403, 1603}, // 1/2 size + {"Sigma", "DP3 Merrill", 4928, 1632, 3900, 12, 0, 4807, 1603}, // 2/3 size + {"Polaroid", "x530", 1440, 1088, 2700, 10, 13, 1419, 1059}, + // dp2 Q + {"Sigma", "dp3 Quattro", 5888, 3776, 16383, 204, 76, 5446, + 3624}, // full size, new fw ?? + {"Sigma", "dp3 Quattro", 5888, 3672, 16383, 204, 24, 5446, + 3624}, // full size + {"Sigma", "dp3 Quattro", 2944, 1836, 16383, 102, 12, 2723, + 1812}, // half size + {"Sigma", "dp3 Quattro", 2944, 1888, 16383, 102, 38, 2723, + 1812}, // half size, new fw?? + + {"Sigma", "dp2 Quattro", 5888, 3776, 16383, 204, 76, 5446, + 3624}, // full size, new fw + {"Sigma", "dp2 Quattro", 5888, 3672, 16383, 204, 24, 5446, + 3624}, // full size + {"Sigma", "dp2 Quattro", 2944, 1836, 16383, 102, 12, 2723, + 1812}, // half size + {"Sigma", "dp2 Quattro", 2944, 1888, 16383, 102, 38, 2723, + 1812}, // half size, new fw + + {"Sigma", "dp1 Quattro", 5888, 3776, 16383, 204, 76, 5446, + 3624}, // full size, new fw?? + {"Sigma", "dp1 Quattro", 5888, 3672, 16383, 204, 24, 5446, + 3624}, // full size + {"Sigma", "dp1 Quattro", 2944, 1836, 16383, 102, 12, 2723, + 1812}, // half size + {"Sigma", "dp1 Quattro", 2944, 1888, 16383, 102, 38, 2723, + 1812}, // half size, new fw + + {"Sigma", "dp0 Quattro", 5888, 3776, 16383, 204, 76, 5446, + 3624}, // full size, new fw?? + {"Sigma", "dp0 Quattro", 5888, 3672, 16383, 204, 24, 5446, + 3624}, // full size + {"Sigma", "dp0 Quattro", 2944, 1836, 16383, 102, 12, 2723, + 1812}, // half size + {"Sigma", "dp0 Quattro", 2944, 1888, 16383, 102, 38, 2723, + 1812}, // half size, new fw + // Sigma sd Quattro + {"Sigma", "sd Quattro", 5888, 3776, 16383, 204, 76, 5446, + 3624}, // full size + {"Sigma", "sd Quattro", 2944, 1888, 16383, 102, 38, 2723, + 1812}, // half size + // Sd Quattro H + {"Sigma", "sd Quattro H", 6656, 4480, 4000, 224, 160, 6208, + 4160}, // full size + {"Sigma", "sd Quattro H", 3328, 2240, 4000, 112, 80, 3104, + 2080}, // half size + {"Sigma", "sd Quattro H", 5504, 3680, 4000, 0, 4, 5496, 3668}, // full size + {"Sigma", "sd Quattro H", 2752, 1840, 4000, 0, 2, 2748, 1834}, // half size +}; +const int foveon_count = sizeof(foveon_data) / sizeof(foveon_data[0]); + +int LibRaw::open_datastream(LibRaw_abstract_datastream *stream) +{ + + if (!stream) + return ENOENT; + if (!stream->valid()) + return LIBRAW_IO_ERROR; + recycle(); + if (callbacks.pre_identify_cb) + { + int r = (callbacks.pre_identify_cb)(this); + if (r == 1) + goto final; + } + + try + { + ID.input = stream; + SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN); + + identify(); + + imgdata.lens.Lens[sizeof(imgdata.lens.Lens) - 1] = 0; // make sure lens is 0-terminated + + if (callbacks.post_identify_cb) + (callbacks.post_identify_cb)(this); + +#define isRIC imgdata.sizes.raw_inset_crop + + if (!imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_Fujifilm) + && (!strcmp(imgdata.idata.normalized_model, "S3Pro") + || !strcmp(imgdata.idata.normalized_model, "S5Pro") + || !strcmp(imgdata.idata.normalized_model, "S2Pro"))) + { + isRIC.cleft = isRIC.ctop = 0xffff; + isRIC.cwidth = isRIC.cheight = 0; + } + + // Wipe out non-standard WB + if (!imgdata.idata.dng_version && + (makeIs(LIBRAW_CAMERAMAKER_Sony) && !strcmp(imgdata.idata.normalized_model, "DSC-F828")) + && !(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_PROVIDE_NONSTANDARD_WB)) + { + for (int i = 0; i < 4; i++) imgdata.color.cam_mul[i] = (i == 1); + memset(imgdata.color.WB_Coeffs, 0, sizeof(imgdata.color.WB_Coeffs)); + memset(imgdata.color.WBCT_Coeffs, 0, sizeof(imgdata.color.WBCT_Coeffs)); + } + + if (load_raw == &LibRaw::nikon_load_raw) + nikon_read_curve(); + + if (load_raw == &LibRaw::lossless_jpeg_load_raw && + imgdata.makernotes.canon.RecordMode && makeIs(LIBRAW_CAMERAMAKER_Kodak) && + /* Not normalized models here, it is intentional */ + (!strncasecmp(imgdata.idata.model, "EOS D2000", 9) || // if we want something different for B&W cameras, + !strncasecmp(imgdata.idata.model, "EOS D6000", 9))) // it's better to compare with CamIDs + { + imgdata.color.black = 0; + imgdata.color.maximum = 4501; + memset(imgdata.color.cblack, 0, sizeof(imgdata.color.cblack)); + memset(imgdata.sizes.mask, 0, sizeof(imgdata.sizes.mask)); + imgdata.sizes.mask[0][3] = 1; // to skip mask re-calc + libraw_internal_data.unpacker_data.load_flags |= 512; + } + + if (load_raw == &LibRaw::panasonic_load_raw) + { + if (libraw_internal_data.unpacker_data.pana_encoding == 6 || + libraw_internal_data.unpacker_data.pana_encoding == 7) + { + for (int i = 0; i < 3; i++) + imgdata.color.cblack[i] = + libraw_internal_data.internal_data.pana_black[i]; + imgdata.color.cblack[3] = imgdata.color.cblack[1]; + imgdata.color.cblack[4] = imgdata.color.cblack[5] = 0; + imgdata.color.black = 0; + imgdata.color.maximum = + MAX(imgdata.color.linear_max[0], + MAX(imgdata.color.linear_max[1], imgdata.color.linear_max[2])); + } + + if (libraw_internal_data.unpacker_data.pana_encoding == 6) + { + int rowbytes = imgdata.sizes.raw_width / 11 * 16; + if ((imgdata.sizes.raw_width % 11) == 0 && + (INT64(imgdata.sizes.raw_height) * rowbytes == + INT64(libraw_internal_data.unpacker_data.data_size))) + load_raw = &LibRaw::panasonicC6_load_raw; + else + imgdata.idata.raw_count = 0; // incorrect size + } + else if (libraw_internal_data.unpacker_data.pana_encoding == 7) + { + int pixperblock = + libraw_internal_data.unpacker_data.pana_bpp == 14 ? 9 : 10; + int rowbytes = imgdata.sizes.raw_width / pixperblock * 16; + if ((imgdata.sizes.raw_width % pixperblock) == 0 && + (INT64(imgdata.sizes.raw_height) * rowbytes == + INT64(libraw_internal_data.unpacker_data.data_size))) + load_raw = &LibRaw::panasonicC7_load_raw; + else + imgdata.idata.raw_count = 0; // incorrect size + } + } + +#define NIKON_14BIT_SIZE(rw, rh) \ + (((unsigned)(ceilf((float)(rw * 7 / 4) / 16.0)) * 16) * rh) + + // Ugly hack, replace with proper data/line size for different + // cameras/format when available + if (makeIs(LIBRAW_CAMERAMAKER_Nikon) + && !strncasecmp(imgdata.idata.model, "Z", 1) && + NIKON_14BIT_SIZE(imgdata.sizes.raw_width, imgdata.sizes.raw_height) == + libraw_internal_data.unpacker_data.data_size) + { + load_raw = &LibRaw::nikon_14bit_load_raw; + } +#undef NIKON_14BIT_SIZE + + // Linear max from 14-bit camera, but on 12-bit data? + if (makeIs(LIBRAW_CAMERAMAKER_Sony) && + imgdata.color.maximum > 0 && + imgdata.color.linear_max[0] > (long)imgdata.color.maximum && + imgdata.color.linear_max[0] <= (long)imgdata.color.maximum * 4) + for (int c = 0; c < 4; c++) + imgdata.color.linear_max[c] /= 4; + + if (makeIs(LIBRAW_CAMERAMAKER_Canon)) + { +#define imC imgdata.makernotes.canon + if (imC.SensorLeftBorder != -1) + { // tag 0x00e0 SensorInfo was parsed + if (isRIC.aspect != LIBRAW_IMAGE_ASPECT_UNKNOWN) + { // tag 0x009a AspectInfo was parsed + isRIC.cleft += imC.SensorLeftBorder; + isRIC.ctop += imC.SensorTopBorder; + } + else + { + isRIC.cleft = imC.SensorLeftBorder; + isRIC.ctop = imC.SensorTopBorder; + isRIC.cwidth = imC.SensorRightBorder - imC.SensorLeftBorder + 1; + isRIC.cheight = imC.SensorBottomBorder - imC.SensorTopBorder + 1; + } + } + else + { + if (isRIC.aspect != LIBRAW_IMAGE_ASPECT_UNKNOWN) + { + } + else + { // Canon PowerShot S2 IS + } + } +#undef isRIC +#undef imC + } + + if (makeIs(LIBRAW_CAMERAMAKER_Canon) && + (load_raw == &LibRaw::canon_sraw_load_raw) && + imgdata.sizes.raw_width > 0) + { + float ratio = + float(imgdata.sizes.raw_height) / float(imgdata.sizes.raw_width); + if ((ratio < 0.57 || ratio > 0.75) && + imgdata.makernotes.canon.SensorHeight > 1 && + imgdata.makernotes.canon.SensorWidth > 1) + { + imgdata.sizes.raw_width = imgdata.makernotes.canon.SensorWidth; + imgdata.sizes.left_margin = imgdata.makernotes.canon.SensorLeftBorder; + imgdata.sizes.iwidth = imgdata.sizes.width = + imgdata.makernotes.canon.SensorRightBorder - + imgdata.makernotes.canon.SensorLeftBorder + 1; + imgdata.sizes.raw_height = imgdata.makernotes.canon.SensorHeight; + imgdata.sizes.top_margin = imgdata.makernotes.canon.SensorTopBorder; + imgdata.sizes.iheight = imgdata.sizes.height = + imgdata.makernotes.canon.SensorBottomBorder - + imgdata.makernotes.canon.SensorTopBorder + 1; + libraw_internal_data.unpacker_data.load_flags |= + 256; // reset width/height in canon_sraw_load_raw() + imgdata.sizes.raw_pitch = 8 * imgdata.sizes.raw_width; + } + else if (imgdata.sizes.raw_width == 4032 && + imgdata.sizes.raw_height == 3402 && + !strcasecmp(imgdata.idata.model, "EOS 80D")) // 80D hardcoded + { + imgdata.sizes.raw_width = 4536; + imgdata.sizes.left_margin = 28; + imgdata.sizes.iwidth = imgdata.sizes.width = + imgdata.sizes.raw_width - imgdata.sizes.left_margin; + imgdata.sizes.raw_height = 3024; + imgdata.sizes.top_margin = 8; + imgdata.sizes.iheight = imgdata.sizes.height = + imgdata.sizes.raw_height - imgdata.sizes.top_margin; + libraw_internal_data.unpacker_data.load_flags |= 256; + imgdata.sizes.raw_pitch = 8 * imgdata.sizes.raw_width; + } + } + +#ifdef USE_DNGSDK + if (imgdata.idata.dng_version + &&libraw_internal_data.unpacker_data.tiff_compress == 34892 + && libraw_internal_data.unpacker_data.tiff_bps == 8 + && libraw_internal_data.unpacker_data.tiff_samples == 3 + && load_raw == &LibRaw::lossy_dng_load_raw) + { + // Data should be linearized by DNG SDK + C.black = 0; + memset(C.cblack, 0, sizeof(C.cblack)); + } +#endif + + // XTrans Compressed? + if (!imgdata.idata.dng_version && + makeIs(LIBRAW_CAMERAMAKER_Fujifilm) && + (load_raw == &LibRaw::unpacked_load_raw)) + { + if (imgdata.sizes.raw_width * (imgdata.sizes.raw_height * 2ul) != + libraw_internal_data.unpacker_data.data_size) + { + if ((imgdata.sizes.raw_width * (imgdata.sizes.raw_height * 7ul)) / 4 == + libraw_internal_data.unpacker_data.data_size) + load_raw = &LibRaw::fuji_14bit_load_raw; + else + parse_fuji_compressed_header(); + } + if (imgdata.idata.filters == 9) + { + // Adjust top/left margins for X-Trans + int newtm = imgdata.sizes.top_margin % 6 + ? (imgdata.sizes.top_margin / 6 + 1) * 6 + : imgdata.sizes.top_margin; + int newlm = imgdata.sizes.left_margin % 6 + ? (imgdata.sizes.left_margin / 6 + 1) * 6 + : imgdata.sizes.left_margin; + if (newtm != imgdata.sizes.top_margin || + newlm != imgdata.sizes.left_margin) + { + imgdata.sizes.height -= (newtm - imgdata.sizes.top_margin); + imgdata.sizes.top_margin = newtm; + imgdata.sizes.width -= (newlm - imgdata.sizes.left_margin); + imgdata.sizes.left_margin = newlm; + for (int c1 = 0; c1 < 6; c1++) + for (int c2 = 0; c2 < 6; c2++) + imgdata.idata.xtrans[c1][c2] = imgdata.idata.xtrans_abs[c1][c2]; + } + } + } + if (!libraw_internal_data.internal_output_params.fuji_width + && imgdata.idata.filters >= 1000 + && ((imgdata.sizes.top_margin % 2) || (imgdata.sizes.left_margin % 2))) + { + int crop[2] = { 0,0 }; + unsigned filt; + int c; + if (imgdata.sizes.top_margin % 2) + { + imgdata.sizes.top_margin += 1; + imgdata.sizes.height -= 1; + crop[1] = 1; + } + if (imgdata.sizes.left_margin % 2) + { + imgdata.sizes.left_margin += 1; + imgdata.sizes.width -= 1; + crop[0] = 1; + } + for (filt = c = 0; c < 16; c++) + filt |= FC((c >> 1) + (crop[1]), (c & 1) + (crop[0])) << c * 2; + imgdata.idata.filters = filt; + } + +#ifdef USE_DNGSDK + if ( + imgdata.params.use_dngsdk && + !(imgdata.params.raw_processing_options & (LIBRAW_PROCESSING_DNG_STAGE2 | LIBRAW_PROCESSING_DNG_STAGE3 | LIBRAW_PROCESSING_DNG_DISABLEWBADJUST))) +#endif + { + // Fix DNG white balance if needed: observed only for Kalpanika X3F tools produced DNGs + if (imgdata.idata.dng_version && (imgdata.idata.filters == 0) && + imgdata.idata.colors > 1 && imgdata.idata.colors < 5) + { + float delta[4] = { 0.f, 0.f, 0.f, 0.f }; + int black[4]; + for (int c = 0; c < 4; c++) + black[c] = imgdata.color.dng_levels.dng_black + + imgdata.color.dng_levels.dng_cblack[c]; + for (int c = 0; c < imgdata.idata.colors; c++) + delta[c] = imgdata.color.dng_levels.dng_whitelevel[c] - black[c]; + float mindelta = delta[0], maxdelta = delta[0]; + for (int c = 1; c < imgdata.idata.colors; c++) + { + if (mindelta > delta[c]) + mindelta = delta[c]; + if (maxdelta < delta[c]) + maxdelta = delta[c]; + } + if (mindelta > 1 && maxdelta < (mindelta * 20)) // safety + { + for (int c = 0; c < imgdata.idata.colors; c++) + { + imgdata.color.cam_mul[c] /= (delta[c] / maxdelta); + imgdata.color.pre_mul[c] /= (delta[c] / maxdelta); + } + imgdata.color.maximum = imgdata.color.cblack[0] + maxdelta; + } + } + } + + if (imgdata.idata.dng_version && + !(imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_USE_DNG_DEFAULT_CROP) && + makeIs(LIBRAW_CAMERAMAKER_Panasonic) + && !strcasecmp(imgdata.idata.normalized_model, "DMC-LX100")) + imgdata.sizes.width = 4288; + + if (imgdata.idata.dng_version && + !(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_USE_DNG_DEFAULT_CROP) + && makeIs(LIBRAW_CAMERAMAKER_Leica) + && !strcasecmp(imgdata.idata.normalized_model, "SL2")) + imgdata.sizes.height -= 16; + + if (makeIs(LIBRAW_CAMERAMAKER_Sony) && + imgdata.idata.dng_version && + !(imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_USE_DNG_DEFAULT_CROP)) + { + if (S.raw_width == 3984) + S.width = 3925; + else if (S.raw_width == 4288) + S.width = S.raw_width - 32; + else if (S.raw_width == 4928 && S.height < 3280) + S.width = S.raw_width - 8; + else if (S.raw_width == 5504) + S.width = S.raw_width - (S.height > 3664 ? 8 : 32); + } + + if (makeIs(LIBRAW_CAMERAMAKER_Sony) && + !imgdata.idata.dng_version) + { + if(load_raw ==&LibRaw::sony_arq_load_raw) + { + if(S.raw_width > 12000) // A7RM4 16x, both APS-C and APS + S.width = S.raw_width - 64; + else // A7RM3/M4 4x merge + S.width = S.raw_width - 32; + } + + if (((!strncasecmp(imgdata.idata.model, "ILCE-7RM", 8) || + !strcasecmp(imgdata.idata.model, "ILCA-99M2")) && + (S.raw_width == 5216 || S.raw_width == 6304)) // A7RM2/M3/A99M2 in APS mode; A7RM4 in APS-C + || + (!strcasecmp(imgdata.idata.model, "ILCE-7R") && S.raw_width >= 4580 && + S.raw_width < 5020) // A7R in crop mode, no samples, so size est. + || (!strcasecmp(imgdata.idata.model, "ILCE-7") && + S.raw_width == 3968) // A7 in crop mode + || + ((!strncasecmp(imgdata.idata.model, "ILCE-7M", 7) || + !strcasecmp(imgdata.idata.model, "ILCE-9") || +#if 0 + !strcasecmp(imgdata.idata.model, + "SLT-A99V")) // Does SLT-A99 also have APS-C mode?? +#endif + (mnCamID == SonyID_SLT_A99)) // 2 reasons: some cameras are SLT-A99, no 'V'; some are Hasselblad HV + && S.raw_width > 3750 && + S.raw_width < 4120) // A7M2, A7M3, AA9, most likely APS-C raw_width + // is 3968 (same w/ A7), but no samples, so guess + || (!strncasecmp(imgdata.idata.model, "ILCE-7S", 7) && + S.raw_width == 2816) // A7S2=> exact, hope it works for A7S-I too + ) + S.width = S.raw_width - 32; + } + + + // FIXME: it is possible that DNG contains 4x main frames + some previews; in this case imgdata.idata.raw_count will be greater than 4 + if (makeIs(LIBRAW_CAMERAMAKER_Pentax) && + /*!strcasecmp(imgdata.idata.model,"K-3 II") &&*/ + imgdata.idata.raw_count == 4 && + (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES)) + { + imgdata.idata.raw_count = 1; + imgdata.idata.filters = 0; + imgdata.idata.colors = 4; + imgdata.sizes.top_margin+=2; + imgdata.sizes.left_margin+=2; + imgdata.sizes.width-=4; + imgdata.sizes.height-=4; + IO.mix_green = 1; + pentax_component_load_raw = load_raw; + load_raw = &LibRaw::pentax_4shot_load_raw; + } + + if (!imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_Leaf) && + !strcmp(imgdata.idata.model, "Credo 50")) + { + imgdata.color.pre_mul[0] = 1.f / 0.3984f; + imgdata.color.pre_mul[2] = 1.f / 0.7666f; + imgdata.color.pre_mul[1] = imgdata.color.pre_mul[3] = 1.0; + } + + if (!imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_Fujifilm) && + (!strncmp(imgdata.idata.model, "S20Pro", 6) || + !strncmp(imgdata.idata.model, "F700", 4))) + { + imgdata.sizes.raw_width /= 2; + load_raw = &LibRaw::unpacked_load_raw_fuji_f700s20; + } + + if (load_raw == &LibRaw::packed_load_raw && + makeIs(LIBRAW_CAMERAMAKER_Nikon) && + !libraw_internal_data.unpacker_data.load_flags && + (!strncasecmp(imgdata.idata.model, "D810", 4) || + !strcasecmp(imgdata.idata.model, "D4S")) && + libraw_internal_data.unpacker_data.data_size * 2 == + imgdata.sizes.raw_height * imgdata.sizes.raw_width * 3) + { + libraw_internal_data.unpacker_data.load_flags = 80; + } + // Adjust BL for Sony A900/A850 + if (load_raw == &LibRaw::packed_load_raw && + makeIs(LIBRAW_CAMERAMAKER_Sony)) // 12 bit sony, but metadata may be for 14-bit range + { + if (C.maximum > 4095) + C.maximum = 4095; + if (C.black > 256 || C.cblack[0] > 256) + { + C.black /= 4; + for (int c = 0; c < 4; c++) + C.cblack[c] /= 4; + for (unsigned c = 0; c < C.cblack[4] * C.cblack[5]; c++) + C.cblack[6 + c] /= 4; + } + } + + if (load_raw == &LibRaw::nikon_yuv_load_raw) // Is it Nikon sRAW? + { + load_raw = &LibRaw::nikon_load_sraw; + C.black = 0; + memset(C.cblack, 0, sizeof(C.cblack)); + imgdata.idata.filters = 0; + libraw_internal_data.unpacker_data.tiff_samples = 3; + imgdata.idata.colors = 3; + double beta_1 = -5.79342238397656E-02; + double beta_2 = 3.28163551282665; + double beta_3 = -8.43136004842678; + double beta_4 = 1.03533181861023E+01; + for (int i = 0; i <= 3072; i++) + { + double x = (double)i / 3072.; + double y = (1. - exp(-beta_1 * x - beta_2 * x * x - beta_3 * x * x * x - + beta_4 * x * x * x * x)); + if (y < 0.) + y = 0.; + imgdata.color.curve[i] = (y * 16383.); + } + for (int i = 0; i < 3; i++) + for (int j = 0; j < 4; j++) + imgdata.color.rgb_cam[i][j] = float(i == j); + } + // Adjust BL for Nikon 12bit + if ((load_raw == &LibRaw::nikon_load_raw || + load_raw == &LibRaw::packed_load_raw || + load_raw == &LibRaw::nikon_load_padded_packed_raw) && + makeIs(LIBRAW_CAMERAMAKER_Nikon) && + strncmp(imgdata.idata.model, "COOLPIX", 7) && + libraw_internal_data.unpacker_data.tiff_bps == 12) + { + C.maximum = 4095; + C.black /= 4; + for (int c = 0; c < 4; c++) + C.cblack[c] /= 4; + for (unsigned c = 0; c < C.cblack[4] * C.cblack[5]; c++) + C.cblack[6 + c] /= 4; + } + + // Adjust wb_already_applied + if (load_raw == &LibRaw::nikon_load_sraw) + imgdata.color.as_shot_wb_applied = + LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_NIKON_SRAW; + else if (makeIs(LIBRAW_CAMERAMAKER_Canon) && + imgdata.makernotes.canon.multishot[0] >= 8 && + imgdata.makernotes.canon.multishot[1] > 0) + imgdata.color.as_shot_wb_applied = + LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_CANON; + else if (makeIs(LIBRAW_CAMERAMAKER_Nikon) && + imgdata.makernotes.nikon.ExposureMode == 1) + imgdata.color.as_shot_wb_applied = + LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_NIKON; + else if (makeIs(LIBRAW_CAMERAMAKER_Pentax) && + ((imgdata.makernotes.pentax.MultiExposure & 0x01) == 1)) + imgdata.color.as_shot_wb_applied = + LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_PENTAX; + else + imgdata.color.as_shot_wb_applied = 0; + + // Adjust Highlight Linearity limit + if (C.linear_max[0] < 0) + { + if (imgdata.idata.dng_version) + { + for (int c = 0; c < 4; c++) + C.linear_max[c] = -1 * C.linear_max[c] + imgdata.color.cblack[c + 6]; + } + else + { + for (int c = 0; c < 4; c++) + C.linear_max[c] = -1 * C.linear_max[c] + imgdata.color.cblack[c]; + } + } + + if (makeIs(LIBRAW_CAMERAMAKER_Nikon) && + (!C.linear_max[0]) && (C.maximum > 1024) && (load_raw != &LibRaw::nikon_load_sraw)) + { + C.linear_max[0] = C.linear_max[1] = C.linear_max[2] = C.linear_max[3] = + (long)((float)(C.maximum) / 1.07f); + } + + // Correct WB for Samsung GX20 + if ( +#if 0 + /* GX20 should be corrected, but K20 is not */ + makeIs(LIBRAW_CAMERAMAKER_Pentax) && + !strcasecmp(imgdata.idata.normalized_model, "K20D") +#endif +#if 0 + !strcasecmp(imgdata.idata.make, "Samsung") && + !strcasecmp(imgdata.idata.model, "GX20") +#endif + makeIs(LIBRAW_CAMERAMAKER_Pentax) && + (mnCamID == PentaxID_GX20) // Samsung rebranding + ) + { + for (int cnt = LIBRAW_WBI_Unknown; cnt <= LIBRAW_WBI_StudioTungsten; cnt++) { + if (C.WB_Coeffs[cnt][1]) { + C.WB_Coeffs[cnt][0] = (int)((float)(C.WB_Coeffs[cnt][0]) * 1.0503f); + C.WB_Coeffs[cnt][2] = (int)((float)(C.WB_Coeffs[cnt][2]) * 2.2867f); + } + } + for (int cnt = 0; cnt < 64; cnt++) { + if (C.WBCT_Coeffs[cnt][0] > 0.0f) { + C.WBCT_Coeffs[cnt][1] *= 1.0503f; + C.WBCT_Coeffs[cnt][3] *= 2.2867f; + } + } + for(int cnt = 0; cnt < 4; cnt++) + imgdata.color.pre_mul[cnt] = + C.WB_Coeffs[LIBRAW_WBI_Daylight][cnt]; + } + + // Adjust BL for Panasonic + if (load_raw == &LibRaw::panasonic_load_raw && + makeIs(LIBRAW_CAMERAMAKER_Panasonic) && + ID.pana_black[0] && ID.pana_black[1] && ID.pana_black[2]) + { + if (libraw_internal_data.unpacker_data.pana_encoding == 5) + libraw_internal_data.internal_output_params.zero_is_bad = 0; + C.black = 0; + int add = libraw_internal_data.unpacker_data.pana_encoding == 4 ? 15 : 0; + C.cblack[0] = ID.pana_black[0] + add; + C.cblack[1] = C.cblack[3] = ID.pana_black[1] + add; + C.cblack[2] = ID.pana_black[2] + add; + unsigned i = C.cblack[3]; + for (int c = 0; c < 3; c++) + if (i > C.cblack[c]) + i = C.cblack[c]; + for (int c = 0; c < 4; c++) + C.cblack[c] -= i; + C.black = i; + } + + // Adjust sizes for X3F processing +#ifdef USE_X3FTOOLS + if (load_raw == &LibRaw::x3f_load_raw) + { + for (int i = 0; i < foveon_count; i++) + if (!strcasecmp(imgdata.idata.make, foveon_data[i].make) && + !strcasecmp(imgdata.idata.model, foveon_data[i].model) && + imgdata.sizes.raw_width == foveon_data[i].raw_width && + imgdata.sizes.raw_height == foveon_data[i].raw_height) + { + imgdata.sizes.top_margin = foveon_data[i].top_margin; + imgdata.sizes.left_margin = foveon_data[i].left_margin; + imgdata.sizes.width = imgdata.sizes.iwidth = foveon_data[i].width; + imgdata.sizes.height = imgdata.sizes.iheight = foveon_data[i].height; + C.maximum = foveon_data[i].white; + break; + } + } +#endif +#if 0 + size_t bytes = ID.input->size()-libraw_internal_data.unpacker_data.data_offset; + float bpp = float(bytes)/float(S.raw_width)/float(S.raw_height); + float bpp2 = float(bytes)/float(S.width)/float(S.height); + if(!strcasecmp(imgdata.idata.make,"Hasselblad") && bpp == 6.0f) + { + load_raw = &LibRaw::hasselblad_full_load_raw; + S.width = S.raw_width; + S.height = S.raw_height; + P1.filters = 0; + P1.colors=3; + P1.raw_count=1; + C.maximum=0xffff; + } +#endif + if (C.profile_length) + { + if (C.profile) + free(C.profile); + C.profile = malloc(C.profile_length); + merror(C.profile, "LibRaw::open_file()"); + ID.input->seek(ID.profile_offset, SEEK_SET); + ID.input->read(C.profile, C.profile_length, 1); + } + + SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY); + } + catch (LibRaw_exceptions err) + { + EXCEPTION_HANDLER(err); + } + catch (const std::exception& ee) + { + EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT); + } + +final:; + + if (P1.raw_count < 1) + return LIBRAW_FILE_UNSUPPORTED; + + write_fun = &LibRaw::write_ppm_tiff; + + if (load_raw == &LibRaw::kodak_ycbcr_load_raw) + { + S.height += S.height & 1; + S.width += S.width & 1; + } + + IO.shrink = + P1.filters && + (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1))); + if (IO.shrink && P1.filters >= 1000) + { + S.width &= 65534; + S.height &= 65534; + } + + S.iheight = (S.height + IO.shrink) >> IO.shrink; + S.iwidth = (S.width + IO.shrink) >> IO.shrink; + + // Save color,sizes and internal data into raw_image fields + memmove(&imgdata.rawdata.color, &imgdata.color, sizeof(imgdata.color)); + memmove(&imgdata.rawdata.sizes, &imgdata.sizes, sizeof(imgdata.sizes)); + memmove(&imgdata.rawdata.iparams, &imgdata.idata, sizeof(imgdata.idata)); + memmove(&imgdata.rawdata.ioparams, + &libraw_internal_data.internal_output_params, + sizeof(libraw_internal_data.internal_output_params)); + + SET_PROC_FLAG(LIBRAW_PROGRESS_SIZE_ADJUST); + + return LIBRAW_SUCCESS; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/phaseone_processing.cpp libkdcraw/libkdcraw/libraw/src/utils/phaseone_processing.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/phaseone_processing.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/phaseone_processing.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,102 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +void LibRaw::phase_one_allocate_tempbuffer() +{ + // Allocate temp raw_image buffer + imgdata.rawdata.raw_image = (ushort *)malloc(S.raw_pitch * S.raw_height); + merror(imgdata.rawdata.raw_image, "phase_one_prepare_to_correct()"); +} +void LibRaw::phase_one_free_tempbuffer() +{ + free(imgdata.rawdata.raw_image); + imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc; +} + +int LibRaw::phase_one_subtract_black(ushort *src, ushort *dest) +{ + + try + { + if (O.user_black < 0 && O.user_cblack[0] <= -1000000 && + O.user_cblack[1] <= -1000000 && O.user_cblack[2] <= -1000000 && + O.user_cblack[3] <= -1000000) + { + if (!imgdata.rawdata.ph1_cblack || !imgdata.rawdata.ph1_rblack) + { + int bl = imgdata.color.phase_one_data.t_black; + for (int row = 0; row < S.raw_height; row++) + { + checkCancel(); + for (int col = 0; col < S.raw_width; col++) + { + int idx = row * S.raw_width + col; + int val = int(src[idx]) - bl; + dest[idx] = val > 0 ? val : 0; + } + } + } + else + { + int bl = imgdata.color.phase_one_data.t_black; + for (int row = 0; row < S.raw_height; row++) + { + checkCancel(); + for (int col = 0; col < S.raw_width; col++) + { + int idx = row * S.raw_width + col; + int val = + int(src[idx]) - bl + + imgdata.rawdata + .ph1_cblack[row][col >= imgdata.rawdata.color.phase_one_data + .split_col] + + imgdata.rawdata + .ph1_rblack[col][row >= imgdata.rawdata.color.phase_one_data + .split_row]; + dest[idx] = val > 0 ? val : 0; + } + } + } + } + else // black set by user interaction + { + // Black level in cblack! + for (int row = 0; row < S.raw_height; row++) + { + checkCancel(); + unsigned short cblk[16]; + for (int cc = 0; cc < 16; cc++) + cblk[cc] = C.cblack[fcol(row, cc)]; + for (int col = 0; col < S.raw_width; col++) + { + int idx = row * S.raw_width + col; + ushort val = src[idx]; + ushort bl = cblk[col & 0xf]; + dest[idx] = val > bl ? val - bl : 0; + } + } + } + return 0; + } + catch (LibRaw_exceptions err) + { + return LIBRAW_CANCELLED_BY_CALLBACK; + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/read_utils.cpp libkdcraw/libkdcraw/libraw/src/utils/read_utils.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/read_utils.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/read_utils.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,149 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +ushort LibRaw::sget2Rev(uchar *s) // specific to some Canon Makernotes fields, + // where they have endian in reverse +{ + if (order == 0x4d4d) /* "II" means little-endian, and we reverse to "MM" - big + endian */ + return s[0] | s[1] << 8; + else /* "MM" means big-endian... */ + return s[0] << 8 | s[1]; +} + +ushort LibRaw::get2() +{ + uchar str[2] = {0xff, 0xff}; + fread(str, 1, 2, ifp); + return sget2(str); +} + +unsigned LibRaw::sget4(uchar *s) +{ + if (order == 0x4949) + return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + else + return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; +} +#define sget4(s) sget4((uchar *)s) + +unsigned LibRaw::get4() +{ + uchar str[4] = {0xff, 0xff, 0xff, 0xff}; + fread(str, 1, 4, ifp); + return sget4(str); +} + +unsigned LibRaw::getint(int type) { return tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) ? get2() : get4(); } + +float LibRaw::int_to_float(int i) +{ + union { + int i; + float f; + } u; + u.i = i; + return u.f; +} + +double LibRaw::getreal(int type) +{ + union { + char c[8]; + double d; + } u, v; + int i, rev; + + switch (type) + { + case LIBRAW_EXIFTAG_TYPE_SHORT: + return (unsigned short)get2(); + case LIBRAW_EXIFTAG_TYPE_LONG: + return (unsigned int)get4(); + case LIBRAW_EXIFTAG_TYPE_RATIONAL: // (unsigned, unsigned) + u.d = (unsigned int)get4(); + v.d = (unsigned int)get4(); + return u.d / (v.d ? v.d : 1); + case LIBRAW_EXIFTAG_TYPE_SSHORT: + return (signed short)get2(); + case LIBRAW_EXIFTAG_TYPE_SLONG: + return (signed int)get4(); + case LIBRAW_EXIFTAG_TYPE_SRATIONAL: // (int, int) + u.d = (signed int)get4(); + v.d = (signed int)get4(); + return u.d / (v.d ? v.d : 1); + case LIBRAW_EXIFTAG_TYPE_FLOAT: + return int_to_float(get4()); + case LIBRAW_EXIFTAG_TYPE_DOUBLE: + rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); + for (i = 0; i < 8; i++) + u.c[i ^ rev] = fgetc(ifp); + return u.d; + default: + return fgetc(ifp); + } +} + +double LibRaw::sgetreal(int type, uchar *s) +{ + union { + char c[8]; + double d; + } u, v; + int i, rev; + + switch (type) + { + case LIBRAW_EXIFTAG_TYPE_SHORT: + return (unsigned short)sget2(s); + case LIBRAW_EXIFTAG_TYPE_LONG: + return (unsigned int)sget4(s); + case LIBRAW_EXIFTAG_TYPE_RATIONAL: // (unsigned, unsigned) + u.d = (unsigned int)sget4(s); + v.d = (unsigned int)sget4(s+4); + return u.d / (v.d ? v.d : 1); + case LIBRAW_EXIFTAG_TYPE_SSHORT: + return (signed short)sget2(s); + case LIBRAW_EXIFTAG_TYPE_SLONG: + return (signed int)sget4(s); + case LIBRAW_EXIFTAG_TYPE_SRATIONAL: // (int, int) + u.d = (signed int)sget4(s); + v.d = (signed int)sget4(s+4); + return u.d / (v.d ? v.d : 1); + case LIBRAW_EXIFTAG_TYPE_FLOAT: + return int_to_float(sget4(s)); + case LIBRAW_EXIFTAG_TYPE_DOUBLE: + rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); + for (i = 0; i < 8; i++) + u.c[i ^ rev] = *(s+1); + return u.d; + default: + return *(s+1); + } +} + + +void LibRaw::read_shorts(ushort *pixel, unsigned count) +{ + if ((unsigned)fread(pixel, 2, count, ifp) < count) + derror(); + if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) + swab((char *)pixel, (char *)pixel, count * 2); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/thumb_utils.cpp libkdcraw/libkdcraw/libraw/src/utils/thumb_utils.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/thumb_utils.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/thumb_utils.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,313 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +void LibRaw::kodak_thumb_loader() +{ + INT64 est_datasize = + T.theight * T.twidth / 3; // is 0.3 bytes per pixel good estimate? + if (ID.toffset < 0) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + if (ID.toffset + est_datasize > ID.input->size() + THUMB_READ_BEYOND) + throw LIBRAW_EXCEPTION_IO_EOF; + + if(INT64(T.theight) * INT64(T.twidth) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + if (INT64(T.theight) * INT64(T.twidth) < 64ULL) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + // some kodak cameras + ushort s_height = S.height, s_width = S.width, s_iwidth = S.iwidth, + s_iheight = S.iheight; + ushort s_flags = libraw_internal_data.unpacker_data.load_flags; + libraw_internal_data.unpacker_data.load_flags = 12; + int s_colors = P1.colors; + unsigned s_filters = P1.filters; + ushort(*s_image)[4] = imgdata.image; + + S.height = T.theight; + S.width = T.twidth; + P1.filters = 0; + + if (thumb_load_raw == &LibRaw::kodak_ycbcr_load_raw) + { + S.height += S.height & 1; + S.width += S.width & 1; + } + + imgdata.image = + (ushort(*)[4])calloc(S.iheight * S.iwidth, sizeof(*imgdata.image)); + merror(imgdata.image, "LibRaw::kodak_thumb_loader()"); + + ID.input->seek(ID.toffset, SEEK_SET); + // read kodak thumbnail into T.image[] + try + { + (this->*thumb_load_raw)(); + } + catch (...) + { + free(imgdata.image); + imgdata.image = s_image; + + T.twidth = 0; + S.width = s_width; + + S.iwidth = s_iwidth; + S.iheight = s_iheight; + + T.theight = 0; + S.height = s_height; + + T.tcolors = 0; + P1.colors = s_colors; + + P1.filters = s_filters; + T.tlength = 0; + libraw_internal_data.unpacker_data.load_flags = s_flags; + return; + } + + // from scale_colors + { + double dmax; + float scale_mul[4]; + int c, val; + for (dmax = DBL_MAX, c = 0; c < 3; c++) + if (dmax > C.pre_mul[c]) + dmax = C.pre_mul[c]; + + for (c = 0; c < 3; c++) + scale_mul[c] = (C.pre_mul[c] / dmax) * 65535.0 / C.maximum; + scale_mul[3] = scale_mul[1]; + + size_t size = S.height * S.width; + for (unsigned i = 0; i < size * 4; i++) + { + val = imgdata.image[0][i]; + if (!val) + continue; + val *= scale_mul[i & 3]; + imgdata.image[0][i] = CLIP(val); + } + } + + // from convert_to_rgb + ushort *img; + int row, col; + + int(*t_hist)[LIBRAW_HISTOGRAM_SIZE] = + (int(*)[LIBRAW_HISTOGRAM_SIZE])calloc(sizeof(*t_hist), 4); + merror(t_hist, "LibRaw::kodak_thumb_loader()"); + + float out[3], out_cam[3][4] = {{2.81761312, -1.98369181, 0.166078627, 0}, + {-0.111855984, 1.73688626, -0.625030339, 0}, + {-0.0379119813, -0.891268849, 1.92918086, 0}}; + + for (img = imgdata.image[0], row = 0; row < S.height; row++) + for (col = 0; col < S.width; col++, img += 4) + { + out[0] = out[1] = out[2] = 0; + int c; + for (c = 0; c < 3; c++) + { + out[0] += out_cam[0][c] * img[c]; + out[1] += out_cam[1][c] * img[c]; + out[2] += out_cam[2][c] * img[c]; + } + for (c = 0; c < 3; c++) + img[c] = CLIP((int)out[c]); + for (c = 0; c < P1.colors; c++) + t_hist[c][img[c] >> 3]++; + } + + // from gamma_lut + int(*save_hist)[LIBRAW_HISTOGRAM_SIZE] = + libraw_internal_data.output_data.histogram; + libraw_internal_data.output_data.histogram = t_hist; + + // make curve output curve! + ushort *t_curve = (ushort *)calloc(sizeof(C.curve), 1); + merror(t_curve, "LibRaw::kodak_thumb_loader()"); + memmove(t_curve, C.curve, sizeof(C.curve)); + memset(C.curve, 0, sizeof(C.curve)); + { + int perc, val, total, t_white = 0x2000, c; + + perc = S.width * S.height * 0.01; /* 99th percentile white level */ + if (IO.fuji_width) + perc /= 2; + if (!((O.highlight & ~2) || O.no_auto_bright)) + for (t_white = c = 0; c < P1.colors; c++) + { + for (val = 0x2000, total = 0; --val > 32;) + if ((total += libraw_internal_data.output_data.histogram[c][val]) > + perc) + break; + if (t_white < val) + t_white = val; + } + gamma_curve(O.gamm[0], O.gamm[1], 2, (t_white << 3) / O.bright); + } + + libraw_internal_data.output_data.histogram = save_hist; + free(t_hist); + + // from write_ppm_tiff - copy pixels into bitmap + + int s_flip = imgdata.sizes.flip; + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_NO_ROTATE_FOR_KODAK_THUMBNAILS) + imgdata.sizes.flip = 0; + + S.iheight = S.height; + S.iwidth = S.width; + if (S.flip & 4) + SWAP(S.height, S.width); + + if (T.thumb) + free(T.thumb); + T.thumb = (char *)calloc(S.width * S.height, P1.colors); + merror(T.thumb, "LibRaw::kodak_thumb_loader()"); + T.tlength = S.width * S.height * P1.colors; + + // from write_tiff_ppm + { + int soff = flip_index(0, 0); + int cstep = flip_index(0, 1) - soff; + int rstep = flip_index(1, 0) - flip_index(0, S.width); + + for (int row = 0; row < S.height; row++, soff += rstep) + { + char *ppm = T.thumb + row * S.width * P1.colors; + for (int col = 0; col < S.width; col++, soff += cstep) + for (int c = 0; c < P1.colors; c++) + ppm[col * P1.colors + c] = + imgdata.color.curve[imgdata.image[soff][c]] >> 8; + } + } + + memmove(C.curve, t_curve, sizeof(C.curve)); + free(t_curve); + + // restore variables + free(imgdata.image); + imgdata.image = s_image; + + if (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_NO_ROTATE_FOR_KODAK_THUMBNAILS) + imgdata.sizes.flip = s_flip; + + T.twidth = S.width; + S.width = s_width; + + S.iwidth = s_iwidth; + S.iheight = s_iheight; + + T.theight = S.height; + S.height = s_height; + + T.tcolors = P1.colors; + P1.colors = s_colors; + + P1.filters = s_filters; + libraw_internal_data.unpacker_data.load_flags = s_flags; +} + +// ������� thumbnail �� �����, ������ thumb_format � ������������ � �������� + +int LibRaw::thumbOK(INT64 maxsz) +{ + if (!ID.input) + return 0; + if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && + load_raw == &LibRaw::broadcom_load_raw) // RPi + ) + return 0; + INT64 fsize = ID.input->size(); + if (fsize > 0x7fffffffU) + return 0; // No thumb for raw > 2Gb + int tsize = 0; + int tcol = (T.tcolors > 0 && T.tcolors < 4) ? T.tcolors : 3; + if (write_thumb == &LibRaw::jpeg_thumb) + tsize = T.tlength; + else if (write_thumb == &LibRaw::ppm_thumb) + tsize = tcol * T.twidth * T.theight; + else if (write_thumb == &LibRaw::ppm16_thumb) + tsize = tcol * T.twidth * T.theight * + ((imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_USE_PPM16_THUMBS) + ? 2 + : 1); +#ifdef USE_X3FTOOLS + else if (write_thumb == &LibRaw::x3f_thumb_loader) + { + tsize = x3f_thumb_size(); + } +#endif + else // Kodak => no check + tsize = 1; + if (tsize < 0) + return 0; + if (maxsz > 0 && tsize > maxsz) + return 0; + return (tsize + ID.toffset <= fsize) ? 1 : 0; +} + +int LibRaw::dcraw_thumb_writer(const char *fname) +{ + // CHECK_ORDER_LOW(LIBRAW_PROGRESS_THUMB_LOAD); + + if (!fname) + return ENOENT; + + FILE *tfp = fopen(fname, "wb"); + + if (!tfp) + return errno; + + if (!T.thumb) + { + fclose(tfp); + return LIBRAW_OUT_OF_ORDER_CALL; + } + + try + { + switch (T.tformat) + { + case LIBRAW_THUMBNAIL_JPEG: + jpeg_thumb_writer(tfp, T.thumb, T.tlength); + break; + case LIBRAW_THUMBNAIL_BITMAP: + fprintf(tfp, "P6\n%d %d\n255\n", T.twidth, T.theight); + fwrite(T.thumb, 1, T.tlength, tfp); + break; + default: + fclose(tfp); + return LIBRAW_UNSUPPORTED_THUMBNAIL; + } + fclose(tfp); + return 0; + } + catch (LibRaw_exceptions err) + { + fclose(tfp); + EXCEPTION_HANDLER(err); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/utils_dcraw.cpp libkdcraw/libkdcraw/libraw/src/utils/utils_dcraw.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/utils_dcraw.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/utils_dcraw.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,337 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +int LibRaw::fcol(int row, int col) +{ + static const char filter[16][16] = { + {2, 1, 1, 3, 2, 3, 2, 0, 3, 2, 3, 0, 1, 2, 1, 0}, + {0, 3, 0, 2, 0, 1, 3, 1, 0, 1, 1, 2, 0, 3, 3, 2}, + {2, 3, 3, 2, 3, 1, 1, 3, 3, 1, 2, 1, 2, 0, 0, 3}, + {0, 1, 0, 1, 0, 2, 0, 2, 2, 0, 3, 0, 1, 3, 2, 1}, + {3, 1, 1, 2, 0, 1, 0, 2, 1, 3, 1, 3, 0, 1, 3, 0}, + {2, 0, 0, 3, 3, 2, 3, 1, 2, 0, 2, 0, 3, 2, 2, 1}, + {2, 3, 3, 1, 2, 1, 2, 1, 2, 1, 1, 2, 3, 0, 0, 1}, + {1, 0, 0, 2, 3, 0, 0, 3, 0, 3, 0, 3, 2, 1, 2, 3}, + {2, 3, 3, 1, 1, 2, 1, 0, 3, 2, 3, 0, 2, 3, 1, 3}, + {1, 0, 2, 0, 3, 0, 3, 2, 0, 1, 1, 2, 0, 1, 0, 2}, + {0, 1, 1, 3, 3, 2, 2, 1, 1, 3, 3, 0, 2, 1, 3, 2}, + {2, 3, 2, 0, 0, 1, 3, 0, 2, 0, 1, 2, 3, 0, 1, 0}, + {1, 3, 1, 2, 3, 2, 3, 2, 0, 2, 0, 1, 1, 0, 3, 0}, + {0, 2, 0, 3, 1, 0, 0, 1, 1, 3, 3, 2, 3, 2, 2, 1}, + {2, 1, 3, 2, 3, 1, 2, 1, 0, 3, 0, 2, 0, 2, 0, 2}, + {0, 3, 1, 0, 0, 2, 0, 3, 2, 1, 3, 1, 1, 3, 1, 3}}; + + if (filters == 1) + return filter[(row + top_margin) & 15][(col + left_margin) & 15]; + if (filters == 9) + return xtrans[(row + 6) % 6][(col + 6) % 6]; + return FC(row, col); +} + +size_t LibRaw::strnlen(const char *s, size_t n) +{ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) + const char *p = (const char *)memchr(s, 0, n); + return (p ? p - s : n); +#else + return ::strnlen(s, n); +#endif +} + +void *LibRaw::memmem(char *haystack, size_t haystacklen, char *needle, + size_t needlelen) +{ +#if !defined(__GLIBC__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) + char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp(c, needle, needlelen)) + return c; + return 0; +#else + return ::memmem(haystack, haystacklen, needle, needlelen); +#endif +} + +char *LibRaw::strcasestr(char *haystack, const char *needle) +{ + char *c; + for (c = haystack; *c; c++) + if (!strncasecmp(c, needle, strlen(needle))) + return c; + return 0; +} + +ushort LibRaw::sget2(uchar *s) +{ + if (order == 0x4949) /* "II" means little-endian */ + return s[0] | s[1] << 8; + else /* "MM" means big-endian */ + return s[0] << 8 | s[1]; +} + +void LibRaw::initdata() +{ + tiff_flip = flip = filters = UINT_MAX; /* unknown */ + raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; + maximum = height = width = top_margin = left_margin = 0; + cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; + iso_speed = shutter = aperture = focal_len = 0; + unique_id = 0ULL; + tiff_nifds = 0; + memset(tiff_ifd, 0, sizeof tiff_ifd); + for (int i = 0; i < LIBRAW_IFD_MAXCOUNT; i++) + { + tiff_ifd[i].dng_color[0].illuminant = tiff_ifd[i].dng_color[1].illuminant = + 0xffff; + for (int c = 0; c < 4; c++) + tiff_ifd[i].dng_levels.analogbalance[c] = 1.0f; + } + for (int i = 0; i < 0x10000; i++) + curve[i] = i; + memset(gpsdata, 0, sizeof gpsdata); + memset(cblack, 0, sizeof cblack); + memset(white, 0, sizeof white); + memset(mask, 0, sizeof mask); + thumb_offset = thumb_length = thumb_width = thumb_height = 0; + load_raw = thumb_load_raw = 0; + write_thumb = &LibRaw::jpeg_thumb; + data_offset = meta_offset = meta_length = tiff_bps = tiff_compress = 0; + kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; + timestamp = shot_order = tiff_samples = black = is_foveon = 0; + mix_green = profile_length = data_error = zero_is_bad = 0; + pixel_aspect = is_raw = raw_color = 1; + tile_width = tile_length = 0; + metadata_blocks = 0; + is_NikonTransfer = 0; + is_Sony = 0; + is_pana_raw = 0; + maker_index = LIBRAW_CAMERAMAKER_Unknown; + is_4K_RAFdata = 0; + FujiCropMode = 0; + is_PentaxRicohMakernotes = 0; + normalized_model[0] = 0; + normalized_make[0] = 0; + CM_found = 0; +} + +void LibRaw::aRGB_coeff(double aRGB_cam[3][3]) +{ + static const double rgb_aRGB[3][3] = { + {1.39828313770000, -0.3982830047, 9.64980900741708E-8}, + {6.09219200572997E-8, 0.9999999809, 1.33230799934103E-8}, + {2.17237099975343E-8, -0.0429383201, 1.04293828050000}}; + + double cmatrix_tmp[3][3] = { + {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + int i, j, k; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + { + for (k = 0; k < 3; k++) + cmatrix_tmp[i][j] += rgb_aRGB[i][k] * aRGB_cam[k][j]; + cmatrix[i][j] = (float)cmatrix_tmp[i][j]; + } +} + +void LibRaw::romm_coeff(float romm_cam[3][3]) +{ + static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ + {{2.034193, -0.727420, -0.306766}, + {-0.228811, 1.231729, -0.002922}, + {-0.008565, -0.153273, 1.161839}}; + int i, j, k; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + for (cmatrix[i][j] = k = 0; k < 3; k++) + cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; +} + +void LibRaw::remove_zeroes() +{ + unsigned row, col, tot, n; + int r, c; + + RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES, 0, 2); + + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) + if (BAYER(row, col) == 0) + { + tot = n = 0; + for (r = (int)row - 2; r <= (int)row + 2; r++) + for (c = (int)col - 2; c <= (int)col + 2; c++) + if (r >= 0 && r < height && c >= 0 && c < width && + FC(r, c) == FC(row, col) && BAYER(r, c)) + tot += (n++, BAYER(r, c)); + if (n) + BAYER(row, col) = tot / n; + } + RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES, 1, 2); +} +void LibRaw::crop_masked_pixels() +{ + int row, col; + unsigned c, m, zero, val; +#define mblack imgdata.color.black_stat + + if (mask[0][3] > 0) + goto mask_set; + if (load_raw == &LibRaw::canon_load_raw || + load_raw == &LibRaw::lossless_jpeg_load_raw || + load_raw == &LibRaw::crxLoadRaw) + { + mask[0][1] = mask[1][1] += 2; + mask[0][3] -= 2; + goto sides; + } + if (load_raw == &LibRaw::canon_600_load_raw || + load_raw == &LibRaw::sony_load_raw || + (load_raw == &LibRaw::eight_bit_load_raw && strncmp(model, "DC2", 3)) || + load_raw == &LibRaw::kodak_262_load_raw || + (load_raw == &LibRaw::packed_load_raw && (load_flags & 32))) + { + sides: + mask[0][0] = mask[1][0] = top_margin; + mask[0][2] = mask[1][2] = top_margin + height; + mask[0][3] += left_margin; + mask[1][1] += left_margin + width; + mask[1][3] += raw_width; + } + if (load_raw == &LibRaw::nokia_load_raw) + { + mask[0][2] = top_margin; + mask[0][3] = width; + } + if (load_raw == &LibRaw::broadcom_load_raw) + { + mask[0][2] = top_margin; + mask[0][3] = width; + } +mask_set: + memset(mblack, 0, sizeof mblack); + for (zero = m = 0; m < 8; m++) + for (row = MAX(mask[m][0], 0); row < MIN(mask[m][2], raw_height); row++) + for (col = MAX(mask[m][1], 0); col < MIN(mask[m][3], raw_width); col++) + { + /* No need to subtract margins because full area and active area filters are the same */ + c = FC(row, col); + mblack[c] += val = raw_image[(row)*raw_pitch / 2 + (col)]; + mblack[4 + c]++; + zero += !val; + } + if (load_raw == &LibRaw::canon_600_load_raw && width < raw_width) + { + black = (mblack[0] + mblack[1] + mblack[2] + mblack[3]) / + MAX(1, (mblack[4] + mblack[5] + mblack[6] + mblack[7])) - + 4; + } + else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7]) + { + FORC4 cblack[c] = mblack[c] / MAX(1, mblack[4 + c]); + black = cblack[4] = cblack[5] = cblack[6] = 0; + } +} +#undef mblack + +void LibRaw::pseudoinverse(double (*in)[3], double (*out)[3], int size) +{ + double work[3][6], num; + int i, j, k; + + for (i = 0; i < 3; i++) + { + for (j = 0; j < 6; j++) + work[i][j] = j == i + 3; + for (j = 0; j < 3; j++) + for (k = 0; k < size && k < 4; k++) + work[i][j] += in[k][i] * in[k][j]; + } + for (i = 0; i < 3; i++) + { + num = work[i][i]; + for (j = 0; j < 6; j++) + if (fabs(num) > 0.00001f) + work[i][j] /= num; + for (k = 0; k < 3; k++) + { + if (k == i) + continue; + num = work[k][i]; + for (j = 0; j < 6; j++) + work[k][j] -= work[i][j] * num; + } + } + for (i = 0; i < size && i < 4; i++) + for (j = 0; j < 3; j++) + for (out[i][j] = k = 0; k < 3; k++) + out[i][j] += work[j][k + 3] * in[i][k]; +} + +void LibRaw::cam_xyz_coeff(float _rgb_cam[3][4], double cam_xyz[4][3]) +{ + double cam_rgb[4][3], inverse[4][3], num; + int i, j, k; + + for (i = 0; i < colors && i < 4; i++) /* Multiply out XYZ colorspace */ + for (j = 0; j < 3; j++) + for (cam_rgb[i][j] = k = 0; k < 3; k++) + cam_rgb[i][j] += cam_xyz[i][k] * LibRaw_constants::xyz_rgb[k][j]; + + for (i = 0; i < colors && i < 4; i++) + { /* Normalize cam_rgb so that */ + for (num = j = 0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ + num += cam_rgb[i][j]; + if (num > 0.00001) + { + for (j = 0; j < 3; j++) + cam_rgb[i][j] /= num; + pre_mul[i] = 1 / num; + } + else + { + for (j = 0; j < 3; j++) + cam_rgb[i][j] = 0.0; + pre_mul[i] = 1.0; + } + } + pseudoinverse(cam_rgb, inverse, colors); + for (i = 0; i < 3; i++) + for (j = 0; j < colors && j < 4; j++) + _rgb_cam[i][j] = inverse[j][i]; +} + +void LibRaw::tiff_get(unsigned base, unsigned *tag, unsigned *type, + unsigned *len, unsigned *save) +{ +#ifdef LIBRAW_IOSPACE_CHECK + INT64 pos = ftell(ifp); + INT64 fsize = ifp->size(); + if (fsize < 12 || (fsize - pos) < 12) + throw LIBRAW_EXCEPTION_IO_EOF; +#endif + *tag = get2(); + *type = get2(); + *len = get4(); + *save = ftell(ifp) + 4; + if (*len * tagtype_dataunit_bytes[(*type <= LIBRAW_EXIFTAG_TYPE_IFD8) ? *type : 0] > 4) + fseek(ifp, get4() + base, SEEK_SET); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/utils/utils_libraw.cpp libkdcraw/libkdcraw/libraw/src/utils/utils_libraw.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/utils/utils_libraw.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/utils/utils_libraw.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,607 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + void default_memory_callback(void *, const char *file, const char *where) + { + fprintf(stderr, "%s: Out of memory in %s\n", file ? file : "unknown file", + where); + } + + void default_data_callback(void *, const char *file, const int offset) + { + if (offset < 0) + fprintf(stderr, "%s: Unexpected end of file\n", + file ? file : "unknown file"); + else + fprintf(stderr, "%s: data corrupted at %d\n", + file ? file : "unknown file", offset); + } + const char *libraw_strerror(int e) + { + enum LibRaw_errors errorcode = (LibRaw_errors)e; + switch (errorcode) + { + case LIBRAW_SUCCESS: + return "No error"; + case LIBRAW_UNSPECIFIED_ERROR: + return "Unspecified error"; + case LIBRAW_FILE_UNSUPPORTED: + return "Unsupported file format or not RAW file"; + case LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE: + return "Request for nonexisting image number"; + case LIBRAW_OUT_OF_ORDER_CALL: + return "Out of order call of libraw function"; + case LIBRAW_NO_THUMBNAIL: + return "No thumbnail in file"; + case LIBRAW_UNSUPPORTED_THUMBNAIL: + return "Unsupported thumbnail format"; + case LIBRAW_INPUT_CLOSED: + return "No input stream, or input stream closed"; + case LIBRAW_MEMPOOL_OVERFLOW: + return "Libraw internal mempool overflowed"; + case LIBRAW_UNSUFFICIENT_MEMORY: + return "Unsufficient memory"; + case LIBRAW_DATA_ERROR: + return "Corrupted data or unexpected EOF"; + case LIBRAW_IO_ERROR: + return "Input/output error"; + case LIBRAW_CANCELLED_BY_CALLBACK: + return "Cancelled by user callback"; + case LIBRAW_BAD_CROP: + return "Bad crop box"; + case LIBRAW_TOO_BIG: + return "Image too big for processing"; + default: + return "Unknown error code"; + } + } + +#ifdef __cplusplus +} +#endif + +unsigned LibRaw::parse_custom_cameras(unsigned limit, + libraw_custom_camera_t table[], + char **list) +{ + if (!list) + return 0; + unsigned index = 0; + for (unsigned i = 0; i < limit; i++) + { + if (!list[i]) + break; + if (strlen(list[i]) < 10) + continue; + char *string = (char *)malloc(strlen(list[i]) + 1); + strcpy(string, list[i]); + char *start = string; + memset(&table[index], 0, sizeof(table[0])); + for (int j = 0; start && j < 14; j++) + { + char *end = strchr(start, ','); + if (end) + { + *end = 0; + end++; + } // move to next char + while (isspace(*start) && *start) + start++; // skip leading spaces? + unsigned val = strtol(start, 0, 10); + switch (j) + { + case 0: + table[index].fsize = val; + break; + case 1: + table[index].rw = val; + break; + case 2: + table[index].rh = val; + break; + case 3: + table[index].lm = val; + break; + case 4: + table[index].tm = val; + break; + case 5: + table[index].rm = val; + break; + case 6: + table[index].bm = val; + break; + case 7: + table[index].lf = val; + break; + case 8: + table[index].cf = val; + break; + case 9: + table[index].max = val; + break; + case 10: + table[index].flags = val; + break; + case 11: + strncpy(table[index].t_make, start, sizeof(table[index].t_make) - 1); + break; + case 12: + strncpy(table[index].t_model, start, sizeof(table[index].t_model) - 1); + break; + case 13: + table[index].offset = val; + break; + default: + break; + } + start = end; + } + free(string); + if (table[index].t_make[0]) + index++; + } + return index; +} + +void LibRaw::derror() +{ + if (!libraw_internal_data.unpacker_data.data_error && + libraw_internal_data.internal_data.input) + { + if (libraw_internal_data.internal_data.input->eof()) + { + if (callbacks.data_cb) + (*callbacks.data_cb)(callbacks.datacb_data, + libraw_internal_data.internal_data.input->fname(), + -1); + throw LIBRAW_EXCEPTION_IO_EOF; + } + else + { + if (callbacks.data_cb) + (*callbacks.data_cb)(callbacks.datacb_data, + libraw_internal_data.internal_data.input->fname(), + libraw_internal_data.internal_data.input->tell()); + // throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + } + libraw_internal_data.unpacker_data.data_error++; +} + +const char *LibRaw::version() { return LIBRAW_VERSION_STR; } +int LibRaw::versionNumber() { return LIBRAW_VERSION; } +const char *LibRaw::strerror(int p) { return libraw_strerror(p); } + +unsigned LibRaw::capabilities() +{ + unsigned ret = 0; +#ifdef USE_RAWSPEED + ret |= LIBRAW_CAPS_RAWSPEED; +#endif +#ifdef USE_DNGSDK + ret |= LIBRAW_CAPS_DNGSDK; +#ifdef USE_GPRSDK + ret |= LIBRAW_CAPS_GPRSDK; +#endif +#ifdef LIBRAW_WIN32_UNICODEPATHS + ret |= LIBRAW_CAPS_UNICODEPATHS; +#endif +#endif +#ifdef USE_X3FTOOLS + ret |= LIBRAW_CAPS_X3FTOOLS; +#endif +#ifdef USE_6BY9RPI + ret |= LIBRAW_CAPS_RPI6BY9; +#endif + return ret; +} + +int LibRaw::is_sraw() +{ + return load_raw == &LibRaw::canon_sraw_load_raw || + load_raw == &LibRaw::nikon_load_sraw; +} +int LibRaw::is_coolscan_nef() +{ + return load_raw == &LibRaw::nikon_coolscan_load_raw; +} +int LibRaw::is_jpeg_thumb() +{ + return thumb_load_raw == 0 && write_thumb == &LibRaw::jpeg_thumb; +} + +int LibRaw::is_nikon_sraw() { return load_raw == &LibRaw::nikon_load_sraw; } +int LibRaw::sraw_midpoint() +{ + if (load_raw == &LibRaw::canon_sraw_load_raw) + return 8192; + else if (load_raw == &LibRaw::nikon_load_sraw) + return 2048; + else + return 0; +} + +void *LibRaw::malloc(size_t t) +{ + void *p = memmgr.malloc(t); + if (!p) + throw LIBRAW_EXCEPTION_ALLOC; + return p; +} +void *LibRaw::realloc(void *q, size_t t) +{ + void *p = memmgr.realloc(q, t); + if (!p) + throw LIBRAW_EXCEPTION_ALLOC; + return p; +} + +void *LibRaw::calloc(size_t n, size_t t) +{ + void *p = memmgr.calloc(n, t); + if (!p) + throw LIBRAW_EXCEPTION_ALLOC; + return p; +} +void LibRaw::free(void *p) { memmgr.free(p); } + +void LibRaw::recycle_datastream() +{ + if (libraw_internal_data.internal_data.input && + libraw_internal_data.internal_data.input_internal) + { + delete libraw_internal_data.internal_data.input; + libraw_internal_data.internal_data.input = NULL; + } + libraw_internal_data.internal_data.input_internal = 0; +} +void LibRaw::merror(void *ptr, const char *where) +{ + if (ptr) + return; + if (callbacks.mem_cb) + (*callbacks.mem_cb)(callbacks.memcb_data, + libraw_internal_data.internal_data.input + ? libraw_internal_data.internal_data.input->fname() + : NULL, + where); + throw LIBRAW_EXCEPTION_ALLOC; +} + +void LibRaw::clearCancelFlag() +{ +#ifdef _MSC_VER + InterlockedExchange(&_exitflag, 0); +#else + __sync_fetch_and_and(&_exitflag, 0); +#endif +#ifdef RAWSPEED_FASTEXIT + if (_rawspeed_decoder) + { + RawSpeed::RawDecoder *d = + static_cast<RawSpeed::RawDecoder *>(_rawspeed_decoder); + d->resumeProcessing(); + } +#endif +} + +void LibRaw::setCancelFlag() +{ +#ifdef _MSC_VER + InterlockedExchange(&_exitflag, 1); +#else + __sync_fetch_and_add(&_exitflag, 1); +#endif +#ifdef RAWSPEED_FASTEXIT + if (_rawspeed_decoder) + { + RawSpeed::RawDecoder *d = + static_cast<RawSpeed::RawDecoder *>(_rawspeed_decoder); + d->cancelProcessing(); + } +#endif +} + +void LibRaw::checkCancel() +{ +#ifdef _MSC_VER + if (InterlockedExchange(&_exitflag, 0)) + throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; +#else + if (__sync_fetch_and_and(&_exitflag, 0)) + throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; +#endif +} + +int LibRaw::is_curve_linear() +{ + for (int i = 0; i < 0x10000; i++) + if (imgdata.color.curve[i] != i) + return 0; + return 1; +} + +void LibRaw::free_image(void) +{ + if (imgdata.image) + { + free(imgdata.image); + imgdata.image = 0; + imgdata.progress_flags = LIBRAW_PROGRESS_START | LIBRAW_PROGRESS_OPEN | + LIBRAW_PROGRESS_IDENTIFY | + LIBRAW_PROGRESS_SIZE_ADJUST | + LIBRAW_PROGRESS_LOAD_RAW; + } +} + +int LibRaw::is_phaseone_compressed() +{ + return (load_raw == &LibRaw::phase_one_load_raw_c || + load_raw == &LibRaw::phase_one_load_raw); +} + +int LibRaw::is_canon_600() { return load_raw == &LibRaw::canon_600_load_raw; } +const char *LibRaw::strprogress(enum LibRaw_progress p) +{ + switch (p) + { + case LIBRAW_PROGRESS_START: + return "Starting"; + case LIBRAW_PROGRESS_OPEN: + return "Opening file"; + case LIBRAW_PROGRESS_IDENTIFY: + return "Reading metadata"; + case LIBRAW_PROGRESS_SIZE_ADJUST: + return "Adjusting size"; + case LIBRAW_PROGRESS_LOAD_RAW: + return "Reading RAW data"; + case LIBRAW_PROGRESS_REMOVE_ZEROES: + return "Clearing zero values"; + case LIBRAW_PROGRESS_BAD_PIXELS: + return "Removing dead pixels"; + case LIBRAW_PROGRESS_DARK_FRAME: + return "Subtracting dark frame data"; + case LIBRAW_PROGRESS_FOVEON_INTERPOLATE: + return "Interpolating Foveon sensor data"; + case LIBRAW_PROGRESS_SCALE_COLORS: + return "Scaling colors"; + case LIBRAW_PROGRESS_PRE_INTERPOLATE: + return "Pre-interpolating"; + case LIBRAW_PROGRESS_INTERPOLATE: + return "Interpolating"; + case LIBRAW_PROGRESS_MIX_GREEN: + return "Mixing green channels"; + case LIBRAW_PROGRESS_MEDIAN_FILTER: + return "Median filter"; + case LIBRAW_PROGRESS_HIGHLIGHTS: + return "Highlight recovery"; + case LIBRAW_PROGRESS_FUJI_ROTATE: + return "Rotating Fuji diagonal data"; + case LIBRAW_PROGRESS_FLIP: + return "Flipping image"; + case LIBRAW_PROGRESS_APPLY_PROFILE: + return "ICC conversion"; + case LIBRAW_PROGRESS_CONVERT_RGB: + return "Converting to RGB"; + case LIBRAW_PROGRESS_STRETCH: + return "Stretching image"; + case LIBRAW_PROGRESS_THUMB_LOAD: + return "Loading thumbnail"; + default: + return "Some strange things"; + } +} +int LibRaw::adjust_sizes_info_only(void) +{ + CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); + + raw2image_start(); + if (O.use_fuji_rotate) + { + if (IO.fuji_width) + { + IO.fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink; + S.iwidth = (ushort)(IO.fuji_width / sqrt(0.5)); + S.iheight = (ushort)((S.iheight - IO.fuji_width) / sqrt(0.5)); + } + else + { + if (S.pixel_aspect < 0.995) + S.iheight = (ushort)(S.iheight / S.pixel_aspect + 0.5); + if (S.pixel_aspect > 1.005) + S.iwidth = (ushort)(S.iwidth * S.pixel_aspect + 0.5); + } + } + SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); + if (S.flip & 4) + { + unsigned short t = S.iheight; + S.iheight = S.iwidth; + S.iwidth = t; + SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP); + } + return 0; +} +int LibRaw::adjust_maximum() +{ + ushort real_max; + float auto_threshold; + + if (O.adjust_maximum_thr < 0.00001) + return LIBRAW_SUCCESS; + else if (O.adjust_maximum_thr > 0.99999) + auto_threshold = LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD; + else + auto_threshold = O.adjust_maximum_thr; + + real_max = C.data_maximum; + if (real_max > 0 && real_max < C.maximum && + real_max > C.maximum * auto_threshold) + { + C.maximum = real_max; + } + return LIBRAW_SUCCESS; +} +void LibRaw::adjust_bl() +{ + int clear_repeat = 0; + if (O.user_black >= 0) + { + C.black = O.user_black; + clear_repeat = 1; + } + for (int i = 0; i < 4; i++) + if (O.user_cblack[i] > -1000000) + { + C.cblack[i] = O.user_cblack[i]; + clear_repeat = 1; + } + + if (clear_repeat) + C.cblack[4] = C.cblack[5] = 0; + + // Add common part to cblack[] early + if (imgdata.idata.filters > 1000 && (C.cblack[4] + 1) / 2 == 1 && + (C.cblack[5] + 1) / 2 == 1) + { + int clrs[4]; + int lastg = -1, gcnt = 0; + for (int c = 0; c < 4; c++) + { + clrs[c] = FC(c / 2, c % 2); + if (clrs[c] == 1) + { + gcnt++; + lastg = c; + } + } + if (gcnt > 1 && lastg >= 0) + clrs[lastg] = 3; + for (int c = 0; c < 4; c++) + C.cblack[clrs[c]] += + C.cblack[6 + c / 2 % C.cblack[4] * C.cblack[5] + c % 2 % C.cblack[5]]; + C.cblack[4] = C.cblack[5] = 0; + // imgdata.idata.filters = sfilters; + } + else if (imgdata.idata.filters <= 1000 && C.cblack[4] == 1 && + C.cblack[5] == 1) // Fuji RAF dng + { + for (int c = 0; c < 4; c++) + C.cblack[c] += C.cblack[6]; + C.cblack[4] = C.cblack[5] = 0; + } + // remove common part from C.cblack[] + int i = C.cblack[3]; + int c; + for (c = 0; c < 3; c++) + if (i > (int)C.cblack[c]) + i = C.cblack[c]; + + for (c = 0; c < 4; c++) + C.cblack[c] -= i; // remove common part + C.black += i; + + // Now calculate common part for cblack[6+] part and move it to C.black + + if (C.cblack[4] && C.cblack[5]) + { + i = C.cblack[6]; + for (c = 1; c < int(C.cblack[4] * C.cblack[5]); c++) + if (i > int(C.cblack[6 + c])) + i = C.cblack[6 + c]; + // Remove i from cblack[6+] + int nonz = 0; + for (c = 0; c < int(C.cblack[4] * C.cblack[5]); c++) + { + C.cblack[6 + c] -= i; + if (C.cblack[6 + c]) + nonz++; + } + C.black += i; + if (!nonz) + C.cblack[4] = C.cblack[5] = 0; + } + for (c = 0; c < 4; c++) + C.cblack[c] += C.black; +} +int LibRaw::getwords(char *line, char *words[], int maxwords, int maxlen) +{ + line[maxlen - 1] = 0; + char *p = line; + int nwords = 0; + + while (1) + { + while (isspace(*p)) + p++; + if (*p == '\0') + return nwords; + words[nwords++] = p; + while (!isspace(*p) && *p != '\0') + p++; + if (*p == '\0') + return nwords; + *p++ = '\0'; + if (nwords >= maxwords) + return nwords; + } +} +int LibRaw::stread(char *buf, size_t len, LibRaw_abstract_datastream *fp) +{ + if (len > 0) + { + int r = fp->read(buf, len, 1); + buf[len - 1] = 0; + return r; + } + else + return 0; +} + +int LibRaw::find_ifd_by_offset(int o) +{ + for(unsigned i = 0; i < libraw_internal_data.identify_data.tiff_nifds && i < LIBRAW_IFD_MAXCOUNT; i++) + if(tiff_ifd[i].offset == o) + return i; + return -1; +} + +short LibRaw::tiff_sget (unsigned save, uchar *buf, unsigned buf_len, INT64 *tag_offset, + unsigned *tag_id, unsigned *tag_type, INT64 *tag_dataoffset, + unsigned *tag_datalen, int *tag_dataunitlen) { + uchar *pos = buf + *tag_offset; + if ((((*tag_offset) + 12) > buf_len) || (*tag_offset < 0)) { // abnormal, tag buffer overrun + return -1; + } + *tag_id = sget2(pos); pos += 2; + *tag_type = sget2(pos); pos += 2; + *tag_datalen = sget4(pos); pos += 4; + *tag_dataunitlen = tagtype_dataunit_bytes[(*tag_type <= LIBRAW_EXIFTAG_TYPE_IFD8) ? *tag_type : 0]; + if ((*tag_datalen * (*tag_dataunitlen)) > 4) { + *tag_dataoffset = sget4(pos) - save; + if ((*tag_dataoffset + *tag_datalen) > buf_len) { // abnormal, tag data buffer overrun + return -2; + } + } else *tag_dataoffset = *tag_offset + 8; + *tag_offset += 12; + return 0; +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/write/apply_profile.cpp libkdcraw/libkdcraw/libraw/src/write/apply_profile.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/write/apply_profile.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/write/apply_profile.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,77 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_fileio_defs.h" + +#ifndef NO_LCMS +void LibRaw::apply_profile(const char *input, const char *output) +{ + char *prof; + cmsHPROFILE hInProfile = 0, hOutProfile = 0; + cmsHTRANSFORM hTransform; + FILE *fp; + unsigned size; + + if (strcmp(input, "embed")) + hInProfile = cmsOpenProfileFromFile(input, "r"); + else if (profile_length) + { + hInProfile = cmsOpenProfileFromMem(imgdata.color.profile, profile_length); + } + else + { + imgdata.process_warnings |= LIBRAW_WARN_NO_EMBEDDED_PROFILE; + } + if (!hInProfile) + { + imgdata.process_warnings |= LIBRAW_WARN_NO_INPUT_PROFILE; + return; + } + if (!output) + hOutProfile = cmsCreate_sRGBProfile(); + else if ((fp = fopen(output, "rb"))) + { + fread(&size, 4, 1, fp); + fseek(fp, 0, SEEK_SET); + oprof = (unsigned *)malloc(size = ntohl(size)); + merror(oprof, "apply_profile()"); + fread(oprof, 1, size, fp); + fclose(fp); + if (!(hOutProfile = cmsOpenProfileFromMem(oprof, size))) + { + free(oprof); + oprof = 0; + } + } + if (!hOutProfile) + { + imgdata.process_warnings |= LIBRAW_WARN_BAD_OUTPUT_PROFILE; + goto quit; + } + RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE, 0, 2); + hTransform = cmsCreateTransform(hInProfile, TYPE_RGBA_16, hOutProfile, + TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); + cmsDoTransform(hTransform, image, image, width * height); + raw_color = 1; /* Don't use rgb_cam with a profile */ + cmsDeleteTransform(hTransform); + cmsCloseProfile(hOutProfile); +quit: + cmsCloseProfile(hInProfile); + RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE, 1, 2); +} +#endif diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/write/file_write.cpp libkdcraw/libkdcraw/libraw/src/write/file_write.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/write/file_write.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/write/file_write.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,289 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/dcraw_defs.h" + +int LibRaw::flip_index(int row, int col) +{ + if (flip & 4) + SWAP(row, col); + if (flip & 2) + row = iheight - 1 - row; + if (flip & 1) + col = iwidth - 1 - col; + return row * iwidth + col; +} + +void LibRaw::tiff_set(struct tiff_hdr *th, ushort *ntag, ushort tag, + ushort type, int count, int val) +{ + struct libraw_tiff_tag *tt; + int c; + + tt = (struct libraw_tiff_tag *)(ntag + 1) + (*ntag)++; + tt->val.i = val; + if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_BYTE) && count <= 4) + FORC(4) tt->val.c[c] = val >> (c << 3); + else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_ASCII)) + { + count = strnlen((char *)th + val, count - 1) + 1; + if (count <= 4) + FORC(4) tt->val.c[c] = ((char *)th)[val + c]; + } + else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) && count <= 2) + FORC(2) tt->val.s[c] = val >> (c << 4); + tt->count = count; + tt->type = type; + tt->tag = tag; +} + +#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) + +void LibRaw::tiff_head(struct tiff_hdr *th, int full) +{ + int c, psize = 0; + struct tm *t; + + memset(th, 0, sizeof *th); + th->t_order = htonl(0x4d4d4949) >> 16; + th->magic = 42; + th->ifd = 10; + th->rat[0] = th->rat[2] = 300; + th->rat[1] = th->rat[3] = 1; + FORC(6) th->rat[4 + c] = 1000000; + th->rat[4] *= shutter; + th->rat[6] *= aperture; + th->rat[8] *= focal_len; + strncpy(th->t_desc, desc, 512); + strncpy(th->t_make, make, 64); + strncpy(th->t_model, model, 64); + strcpy(th->soft, "dcraw v" 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->t_artist, artist, 64); + if (full) + { + tiff_set(th, &th->ntag, 254, 4, 1, 0); + tiff_set(th, &th->ntag, 256, 4, 1, width); + tiff_set(th, &th->ntag, 257, 4, 1, height); + tiff_set(th, &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, &th->ntag, 259, 3, 1, 1); + tiff_set(th, &th->ntag, 262, 3, 1, 1 + (colors > 1)); + } + tiff_set(th, &th->ntag, 270, 2, 512, TOFF(th->t_desc)); + tiff_set(th, &th->ntag, 271, 2, 64, TOFF(th->t_make)); + tiff_set(th, &th->ntag, 272, 2, 64, TOFF(th->t_model)); + if (full) + { + if (oprof) + psize = ntohl(oprof[0]); + tiff_set(th, &th->ntag, 273, 4, 1, sizeof *th + psize); + tiff_set(th, &th->ntag, 277, 3, 1, colors); + tiff_set(th, &th->ntag, 278, 4, 1, height); + tiff_set(th, &th->ntag, 279, 4, 1, + height * width * colors * output_bps / 8); + } + else + tiff_set(th, &th->ntag, 274, 3, 1, "12435867"[flip] - '0'); + tiff_set(th, &th->ntag, 282, 5, 1, TOFF(th->rat[0])); + tiff_set(th, &th->ntag, 283, 5, 1, TOFF(th->rat[2])); + tiff_set(th, &th->ntag, 284, 3, 1, 1); + tiff_set(th, &th->ntag, 296, 3, 1, 2); + tiff_set(th, &th->ntag, 305, 2, 32, TOFF(th->soft)); + tiff_set(th, &th->ntag, 306, 2, 20, TOFF(th->date)); + tiff_set(th, &th->ntag, 315, 2, 64, TOFF(th->t_artist)); + tiff_set(th, &th->ntag, 34665, 4, 1, TOFF(th->nexif)); + if (psize) + tiff_set(th, &th->ntag, 34675, 7, psize, sizeof *th); + tiff_set(th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4])); + tiff_set(th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6])); + tiff_set(th, &th->nexif, 34855, 3, 1, iso_speed); + tiff_set(th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8])); + if (gpsdata[1]) + { + uchar latref[4] = { (uchar)(gpsdata[29]),0,0,0 }, + lonref[4] = { (uchar)(gpsdata[30]),0,0,0 }; + tiff_set(th, &th->ntag, 34853, 4, 1, TOFF(th->ngps)); + tiff_set(th, &th->ngps, 0, 1, 4, 0x202); + tiff_set(th, &th->ngps, 1, 2, 2, TOFF(latref)); + tiff_set(th, &th->ngps, 2, 5, 3, TOFF(th->gps[0])); + tiff_set(th, &th->ngps, 3, 2, 2, TOFF(lonref)); + tiff_set(th, &th->ngps, 4, 5, 3, TOFF(th->gps[6])); + tiff_set(th, &th->ngps, 5, 1, 1, gpsdata[31]); + tiff_set(th, &th->ngps, 6, 5, 1, TOFF(th->gps[18])); + tiff_set(th, &th->ngps, 7, 5, 3, TOFF(th->gps[12])); + tiff_set(th, &th->ngps, 18, 2, 12, TOFF(th->gps[20])); + tiff_set(th, &th->ngps, 29, 2, 12, TOFF(th->gps[23])); + memcpy(th->gps, gpsdata, sizeof th->gps); + } +} + +void LibRaw::jpeg_thumb_writer(FILE *tfp, char *t_humb, int t_humb_length) +{ + ushort exif[5]; + struct tiff_hdr th; + fputc(0xff, tfp); + fputc(0xd8, tfp); + if (strcmp(t_humb + 6, "Exif")) + { + memcpy(exif, "\xff\xe1 Exif\0\0", 10); + exif[1] = htons(8 + sizeof th); + fwrite(exif, 1, sizeof exif, tfp); + tiff_head(&th, 0); + fwrite(&th, 1, sizeof th, tfp); + } + fwrite(t_humb + 2, 1, t_humb_length - 2, tfp); +} +void LibRaw::write_ppm_tiff() +{ + struct tiff_hdr th; + uchar *ppm; + ushort *ppm2; + int c, row, col, soff, rstep, cstep; + int perc, val, total, t_white = 0x2000; + + perc = width * height * auto_bright_thr; + + if (fuji_width) + perc /= 2; + if (!((highlight & ~2) || no_auto_bright)) + for (t_white = c = 0; c < colors; c++) + { + for (val = 0x2000, total = 0; --val > 32;) + if ((total += histogram[c][val]) > perc) + break; + if (t_white < val) + t_white = val; + } + gamma_curve(gamm[0], gamm[1], 2, (t_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((char *)ppm2, (char *)ppm2, width * colors * 2); + fwrite(ppm, colors * output_bps / 8, width, ofp); + } + free(ppm); +} +void LibRaw::ppm_thumb() +{ + char *thumb; + thumb_length = thumb_width * thumb_height * 3; + thumb = (char *)malloc(thumb_length); + merror(thumb, "ppm_thumb()"); + fprintf(ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fread(thumb, 1, thumb_length, ifp); + fwrite(thumb, 1, thumb_length, ofp); + free(thumb); +} + +void LibRaw::ppm16_thumb() +{ + unsigned i; + char *thumb; + thumb_length = thumb_width * thumb_height * 3; + thumb = (char *)calloc(thumb_length, 2); + merror(thumb, "ppm16_thumb()"); + read_shorts((ushort *)thumb, thumb_length); + for (i = 0; i < thumb_length; i++) + thumb[i] = ((ushort *)thumb)[i] >> 8; + fprintf(ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fwrite(thumb, 1, thumb_length, ofp); + free(thumb); +} + +void LibRaw::layer_thumb() +{ + unsigned int i; + int c; + char *thumb, map[][4] = {"012", "102"}; + + colors = thumb_misc >> 5 & 7; + thumb_length = thumb_width * thumb_height; + thumb = (char *)calloc(colors, thumb_length); + merror(thumb, "layer_thumb()"); + fprintf(ofp, "P%d\n%d %d\n255\n", 5 + (colors >> 1), thumb_width, + thumb_height); + fread(thumb, thumb_length, colors, ifp); + for (i = 0; i < thumb_length; i++) + FORCC putc(thumb[i + thumb_length * (map[thumb_misc >> 8][c] - '0')], ofp); + free(thumb); +} + +void LibRaw::rollei_thumb() +{ + unsigned i; + ushort *thumb; + + thumb_length = thumb_width * thumb_height; + thumb = (ushort *)calloc(thumb_length, 2); + merror(thumb, "rollei_thumb()"); + fprintf(ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + read_shorts(thumb, thumb_length); + for (i = 0; i < thumb_length; i++) + { + putc(thumb[i] << 3, ofp); + putc(thumb[i] >> 5 << 2, ofp); + putc(thumb[i] >> 11 << 3, ofp); + } + free(thumb); +} + +void LibRaw::jpeg_thumb() +{ + char *thumb; + + thumb = (char *)malloc(thumb_length); + merror(thumb, "jpeg_thumb()"); + fread(thumb, 1, thumb_length, ifp); + jpeg_thumb_writer(ofp, thumb, thumb_length); + free(thumb); +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/write/tiff_writer.cpp libkdcraw/libkdcraw/libraw/src/write/tiff_writer.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/write/tiff_writer.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/write/tiff_writer.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,68 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, + dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. + LibRaw do not use RESTRICTED code from dcraw.c + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + +#include "../../internal/libraw_cxx_defs.h" + +int LibRaw::dcraw_ppm_tiff_writer(const char *filename) +{ + CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); + + if (!imgdata.image) + return LIBRAW_OUT_OF_ORDER_CALL; + + if (!filename) + return ENOENT; + FILE *f = NULL; + if (!strcmp(filename, "-")) + { +#ifdef LIBRAW_WIN32_CALLS + _setmode(_fileno(stdout), _O_BINARY); +#endif + f = stdout; + } + else + f = fopen(filename, "wb"); + + if (!f) + return errno; + + try + { + if (!libraw_internal_data.output_data.histogram) + { + libraw_internal_data.output_data.histogram = + (int(*)[LIBRAW_HISTOGRAM_SIZE])malloc( + sizeof(*libraw_internal_data.output_data.histogram) * 4); + merror(libraw_internal_data.output_data.histogram, + "LibRaw::dcraw_ppm_tiff_writer()"); + } + libraw_internal_data.internal_data.output = f; + write_ppm_tiff(); + SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP); + libraw_internal_data.internal_data.output = NULL; + if (strcmp(filename, "-")) + fclose(f); + return 0; + } + catch (LibRaw_exceptions err) + { + if (strcmp(filename, "-")) + fclose(f); + EXCEPTION_HANDLER(err); + } +} diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/write/write_ph.cpp libkdcraw/libkdcraw/libraw/src/write/write_ph.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/write/write_ph.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/write/write_ph.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,37 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + Placehoder functions to build LibRaw w/o postprocessing + and preprocessing calls + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + + */ + + +#include "../../internal/dcraw_defs.h" +int LibRaw::flip_index(int row, int col) +{ + if (flip & 4) + SWAP(row, col); + if (flip & 2) + row = iheight - 1 - row; + if (flip & 1) + col = iwidth - 1 - col; + return row * iwidth + col; +} + +void LibRaw::ppm_thumb(){} +void LibRaw::jpeg_thumb(){} +void LibRaw::rollei_thumb(){} +void LibRaw::jpeg_thumb_writer(FILE *tfp, char *t_humb, int t_humb_length){} +void LibRaw::write_ppm_tiff(){} +void LibRaw::ppm16_thumb(){} +void LibRaw::layer_thumb(){} \ No newline at end of file diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/x3f/x3f_parse_process.cpp libkdcraw/libkdcraw/libraw/src/x3f/x3f_parse_process.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/x3f/x3f_parse_process.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/x3f/x3f_parse_process.cpp 2022-11-07 07:46:31.738795008 +0300 @@ -0,0 +1,725 @@ +/* -*- C++ -*- + * Copyright 2019-2020 LibRaw LLC (info@libraw.org) + * + + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + */ + +/* Library for accessing X3F Files +---------------------------------------------------------------- +BSD-style License +---------------------------------------------------------------- + +* Copyright (c) 2010, Roland Karlsson (roland@proxel.se) +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the organization nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ROLAND KARLSSON ''AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL ROLAND KARLSSON BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef USE_X3FTOOLS + +#include "../../internal/libraw_cxx_defs.h" + +#if defined __sun && defined DS +#undef DS +#endif +#ifdef ID +#undef ID /* used in x3f utils */ +#endif + +#include "../../internal/x3f_tools.h" + +#define Sigma_X3F 22 + +void x3f_clear(void *p) { x3f_delete((x3f_t *)p); } + +static void utf2char(utf16_t *str, char *buffer, unsigned bufsz) +{ + if (bufsz < 1) + return; + buffer[bufsz - 1] = 0; + char *b = buffer; + + while (*str != 0x00 && --bufsz > 0) + { + char *chr = (char *)str; + *b++ = *chr; + str++; + } + *b = 0; +} + +static void *lr_memmem(const void *l, size_t l_len, const void *s, size_t s_len) +{ + char *cur, *last; + const char *cl = (const char *)l; + const char *cs = (const char *)s; + + /* we need something to compare */ + if (l_len == 0 || s_len == 0) + return NULL; + + /* "s" must be smaller or equal to "l" */ + if (l_len < s_len) + return NULL; + + /* special case where s_len == 1 */ + if (s_len == 1) + return (void *)memchr(l, (int)*cs, l_len); + + /* the last position where its possible to find "s" in "l" */ + last = (char *)cl + l_len - s_len; + + for (cur = (char *)cl; cur <= last; cur++) + if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) + return cur; + return NULL; +} + +void LibRaw::parse_x3f() +{ + x3f_t *x3f = x3f_new_from_file(libraw_internal_data.internal_data.input); + if (!x3f) + return; + _x3f_data = x3f; + + x3f_header_t *H = NULL; + + H = &x3f->header; + // Parse RAW size from RAW section + x3f_directory_entry_t *DE = x3f_get_raw(x3f); + if (!DE) + return; + imgdata.sizes.flip = H->rotation; + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + imgdata.sizes.raw_width = ID->columns; + imgdata.sizes.raw_height = ID->rows; + // Parse other params from property section + + DE = x3f_get_prop(x3f); + if ((x3f_load_data(x3f, DE) == X3F_OK)) + { + // Parse property list + DEH = &DE->header; + x3f_property_list_t *PL = &DEH->data_subsection.property_list; + utf16_t *datap = (utf16_t *)PL->data; + uint32_t maxitems = PL->data_size / sizeof(utf16_t); + if (PL->property_table.size != 0) + { + int i; + x3f_property_t *P = PL->property_table.element; + for (i = 0; i < PL->num_properties; i++) + { + char name[100], value[100]; + int noffset = (P[i].name - datap); + int voffset = (P[i].value - datap); + if (noffset < 0 || noffset > maxitems || voffset < 0 || + voffset > maxitems) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + int maxnsize = maxitems - (P[i].name - datap); + int maxvsize = maxitems - (P[i].value - datap); + utf2char(P[i].name, name, MIN(maxnsize, sizeof(name))); + utf2char(P[i].value, value, MIN(maxvsize, sizeof(value))); + if (!strcmp(name, "ISO")) + imgdata.other.iso_speed = atoi(value); + if (!strcmp(name, "CAMMANUF")) + strcpy(imgdata.idata.make, value); + if (!strcmp(name, "CAMMODEL")) + strcpy(imgdata.idata.model, value); + if (!strcmp(name, "CAMSERIAL")) + strcpy(imgdata.shootinginfo.BodySerial, value); + if (!strcmp(name, "WB_DESC")) + strcpy(imgdata.color.model2, value); + if (!strcmp(name, "TIME")) + imgdata.other.timestamp = atoi(value); + if (!strcmp(name, "SHUTTER")) + imgdata.other.shutter = atof(value); + if (!strcmp(name, "APERTURE")) + imgdata.other.aperture = atof(value); + if (!strcmp(name, "FLENGTH")) + imgdata.other.focal_len = atof(value); + if (!strcmp(name, "FLEQ35MM")) + imgdata.lens.makernotes.FocalLengthIn35mmFormat = atof(value); + if (!strcmp(name, "IMAGERTEMP")) + imgdata.makernotes.common.SensorTemperature = atof(value); + if (!strcmp(name, "LENSARANGE")) + { + char *sp; + imgdata.lens.makernotes.MaxAp4CurFocal = + imgdata.lens.makernotes.MinAp4CurFocal = atof(value); + sp = strrchr(value, ' '); + if (sp) + { + imgdata.lens.makernotes.MinAp4CurFocal = atof(sp); + if (imgdata.lens.makernotes.MaxAp4CurFocal > + imgdata.lens.makernotes.MinAp4CurFocal) + my_swap(float, imgdata.lens.makernotes.MaxAp4CurFocal, + imgdata.lens.makernotes.MinAp4CurFocal); + } + } + if (!strcmp(name, "LENSFRANGE")) + { + char *sp; + imgdata.lens.makernotes.MinFocal = imgdata.lens.makernotes.MaxFocal = + atof(value); + sp = strrchr(value, ' '); + if (sp) + { + imgdata.lens.makernotes.MaxFocal = atof(sp); + if ((imgdata.lens.makernotes.MaxFocal + 0.17f) < + imgdata.lens.makernotes.MinFocal) + my_swap(float, imgdata.lens.makernotes.MaxFocal, + imgdata.lens.makernotes.MinFocal); + } + } + if (!strcmp(name, "LENSMODEL")) + { + char *sp; + imgdata.lens.makernotes.LensID = + strtol(value, &sp, 16); // atoi(value); + if (imgdata.lens.makernotes.LensID) + imgdata.lens.makernotes.LensMount = Sigma_X3F; + } + } + imgdata.idata.raw_count = 1; + load_raw = &LibRaw::x3f_load_raw; + imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 6; + imgdata.idata.is_foveon = 1; + libraw_internal_data.internal_output_params.raw_color = + 1; // Force adobe coeff + imgdata.color.maximum = 0x3fff; // To be reset by color table + libraw_internal_data.unpacker_data.order = 0x4949; + } + } + else + { + // No property list + if (imgdata.sizes.raw_width == 5888 || imgdata.sizes.raw_width == 2944 || + imgdata.sizes.raw_width == 6656 || imgdata.sizes.raw_width == 3328 || + imgdata.sizes.raw_width == 5504 || + imgdata.sizes.raw_width == 2752) // Quattro + { + imgdata.idata.raw_count = 1; + load_raw = &LibRaw::x3f_load_raw; + imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 6; + imgdata.idata.is_foveon = 1; + libraw_internal_data.internal_output_params.raw_color = + 1; // Force adobe coeff + libraw_internal_data.unpacker_data.order = 0x4949; + strcpy(imgdata.idata.make, "SIGMA"); +#if 1 + // Try to find model number in first 2048 bytes; + int pos = libraw_internal_data.internal_data.input->tell(); + libraw_internal_data.internal_data.input->seek(0, SEEK_SET); + unsigned char buf[2048]; + libraw_internal_data.internal_data.input->read(buf, 2048, 1); + libraw_internal_data.internal_data.input->seek(pos, SEEK_SET); + unsigned char *fnd = (unsigned char *)lr_memmem(buf, 2048, "SIGMA dp", 8); + unsigned char *fndsd = + (unsigned char *)lr_memmem(buf, 2048, "sd Quatt", 8); + if (fnd) + { + unsigned char *nm = fnd + 8; + snprintf(imgdata.idata.model, 64, "dp%c Quattro", + *nm <= '9' && *nm >= '0' ? *nm : '2'); + } + else if (fndsd) + { + snprintf(imgdata.idata.model, 64, "%s", fndsd); + } + else +#endif + if (imgdata.sizes.raw_width == 6656 || + imgdata.sizes.raw_width == 3328) + strcpy(imgdata.idata.model, "sd Quattro H"); + else + strcpy(imgdata.idata.model, "dp2 Quattro"); + } + // else + } + // Try to get thumbnail data + LibRaw_thumbnail_formats format = LIBRAW_THUMBNAIL_UNKNOWN; + if ((DE = x3f_get_thumb_jpeg(x3f))) + { + format = LIBRAW_THUMBNAIL_JPEG; + } + else if ((DE = x3f_get_thumb_plain(x3f))) + { + format = LIBRAW_THUMBNAIL_BITMAP; + } + if (DE) + { + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + imgdata.thumbnail.twidth = ID->columns; + imgdata.thumbnail.theight = ID->rows; + imgdata.thumbnail.tcolors = 3; + imgdata.thumbnail.tformat = format; + libraw_internal_data.internal_data.toffset = DE->input.offset; + write_thumb = &LibRaw::x3f_thumb_loader; + } + DE = x3f_get_camf(x3f); + if (DE && DE->input.size > 28) + { + libraw_internal_data.unpacker_data.meta_offset = DE->input.offset + 8; + libraw_internal_data.unpacker_data.meta_length = DE->input.size - 28; + } +} + +INT64 LibRaw::x3f_thumb_size() +{ + try + { + x3f_t *x3f = (x3f_t *)_x3f_data; + if (!x3f) + return -1; // No data pointer set + x3f_directory_entry_t *DE = x3f_get_thumb_jpeg(x3f); + if (!DE) + DE = x3f_get_thumb_plain(x3f); + if (!DE) + return -1; + int64_t p = x3f_load_data_size(x3f, DE); + if (p < 0 || p > 0xffffffff) + return -1; + return p; + } + catch (...) + { + return -1; + } +} + +void LibRaw::x3f_thumb_loader() +{ + try + { + x3f_t *x3f = (x3f_t *)_x3f_data; + if (!x3f) + return; // No data pointer set + x3f_directory_entry_t *DE = x3f_get_thumb_jpeg(x3f); + if (!DE) + DE = x3f_get_thumb_plain(x3f); + if (!DE) + return; + if (X3F_OK != x3f_load_data(x3f, DE)) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + imgdata.thumbnail.twidth = ID->columns; + imgdata.thumbnail.theight = ID->rows; + imgdata.thumbnail.tcolors = 3; + if (imgdata.thumbnail.tformat == LIBRAW_THUMBNAIL_JPEG) + { + imgdata.thumbnail.thumb = (char *)malloc(ID->data_size); + merror(imgdata.thumbnail.thumb, "LibRaw::x3f_thumb_loader()"); + memmove(imgdata.thumbnail.thumb, ID->data, ID->data_size); + imgdata.thumbnail.tlength = ID->data_size; + } + else if (imgdata.thumbnail.tformat == LIBRAW_THUMBNAIL_BITMAP) + { + imgdata.thumbnail.tlength = ID->columns * ID->rows * 3; + imgdata.thumbnail.thumb = (char *)malloc(ID->columns * ID->rows * 3); + merror(imgdata.thumbnail.thumb, "LibRaw::x3f_thumb_loader()"); + char *src0 = (char *)ID->data; + for (int row = 0; row < ID->rows; row++) + { + int offset = row * ID->row_stride; + if (offset + ID->columns * 3 > ID->data_size) + break; + char *dest = &imgdata.thumbnail.thumb[row * ID->columns * 3]; + char *src = &src0[offset]; + memmove(dest, src, ID->columns * 3); + } + } + } + catch (...) + { + // do nothing + } +} + +static inline uint32_t _clampbits(int x, uint32_t n) +{ + uint32_t _y_temp; + if ((_y_temp = x >> n)) + x = ~_y_temp >> (32 - n); + return x; +} + +void LibRaw::x3f_dpq_interpolate_rg() +{ + int w = imgdata.sizes.raw_width / 2; + int h = imgdata.sizes.raw_height / 2; + unsigned short *image = (ushort *)imgdata.rawdata.color3_image; + + for (int color = 0; color < 2; color++) + { + for (int y = 2; y < (h - 2); y++) + { + uint16_t *row0 = + &image[imgdata.sizes.raw_width * 3 * (y * 2) + color]; // dst[1] + uint16_t row0_3 = row0[3]; + uint16_t *row1 = + &image[imgdata.sizes.raw_width * 3 * (y * 2 + 1) + color]; // dst1[1] + uint16_t row1_3 = row1[3]; + for (int x = 2; x < (w - 2); x++) + { + row1[0] = row1[3] = row0[3] = row0[0]; + row0 += 6; + row1 += 6; + } + } + } +} + +#ifdef _ABS +#undef _ABS +#endif +#define _ABS(a) ((a) < 0 ? -(a) : (a)) + +#undef CLIP +#define CLIP(value, high) ((value) > (high) ? (high) : (value)) + +void LibRaw::x3f_dpq_interpolate_af(int xstep, int ystep, int scale) +{ + unsigned short *image = (ushort *)imgdata.rawdata.color3_image; + unsigned int rowpitch = + imgdata.rawdata.sizes.raw_pitch / 2; // in 16-bit words + // Interpolate single pixel + for (int y = 0; + y < imgdata.rawdata.sizes.height + imgdata.rawdata.sizes.top_margin; + y += ystep) + { + if (y < imgdata.rawdata.sizes.top_margin) + continue; + if (y < scale) + continue; + if (y > imgdata.rawdata.sizes.raw_height - scale) + break; + uint16_t *row0 = &image[imgdata.sizes.raw_width * 3 * y]; // Ðаша Ñтрока + uint16_t *row_minus = + &image[imgdata.sizes.raw_width * 3 * (y - scale)]; // Строка выше + uint16_t *row_plus = + &image[imgdata.sizes.raw_width * 3 * (y + scale)]; // Строка ниже + for (int x = 0; + x < imgdata.rawdata.sizes.width + imgdata.rawdata.sizes.left_margin; + x += xstep) + { + if (x < imgdata.rawdata.sizes.left_margin) + continue; + if (x < scale) + continue; + if (x > imgdata.rawdata.sizes.raw_width - scale) + break; + uint16_t *pixel0 = &row0[x * 3]; + uint16_t *pixel_top = &row_minus[x * 3]; + uint16_t *pixel_bottom = &row_plus[x * 3]; + uint16_t *pixel_left = &row0[(x - scale) * 3]; + uint16_t *pixel_right = &row0[(x + scale) * 3]; + uint16_t *pixf = pixel_top; + if (_ABS(pixf[2] - pixel0[2]) > _ABS(pixel_bottom[2] - pixel0[2])) + pixf = pixel_bottom; + if (_ABS(pixf[2] - pixel0[2]) > _ABS(pixel_left[2] - pixel0[2])) + pixf = pixel_left; + if (_ABS(pixf[2] - pixel0[2]) > _ABS(pixel_right[2] - pixel0[2])) + pixf = pixel_right; + int blocal = pixel0[2], bnear = pixf[2]; + if (blocal < imgdata.color.black + 16 || bnear < imgdata.color.black + 16) + { + if (pixel0[0] < imgdata.color.black) + pixel0[0] = imgdata.color.black; + if (pixel0[1] < imgdata.color.black) + pixel0[1] = imgdata.color.black; + pixel0[0] = CLIP( + (pixel0[0] - imgdata.color.black) * 4 + imgdata.color.black, 16383); + pixel0[1] = CLIP( + (pixel0[1] - imgdata.color.black) * 4 + imgdata.color.black, 16383); + } + else + { + float multip = float(bnear - imgdata.color.black) / + float(blocal - imgdata.color.black); + if (pixel0[0] < imgdata.color.black) + pixel0[0] = imgdata.color.black; + if (pixel0[1] < imgdata.color.black) + pixel0[1] = imgdata.color.black; + float pixf0 = pixf[0]; + if (pixf0 < imgdata.color.black) + pixf0 = imgdata.color.black; + float pixf1 = pixf[1]; + if (pixf1 < imgdata.color.black) + pixf1 = imgdata.color.black; + + pixel0[0] = CLIP( + ((float(pixf0 - imgdata.color.black) * multip + + imgdata.color.black) + + ((pixel0[0] - imgdata.color.black) * 3.75 + imgdata.color.black)) / + 2, + 16383); + pixel0[1] = CLIP( + ((float(pixf1 - imgdata.color.black) * multip + + imgdata.color.black) + + ((pixel0[1] - imgdata.color.black) * 3.75 + imgdata.color.black)) / + 2, + 16383); + // pixel0[1] = float(pixf[1]-imgdata.color.black)*multip + + // imgdata.color.black; + } + } + } +} + +void LibRaw::x3f_dpq_interpolate_af_sd(int xstart, int ystart, int xend, + int yend, int xstep, int ystep, + int scale) +{ + unsigned short *image = (ushort *)imgdata.rawdata.color3_image; + unsigned int rowpitch = + imgdata.rawdata.sizes.raw_pitch / 2; // in 16-bit words + // Interpolate single pixel + for (int y = ystart; y <= yend && y < imgdata.rawdata.sizes.height + + imgdata.rawdata.sizes.top_margin; + y += ystep) + { + uint16_t *row0 = &image[imgdata.sizes.raw_width * 3 * y]; // Ðаша Ñтрока + uint16_t *row1 = + &image[imgdata.sizes.raw_width * 3 * (y + 1)]; // Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ñтрока + uint16_t *row_minus = + &image[imgdata.sizes.raw_width * 3 * (y - scale)]; // Строка выше + uint16_t *row_plus = + &image[imgdata.sizes.raw_width * 3 * + (y + scale)]; // Строка ниже AF-point (scale=2 -> ниже row1 + uint16_t *row_minus1 = &image[imgdata.sizes.raw_width * 3 * (y - 1)]; + for (int x = xstart; x < xend && x < imgdata.rawdata.sizes.width + + imgdata.rawdata.sizes.left_margin; + x += xstep) + { + uint16_t *pixel00 = &row0[x * 3]; // Current pixel + float sumR = 0.f, sumG = 0.f; + float cnt = 0.f; + for (int xx = -scale; xx <= scale; xx += scale) + { + sumR += row_minus[(x + xx) * 3]; + sumR += row_plus[(x + xx) * 3]; + sumG += row_minus[(x + xx) * 3 + 1]; + sumG += row_plus[(x + xx) * 3 + 1]; + cnt += 1.f; + if (xx) + { + cnt += 1.f; + sumR += row0[(x + xx) * 3]; + sumG += row0[(x + xx) * 3 + 1]; + } + } + pixel00[0] = sumR / 8.f; + pixel00[1] = sumG / 8.f; + + if (scale == 2) + { + uint16_t *pixel0B = &row0[x * 3 + 3]; // right pixel + uint16_t *pixel1B = &row1[x * 3 + 3]; // right pixel + float sumG0 = 0, sumG1 = 0.f; + float cnt = 0.f; + for (int xx = -scale; xx <= scale; xx += scale) + { + sumG0 += row_minus1[(x + xx) * 3 + 2]; + sumG1 += row_plus[(x + xx) * 3 + 2]; + cnt += 1.f; + if (xx) + { + sumG0 += row0[(x + xx) * 3 + 2]; + sumG1 += row1[(x + xx) * 3 + 2]; + cnt += 1.f; + } + } + pixel0B[2] = sumG0 / cnt; + pixel1B[2] = sumG1 / cnt; + } + + // uint16_t* pixel10 = &row1[x*3]; // Pixel below current + // uint16_t* pixel_bottom = &row_plus[x*3]; + } + } +} + +void LibRaw::x3f_load_raw() +{ + // already in try/catch + int raise_error = 0; + x3f_t *x3f = (x3f_t *)_x3f_data; + if (!x3f) + return; // No data pointer set + if (X3F_OK == x3f_load_data(x3f, x3f_get_raw(x3f))) + { + x3f_directory_entry_t *DE = x3f_get_raw(x3f); + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + if (!ID) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + x3f_quattro_t *Q = ID->quattro; + x3f_huffman_t *HUF = ID->huffman; + x3f_true_t *TRU = ID->tru; + uint16_t *data = NULL; + if (ID->rows != S.raw_height || ID->columns != S.raw_width) + { + raise_error = 1; + goto end; + } + if (HUF != NULL) + data = HUF->x3rgb16.data; + if (TRU != NULL) + data = TRU->x3rgb16.data; + if (data == NULL) + { + raise_error = 1; + goto end; + } + + size_t datasize = S.raw_height * S.raw_width * 3 * sizeof(unsigned short); + S.raw_pitch = S.raw_width * 3 * sizeof(unsigned short); + if (!(imgdata.rawdata.raw_alloc = malloc(datasize))) + throw LIBRAW_EXCEPTION_ALLOC; + + imgdata.rawdata.color3_image = (ushort(*)[3])imgdata.rawdata.raw_alloc; + // swap R/B channels for known old cameras + if (!strcasecmp(P1.make, "Polaroid") && !strcasecmp(P1.model, "x530")) + { + ushort(*src)[3] = (ushort(*)[3])data; + for (int p = 0; p < S.raw_height * S.raw_width; p++) + { + imgdata.rawdata.color3_image[p][0] = src[p][2]; + imgdata.rawdata.color3_image[p][1] = src[p][1]; + imgdata.rawdata.color3_image[p][2] = src[p][0]; + } + } + else if (HUF) + memmove(imgdata.rawdata.raw_alloc, data, datasize); + else if (TRU && (!Q || !Q->quattro_layout)) + memmove(imgdata.rawdata.raw_alloc, data, datasize); + else if (TRU && Q) + { + // Move quattro data in place + // R/B plane + for (int prow = 0; prow < TRU->x3rgb16.rows && prow < S.raw_height / 2; + prow++) + { + ushort(*destrow)[3] = + (unsigned short(*)[3]) & + imgdata.rawdata + .color3_image[prow * 2 * S.raw_pitch / 3 / sizeof(ushort)][0]; + ushort(*srcrow)[3] = + (unsigned short(*)[3]) & data[prow * TRU->x3rgb16.row_stride]; + for (int pcol = 0; + pcol < TRU->x3rgb16.columns && pcol < S.raw_width / 2; pcol++) + { + destrow[pcol * 2][0] = srcrow[pcol][0]; + destrow[pcol * 2][1] = srcrow[pcol][1]; + } + } + for (int row = 0; row < Q->top16.rows && row < S.raw_height; row++) + { + ushort(*destrow)[3] = + (unsigned short(*)[3]) & + imgdata.rawdata + .color3_image[row * S.raw_pitch / 3 / sizeof(ushort)][0]; + ushort(*srcrow) = + (unsigned short *)&Q->top16.data[row * Q->top16.columns]; + for (int col = 0; col < Q->top16.columns && col < S.raw_width; col++) + destrow[col][2] = srcrow[col]; + } + } + +#if 1 + if (TRU && Q && + (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF)) + { + if (imgdata.sizes.raw_width == 5888 && + imgdata.sizes.raw_height == 3672) // dpN Quattro normal + { + x3f_dpq_interpolate_af(32, 8, 2); + } + else if (imgdata.sizes.raw_width == 5888 && + imgdata.sizes.raw_height == 3776) // sd Quattro normal raw + { + x3f_dpq_interpolate_af_sd(216, 464, imgdata.sizes.raw_width - 1, 3312, + 16, 32, 2); + } + else if (imgdata.sizes.raw_width == 6656 && + imgdata.sizes.raw_height == 4480) // sd Quattro H normal raw + { + x3f_dpq_interpolate_af_sd(232, 592, imgdata.sizes.raw_width - 1, 3920, + 16, 32, 2); + } + else if (imgdata.sizes.raw_width == 3328 && + imgdata.sizes.raw_height == 2240) // sd Quattro H half size + { + x3f_dpq_interpolate_af_sd(116, 296, imgdata.sizes.raw_width - 1, 2200, + 8, 16, 1); + } + else if (imgdata.sizes.raw_width == 5504 && + imgdata.sizes.raw_height == 3680) // sd Quattro H APS-C raw + { + x3f_dpq_interpolate_af_sd(8, 192, imgdata.sizes.raw_width - 1, 3185, 16, + 32, 2); + } + else if (imgdata.sizes.raw_width == 2752 && + imgdata.sizes.raw_height == 1840) // sd Quattro H APS-C half size + { + x3f_dpq_interpolate_af_sd(4, 96, imgdata.sizes.raw_width - 1, 1800, 8, + 16, 1); + } + else if (imgdata.sizes.raw_width == 2944 && + imgdata.sizes.raw_height == 1836) // dpN Quattro small raw + { + x3f_dpq_interpolate_af(16, 4, 1); + } + else if (imgdata.sizes.raw_width == 2944 && + imgdata.sizes.raw_height == 1888) // sd Quattro small + { + x3f_dpq_interpolate_af_sd(108, 232, imgdata.sizes.raw_width - 1, 1656, + 8, 16, 1); + } + } +#endif + if (TRU && Q && Q->quattro_layout && + (imgdata.params.raw_processing_options & + LIBRAW_PROCESSING_DP2Q_INTERPOLATERG)) + x3f_dpq_interpolate_rg(); + } + else + raise_error = 1; +end: + if (raise_error) + throw LIBRAW_EXCEPTION_IO_CORRUPT; +} +#endif \ No newline at end of file diff -x .git -x libkdcraw/libkdcraw/test -uNr libkdcraw-wrk/libkdcraw/libraw/src/x3f/x3f_utils_patched.cpp libkdcraw/libkdcraw/libraw/src/x3f/x3f_utils_patched.cpp --- libkdcraw-wrk/libkdcraw/libraw/src/x3f/x3f_utils_patched.cpp 1970-01-01 03:00:00.000000000 +0300 +++ libkdcraw/libkdcraw/libraw/src/x3f/x3f_utils_patched.cpp 2022-11-07 07:46:31.742795008 +0300 @@ -0,0 +1,2123 @@ +#ifdef USE_X3FTOOLS + +/* Library for accessing X3F Files +---------------------------------------------------------------- +BSD-style License +---------------------------------------------------------------- + +* Copyright (c) 2010, Roland Karlsson (roland@proxel.se) +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the organization nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ROLAND KARLSSON ''AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL ROLAND KARLSSON BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "../../internal/libraw_cxx_defs.h" + +#if defined __sun && defined DS +#undef DS +#endif +#ifdef ID +#undef ID /* used in x3f utils */ +#endif + +#include "../../internal/x3f_tools.h" + +/* extern */ int legacy_offset = 0; +/* extern */ bool_t auto_legacy_offset = 1; + +/* --------------------------------------------------------------------- */ +/* Reading and writing - assuming little endian in the file */ +/* --------------------------------------------------------------------- */ + +static int x3f_get1(LibRaw_abstract_datastream *f) +{ + /* Little endian file */ + return f->get_char(); +} + +static int x3f_sget2(uchar *s) { return s[0] | s[1] << 8; } + +static int x3f_get2(LibRaw_abstract_datastream *f) +{ + uchar str[2] = {0xff, 0xff}; + f->read(str, 1, 2); + return x3f_sget2(str); +} + +unsigned x3f_sget4(uchar *s) +{ + return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; +} + +unsigned x3f_get4(LibRaw_abstract_datastream *f) +{ + uchar str[4] = {0xff, 0xff, 0xff, 0xff}; + f->read(str, 1, 4); + return x3f_sget4(str); +} + +#define FREE(P) \ + do \ + { \ + free(P); \ + (P) = NULL; \ + } while (0) + +#define PUT_GET_N(_buffer, _size, _file, _func) \ + do \ + { \ + int _left = _size; \ + while (_left != 0) \ + { \ + int _cur = _file->_func(_buffer, 1, _left); \ + if (_cur == 0) \ + { \ + throw LIBRAW_EXCEPTION_IO_CORRUPT; \ + } \ + _left -= _cur; \ + } \ + } while (0) + +#define GET1(_v) \ + do \ + { \ + (_v) = x3f_get1(I->input.file); \ + } while (0) +#define GET2(_v) \ + do \ + { \ + (_v) = x3f_get2(I->input.file); \ + } while (0) +#define GET4(_v) \ + do \ + { \ + (_v) = x3f_get4(I->input.file); \ + } while (0) + +#define GET4F(_v) \ + do \ + { \ + union { \ + int32_t i; \ + float f; \ + } _tmp; \ + _tmp.i = x3f_get4(I->input.file); \ + (_v) = _tmp.f; \ + } while (0) + +#define GETN(_v, _s) PUT_GET_N(_v, _s, I->input.file, read) + +#define GET_TABLE(_T, _GETX, _NUM, _TYPE) \ + do \ + { \ + int _i; \ + (_T).size = (_NUM); \ + (_T).element = \ + (_TYPE *)realloc((_T).element, (_NUM) * sizeof((_T).element[0])); \ + for (_i = 0; _i < (_T).size; _i++) \ + _GETX((_T).element[_i]); \ + } while (0) + +#define GET_PROPERTY_TABLE(_T, _NUM) \ + do \ + { \ + int _i; \ + (_T).size = (_NUM); \ + (_T).element = (x3f_property_t *)realloc( \ + (_T).element, (_NUM) * sizeof((_T).element[0])); \ + for (_i = 0; _i < (_T).size; _i++) \ + { \ + GET4((_T).element[_i].name_offset); \ + GET4((_T).element[_i].value_offset); \ + } \ + } while (0) + +#define GET_TRUE_HUFF_TABLE(_T) \ + do \ + { \ + int _i; \ + (_T).element = NULL; \ + for (_i = 0;; _i++) \ + { \ + (_T).size = _i + 1; \ + (_T).element = (x3f_true_huffman_element_t *)realloc( \ + (_T).element, (_i + 1) * sizeof((_T).element[0])); \ + GET1((_T).element[_i].code_size); \ + GET1((_T).element[_i].code); \ + if ((_T).element[_i].code_size == 0) \ + break; \ + } \ + } while (0) + +/* --------------------------------------------------------------------- */ +/* Allocating Huffman tree help data */ +/* --------------------------------------------------------------------- */ + +static void cleanup_huffman_tree(x3f_hufftree_t *HTP) { free(HTP->nodes); } + +static void new_huffman_tree(x3f_hufftree_t *HTP, int bits) +{ + int leaves = 1 << bits; + + HTP->free_node_index = 0; + HTP->total_node_index = HUF_TREE_MAX_NODES(leaves); + HTP->nodes = (x3f_huffnode_t *)calloc(1, HUF_TREE_MAX_NODES(leaves) * + sizeof(x3f_huffnode_t)); +} + +/* --------------------------------------------------------------------- */ +/* Allocating TRUE engine RAW help data */ +/* --------------------------------------------------------------------- */ + +static void cleanup_true(x3f_true_t **TRUP) +{ + x3f_true_t *TRU = *TRUP; + + if (TRU == NULL) + return; + + FREE(TRU->table.element); + FREE(TRU->plane_size.element); + cleanup_huffman_tree(&TRU->tree); + FREE(TRU->x3rgb16.buf); + + FREE(TRU); + + *TRUP = NULL; +} + +static x3f_true_t *new_true(x3f_true_t **TRUP) +{ + x3f_true_t *TRU = (x3f_true_t *)calloc(1, sizeof(x3f_true_t)); + + cleanup_true(TRUP); + + TRU->table.size = 0; + TRU->table.element = NULL; + TRU->plane_size.size = 0; + TRU->plane_size.element = NULL; + TRU->tree.nodes = NULL; + TRU->x3rgb16.data = NULL; + TRU->x3rgb16.buf = NULL; + + *TRUP = TRU; + + return TRU; +} + +static void cleanup_quattro(x3f_quattro_t **QP) +{ + x3f_quattro_t *Q = *QP; + + if (Q == NULL) + return; + + FREE(Q->top16.buf); + FREE(Q); + + *QP = NULL; +} + +static x3f_quattro_t *new_quattro(x3f_quattro_t **QP) +{ + x3f_quattro_t *Q = (x3f_quattro_t *)calloc(1, sizeof(x3f_quattro_t)); + int i; + + cleanup_quattro(QP); + + for (i = 0; i < TRUE_PLANES; i++) + { + Q->plane[i].columns = 0; + Q->plane[i].rows = 0; + } + + Q->unknown = 0; + + Q->top16.data = NULL; + Q->top16.buf = NULL; + + *QP = Q; + + return Q; +} + +/* --------------------------------------------------------------------- */ +/* Allocating Huffman engine help data */ +/* --------------------------------------------------------------------- */ + +static void cleanup_huffman(x3f_huffman_t **HUFP) +{ + x3f_huffman_t *HUF = *HUFP; + + if (HUF == NULL) + return; + + FREE(HUF->mapping.element); + FREE(HUF->table.element); + cleanup_huffman_tree(&HUF->tree); + FREE(HUF->row_offsets.element); + FREE(HUF->rgb8.buf); + FREE(HUF->x3rgb16.buf); + FREE(HUF); + + *HUFP = NULL; +} + +static x3f_huffman_t *new_huffman(x3f_huffman_t **HUFP) +{ + x3f_huffman_t *HUF = (x3f_huffman_t *)calloc(1, sizeof(x3f_huffman_t)); + + cleanup_huffman(HUFP); + + /* Set all not read data block pointers to NULL */ + HUF->mapping.size = 0; + HUF->mapping.element = NULL; + HUF->table.size = 0; + HUF->table.element = NULL; + HUF->tree.nodes = NULL; + HUF->row_offsets.size = 0; + HUF->row_offsets.element = NULL; + HUF->rgb8.data = NULL; + HUF->rgb8.buf = NULL; + HUF->x3rgb16.data = NULL; + HUF->x3rgb16.buf = NULL; + + *HUFP = HUF; + + return HUF; +} + +/* --------------------------------------------------------------------- */ +/* Creating a new x3f structure from file */ +/* --------------------------------------------------------------------- */ + +/* extern */ x3f_t *x3f_new_from_file(LibRaw_abstract_datastream *infile) +{ + if (!infile) + return NULL; + INT64 fsize = infile->size(); + x3f_t *x3f = (x3f_t *)calloc(1, sizeof(x3f_t)); + if (!x3f) + throw LIBRAW_EXCEPTION_ALLOC; + try + { + x3f_info_t *I = NULL; + x3f_header_t *H = NULL; + x3f_directory_section_t *DS = NULL; + int i, d; + + I = &x3f->info; + I->error = NULL; + I->input.file = infile; + I->output.file = NULL; + + /* Read file header */ + H = &x3f->header; + infile->seek(0, SEEK_SET); + GET4(H->identifier); + + if (H->identifier != X3F_FOVb) + { + free(x3f); + return NULL; + } + + GET4(H->version); + GETN(H->unique_identifier, SIZE_UNIQUE_IDENTIFIER); + /* TODO: the meaning of the rest of the header for version >= 4.0 (Quattro) + * is unknown */ + if (H->version < X3F_VERSION_4_0) + { + GET4(H->mark_bits); + GET4(H->columns); + GET4(H->rows); + GET4(H->rotation); + if (H->version >= X3F_VERSION_2_1) + { + int num_ext_data = + H->version >= X3F_VERSION_3_0 ? NUM_EXT_DATA_3_0 : NUM_EXT_DATA_2_1; + + GETN(H->white_balance, SIZE_WHITE_BALANCE); + if (H->version >= X3F_VERSION_2_3) + GETN(H->color_mode, SIZE_COLOR_MODE); + GETN(H->extended_types, num_ext_data); + for (i = 0; i < num_ext_data; i++) + GET4F(H->extended_data[i]); + } + } + + /* Go to the beginning of the directory */ + infile->seek(-4, SEEK_END); + infile->seek(x3f_get4(infile), SEEK_SET); + + /* Read the directory header */ + DS = &x3f->directory_section; + GET4(DS->identifier); + GET4(DS->version); + GET4(DS->num_directory_entries); + + if (DS->num_directory_entries > 50) + goto _err; // too much direntries, most likely broken file + + if (DS->num_directory_entries > 0) + { + size_t size = DS->num_directory_entries * sizeof(x3f_directory_entry_t); + DS->directory_entry = (x3f_directory_entry_t *)calloc(1, size); + } + + /* Traverse the directory */ + for (d = 0; d < DS->num_directory_entries; d++) + { + x3f_directory_entry_t *DE = &DS->directory_entry[d]; + x3f_directory_entry_header_t *DEH = &DE->header; + uint32_t save_dir_pos; + + /* Read the directory entry info */ + GET4(DE->input.offset); + GET4(DE->input.size); + if (DE->input.offset + DE->input.size > fsize * 2) + goto _err; + + DE->output.offset = 0; + DE->output.size = 0; + + GET4(DE->type); + + /* Save current pos and go to the entry */ + save_dir_pos = infile->tell(); + infile->seek(DE->input.offset, SEEK_SET); + + /* Read the type independent part of the entry header */ + DEH = &DE->header; + GET4(DEH->identifier); + GET4(DEH->version); + + /* NOTE - the tests below could be made on DE->type instead */ + + if (DEH->identifier == X3F_SECp) + { + x3f_property_list_t *PL = &DEH->data_subsection.property_list; + if (!PL) + goto _err; + /* Read the property part of the header */ + GET4(PL->num_properties); + GET4(PL->character_format); + GET4(PL->reserved); + GET4(PL->total_length); + + /* Set all not read data block pointers to NULL */ + PL->data = NULL; + PL->data_size = 0; + } + + if (DEH->identifier == X3F_SECi) + { + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + if (!ID) + goto _err; + /* Read the image part of the header */ + GET4(ID->type); + GET4(ID->format); + ID->type_format = (ID->type << 16) + (ID->format); + GET4(ID->columns); + GET4(ID->rows); + GET4(ID->row_stride); + + /* Set all not read data block pointers to NULL */ + ID->huffman = NULL; + + ID->data = NULL; + ID->data_size = 0; + } + + if (DEH->identifier == X3F_SECc) + { + x3f_camf_t *CAMF = &DEH->data_subsection.camf; + if (!CAMF) + goto _err; + /* Read the CAMF part of the header */ + GET4(CAMF->type); + GET4(CAMF->tN.val0); + GET4(CAMF->tN.val1); + GET4(CAMF->tN.val2); + GET4(CAMF->tN.val3); + + /* Set all not read data block pointers to NULL */ + CAMF->data = NULL; + CAMF->data_size = 0; + + /* Set all not allocated help pointers to NULL */ + CAMF->table.element = NULL; + CAMF->table.size = 0; + CAMF->tree.nodes = NULL; + CAMF->decoded_data = NULL; + CAMF->decoded_data_size = 0; + CAMF->entry_table.element = NULL; + CAMF->entry_table.size = 0; + } + + /* Reset the file pointer back to the directory */ + infile->seek(save_dir_pos, SEEK_SET); + } + + return x3f; + _err: + if (x3f) + { + DS = &x3f->directory_section; + if (DS && DS->directory_entry) + free(DS->directory_entry); + free(x3f); + } + return NULL; + } + catch (...) + { + x3f_directory_section_t *DS = &x3f->directory_section; + if (DS && DS->directory_entry) + free(DS->directory_entry); + free(x3f); + return NULL; + } +} + +/* --------------------------------------------------------------------- */ +/* Clean up an x3f structure */ +/* --------------------------------------------------------------------- */ + +static void free_camf_entry(camf_entry_t *entry) +{ + FREE(entry->property_name); + FREE(entry->property_value); + FREE(entry->matrix_decoded); + FREE(entry->matrix_dim_entry); +} + +/* extern */ x3f_return_t x3f_delete(x3f_t *x3f) +{ + x3f_directory_section_t *DS; + int d; + + if (x3f == NULL) + return X3F_ARGUMENT_ERROR; + + DS = &x3f->directory_section; + if (DS->num_directory_entries > 50) + return X3F_ARGUMENT_ERROR; + + for (d = 0; d < DS->num_directory_entries; d++) + { + x3f_directory_entry_t *DE = &DS->directory_entry[d]; + x3f_directory_entry_header_t *DEH = &DE->header; + if (DEH->identifier == X3F_SECp) + { + x3f_property_list_t *PL = &DEH->data_subsection.property_list; + if (PL) + { + int i; + } + FREE(PL->property_table.element); + FREE(PL->data); + } + + if (DEH->identifier == X3F_SECi) + { + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + + if (ID) + { + cleanup_huffman(&ID->huffman); + cleanup_true(&ID->tru); + cleanup_quattro(&ID->quattro); + FREE(ID->data); + } + } + + if (DEH->identifier == X3F_SECc) + { + x3f_camf_t *CAMF = &DEH->data_subsection.camf; + int i; + if (CAMF) + { + FREE(CAMF->data); + FREE(CAMF->table.element); + cleanup_huffman_tree(&CAMF->tree); + FREE(CAMF->decoded_data); + for (i = 0; i < CAMF->entry_table.size; i++) + { + free_camf_entry(&CAMF->entry_table.element[i]); + } + } + FREE(CAMF->entry_table.element); + } + } + + FREE(DS->directory_entry); + FREE(x3f); + + return X3F_OK; +} + +/* --------------------------------------------------------------------- */ +/* Getting a reference to a directory entry */ +/* --------------------------------------------------------------------- */ + +/* TODO: all those only get the first instance */ + +static x3f_directory_entry_t *x3f_get(x3f_t *x3f, uint32_t type, + uint32_t image_type) +{ + x3f_directory_section_t *DS; + int d; + + if (x3f == NULL) + return NULL; + + DS = &x3f->directory_section; + + for (d = 0; d < DS->num_directory_entries; d++) + { + x3f_directory_entry_t *DE = &DS->directory_entry[d]; + x3f_directory_entry_header_t *DEH = &DE->header; + + if (DEH->identifier == type) + { + switch (DEH->identifier) + { + case X3F_SECi: + { + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + + if (ID->type_format == image_type) + return DE; + } + break; + default: + return DE; + } + } + } + + return NULL; +} + +/* extern */ x3f_directory_entry_t *x3f_get_raw(x3f_t *x3f) +{ + x3f_directory_entry_t *DE; + + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_HUFFMAN_X530)) != NULL) + return DE; + + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_HUFFMAN_10BIT)) != NULL) + return DE; + + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_TRUE)) != NULL) + return DE; + + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_MERRILL)) != NULL) + return DE; + + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_QUATTRO)) != NULL) + return DE; + + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_SDQ)) != NULL) + return DE; + + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_SDQH)) != NULL) + return DE; + if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_SDQH2)) != NULL) + return DE; + + return NULL; +} + +/* extern */ x3f_directory_entry_t *x3f_get_thumb_plain(x3f_t *x3f) +{ + return x3f_get(x3f, X3F_SECi, X3F_IMAGE_THUMB_PLAIN); +} + +/* extern */ x3f_directory_entry_t *x3f_get_thumb_huffman(x3f_t *x3f) +{ + return x3f_get(x3f, X3F_SECi, X3F_IMAGE_THUMB_HUFFMAN); +} + +/* extern */ x3f_directory_entry_t *x3f_get_thumb_jpeg(x3f_t *x3f) +{ + return x3f_get(x3f, X3F_SECi, X3F_IMAGE_THUMB_JPEG); +} + +/* extern */ x3f_directory_entry_t *x3f_get_camf(x3f_t *x3f) +{ + return x3f_get(x3f, X3F_SECc, 0); +} + +/* extern */ x3f_directory_entry_t *x3f_get_prop(x3f_t *x3f) +{ + return x3f_get(x3f, X3F_SECp, 0); +} + +/* For some obscure reason, the bit numbering is weird. It is + generally some kind of "big endian" style - e.g. the bit 7 is the + first in a byte and bit 31 first in a 4 byte int. For patterns in + the huffman pattern table, bit 27 is the first bit and bit 26 the + next one. */ + +#define PATTERN_BIT_POS(_len, _bit) ((_len) - (_bit)-1) +#define MEMORY_BIT_POS(_bit) PATTERN_BIT_POS(8, _bit) + +/* --------------------------------------------------------------------- */ +/* Huffman Decode */ +/* --------------------------------------------------------------------- */ + +/* Make the huffman tree */ + +#ifdef DBG_PRNT +static char *display_code(int length, uint32_t code, char *buffer) +{ + int i; + + for (i = 0; i < length; i++) + { + int pos = PATTERN_BIT_POS(length, i); + buffer[i] = ((code >> pos) & 1) == 0 ? '0' : '1'; + } + + buffer[i] = 0; + + return buffer; +} +#endif + +static x3f_huffnode_t *new_node(x3f_hufftree_t *tree) +{ + if (tree->free_node_index >= tree->total_node_index) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + x3f_huffnode_t *t = &tree->nodes[tree->free_node_index]; + + t->branch[0] = NULL; + t->branch[1] = NULL; + t->leaf = UNDEFINED_LEAF; + + tree->free_node_index++; + + return t; +} + +static void add_code_to_tree(x3f_hufftree_t *tree, int length, uint32_t code, + uint32_t value) +{ + int i; + + x3f_huffnode_t *t = tree->nodes; + + for (i = 0; i < length; i++) + { + int pos = PATTERN_BIT_POS(length, i); + int bit = (code >> pos) & 1; + x3f_huffnode_t *t_next = t->branch[bit]; + + if (t_next == NULL) + t_next = t->branch[bit] = new_node(tree); + + t = t_next; + } + + t->leaf = value; +} + +static void populate_true_huffman_tree(x3f_hufftree_t *tree, + x3f_true_huffman_t *table) +{ + int i; + + new_node(tree); + + for (i = 0; i < table->size; i++) + { + x3f_true_huffman_element_t *element = &table->element[i]; + uint32_t length = element->code_size; + + if (length != 0) + { + /* add_code_to_tree wants the code right adjusted */ + uint32_t code = ((element->code) >> (8 - length)) & 0xff; + uint32_t value = i; + + add_code_to_tree(tree, length, code, value); + +#ifdef DBG_PRNT + { + char buffer[100]; + + x3f_printf(DEBUG, "H %5d : %5x : %5d : %02x %08x (%08x) (%s)\n", i, i, + value, length, code, value, + display_code(length, code, buffer)); + } +#endif + } + } +} + +static void populate_huffman_tree(x3f_hufftree_t *tree, x3f_table32_t *table, + x3f_table16_t *mapping) +{ + int i; + + new_node(tree); + + for (i = 0; i < table->size; i++) + { + uint32_t element = table->element[i]; + + if (element != 0) + { + uint32_t length = HUF_TREE_GET_LENGTH(element); + uint32_t code = HUF_TREE_GET_CODE(element); + uint32_t value; + + /* If we have a valid mapping table - then the value from the + mapping table shall be used. Otherwise we use the current + index in the table as value. */ + if (table->size == mapping->size) + value = mapping->element[i]; + else + value = i; + + add_code_to_tree(tree, length, code, value); + +#ifdef DBG_PRNT + { + char buffer[100]; + + x3f_printf(DEBUG, "H %5d : %5x : %5d : %02x %08x (%08x) (%s)\n", i, i, + value, length, code, element, + display_code(length, code, buffer)); + } +#endif + } + } +} + +#ifdef DBG_PRNT +static void print_huffman_tree(x3f_huffnode_t *t, int length, uint32_t code) +{ + char buf1[100]; + char buf2[100]; + + x3f_printf(DEBUG, "%*s (%s,%s) %s (%s)\n", length, + length < 1 ? "-" : (code & 1) ? "1" : "0", + t->branch[0] == NULL ? "-" : "0", t->branch[1] == NULL ? "-" : "1", + t->leaf == UNDEFINED_LEAF ? "-" + : (sprintf(buf1, "%x", t->leaf), buf1), + display_code(length, code, buf2)); + + code = code << 1; + if (t->branch[0]) + print_huffman_tree(t->branch[0], length + 1, code + 0); + if (t->branch[1]) + print_huffman_tree(t->branch[1], length + 1, code + 1); +} +#endif + +/* Help machinery for reading bits in a memory */ + +typedef struct bit_state_s +{ + uint8_t *next_address; + uint8_t bit_offset; + uint8_t bits[8]; +} bit_state_t; + +static void set_bit_state(bit_state_t *BS, uint8_t *address) +{ + BS->next_address = address; + BS->bit_offset = 8; +} + +static uint8_t get_bit(bit_state_t *BS) +{ + if (BS->bit_offset == 8) + { + uint8_t byte = *BS->next_address; + int i; + + for (i = 7; i >= 0; i--) + { + BS->bits[i] = byte & 1; + byte = byte >> 1; + } + BS->next_address++; + BS->bit_offset = 0; + } + + return BS->bits[BS->bit_offset++]; +} + +/* Decode use the TRUE algorithm */ + +static int32_t get_true_diff(bit_state_t *BS, x3f_hufftree_t *HTP) +{ + int32_t diff; + x3f_huffnode_t *node = &HTP->nodes[0]; + uint8_t bits; + + while (node->branch[0] != NULL || node->branch[1] != NULL) + { + uint8_t bit = get_bit(BS); + x3f_huffnode_t *new_node = node->branch[bit]; + + node = new_node; + if (node == NULL) + { + /* TODO: Shouldn't this be treated as a fatal error? */ + return 0; + } + } + + bits = node->leaf; + + if (bits == 0) + diff = 0; + else + { + uint8_t first_bit = get_bit(BS); + int i; + + diff = first_bit; + + for (i = 1; i < bits; i++) + diff = (diff << 1) + get_bit(BS); + + if (first_bit == 0) + diff -= (1 << bits) - 1; + } + + return diff; +} + +/* This code (that decodes one of the X3F color planes, really is a + decoding of a compression algorithm suited for Bayer CFA data. In + Bayer CFA the data is divided into 2x2 squares that represents + (R,G1,G2,B) data. Those four positions are (in this compression) + treated as one data stream each, where you store the differences to + previous data in the stream. The reason for this is, of course, + that the date is more often than not near to the next data in a + stream that represents the same color. */ + +/* TODO: write more about the compression */ + +static void true_decode_one_color(x3f_image_data_t *ID, int color) +{ + x3f_true_t *TRU = ID->tru; + x3f_quattro_t *Q = ID->quattro; + uint32_t seed = TRU->seed[color]; /* TODO : Is this correct ? */ + int row; + + x3f_hufftree_t *tree = &TRU->tree; + bit_state_t BS; + + int32_t row_start_acc[2][2]; + uint32_t rows = ID->rows; + uint32_t cols = ID->columns; + x3f_area16_t *area = &TRU->x3rgb16; + uint16_t *dst = area->data + color; + + set_bit_state(&BS, TRU->plane_address[color]); + + row_start_acc[0][0] = seed; + row_start_acc[0][1] = seed; + row_start_acc[1][0] = seed; + row_start_acc[1][1] = seed; + + if (ID->type_format == X3F_IMAGE_RAW_QUATTRO || + ID->type_format == X3F_IMAGE_RAW_SDQ || + ID->type_format == X3F_IMAGE_RAW_SDQH || + ID->type_format == X3F_IMAGE_RAW_SDQH2) + { + rows = Q->plane[color].rows; + cols = Q->plane[color].columns; + + if (Q->quattro_layout && color == 2) + { + area = &Q->top16; + dst = area->data; + } + } + else + { + } + + if (rows != area->rows || cols < area->columns) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + for (row = 0; row < rows; row++) + { + int col; + bool_t odd_row = row & 1; + int32_t acc[2]; + + for (col = 0; col < cols; col++) + { + bool_t odd_col = col & 1; + int32_t diff = get_true_diff(&BS, tree); + int32_t prev = col < 2 ? row_start_acc[odd_row][odd_col] : acc[odd_col]; + int32_t value = prev + diff; + + acc[odd_col] = value; + if (col < 2) + row_start_acc[odd_row][odd_col] = value; + + /* Discard additional data at the right for binned Quattro plane 2 */ + if (col >= area->columns) + continue; + + *dst = value; + dst += area->channels; + } + } +} + +static void true_decode(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + int color; + + for (color = 0; color < 3; color++) + { + true_decode_one_color(ID, color); + } +} + +/* Decode use the huffman tree */ + +static int32_t get_huffman_diff(bit_state_t *BS, x3f_hufftree_t *HTP) +{ + int32_t diff; + x3f_huffnode_t *node = &HTP->nodes[0]; + + while (node->branch[0] != NULL || node->branch[1] != NULL) + { + uint8_t bit = get_bit(BS); + x3f_huffnode_t *new_node = node->branch[bit]; + + node = new_node; + if (node == NULL) + { + /* TODO: Shouldn't this be treated as a fatal error? */ + throw LIBRAW_EXCEPTION_IO_CORRUPT; + return 0; + } + } + + diff = node->leaf; + + return diff; +} + +static void huffman_decode_row(x3f_info_t *I, x3f_directory_entry_t *DE, + int bits, int row, int offset, int *minimum) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + x3f_huffman_t *HUF = ID->huffman; + + int16_t c[3] = {(int16_t)offset, (int16_t)offset, (int16_t)offset}; + int col; + bit_state_t BS; + + if (HUF->row_offsets.element[row] > ID->data_size - 1) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + set_bit_state(&BS, (uint8_t *)ID->data + HUF->row_offsets.element[row]); + + for (col = 0; col < ID->columns; col++) + { + int color; + + for (color = 0; color < 3; color++) + { + uint16_t c_fix; + + c[color] += get_huffman_diff(&BS, &HUF->tree); + if (c[color] < 0) + { + c_fix = 0; + if (c[color] < *minimum) + *minimum = c[color]; + } + else + { + c_fix = c[color]; + } + + switch (ID->type_format) + { + case X3F_IMAGE_RAW_HUFFMAN_X530: + case X3F_IMAGE_RAW_HUFFMAN_10BIT: + HUF->x3rgb16.data[3 * (row * ID->columns + col) + color] = + (uint16_t)c_fix; + break; + case X3F_IMAGE_THUMB_HUFFMAN: + HUF->rgb8.data[3 * (row * ID->columns + col) + color] = (uint8_t)c_fix; + break; + default: + /* TODO: Shouldn't this be treated as a fatal error? */ + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + } + } +} + +static void huffman_decode(x3f_info_t *I, x3f_directory_entry_t *DE, int bits) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + + int row; + int minimum = 0; + int offset = legacy_offset; + + for (row = 0; row < ID->rows; row++) + huffman_decode_row(I, DE, bits, row, offset, &minimum); + + if (auto_legacy_offset && minimum < 0) + { + offset = -minimum; + for (row = 0; row < ID->rows; row++) + huffman_decode_row(I, DE, bits, row, offset, &minimum); + } +} + +static int32_t get_simple_diff(x3f_huffman_t *HUF, uint16_t index) +{ + if (HUF->mapping.size == 0) + return index; + else + return HUF->mapping.element[index]; +} + +static void simple_decode_row(x3f_info_t *I, x3f_directory_entry_t *DE, + int bits, int row, int row_stride) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + x3f_huffman_t *HUF = ID->huffman; + + if (row*row_stride > ID->data_size - (ID->columns*sizeof(uint32_t))) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + uint32_t *data = (uint32_t *)((unsigned char *)ID->data + row * row_stride); + + uint16_t c[3] = {0, 0, 0}; + int col; + + uint32_t mask = 0; + + switch (bits) + { + case 8: + mask = 0x0ff; + break; + case 9: + mask = 0x1ff; + break; + case 10: + mask = 0x3ff; + break; + case 11: + mask = 0x7ff; + break; + case 12: + mask = 0xfff; + break; + default: + mask = 0; + /* TODO: Shouldn't this be treated as a fatal error? */ + throw LIBRAW_EXCEPTION_IO_CORRUPT; + break; + } + + for (col = 0; col < ID->columns; col++) + { + int color; + uint32_t val = data[col]; + + for (color = 0; color < 3; color++) + { + uint16_t c_fix; + c[color] += get_simple_diff(HUF, (val >> (color * bits)) & mask); + + switch (ID->type_format) + { + case X3F_IMAGE_RAW_HUFFMAN_X530: + case X3F_IMAGE_RAW_HUFFMAN_10BIT: + c_fix = (int16_t)c[color] > 0 ? c[color] : 0; + + HUF->x3rgb16.data[3 * (row * ID->columns + col) + color] = c_fix; + break; + case X3F_IMAGE_THUMB_HUFFMAN: + c_fix = (int8_t)c[color] > 0 ? c[color] : 0; + + HUF->rgb8.data[3 * (row * ID->columns + col) + color] = c_fix; + break; + default: + /* TODO: Shouldn't this be treated as a fatal error? */ + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + } + } +} + +static void simple_decode(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, + int row_stride) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + + int row; + + for (row = 0; row < ID->rows; row++) + simple_decode_row(I, DE, bits, row, row_stride); +} + +/* --------------------------------------------------------------------- */ +/* Loading the data in a directory entry */ +/* --------------------------------------------------------------------- */ + +/* First you set the offset to where to start reading the data ... */ + +static void read_data_set_offset(x3f_info_t *I, x3f_directory_entry_t *DE, + uint32_t header_size) +{ + uint32_t i_off = DE->input.offset + header_size; + + I->input.file->seek(i_off, SEEK_SET); +} + +/* ... then you read the data, block for block */ + +static uint32_t read_data_block(void **data, x3f_info_t *I, + x3f_directory_entry_t *DE, uint32_t footer) +{ + INT64 fpos = I->input.file->tell(); + uint32_t size = DE->input.size + DE->input.offset - fpos - footer; + + if (fpos + size > I->input.file->size()) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + *data = (void *)malloc(size); + + GETN(*data, size); + + return size; +} + +static uint32_t data_block_size(void **data, x3f_info_t *I, + x3f_directory_entry_t *DE, uint32_t footer) +{ + uint32_t size = + DE->input.size + DE->input.offset - I->input.file->tell() - footer; + return size; +} + +static void x3f_load_image_verbatim(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + if (!ID->data_size) + ID->data_size = read_data_block(&ID->data, I, DE, 0); +} + +static int32_t x3f_load_image_verbatim_size(x3f_info_t *I, + x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + return data_block_size(&ID->data, I, DE, 0); +} + +static void x3f_load_property_list(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_property_list_t *PL = &DEH->data_subsection.property_list; + int i; + + read_data_set_offset(I, DE, X3F_PROPERTY_LIST_HEADER_SIZE); + + GET_PROPERTY_TABLE(PL->property_table, PL->num_properties); + + if (!PL->data_size) + PL->data_size = read_data_block(&PL->data, I, DE, 0); + uint32_t maxoffset = PL->data_size / sizeof(utf16_t) - + 2; // at least 2 chars, value + terminating 0x0000 + + for (i = 0; i < PL->num_properties; i++) + { + x3f_property_t *P = &PL->property_table.element[i]; + if (P->name_offset > maxoffset || P->value_offset > maxoffset) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + P->name = ((utf16_t *)PL->data + P->name_offset); + P->value = ((utf16_t *)PL->data + P->value_offset); + } +} + +static void x3f_load_true(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + x3f_true_t *TRU = new_true(&ID->tru); + x3f_quattro_t *Q = NULL; + int i; + + if (ID->type_format == X3F_IMAGE_RAW_QUATTRO || + ID->type_format == X3F_IMAGE_RAW_SDQ || + ID->type_format == X3F_IMAGE_RAW_SDQH || + ID->type_format == X3F_IMAGE_RAW_SDQH2) + { + Q = new_quattro(&ID->quattro); + + for (i = 0; i < TRUE_PLANES; i++) + { + GET2(Q->plane[i].columns); + GET2(Q->plane[i].rows); + } + + if (Q->plane[0].rows == ID->rows / 2) + { + Q->quattro_layout = 1; + } + else if (Q->plane[0].rows == ID->rows) + { + Q->quattro_layout = 0; + } + else + { + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + } + + /* Read TRUE header data */ + GET2(TRU->seed[0]); + GET2(TRU->seed[1]); + GET2(TRU->seed[2]); + GET2(TRU->unknown); + GET_TRUE_HUFF_TABLE(TRU->table); + + if (ID->type_format == X3F_IMAGE_RAW_QUATTRO || + ID->type_format == X3F_IMAGE_RAW_SDQ || + ID->type_format == X3F_IMAGE_RAW_SDQH || + ID->type_format == X3F_IMAGE_RAW_SDQH2) + { + GET4(Q->unknown); + } + + GET_TABLE(TRU->plane_size, GET4, TRUE_PLANES, uint32_t); + + /* Read image data */ + if (!ID->data_size) + ID->data_size = read_data_block(&ID->data, I, DE, 0); + + /* TODO: can it be fewer than 8 bits? Maybe taken from TRU->table? */ + new_huffman_tree(&TRU->tree, 8); + + populate_true_huffman_tree(&TRU->tree, &TRU->table); + +#ifdef DBG_PRNT + print_huffman_tree(TRU->tree.nodes, 0, 0); +#endif + + TRU->plane_address[0] = (uint8_t *)ID->data; + for (i = 1; i < TRUE_PLANES; i++) + TRU->plane_address[i] = TRU->plane_address[i - 1] + + (((TRU->plane_size.element[i - 1] + 15) / 16) * 16); + + if ((ID->type_format == X3F_IMAGE_RAW_QUATTRO || + ID->type_format == X3F_IMAGE_RAW_SDQ || + ID->type_format == X3F_IMAGE_RAW_SDQH || + ID->type_format == X3F_IMAGE_RAW_SDQH2) && + Q->quattro_layout) + { + uint32_t columns = Q->plane[0].columns; + uint32_t rows = Q->plane[0].rows; + uint32_t channels = 3; + uint32_t size = columns * rows * channels; + + TRU->x3rgb16.columns = columns; + TRU->x3rgb16.rows = rows; + TRU->x3rgb16.channels = channels; + TRU->x3rgb16.row_stride = columns * channels; + TRU->x3rgb16.buf = malloc(sizeof(uint16_t) * size); + TRU->x3rgb16.data = (uint16_t *)TRU->x3rgb16.buf; + + columns = Q->plane[2].columns; + rows = Q->plane[2].rows; + channels = 1; + size = columns * rows * channels; + + Q->top16.columns = columns; + Q->top16.rows = rows; + Q->top16.channels = channels; + Q->top16.row_stride = columns * channels; + Q->top16.buf = malloc(sizeof(uint16_t) * size); + Q->top16.data = (uint16_t *)Q->top16.buf; + } + else + { + uint32_t size = ID->columns * ID->rows * 3; + + TRU->x3rgb16.columns = ID->columns; + TRU->x3rgb16.rows = ID->rows; + TRU->x3rgb16.channels = 3; + TRU->x3rgb16.row_stride = ID->columns * 3; + TRU->x3rgb16.buf = malloc(sizeof(uint16_t) * size); + TRU->x3rgb16.data = (uint16_t *)TRU->x3rgb16.buf; + } + + true_decode(I, DE); +} + +static void x3f_load_huffman_compressed(x3f_info_t *I, + x3f_directory_entry_t *DE, int bits, + int use_map_table) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + x3f_huffman_t *HUF = ID->huffman; + int table_size = 1 << bits; + int row_offsets_size = ID->rows * sizeof(HUF->row_offsets.element[0]); + + GET_TABLE(HUF->table, GET4, table_size, uint32_t); + + if (!ID->data_size) + ID->data_size = read_data_block(&ID->data, I, DE, row_offsets_size); + + GET_TABLE(HUF->row_offsets, GET4, ID->rows, uint32_t); + + new_huffman_tree(&HUF->tree, bits); + populate_huffman_tree(&HUF->tree, &HUF->table, &HUF->mapping); + + huffman_decode(I, DE, bits); +} + +static void x3f_load_huffman_not_compressed(x3f_info_t *I, + x3f_directory_entry_t *DE, int bits, + int use_map_table, int row_stride) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + + if (!ID->data_size) + ID->data_size = read_data_block(&ID->data, I, DE, 0); + + simple_decode(I, DE, bits, row_stride); +} + +static void x3f_load_huffman(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, + int use_map_table, int row_stride) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + x3f_huffman_t *HUF = new_huffman(&ID->huffman); + uint32_t size; + + if (use_map_table) + { + int table_size = 1 << bits; + + GET_TABLE(HUF->mapping, GET2, table_size, uint16_t); + } + + switch (ID->type_format) + { + case X3F_IMAGE_RAW_HUFFMAN_X530: + case X3F_IMAGE_RAW_HUFFMAN_10BIT: + size = ID->columns * ID->rows * 3; + HUF->x3rgb16.columns = ID->columns; + HUF->x3rgb16.rows = ID->rows; + HUF->x3rgb16.channels = 3; + HUF->x3rgb16.row_stride = ID->columns * 3; + HUF->x3rgb16.buf = malloc(sizeof(uint16_t) * size); + HUF->x3rgb16.data = (uint16_t *)HUF->x3rgb16.buf; + break; + case X3F_IMAGE_THUMB_HUFFMAN: + size = ID->columns * ID->rows * 3; + HUF->rgb8.columns = ID->columns; + HUF->rgb8.rows = ID->rows; + HUF->rgb8.channels = 3; + HUF->rgb8.row_stride = ID->columns * 3; + HUF->rgb8.buf = malloc(sizeof(uint8_t) * size); + HUF->rgb8.data = (uint8_t *)HUF->rgb8.buf; + break; + default: + /* TODO: Shouldn't this be treated as a fatal error? */ + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + + if (row_stride == 0) + return x3f_load_huffman_compressed(I, DE, bits, use_map_table); + else + return x3f_load_huffman_not_compressed(I, DE, bits, use_map_table, + row_stride); +} + +static void x3f_load_pixmap(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_load_image_verbatim(I, DE); +} + +static uint32_t x3f_load_pixmap_size(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + return x3f_load_image_verbatim_size(I, DE); +} + +static void x3f_load_jpeg(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_load_image_verbatim(I, DE); +} + +static uint32_t x3f_load_jpeg_size(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + return x3f_load_image_verbatim_size(I, DE); +} + +static void x3f_load_image(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + + if (ID->rows > 65535 || ID->columns > 65535) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + + read_data_set_offset(I, DE, X3F_IMAGE_HEADER_SIZE); + + switch (ID->type_format) + { + case X3F_IMAGE_RAW_TRUE: + case X3F_IMAGE_RAW_MERRILL: + case X3F_IMAGE_RAW_QUATTRO: + case X3F_IMAGE_RAW_SDQ: + case X3F_IMAGE_RAW_SDQH: + case X3F_IMAGE_RAW_SDQH2: + x3f_load_true(I, DE); + break; + case X3F_IMAGE_RAW_HUFFMAN_X530: + case X3F_IMAGE_RAW_HUFFMAN_10BIT: + x3f_load_huffman(I, DE, 10, 1, ID->row_stride); + break; + case X3F_IMAGE_THUMB_PLAIN: + x3f_load_pixmap(I, DE); + break; + case X3F_IMAGE_THUMB_HUFFMAN: + x3f_load_huffman(I, DE, 8, 0, ID->row_stride); + break; + case X3F_IMAGE_THUMB_JPEG: + x3f_load_jpeg(I, DE); + break; + default: + /* TODO: Shouldn't this be treated as a fatal error? */ + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } +} + +// Used only for thumbnail size estimation +static uint32_t x3f_load_image_size(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_image_data_t *ID = &DEH->data_subsection.image_data; + + read_data_set_offset(I, DE, X3F_IMAGE_HEADER_SIZE); + + switch (ID->type_format) + { + case X3F_IMAGE_THUMB_PLAIN: + return x3f_load_pixmap_size(I, DE); + case X3F_IMAGE_THUMB_JPEG: + return x3f_load_jpeg_size(I, DE); + break; + default: + return 0; + } +} + +static void x3f_load_camf_decode_type2(x3f_camf_t *CAMF) +{ + uint32_t key = CAMF->t2.crypt_key; + int i; + + CAMF->decoded_data_size = CAMF->data_size; + CAMF->decoded_data = malloc(CAMF->decoded_data_size); + + for (i = 0; i < CAMF->data_size; i++) + { + uint8_t old, _new; + uint32_t tmp; + + old = ((uint8_t *)CAMF->data)[i]; + key = (key * 1597 + 51749) % 244944; + tmp = (uint32_t)(key * ((int64_t)301593171) >> 24); + _new = (uint8_t)(old ^ (uint8_t)(((((key << 8) - tmp) >> 1) + tmp) >> 17)); + ((uint8_t *)CAMF->decoded_data)[i] = _new; + } +} + +/* NOTE: the unpacking in this code is in big respects identical to + true_decode_one_color(). The difference is in the output you + build. It might be possible to make some parts shared. NOTE ALSO: + This means that the meta data is obfuscated using an image + compression algorithm. */ + +static void camf_decode_type4(x3f_camf_t *CAMF) +{ + uint32_t seed = CAMF->t4.decode_bias; + int row; + + uint8_t *dst; + uint32_t dst_size = CAMF->t4.decoded_data_size; + uint8_t *dst_end; + + bool_t odd_dst = 0; + + x3f_hufftree_t *tree = &CAMF->tree; + bit_state_t BS; + + int32_t row_start_acc[2][2]; + uint32_t rows = CAMF->t4.block_count; + uint32_t cols = CAMF->t4.block_size; + + CAMF->decoded_data_size = dst_size; + + CAMF->decoded_data = malloc(CAMF->decoded_data_size); + memset(CAMF->decoded_data, 0, CAMF->decoded_data_size); + + dst = (uint8_t *)CAMF->decoded_data; + dst_end = dst + dst_size; + + set_bit_state(&BS, CAMF->decoding_start); + + row_start_acc[0][0] = seed; + row_start_acc[0][1] = seed; + row_start_acc[1][0] = seed; + row_start_acc[1][1] = seed; + + for (row = 0; row < rows; row++) + { + int col; + bool_t odd_row = row & 1; + int32_t acc[2]; + + /* We loop through all the columns and the rows. But the actual + data is smaller than that, so we break the loop when reaching + the end. */ + for (col = 0; col < cols; col++) + { + bool_t odd_col = col & 1; + int32_t diff = get_true_diff(&BS, tree); + int32_t prev = col < 2 ? row_start_acc[odd_row][odd_col] : acc[odd_col]; + int32_t value = prev + diff; + + acc[odd_col] = value; + if (col < 2) + row_start_acc[odd_row][odd_col] = value; + + switch (odd_dst) + { + case 0: + *dst++ = (uint8_t)((value >> 4) & 0xff); + + if (dst >= dst_end) + { + goto ready; + } + + *dst = (uint8_t)((value << 4) & 0xf0); + break; + case 1: + *dst++ |= (uint8_t)((value >> 8) & 0x0f); + + if (dst >= dst_end) + { + goto ready; + } + + *dst++ = (uint8_t)((value << 0) & 0xff); + + if (dst >= dst_end) + { + goto ready; + } + + break; + } + + odd_dst = !odd_dst; + } /* end col */ + } /* end row */ + +ready:; +} + +static void x3f_load_camf_decode_type4(x3f_camf_t *CAMF) +{ + int i; + uint8_t *p; + x3f_true_huffman_element_t *element = NULL; + + for (i = 0, p = (uint8_t *)CAMF->data; *p != 0; i++) + { + /* TODO: Is this too expensive ??*/ + element = (x3f_true_huffman_element_t *)realloc(element, + (i + 1) * sizeof(*element)); + + element[i].code_size = *p++; + element[i].code = *p++; + } + + CAMF->table.size = i; + CAMF->table.element = element; + + /* TODO: where does the values 28 and 32 come from? */ +#define CAMF_T4_DATA_SIZE_OFFSET 28 +#define CAMF_T4_DATA_OFFSET 32 + CAMF->decoding_size = + *(uint32_t *)((unsigned char *)CAMF->data + CAMF_T4_DATA_SIZE_OFFSET); + CAMF->decoding_start = (uint8_t *)CAMF->data + CAMF_T4_DATA_OFFSET; + + /* TODO: can it be fewer than 8 bits? Maybe taken from TRU->table? */ + new_huffman_tree(&CAMF->tree, 8); + + populate_true_huffman_tree(&CAMF->tree, &CAMF->table); + +#ifdef DBG_PRNT + print_huffman_tree(CAMF->tree.nodes, 0, 0); +#endif + + camf_decode_type4(CAMF); +} + +static void camf_decode_type5(x3f_camf_t *CAMF) +{ + int32_t acc = CAMF->t5.decode_bias; + + uint8_t *dst; + + x3f_hufftree_t *tree = &CAMF->tree; + bit_state_t BS; + + int32_t i; + + CAMF->decoded_data_size = CAMF->t5.decoded_data_size; + CAMF->decoded_data = malloc(CAMF->decoded_data_size); + + dst = (uint8_t *)CAMF->decoded_data; + + set_bit_state(&BS, CAMF->decoding_start); + + for (i = 0; i < CAMF->decoded_data_size; i++) + { + int32_t diff = get_true_diff(&BS, tree); + + acc = acc + diff; + *dst++ = (uint8_t)(acc & 0xff); + } +} + +static void x3f_load_camf_decode_type5(x3f_camf_t *CAMF) +{ + int i; + uint8_t *p; + x3f_true_huffman_element_t *element = NULL; + + for (i = 0, p = (uint8_t *)CAMF->data; *p != 0; i++) + { + /* TODO: Is this too expensive ??*/ + element = (x3f_true_huffman_element_t *)realloc(element, + (i + 1) * sizeof(*element)); + + element[i].code_size = *p++; + element[i].code = *p++; + } + + CAMF->table.size = i; + CAMF->table.element = element; + + /* TODO: where does the values 28 and 32 come from? */ +#define CAMF_T5_DATA_SIZE_OFFSET 28 +#define CAMF_T5_DATA_OFFSET 32 + CAMF->decoding_size = + *(uint32_t *)((uint8_t *)CAMF->data + CAMF_T5_DATA_SIZE_OFFSET); + CAMF->decoding_start = (uint8_t *)CAMF->data + CAMF_T5_DATA_OFFSET; + + /* TODO: can it be fewer than 8 bits? Maybe taken from TRU->table? */ + new_huffman_tree(&CAMF->tree, 8); + + populate_true_huffman_tree(&CAMF->tree, &CAMF->table); + +#ifdef DBG_PRNT + print_huffman_tree(CAMF->tree.nodes, 0, 0); +#endif + + camf_decode_type5(CAMF); +} + +static void x3f_setup_camf_text_entry(camf_entry_t *entry) +{ + entry->text_size = *(uint32_t *)entry->value_address; + entry->text = (char *)entry->value_address + 4; +} + +static void x3f_setup_camf_property_entry(camf_entry_t *entry) +{ + int i; + uint8_t *e = (uint8_t *)entry->entry; + uint8_t *v = (uint8_t *)entry->value_address; + uint32_t num = entry->property_num = *(uint32_t *)v; + uint32_t off = *(uint32_t *)(v + 4); + + entry->property_name = (char **)malloc(num * sizeof(uint8_t *)); + entry->property_value = (uint8_t **)malloc(num * sizeof(uint8_t *)); + + for (i = 0; i < num; i++) + { + uint32_t name_off = off + *(uint32_t *)(v + 8 + 8 * i); + uint32_t value_off = off + *(uint32_t *)(v + 8 + 8 * i + 4); + + entry->property_name[i] = (char *)(e + name_off); + entry->property_value[i] = e + value_off; + } +} + +static void set_matrix_element_info(uint32_t type, uint32_t *size, + matrix_type_t *decoded_type) +{ + switch (type) + { + case 0: + *size = 2; + *decoded_type = M_INT; /* known to be true */ + break; + case 1: + *size = 4; + *decoded_type = M_UINT; /* TODO: unknown ???? */ + break; + case 2: + *size = 4; + *decoded_type = M_UINT; /* TODO: unknown ???? */ + break; + case 3: + *size = 4; + *decoded_type = M_FLOAT; /* known to be true */ + break; + case 5: + *size = 1; + *decoded_type = M_UINT; /* TODO: unknown ???? */ + break; + case 6: + *size = 2; + *decoded_type = M_UINT; /* TODO: unknown ???? */ + break; + default: + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } +} + +static void get_matrix_copy(camf_entry_t *entry) +{ + uint32_t element_size = entry->matrix_element_size; + uint32_t elements = entry->matrix_elements; + int i, size = (entry->matrix_decoded_type == M_FLOAT ? sizeof(double) + : sizeof(uint32_t)) * + elements; + + entry->matrix_decoded = malloc(size); + + switch (element_size) + { + case 4: + switch (entry->matrix_decoded_type) + { + case M_INT: + case M_UINT: + memcpy(entry->matrix_decoded, entry->matrix_data, size); + break; + case M_FLOAT: + for (i = 0; i < elements; i++) + ((double *)entry->matrix_decoded)[i] = + (double)((float *)entry->matrix_data)[i]; + break; + default: + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + break; + case 2: + switch (entry->matrix_decoded_type) + { + case M_INT: + for (i = 0; i < elements; i++) + ((int32_t *)entry->matrix_decoded)[i] = + (int32_t)((int16_t *)entry->matrix_data)[i]; + break; + case M_UINT: + for (i = 0; i < elements; i++) + ((uint32_t *)entry->matrix_decoded)[i] = + (uint32_t)((uint16_t *)entry->matrix_data)[i]; + break; + default: + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + break; + case 1: + switch (entry->matrix_decoded_type) + { + case M_INT: + for (i = 0; i < elements; i++) + ((int32_t *)entry->matrix_decoded)[i] = + (int32_t)((int8_t *)entry->matrix_data)[i]; + break; + case M_UINT: + for (i = 0; i < elements; i++) + ((uint32_t *)entry->matrix_decoded)[i] = + (uint32_t)((uint8_t *)entry->matrix_data)[i]; + break; + default: + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + break; + default: + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } +} + +static void x3f_setup_camf_matrix_entry(camf_entry_t *entry) +{ + int i; + int totalsize = 1; + + uint8_t *e = (uint8_t *)entry->entry; + uint8_t *v = (uint8_t *)entry->value_address; + uint32_t type = entry->matrix_type = *(uint32_t *)(v + 0); + uint32_t dim = entry->matrix_dim = *(uint32_t *)(v + 4); + uint32_t off = entry->matrix_data_off = *(uint32_t *)(v + 8); + camf_dim_entry_t *dentry = entry->matrix_dim_entry = + (camf_dim_entry_t *)malloc(dim * sizeof(camf_dim_entry_t)); + + for (i = 0; i < dim; i++) + { + uint32_t size = dentry[i].size = *(uint32_t *)(v + 12 + 12 * i + 0); + dentry[i].name_offset = *(uint32_t *)(v + 12 + 12 * i + 4); + dentry[i].n = *(uint32_t *)(v + 12 + 12 * i + 8); + dentry[i].name = (char *)(e + dentry[i].name_offset); + + if (dentry[i].n != i) + { + } + + totalsize *= size; + } + + set_matrix_element_info(type, &entry->matrix_element_size, + &entry->matrix_decoded_type); + entry->matrix_data = (void *)(e + off); + + entry->matrix_elements = totalsize; + entry->matrix_used_space = entry->entry_size - off; + + /* This estimate only works for matrices above a certain size */ + entry->matrix_estimated_element_size = entry->matrix_used_space / totalsize; + + get_matrix_copy(entry); +} + +static void x3f_setup_camf_entries(x3f_camf_t *CAMF) +{ + uint8_t *p = (uint8_t *)CAMF->decoded_data; + uint8_t *end = p + CAMF->decoded_data_size; + camf_entry_t *entry = NULL; + int i; + + for (i = 0; p < end; i++) + { + uint32_t *p4 = (uint32_t *)p; + + switch (*p4) + { + case X3F_CMbP: + case X3F_CMbT: + case X3F_CMbM: + break; + default: + goto stop; + } + + /* TODO: lots of realloc - may be inefficient */ + entry = (camf_entry_t *)realloc(entry, (i + 1) * sizeof(camf_entry_t)); + + /* Pointer */ + entry[i].entry = p; + + /* Header */ + entry[i].id = *p4++; + entry[i].version = *p4++; + entry[i].entry_size = *p4++; + entry[i].name_offset = *p4++; + entry[i].value_offset = *p4++; + + /* Compute adresses and sizes */ + entry[i].name_address = (char *)(p + entry[i].name_offset); + entry[i].value_address = p + entry[i].value_offset; + entry[i].name_size = entry[i].value_offset - entry[i].name_offset; + entry[i].value_size = entry[i].entry_size - entry[i].value_offset; + + entry[i].text_size = 0; + entry[i].text = NULL; + entry[i].property_num = 0; + entry[i].property_name = NULL; + entry[i].property_value = NULL; + entry[i].matrix_type = 0; + entry[i].matrix_dim = 0; + entry[i].matrix_data_off = 0; + entry[i].matrix_data = NULL; + entry[i].matrix_dim_entry = NULL; + + entry[i].matrix_decoded = NULL; + + switch (entry[i].id) + { + case X3F_CMbP: + x3f_setup_camf_property_entry(&entry[i]); + break; + case X3F_CMbT: + x3f_setup_camf_text_entry(&entry[i]); + break; + case X3F_CMbM: + x3f_setup_camf_matrix_entry(&entry[i]); + break; + } + + p += entry[i].entry_size; + } + +stop: + + CAMF->entry_table.size = i; + CAMF->entry_table.element = entry; +} + +static void x3f_load_camf(x3f_info_t *I, x3f_directory_entry_t *DE) +{ + x3f_directory_entry_header_t *DEH = &DE->header; + x3f_camf_t *CAMF = &DEH->data_subsection.camf; + + read_data_set_offset(I, DE, X3F_CAMF_HEADER_SIZE); + + if (!CAMF->data_size) + CAMF->data_size = read_data_block(&CAMF->data, I, DE, 0); + + switch (CAMF->type) + { + case 2: /* Older SD9-SD14 */ + x3f_load_camf_decode_type2(CAMF); + break; + case 4: /* TRUE ... Merrill */ + x3f_load_camf_decode_type4(CAMF); + break; + case 5: /* Quattro ... */ + x3f_load_camf_decode_type5(CAMF); + break; + default: + /* TODO: Shouldn't this be treated as a fatal error? */ + throw LIBRAW_EXCEPTION_IO_CORRUPT; + } + + if (CAMF->decoded_data != NULL) + x3f_setup_camf_entries(CAMF); + else + throw LIBRAW_EXCEPTION_IO_CORRUPT; +} + +/* extern */ x3f_return_t x3f_load_data(x3f_t *x3f, x3f_directory_entry_t *DE) +{ + x3f_info_t *I = &x3f->info; + + if (DE == NULL) + return X3F_ARGUMENT_ERROR; + + switch (DE->header.identifier) + { + case X3F_SECp: + x3f_load_property_list(I, DE); + break; + case X3F_SECi: + x3f_load_image(I, DE); + break; + case X3F_SECc: + x3f_load_camf(I, DE); + break; + default: + return X3F_INTERNAL_ERROR; + } + return X3F_OK; +} + +/* extern */ int64_t x3f_load_data_size(x3f_t *x3f, x3f_directory_entry_t *DE) +{ + x3f_info_t *I = &x3f->info; + + if (DE == NULL) + return -1; + + switch (DE->header.identifier) + { + case X3F_SECi: + return x3f_load_image_size(I, DE); + default: + return 0; + } +} + +/* extern */ x3f_return_t x3f_load_image_block(x3f_t *x3f, + x3f_directory_entry_t *DE) +{ + x3f_info_t *I = &x3f->info; + + if (DE == NULL) + return X3F_ARGUMENT_ERROR; + + switch (DE->header.identifier) + { + case X3F_SECi: + read_data_set_offset(I, DE, X3F_IMAGE_HEADER_SIZE); + x3f_load_image_verbatim(I, DE); + break; + default: + throw LIBRAW_EXCEPTION_IO_CORRUPT; + return X3F_INTERNAL_ERROR; + } + + return X3F_OK; +} + +/* --------------------------------------------------------------------- */ +/* The End */ +/* --------------------------------------------------------------------- */ + +#endif \ No newline at end of file
Attachment:
v14_libraw_upd.tar.gz
Description: application/gzip
____________________________________________________ tde-devels mailing list -- devels@xxxxxxxxxxxxxxxxxx To unsubscribe send an email to devels-leave@xxxxxxxxxxxxxxxxxx Web mail archive available at https://mail.trinitydesktop.org/mailman3/hyperkitty/list/devels@xxxxxxxxxxxxxxxxxx