diff --git a/rtengine/camconst.json b/rtengine/camconst.json index b3294e379..14bc842d7 100755 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -60,7 +60,8 @@ Examples: "make_model": "ManufacturerA ModelB", // ColorMatrix with D65 Calibration Illuminant, in dcraw format "dcraw_matrix": [ 7530, -1942, -255, -4318, 11390, 3362, -926, 1694, 7649 ], - // black and white level same for all colors at all ISOs + // black level (or black offset if a base black is already calculated by Dcraw, see Panasonic) + // and white level same for all colors at all ISOs "ranges": { "black": 10, "white": 1000 }, // crop away masked sensor borders, 10 pixels left, 20 pixels top, resulting image width/height 4000x3000 // instead of width/height you can write a negative number which specifies how much of right/bottom border @@ -278,10 +279,9 @@ end up providing incompatible black/white levels. You can use RawTherapee for analysis too, it's safer as you are using it's own raw decoder but it's not as user-friendly: enable verbose mode in options -so you get output on the console (you need to start RT from a console to see -the output). When you load a file you will see a message of current black -and white levels and if they came from dcraw or camconst.json. If you're -adjusting an existing camconst.json value you can just read what it is in +so you get output on the console. When you load a file you will see a message +of current black and white levels and if they came from dcraw or camconst.json. +If you're adjusting an existing camconst.json value you can just read what it is in the file and not need to enable verbose output. Reset exposure sliders to neutral, and zoom in on a large clipped highlight. @@ -295,7 +295,7 @@ apply it on the old white level to find a new larger one. As RT's "whitepoint linear correction factor" work after blacklevel subtraction and camconst.json want values without it we need to do some math: -BL = black level (typically something near 0, 256, 512 or 1024, find it in the +BL = black level (typically something near 0, 256, 512, 1024 or 2048 find it in the verbose output or if available in camconst.json) F = whitepoint linear correction factor you just found out (typically in the range 0.90 to 0.99 if you need to increase white level, 1.01 to 1.10 if @@ -325,15 +325,19 @@ About black levels: ------------------- Unlike for white levels it's much more common that black levels can be -derived from the format. Either it's simply 0 (typical for Nikon cameras), or -it can be derived from masked pixels (typical for Canon cameras) or otherwise -be extracted from some tag. Some formats are have built-in subtraction -information and are pre-processed by DCRaw to end up at a black level of zero -(Phase One's IIQ). In all, you typically should not care about the black -level in camconst.json: any information that can be derived from the raw file -itself should not be specified in camconst.json! Sony's ARW2 is one of the -few exceptions (which has a single black level around 512), but DCraw -generally has good constants for these already. +derived from the format. Either it's simply 0 (typical for old Nikon cameras, +newer Nikons (year2013-14) have a BL at around 150 12bit or 600/768 14bit ), +or it can be derived from masked pixels (typical for Canon cameras) or otherwise +be extracted from some tag. +Some formats have built-in subtraction information and are pre-processed by DCRaw +to end up at a black level of zero(Phase One's IIQ). +For Panasonic raws beginning from Dcraw v9.21 Dcraw/RT reads base BL from exif data +(tags 0x001c BlackLevelRed, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue)and we +define in "ranges": { "black": the needed offset of around 15. The (total) BL RT displays is base+offset +In all, you typically should not care about the black level in camconst.json, +any information that can be derived from the raw file itself should not be specified in camconst.json! +Sony's ARW2 is one of the few exceptions (which has a single black level around 512), +but DCraw generally has good constants for these already. Currently we have chosen not to provide any guide how to measure black levels as we don't think it will be a common task (it's also more difficult to do @@ -617,7 +621,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know } }, - { // Quality B, only one some scaling factors missing + { // Quality B, missing scaling factors are guessed safely from 650D relative data "make_model": "Canon EOS-M", "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], "ranges": { @@ -644,19 +648,19 @@ Quality X: unknown, ie we knowing to little about the camera properties to know } }, - { /* Quality C, needs a way to auto apply 3/2 or 4/3 crops (read exif tags ..) to work better with auto distortion, + { /* Quality B, needs a way to auto apply 3/2 or 4/3 crops (read exif tags ..) to work better with auto distortion, for the moment just comment-uncomment the desired raw crop */ "make_model": "Canon PowerShot G1 X Mark II", "dcraw_matrix": [ 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 ], // D65 matrix from adobe dcp // "raw_crop": [ 80, 50, 4400, 3316 ], // full frame 4480x3366 borders 80,50 - much shade in corners, no/wrong auto distortion - // "raw_crop": [ 104, 144, 4360, 3128 ], // Mixed best average frame - , width is 4352 from 3/2, height 3120 from 4/3 - auto distortion does not work correctly - // "raw_crop": [ 200, 144, 4168, 3128 ], // Optional 4/3 frame 4160x3120, 4pix borders, Left Border 204-4, Top Border 148-4 - "raw_crop": [ 104, 252, 4360, 2912 ], // Default 3/2 frame 4352X2904, 4pix borders, Left Border 108-4, Top border 256-4 + // "raw_crop": [ 104, 144, 4360, 3128 ], // Mixed best average frame, width is 4352 from 3/2, height 3120 from 4/3 - auto distortion does not work correctly + // "raw_crop": [ 200, 144, 4168, 3128 ], // Optional official 4/3 frame 4160x3120, 4pix borders, Left Border 204-4, Top Border 148-4 + "raw_crop": [ 104, 252, 4360, 2912 ], // Default official 3/2 frame 4352X2904, 4pix borders, Left Border 108-4, Top border 256-4 "masked_areas": [ 148, 2, 3340, 78 ], "ranges": { "white": 16300 } }, - { // Quality A + { // Quality A, changes for raw crop which is wrong (larger) in Dcraw "make_model": "Canon PowerShot S120", "dcraw_matrix": [ 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 ], "raw_crop": [ 120, 30, 4024, 3030 ], @@ -669,12 +673,12 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "dcraw_matrix": [ 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 ] // MATRIX FROM FUJI SL1000 }, - { // Quality C, PRELIMINARY - new model not supported by dcraw9.20 or dng 8.4 - "make_model": "Nikon 1 V3", - "dcraw_matrix": [ 5306,-1066,-469,-3865,11189,3076,-399,1341,5120 ], // matrix dXo D50 -// "dcraw_matrix": [ 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 ], // copy from 1 V2 - "ranges": { "black": 200, "white": 4080 } // exif 800 - }, + // { // Quality C, PRELIMINARY - new model not supported by dcraw9.20 or dng 8.4 + // "make_model": "Nikon 1 V3", + // "dcraw_matrix": [ 5306,-1066,-469,-3865,11189,3076,-399,1341,5120 ], // matrix dXo D50 + // // "dcraw_matrix": [ 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 ], // copy from 1 V2 + // "ranges": { "black": 200, "white": 4080 } // exif 800 + // }, { // quality B, lacks aperture and ISO scaling, known to exist, but little to gain as the levels are so close to white_max "make_model": "Nikon D7000", @@ -689,21 +693,21 @@ Quality X: unknown, ie we knowing to little about the camera properties to know // aperture scaling not measured, but known to exist, at f/1.8 the G channels hits white_max } }, - { // Quality A, new model, not in dcraw 9.20, conflict with D4 in dcraw 9.20, sRAW format not supported - "make_model": "Nikon D4s", - "dcraw_matrix": [ 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 ], - "ranges": { "black": 768, "white": 16300 } - }, - { // Quality A, // correction for BL 147 to 150 and color matrix - "make_model": "Nikon D3300", - "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // matrix from adobe dcp d65 - "ranges": { "black": 150, "white": 4095 } - }, + // { // Quality A, new model, not in dcraw 9.20, conflict with D4 in dcraw 9.20, sRAW format not supported + // "make_model": "Nikon D4s", + // "dcraw_matrix": [ 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 ], + // "ranges": { "black": 768, "white": 16300 } + // }, + // { // Quality A, // correction for BL 147 to 150 and color matrix + // "make_model": "Nikon D3300", + // "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // matrix from adobe dcp d65 + // "ranges": { "black": 150, "white": 4095 } + // }, // { // Quality B, does not work with 12bit files - experimenting with matrices // "make_model": "Nikon D5300", // "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // matrix from adobe dcp d65 // "dcraw_matrix": [ 7009,-1699,-414,-5209,12641,2886,-1201,1904,7229 ], // Calculated from DxO d50 -// "ranges": { "black": 600 } +// "ranges": { "black": 600 } // attention .. this is for 14bit files and has to be 150 for 12bit files // }, { // quality B, lacks WL measures at intermediate ISOs (160-250-320 ..) and measures at long exposures with LongExposureNoiseReduction @@ -736,23 +740,120 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "ranges": { "white": 4040 } // nominal 4056 }, - { // Quality B + /* since Dcraw_v9.21 Panasonic base BL is read from exif (tags 0x001c BlackLevelRed15 is BL offstet. + Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue + and we define here the needed offset of around 15. The total BL is base+offset */ + + { // Quality A , replicated from rawimage.cc + "make_model": "Panasonic DMC-FZ150", + "dcraw_matrix": [ 10435,-3208,-72,-2293,10506,2067,-486,1725,4682 ], // RT + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + }, + { // Quality A "make_model": "Panasonic DMC-LF1", "dcraw_matrix": [ 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 ], - "ranges": { "black": 143, "white": 4080 } // BL is floating and should be extracted from exif + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset }, - { // Quality B + { // Quality A "make_model": [ "Panasonic DMC-TZ60", "Panasonic DMC-TZ61", "Panasonic DMC-ZS40", "Panasonic DMC-ZS41" ], "dcraw_matrix": [ 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 ], // matrix from Adobe dcp v8.4 "raw_crop": [ 8, 8, 4904, 3680 ], // crop according to exif 4896 X 3672 plus 4 pixels borders. RT's frame gets smaller than Dcraw but works better with auto distortion - "ranges": { "black": 143, "white": 4050 } // BL is floating and should be extracted from exif + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + }, + + // Panasonic DMC-FZ150,G10,G1,G2,G3,G5,GF1,GF2,GF3 are included as overwrites of the same items of rawimage.cc to test the Dcraw9.21 patch + + { // Quality A, Replicated from rawimage.cc + "make_model": [ "Panasonic DMC-G10", "Panasonic DMC-G2" ], + "dcraw_matrix": [ 8310,-1811,-960,-4941,12990,2151,-1378,2468,6860 ], // Colin Walker + "ranges": { + "black": 15, // 15 is black offset, Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:3967 distribution peak at 3967 +/- up to 50 + { "iso": [ 1600, 3200, 6400 ], "levels": 4060 } // exif 3967, histogram peak 4095 and distribution down to 4070 + ] + } + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-G1", + "dcraw_matrix": [ 7477,-1615,-651,-5016,12769,2506,-1380,2475,7240 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 + { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-G3", + "dcraw_matrix": [ 6051,-1406,-671,-4015,11505,2868,-1654,2667,6219 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-G5", + "dcraw_matrix": [ 7122,-2092,-419,-4643,11769,3283,-1363,2413,5944 ], // RT + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GF1", + "dcraw_matrix": [ 7863,-2080,-668,-4623,12331,2578,-1020,2066,7266 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 + { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } + }, + + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GF2", + "dcraw_matrix": [ 7694,-1791,-745,-4917,12818,2332,-1221,2322,7197 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GF3", + "dcraw_matrix": [ 8074,-1846,-861,-5026,12999,2239,-1320,2375,7422 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GH1", + "dcraw_matrix": [ 6360,-1557,-375,-4201,11504,3086,-1378,2518,5843 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 + { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GH2", + // "dcraw_matrix": [ 6855,-1765,-456,-4223,11600,2996,-1450,2602,5761 ], // Colin Walker - disabled due to problems with underwater + "dcraw_matrix": [ 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 ], // Dcraw d65 + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 + { "iso": [ 1600, 3200, 6400, 12800 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } }, { // Quality B, BL is floating and should be extracted from exif maker data "make_model": "Panasonic DMC-GH3", "dcraw_matrix": [ 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 ], // dcp d65 "ranges": { - "black": 144, + "black": 16, // 16 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 125, "levels": 3500 }, // gaussian 3600-4095 { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 @@ -764,7 +865,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-GH4", "dcraw_matrix": [ 5545,-878,-249,-4592,12128,2709,-1225,1928,5260 ], // calculated from dxo D50 matrix "ranges": { - "black": 144, // BL is floating and should be extracted from exif maker data + "black": 16, // // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 100, "levels": 2700 }, // gaussian center at 2870-2920 range +/- 150 { "iso": 125, "levels": 3100 }, // guessed @@ -773,11 +874,11 @@ Quality X: unknown, ie we knowing to little about the camera properties to know } }, - { // Quality B, BL is floating and should be extracted from exif maker data + { // Quality A, "make_model": "Panasonic DMC-GM1", "dcraw_matrix": [ 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 ], "ranges": { - "black": 143, + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 125, "levels": 3100 }, // bell shape 3150-3650 - exif 2616 { "iso": 160, "levels": 3600 }, // guessed from relative GX7 data @@ -785,11 +886,11 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ] } }, - { // Quality B, BL is floating and should be extracted from exif maker data + { // Quality A, "make_model": "Panasonic DMC-GX7", "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ], "ranges": { - "black": 143, + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 125, "levels": 3100 }, { "iso": 160, "levels": 3600 }, @@ -815,7 +916,13 @@ Quality X: unknown, ie we knowing to little about the camera properties to know } }, - { // Quality A, Conflict with Samsung NX in Dcraw.c-Dcraw.cc if not included in camconst.json + { // Quality B, color looks bad with Dcraw matrix - corrections for raw crop vs Dcraw9.21, matched to Samsung's default + "make_model": "Samsung NX mini", + "dcraw_matrix": [ 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 ], // Dcraw921 + "raw_crop": [ 128, 36, 5480, 3656 ], // jpeg 5472x3648 - full raw: 5664 x 3710 - Samsung's official crop: 132, 40, 5604, 3688 + "ranges": { "white": 4030 } // double clipping point for each channel at a) 4095 and b) bell distribution with peak at 4038 .. used the conservative one + }, + { // Quality A, "make_model": "Samsung NX30", "dcraw_matrix": [ 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 ] // D65 matrix from Adobe's Dcp profile - DxoD50 6661,-1695,-616,-6456,14646,1913,-1417,2142,5646 }, diff --git a/rtengine/dcraw.c b/rtengine/dcraw.c index 059153740..ed86154e0 100644 --- a/rtengine/dcraw.c +++ b/rtengine/dcraw.c @@ -19,11 +19,11 @@ *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". - $Revision: 1.461 $ - $Date: 2014/01/31 04:05:31 $ + $Revision: 1.463 $ + $Date: 2014/05/05 22:03:20 $ */ -#define DCRAW_VERSION "9.20" +#define DCRAW_VERSION "9.21" #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -161,7 +161,8 @@ struct tiff_ifd { } tiff_ifd[10]; struct ph1 { - int format, key_off, black, black_off, split_col, tag_21a; + int format, key_off, tag_21a; + int black, split_col, black_col, split_row, black_row; float tag_210; } ph1; @@ -372,6 +373,59 @@ void CLASS read_shorts (ushort *pixel, int count) swab (pixel, pixel, count*2); } +void CLASS cubic_spline (const int *x_, const int *y_, const int len) +{ + float A[2*len][2*len], b[2*len], c[2*len], d[2*len]; + float x[len], y[len]; + int i, j; + + memset (A, 0, sizeof(A)); + memset (b, 0, sizeof(b)); + memset (c, 0, sizeof(c)); + memset (d, 0, sizeof(d)); + for (i = 0; i < len; i++) { + x[i] = x_[i] / 65535.0; + y[i] = y_[i] / 65535.0; + } + for (i = len-1; i > 0; i--) { + b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]); + d[i-1] = x[i] - x[i-1]; + } + for (i = 1; i < len-1; i++) { + A[i][i] = 2 * (d[i-1] + d[i]); + if (i > 1) { + A[i][i-1] = d[i-1]; + A[i-1][i] = d[i-1]; + } + A[i][len-1] = 6 * (b[i+1] - b[i]); + } + for(i = 1; i < len-2; i++) { + float v = A[i+1][i] / A[i][i]; + for(j = 1; j <= len-1; j++) + A[i+1][j] -= v * A[i][j]; + } + for(i = len-2; i > 0; i--) { + float acc = 0; + for(j = i; j <= len-2; j++) + acc += A[i][j]*c[j]; + c[i] = (A[i][len-1] - acc) / A[i][i]; + } + for (i = 0; i < 0x10000; i++) { + float x_out = (float)(i / 65535.0); + float y_out = 0; + for (j = 0; j < len-1; j++) { + if (x[j] <= x_out && x_out <= x[j+1]) { + float v = x_out - x[j]; + y_out = y[j] + + ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j])/6) * v + + (c[j] * 0.5) * v*v + ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v; + } + } + curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 : + (ushort)(y_out * 65535.0 + 0.5)); + } +} + void CLASS canon_600_fixed_wb (int temp) { static const short mul[4][5] = { @@ -1310,14 +1364,16 @@ int CLASS raw (unsigned row, unsigned col) 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; @@ -1326,14 +1382,18 @@ void CLASS phase_one_flat_field (int is_float, int nc) } if (y==0) continue; rend = head[1] + y*head[5]; - for (row = rend-head[5]; row < raw_height && row < rend; row++) { + for (row = rend-head[5]; + row < raw_height && row < rend && + row < head[1]+head[3]-head[5]; row++) { for (x=1; x < wide; x++) { for (c=0; c < nc; c+=2) { mult[c] = mrow[c*wide+x-1]; mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; } cend = head[0] + x*head[4]; - for (col = cend-head[4]; col < raw_width && col < cend; col++) { + for (col = cend-head[4]; + col < raw_width && + col < cend && col < head[0]+head[2]-head[4]; col++) { c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0; if (!(c & 1)) { c = RAW(row,col) * mult[c]; @@ -1361,6 +1421,7 @@ void CLASS phase_one_correct() {-2,-2}, {-2,2}, {2,-2}, {2,2} }; float poly[8], num, cfrac, frac, mult[2], *yval[2]; ushort *xval[2]; + int qmult_applied = 0, qlin_applied = 0; if (half_size || !meta_length) return; if (verbose) fprintf (stderr,_("Phase One correction...\n")); @@ -1400,7 +1461,7 @@ void CLASS phase_one_correct() row = get2(); type = get2(); get2(); if (col >= raw_width) continue; - if (type == 131) /* Bad column */ + 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++) @@ -1437,6 +1498,83 @@ void CLASS phase_one_correct() 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] = (ushort)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[18], cf[18]; + for (i = 0; i < 16; i++) { + cx[1+i] = lc[qr][qc][i]; + cf[1+i] = ref[i]; + } + cx[0] = cf[0] = 0; + cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15]; + cubic_spline(cx, cf, 18); + + 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] = (ushort)get4(); + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 7; i++) + lc[qr][qc][i] = (ushort)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 int)ref[i] * lc[qr][qc][i]) / 10000; + } + cx[0] = cf[0] = 0; + cx[8] = cf[8] = 65535; + cubic_spline(cx, cf, 9); + for (row = (qr ? ph1.split_row : 0); + row < (qr ? raw_height : ph1.split_row); row++) + for (col = (qc ? ph1.split_col : 0); + col < (qc ? raw_width : ph1.split_col); col++) + RAW(row,col) = curve[RAW(row,col)]; + } + } + qmult_applied = 1; + qlin_applied = 1; } fseek (ifp, save, SEEK_SET); } @@ -1523,18 +1661,22 @@ 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++) { @@ -1558,8 +1700,10 @@ void CLASS phase_one_load_raw_c() pixel[col] = curve[pixel[col]]; } for (col=0; col < raw_width; col++) { - i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col]; - if (i > 0) RAW(row,col) = i; + i = (pixel[col] << 2) - ph1.black + + cblack[row][col >= ph1.split_col] + + rblack[col][row >= ph1.split_row]; + if (i > 0) RAW(row,col) = i; } } free (pixel); @@ -2099,6 +2243,8 @@ void CLASS kodak_jpeg_load_raw() 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; @@ -2107,29 +2253,34 @@ void CLASS lossy_dng_load_raw() JSAMPLE (*pixel)[3]; unsigned sorder=order, ntags, opcode, deg, i, j, c; unsigned save=data_offset-4, trow=0, tcol=0, row, col; - ushort curve[3][256]; + ushort cur[3][256]; double coeff[9], tot; - 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); - curve[c][i] = tot*0xffff; + 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]); } - order = sorder; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); while (trow < raw_height) { @@ -2146,7 +2297,7 @@ void CLASS lossy_dng_load_raw() 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] = curve[c][pixel[col][c]]; + FORC3 image[row*width+tcol+col][c] = cur[c][pixel[col][c]]; } } jpeg_abort_decompress (&cinfo); @@ -2416,23 +2567,20 @@ void CLASS sony_load_raw() void CLASS sony_arw_load_raw() { - ushort huff[32768]; + 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, len, diff, sum=0; + 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]; + 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 = getbithuff(15,huff); - diff = getbits(len); - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - if ((sum += diff) >> 12) derror(); + if ((sum += ljpeg_diff(huff)) >> 12) derror(); if (row < height) RAW(row,col) = sum; } } @@ -2500,6 +2648,28 @@ void CLASS samsung_load_raw() 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(); + } +} + #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ @@ -3455,8 +3625,10 @@ mask_set: 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]) + } 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() @@ -5333,8 +5505,12 @@ int CLASS parse_tiff_ifd (int base) 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; @@ -5443,6 +5619,8 @@ int CLASS parse_tiff_ifd (int base) 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; @@ -5489,7 +5667,16 @@ int CLASS parse_tiff_ifd (int base) 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) + xtrans[(c/6+top_margin)%6][(c+left_margin)%6] = fgetc(ifp) & 3; + break; + } case 64777: /* Kodak P-series */ if ((plen=len) > 16) plen = 16; fread (cfa_pat, 1, plen, ifp); @@ -5561,7 +5748,10 @@ int CLASS parse_tiff_ifd (int base) break; case 40976: strip_offset = get4(); - load_raw = &CLASS samsung_load_raw; + switch (tiff_ifd[ifd].comp) { + case 32770: load_raw = &CLASS samsung_load_raw; break; + case 32772: load_raw = &CLASS samsung2_load_raw; + } break; case 46275: /* Imacon tags */ strcpy (make, "Imacon"); @@ -5631,6 +5821,7 @@ int CLASS parse_tiff_ifd (int base) is_raw = 1; break; case 50710: /* CFAPlaneColor */ + if (filters == 9) break; if (len > 4) len = 4; colors = len; fread (cfa_pc, 1, colors, ifp); @@ -5863,6 +6054,8 @@ void CLASS apply_tiff() 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; } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; @@ -5882,7 +6075,7 @@ void CLASS apply_tiff() } if (!dng_version) if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && - tiff_compress != 32769 && tiff_compress != 32770) + (tiff_compress & -16) != 32768) || (tiff_bps == 8 && !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) is_raw = 0; @@ -6255,7 +6448,9 @@ void CLASS parse_phase_one (int base) case 0x21c: strip_offset = data+base; break; case 0x21d: ph1.black = data; break; case 0x222: ph1.split_col = data; break; - case 0x223: ph1.black_off = data+base; 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); @@ -6650,6 +6845,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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 M", 0, 0, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS-1Ds Mark III", 0, 0x3bb0, @@ -6858,6 +7055,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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, + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm XF1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm XQ1", 0, 0, @@ -6972,8 +7171,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, { "Nikon D3200", 0, 0xfb9, { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, - { "Nikon D3300", 147, 0, /* DJC */ - { 6108,-2161,-13,-4091,9871,4220,-1222,2469,7907 } }, + { "Nikon D3300", 150, 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, @@ -6986,6 +7185,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, { "Nikon D40", 0, 0, { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, + { "Nikon D4S", 768, 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, @@ -7054,6 +7255,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon COOLPIX P330", 0, 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, @@ -7064,6 +7267,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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", 200, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 V2", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 J3", 0, 0, @@ -7140,6 +7345,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, { "Olympus E-M5", 0, 0xfe1, @@ -7212,13 +7419,13 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, - { "Panasonic DMC-FZ3", 143, 0, + { "Panasonic DMC-FZ3", 15, 0, { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, - { "Panasonic DMC-FZ4", 143, 0, + { "Panasonic DMC-FZ4", 15, 0, { 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", 144, 0, + { "Panasonic DMC-FZ7", 15, 0, { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } }, { "Leica V-LUX1", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, @@ -7232,9 +7439,9 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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-LF1", 143, 0, + { "Panasonic DMC-LF1", 15, 0, { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, - { "Leica C (Typ 112)", 143, 0, + { "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 } }, @@ -7248,25 +7455,25 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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", 143, 0, + { "Panasonic DMC-LX5", 15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, - { "Leica D-LUX 5", 143, 0, + { "Leica D-LUX 5", 15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, - { "Panasonic DMC-LX7", 143, 0, + { "Panasonic DMC-LX7", 15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, - { "Leica D-LUX 6", 143, 0, + { "Leica D-LUX 6", 15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, - { "Panasonic DMC-FZ100", 143, 0xfff, + { "Panasonic DMC-FZ100", 15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, - { "Leica V-LUX 2", 143, 0xfff, + { "Leica V-LUX 2", 15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, - { "Panasonic DMC-FZ150", 143, 0xfff, + { "Panasonic DMC-FZ150", 15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, - { "Leica V-LUX 3", 143, 0xfff, + { "Leica V-LUX 3", 15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, - { "Panasonic DMC-FZ200", 143, 0xfff, + { "Panasonic DMC-FZ200", 15, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, - { "Leica V-LUX 4", 143, 0xfff, + { "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 } }, @@ -7276,36 +7483,38 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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", 143, 0xfff, + { "Panasonic DMC-G3", 15, 0xfff, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, - { "Panasonic DMC-G5", 143, 0xfff, + { "Panasonic DMC-G5", 15, 0xfff, { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, - { "Panasonic DMC-G6", 142, 0xfff, + { "Panasonic DMC-G6", 15, 0xfff, { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, { "Panasonic DMC-GF1", 15, 0xf92, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, - { "Panasonic DMC-GF2", 143, 0xfff, + { "Panasonic DMC-GF2", 15, 0xfff, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, - { "Panasonic DMC-GF3", 143, 0xfff, + { "Panasonic DMC-GF3", 15, 0xfff, { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, - { "Panasonic DMC-GF5", 143, 0xfff, + { "Panasonic DMC-GF5", 15, 0xfff, { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, - { "Panasonic DMC-GF6", 143, 0, + { "Panasonic DMC-GF6", 15, 0, { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, { "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", 144, 0, + { "Panasonic DMC-GH3", 15, 0, { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, - { "Panasonic DMC-GM1", 143, 0, + { "Panasonic DMC-GM1", 15, 0, { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } }, - { "Panasonic DMC-GX1", 143, 0, + { "Panasonic DMC-GX1", 15, 0, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, - { "Panasonic DMC-GX7", 143, 0, + { "Panasonic DMC-GX7", 15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, - { "Panasonic DMC-TZ61", 143, 0, /* DJC */ - { 6211,-2325,27,-3800,9449,4352,-943,2166,6293 } }, + { "Panasonic DMC-TZ6", 15, 0, + { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, + { "Panasonic DMC-ZS4", 15, 0, + { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, { "Phase One H 25", 0, 0, @@ -7328,7 +7537,9 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, { "Samsung EK-GN120", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, - { "Samsung NX300", 0, 0, + { "Samsung NX mini", 0, 0, + { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, + { "Samsung NX30", 0, 0, /* NX30, NX300 */ { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2000", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, @@ -7384,6 +7595,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A580", 128, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { "Sony DSLR-A500", 128, 0xfeb, + { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, { "Sony DSLR-A5", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A700", 128, 0, @@ -7396,10 +7609,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, { "Sony ILCE-7", 128, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE-3000", 128, 0, + { "Sony ILCE", 128, 0, /* 3000, 5000, and 6000 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony ILCE-5000", 128, 0, /* DJC */ - { 4130,-1407,93,-4151,9566,4586,-1035,1976,7000 } }, { "Sony NEX-5N", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony NEX-5R", 128, 0, @@ -7579,6 +7790,7 @@ void CLASS identify() { 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 }, { 4832, 3204, 62, 26, 0, 0 }, { 4832, 3228, 62, 51, 0, 0 }, @@ -7615,6 +7827,7 @@ void CLASS identify() { 0x326, "EOS 700D" }, { 0x250, "EOS 7D" }, { 0x254, "EOS 1000D" }, { 0x288, "EOS 1100D" }, + { 0x327, "EOS 1200D" }, { 0x346, "EOS 100D" }, }; static const struct { @@ -7677,7 +7890,7 @@ void CLASS identify() { 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","640x480" }, + { 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" }, @@ -7714,9 +7927,9 @@ void CLASS identify() { 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","3072x2048",68 }, - { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","4080x4080",68 }, - { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","4080x5440",68 }, + { 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" }, }; @@ -7743,7 +7956,7 @@ void CLASS identify() 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; + 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; @@ -8287,6 +8500,11 @@ konica_400z: 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; } else if (!strcmp(model,"EX1")) { order = 0x4949; height -= 20; @@ -8466,15 +8684,23 @@ konica_400z: adobe_coeff ("Sony","DSC-R1"); width = 3925; order = 0x4d4d; + } else if (!strcmp(make,"Sony") && raw_width == 4928) { + if (height < 3280) width -= 8; } else if (!strcmp(make,"Sony") && raw_width == 5504) { - width -= 8; + width -= height > 3664 ? 8 : 32; } 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(model,"DSLR-A100")) { if (width == 3880) { height--; width = ++raw_width; } else { + height -= 4; + width -= 4; order = 0x4d4d; load_flags = 2; } diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index e97b71106..c068a6f88 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -31,11 +31,11 @@ *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". - $Revision: 1.461 $ - $Date: 2014/01/31 04:05:31 $ + $Revision: 1.463 $ + $Date: 2014/05/05 22:03:20 $ */ -#define DCRAW_VERSION "9.20" +#define DCRAW_VERSION "9.21" #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -336,61 +336,57 @@ void CLASS read_shorts (ushort *pixel, int count) swab ((char*)pixel, (char*)pixel, count*2); } -/* spline interpolation to 16 bit curve */ -void CLASS cubic_spline(const int *x_, const int *y_, const int len) +void CLASS cubic_spline (const int *x_, const int *y_, const int len) { - float A[2*len][2*len], b[2*len], c[2*len], d[2*len]; - float x[len], y[len]; - int i, j; + float A[2*len][2*len], b[2*len], c[2*len], d[2*len]; + float x[len], y[len]; + int i, j; - memset(A, 0, sizeof(A)); - memset(b, 0, sizeof(b)); - memset(c, 0, sizeof(c)); - memset(d, 0, sizeof(d)); - for (i = 0; i < len; i++) { - x[i] = x_[i] / 65535.0; - y[i] = y_[i] / 65535.0; + memset (A, 0, sizeof(A)); + memset (b, 0, sizeof(b)); + memset (c, 0, sizeof(c)); + memset (d, 0, sizeof(d)); + for (i = 0; i < len; i++) { + x[i] = x_[i] / 65535.0; + y[i] = y_[i] / 65535.0; + } + for (i = len-1; i > 0; i--) { + b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]); + d[i-1] = x[i] - x[i-1]; + } + for (i = 1; i < len-1; i++) { + A[i][i] = 2 * (d[i-1] + d[i]); + if (i > 1) { + A[i][i-1] = d[i-1]; + A[i-1][i] = d[i-1]; } - - for (i = len-1; i > 0; i--) { - b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]); - d[i-1] = x[i] - x[i-1]; - } - for (i = 1; i < len-1; i++) { - A[i][i] = 2 * (d[i-1] + d[i]); - if (i > 1) { - A[i][i-1] = d[i-1]; - A[i-1][i] = d[i-1]; - } - A[i][len-1] = 6 * (b[i+1] - b[i]); - } - for(i = 1; i < len-2; i++) { - float v = A[i+1][i] / A[i][i]; - for(j = 1; j <= len-1; j++) { - A[i+1][j] -= v * A[i][j]; - } - } - for(i = len-2; i > 0; i--) { - float acc = 0; - for(j = i; j <= len-2; j++) { - acc += A[i][j]*c[j]; - } - c[i] = (A[i][len-1] - acc) / A[i][i]; - } - for (i = 0; i < 0x10000; i++) { - float x_out = (float)(i / 65535.0); - float y_out = 0; - for (j = 0; j < len-1; j++) { - if (x[j] <= x_out && x_out <= x[j+1]) { - float v = x_out - x[j]; - y_out = y[j] + - ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j]) / 6) * v + - (c[j] * 0.5) * v*v + - ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v; - } - } - curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 : (ushort)nearbyintf(y_out * 65535.0)); + 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)); + } } void CLASS canon_600_fixed_wb (int temp) @@ -1335,7 +1331,7 @@ void CLASS phase_one_flat_field (int is_float, int nc) float *mrow, num, mult[4]; read_shorts (head, 8); - if (head[2] == 0 || head[3] == 0 || head[4] == 0 || head[5] == 0) return; // RT: should not really happen, but when reverse-engineering IIQ files zero'd calibration data was used, so it's nice if not crashing. + 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); @@ -1349,14 +1345,18 @@ void CLASS phase_one_flat_field (int is_float, int nc) } if (y==0) continue; 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 (row = rend-head[5]; + row < raw_height && row < rend && + row < head[1]+head[3]-head[5]; row++) { for (x=1; x < wide; x++) { for (c=0; c < nc; c+=2) { mult[c] = mrow[c*wide+x-1]; mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; } cend = head[0] + x*head[4]; - for (col = cend-head[4]; col < raw_width && col < cend && col < head[0]+head[2]-head[4]; col++) { + for (col = cend-head[4]; + col < raw_width && + col < cend && col < head[0]+head[2]-head[4]; col++) { c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0; if (!(c & 1)) { c = RAW(row,col) * mult[c]; @@ -1424,7 +1424,7 @@ void CLASS phase_one_correct() row = get2(); type = get2(); get2(); if (col >= raw_width) continue; - if (type == 131) /* Bad column */ + 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++) @@ -1461,154 +1461,83 @@ void CLASS phase_one_correct() mindiff = diff; off_412 = ftell(ifp) - 38; } - } else if (tag == 0x41f && !qlin_applied) { /* Per quadrant linearization, P40+/P65+ */ - ushort lc[2][2][16], ref[16]; - int qr, qc; - /* Get curves for each quadrant (ordered top left, top right, bottom left, bottom right) */ - for (qr = 0; qr < 2; qr++) { - for (qc = 0; qc < 2; qc++) { - for (i = 0; i < 16; i++) { - lc[qr][qc][i] = (ushort)get4(); - } - } + } 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] = (ushort)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[18], cf[18]; + for (i = 0; i < 16; i++) { + cx[1+i] = lc[qr][qc][i]; + cf[1+i] = ref[i]; + } + cx[0] = cf[0] = 0; + cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15]; + cubic_spline(cx, cf, 18); + + 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] = (ushort)get4(); + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 7; i++) + lc[qr][qc][i] = (ushort)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 int)ref[i] * lc[qr][qc][i]) / 10000; + } + cx[0] = cf[0] = 0; + cx[8] = cf[8] = 65535; + cubic_spline(cx, cf, 9); + for (row = (qr ? ph1.split_row : 0); + row < (qr ? raw_height : ph1.split_row); row++) + for (col = (qc ? ph1.split_col : 0); + col < (qc ? raw_width : ph1.split_col); col++) + RAW(row,col) = curve[RAW(row,col)]; } - /* - Each curve hold values along some exponential function, from ~20 to about ~50000, example: - 28 41 64 106 172 282 462 762 1240 2353 5111 10127 17867 27385 39122 58451 - */ - - /* Derive a reference curve, by taking the average value in each column. Note: seems to work well, - but not 100% sure this is how the reference curve should be derived. */ - for (i = 0; i < 16; i++) { - int v = 0; - for (qr = 0; qr < 2; qr++) { - for (qc = 0; qc < 2; qc++) { - v += lc[qr][qc][i]; - } - } - ref[i] = (v + 2) >> 2; - } - - /* Interpolate full calibration curves and apply. Spline interpolation used here, - as the curves are so coarsely specified and would get sharp corners if linearly - interpolated. */ - for (qr = 0; qr < 2; qr++) { - for (qc = 0; qc < 2; qc++) { - int cx[18]; - int cf[18]; - for (i = 0; i < 16; i++) { - cx[1+i] = lc[qr][qc][i]; - cf[1+i] = ref[i]; - } - cx[0] = cf[0] = 0; - cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15]; - cubic_spline(cx, cf, 18); - /* Apply curve in designated quadrant */ - for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { - for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) { - RAW(row,col) = curve[RAW(row,col)]; - } - } - } - } - /* By some unknown reason some backs provide more than one copy of this tag, make sure - that we only apply this once. */ - qlin_applied = 1; - } else if (tag == 0x41e && !qmult_applied) { /* Per quadrant multipliers P40+/P65+ */ - float qmult[2][2] = { { 1, 1 }, { 1, 1 } }; - - /* - This tag has not been fully reverse-engineered, seems to be used only on P40+ and P65+ backs, - and will then have most values set to zero. - - Layout: - - - First 4 bytes contains 'II' (or 'MM' I guess if file is big endian, but don't think there are - any such backs produced) plus short integer 1 - - The remaining 80 bytes seems to be 20 floats, most of them always zero. Example contents, - with map: - - 0.000000, 0.000000, 0.080410, 0.078530, - 0.000000, 0.000000, 0.000000, 0.000000, - 0.104100, 0.103500, 0.000000, 0.000000, - 0.000000, 0.000000, 0.000000, 0.000000, - 0.089540, 0.092230, 0.000000, 0.000000 - - noeffect, noeffect, noeffect, topleft , - noeffect, TL++ , global , noeffect, - noeffect, topright, , TR++ , - , bottmlft, , BL++ , - noeffect, bottmrgt, , BR++ , - - 'noeffect' tested with no effect, empty not tested, the ++ versions are stronger effect - multpliers that doesn't seem to be used, the global multiplier seems to unused as well. - - It seems like one quadrant always is generally used as reference, (ie value 0 => multiplier 1.0), - but it's not always the same quadrant for different backs. - - The 'noeffect' fields which actually have values are suspicious, maybe these multipliers are - used in Sensor+ or at some different ISO or something? They seem to be close to the ordinary - multipliers though so using the 'wrong' ones in some special case should yield quite good - result still. - */ - - /* We only read out the multipliers that are used and seem to have any effect and are used */ - get4(); get4(); get4(); get4(); - qmult[0][0] = 1.0 + getreal(11); - get4(); get4(); get4(); get4(); get4(); - qmult[0][1] = 1.0 + getreal(11); - get4(); get4(); get4(); - qmult[1][0] = 1.0 + getreal(11); - get4(); get4(); get4(); - qmult[1][1] = 1.0 + getreal(11); - for (row=0; row < raw_height; row++) { - for (col=0; col < raw_width; col++) { - i = qmult[row >= ph1.split_row][col >= ph1.split_col] * RAW(row,col); - RAW(row,col) = LIM(i,0,65535); - } - } - /* By some unknown reason some backs provide more than one copy of this tag, make sure - that we only apply this once. */ - qmult_applied = 1; - } else if (tag == 0x431 && !qmult_applied) { /* Per quadrant multiplication and linearization, IQ series backs */ - ushort lc[2][2][7], ref[7]; - int qr, qc; - - /* Read reference curve */ - for (i = 0; i < 7; i++) { - ref[i] = (ushort)get4(); - } - - /* Get multipliers for each quadrant */ - for (qr = 0; qr < 2; qr++) { - for (qc = 0; qc < 2; qc++) { - for (i = 0; i < 7; i++) { - lc[qr][qc][i] = (ushort)get4(); - } - } - } - /* Spline interpolation and apply in each quadrant */ - for (qr = 0; qr < 2; qr++) { - for (qc = 0; qc < 2; qc++) { - int cx[9]; - int cf[9]; - for (i = 0; i < 7; i++) { - cx[1+i] = ref[i]; - cf[1+i] = ((unsigned int)ref[i] * lc[qr][qc][i]) / 10000; - } - cx[0] = cf[0] = 0; - cx[8] = cf[8] = 65535; - cubic_spline(cx, cf, 9); - for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { - for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) { - RAW(row,col) = curve[RAW(row,col)]; - } - } - } - } - /* not seen any backs that have this tag multiplied, but just to make sure */ - qmult_applied = 1; - qlin_applied = 1; + } + qmult_applied = 1; + qlin_applied = 1; } fseek (ifp, save, SEEK_SET); } @@ -1695,23 +1624,22 @@ 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], (*black2)[2]; + short (*cblack)[2], (*rblack)[2]; - black2 = (short (*)[2]) calloc (raw_width*2, 2); - merror (black2, "phase_one_load_raw_c()"); - pixel = (ushort *) calloc (raw_width + raw_height*4, 2); + 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); - fseek (ifp, ph1.black_off2, SEEK_SET); - if (ph1.black_off2) - read_shorts ((ushort *) black2[0], raw_width*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++) { @@ -1735,12 +1663,13 @@ void CLASS phase_one_load_raw_c() pixel[col] = curve[pixel[col]]; } for (col=0; col < raw_width; col++) { - i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col] + black2[col][row >= ph1.split_row]; - if (i > 0) RAW(row,col) = i; + i = (pixel[col] << 2) - ph1.black + + cblack[row][col >= ph1.split_col] + + rblack[col][row >= ph1.split_row]; + if (i > 0) RAW(row,col) = i; } } free (pixel); - free (black2); maximum = 0xfffc - ph1.black; } @@ -2277,6 +2206,8 @@ void CLASS kodak_jpeg_load_raw() 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; @@ -2285,29 +2216,34 @@ void CLASS lossy_dng_load_raw() JSAMPLE (*pixel)[3]; unsigned sorder=order, ntags, opcode, deg, i, j, c; unsigned save=data_offset-4, trow=0, tcol=0, row, col; - ushort curve[3][256]; + ushort cur[3][256]; double coeff[9], tot; - 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); - curve[c][i] = tot*0xffff; + 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]); } - order = sorder; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); while (trow < raw_height) { @@ -2324,7 +2260,7 @@ void CLASS lossy_dng_load_raw() 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] = curve[c][pixel[col][c]]; + FORC3 image[row*width+tcol+col][c] = cur[c][pixel[col][c]]; } } jpeg_abort_decompress (&cinfo); @@ -2593,23 +2529,20 @@ void CLASS sony_load_raw() void CLASS sony_arw_load_raw() { - ushort huff[32768]; + 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, len, diff, sum=0; + 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]; + 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 = getbithuff(15,huff); - diff = getbits(len); - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - if ((sum += diff) >> 12) derror(); + if ((sum += ljpeg_diff(huff)) >> 12) derror(); if (row < height) RAW(row,col) = sum; } } @@ -2679,6 +2612,28 @@ void CLASS samsung_load_raw() 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(); + } +} + #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ @@ -3637,8 +3592,10 @@ mask_set: 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]) + } 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() @@ -5182,8 +5139,12 @@ int CLASS parse_tiff_ifd (int base) 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; @@ -5296,6 +5257,8 @@ int CLASS parse_tiff_ifd (int base) 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; @@ -5348,7 +5311,16 @@ int CLASS parse_tiff_ifd (int base) 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) + xtrans[(c/6+top_margin)%6][(c+left_margin)%6] = fgetc(ifp) & 3; + break; + } case 64777: /* Kodak P-series */ if ((plen=len) > 16) plen = 16; fread (cfa_pat, 1, plen, ifp); @@ -5420,7 +5392,10 @@ int CLASS parse_tiff_ifd (int base) break; case 40976: strip_offset = get4(); - load_raw = &CLASS samsung_load_raw; + switch (tiff_ifd[ifd].comp) { + case 32770: load_raw = &CLASS samsung_load_raw; break; + case 32772: load_raw = &CLASS samsung2_load_raw; + } break; case 46275: /* Imacon tags */ strcpy (make, "Imacon"); @@ -5493,6 +5468,7 @@ int CLASS parse_tiff_ifd (int base) fgets (model3, 64, ifp); break; case 50710: /* CFAPlaneColor */ + if (filters == 9) break; if (len > 4) len = 4; colors = len; fread (cfa_pc, 1, colors, ifp); @@ -5740,6 +5716,8 @@ void CLASS apply_tiff() 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; } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; @@ -5760,7 +5738,7 @@ void CLASS apply_tiff() } if (!dng_version) if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && - tiff_compress != 32769 && tiff_compress != 32770) + (tiff_compress & -16) != 32768) || (tiff_bps == 8 && !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) is_raw = 0; @@ -6134,9 +6112,9 @@ void CLASS parse_phase_one (int base) case 0x21c: strip_offset = data+base; break; case 0x21d: ph1.black = data; break; case 0x222: ph1.split_col = data; break; - case 0x223: ph1.black_off = data+base; break; + case 0x223: ph1.black_col = data+base; break; case 0x224: ph1.split_row = data; break; - case 0x225: ph1.black_off2= data+base; break; + case 0x225: ph1.black_row = data+base; break; case 0x301: model[63] = 0; fread (model, 1, 63, ifp); @@ -6536,6 +6514,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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 M", 0, 0, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS-1Ds Mark III", 0, 0x3bb0, @@ -6744,6 +6724,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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, + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm XF1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm XQ1", 0, 0, @@ -6858,8 +6840,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, { "Nikon D3200", 0, 0xfb9, { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, - { "Nikon D3300", 147, 0, /* DJC */ - { 6108,-2161,-13,-4091,9871,4220,-1222,2469,7907 } }, + { "Nikon D3300", 150, 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, @@ -6872,6 +6854,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, { "Nikon D40", 0, 0, { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, + { "Nikon D4S", 768, 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, @@ -6940,6 +6924,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon COOLPIX P330", 0, 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, @@ -6950,6 +6936,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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", 200, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 V2", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 J3", 0, 0, @@ -7026,6 +7014,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, { "Olympus E-M5", 0, 0xfe1, @@ -7098,13 +7088,13 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, - { "Panasonic DMC-FZ3", 143, 0, + { "Panasonic DMC-FZ3", 15, 0, { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, - { "Panasonic DMC-FZ4", 143, 0, + { "Panasonic DMC-FZ4", 15, 0, { 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", 144, 0, + { "Panasonic DMC-FZ7", 15, 0, { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } }, { "Leica V-LUX1", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, @@ -7118,9 +7108,9 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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-LF1", 143, 0, + { "Panasonic DMC-LF1", 15, 0, { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, - { "Leica C (Typ 112)", 143, 0, + { "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 } }, @@ -7134,25 +7124,25 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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", 143, 0, + { "Panasonic DMC-LX5", 15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, - { "Leica D-LUX 5", 143, 0, + { "Leica D-LUX 5", 15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, - { "Panasonic DMC-LX7", 143, 0, + { "Panasonic DMC-LX7", 15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, - { "Leica D-LUX 6", 143, 0, + { "Leica D-LUX 6", 15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, - { "Panasonic DMC-FZ100", 143, 0xfff, + { "Panasonic DMC-FZ100", 15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, - { "Leica V-LUX 2", 143, 0xfff, + { "Leica V-LUX 2", 15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, - { "Panasonic DMC-FZ150", 143, 0xfff, + { "Panasonic DMC-FZ150", 15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, - { "Leica V-LUX 3", 143, 0xfff, + { "Leica V-LUX 3", 15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, - { "Panasonic DMC-FZ200", 143, 0xfff, + { "Panasonic DMC-FZ200", 15, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, - { "Leica V-LUX 4", 143, 0xfff, + { "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 } }, @@ -7162,36 +7152,38 @@ void CLASS adobe_coeff (const char *make, const char *model) { 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", 143, 0xfff, + { "Panasonic DMC-G3", 15, 0xfff, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, - { "Panasonic DMC-G5", 143, 0xfff, + { "Panasonic DMC-G5", 15, 0xfff, { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, - { "Panasonic DMC-G6", 142, 0xfff, + { "Panasonic DMC-G6", 15, 0xfff, { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, { "Panasonic DMC-GF1", 15, 0xf92, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, - { "Panasonic DMC-GF2", 143, 0xfff, + { "Panasonic DMC-GF2", 15, 0xfff, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, - { "Panasonic DMC-GF3", 143, 0xfff, + { "Panasonic DMC-GF3", 15, 0xfff, { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, - { "Panasonic DMC-GF5", 143, 0xfff, + { "Panasonic DMC-GF5", 15, 0xfff, { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, - { "Panasonic DMC-GF6", 143, 0, + { "Panasonic DMC-GF6", 15, 0, { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, { "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", 144, 0, + { "Panasonic DMC-GH3", 15, 0, { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, - { "Panasonic DMC-GM1", 143, 0, + { "Panasonic DMC-GM1", 15, 0, { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } }, - { "Panasonic DMC-GX1", 143, 0, + { "Panasonic DMC-GX1", 15, 0, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, - { "Panasonic DMC-GX7", 143, 0, + { "Panasonic DMC-GX7", 15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, - { "Panasonic DMC-TZ61", 143, 0, /* DJC */ - { 6211,-2325,27,-3800,9449,4352,-943,2166,6293 } }, + { "Panasonic DMC-TZ6", 15, 0, + { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, + { "Panasonic DMC-ZS4", 15, 0, + { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, { "Phase One H 25", 0, 0, @@ -7214,7 +7206,9 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, { "Samsung EK-GN120", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, - { "Samsung NX300", 0, 0, + { "Samsung NX mini", 0, 0, + { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, + { "Samsung NX30", 0, 0, /* NX30, NX300 */ { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2000", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, @@ -7270,6 +7264,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A580", 128, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { "Sony DSLR-A500", 128, 0xfeb, + { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, { "Sony DSLR-A5", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A700", 128, 0, @@ -7282,10 +7278,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, { "Sony ILCE-7", 128, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE-3000", 128, 0, + { "Sony ILCE", 128, 0, /* 3000, 5000, and 6000 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony ILCE-5000", 128, 0, /* DJC */ - { 4130,-1407,93,-4151,9566,4586,-1035,1976,7000 } }, { "Sony NEX-5N", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony NEX-5R", 128, 0, @@ -7486,6 +7480,7 @@ void CLASS identify() { 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 }, { 4832, 3204, 62, 26, 0, 0 }, { 4832, 3228, 62, 51, 0, 0 }, @@ -7522,6 +7517,7 @@ void CLASS identify() { 0x326, "EOS 700D" }, { 0x250, "EOS 7D" }, { 0x254, "EOS 1000D" }, { 0x288, "EOS 1100D" }, + { 0x327, "EOS 1200D" }, { 0x346, "EOS 100D" }, }; static const struct { @@ -7584,7 +7580,7 @@ void CLASS identify() { 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","640x480" }, + { 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" }, @@ -7621,9 +7617,9 @@ void CLASS identify() { 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","3072x2048",68 }, - { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","4080x4080",68 }, - { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","4080x5440",68 }, + { 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" }, }; @@ -7650,7 +7646,7 @@ void CLASS identify() 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; + 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; @@ -8206,6 +8202,11 @@ konica_400z: 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; } else if (!strcmp(model,"EX1")) { order = 0x4949; height -= 20; @@ -8406,15 +8407,23 @@ konica_400z: adobe_coeff ("Sony","DSC-R1"); width = 3925; order = 0x4d4d; + } else if (!strcmp(make,"Sony") && raw_width == 4928) { + if (height < 3280) width -= 8; } else if (!strcmp(make,"Sony") && raw_width == 5504) { - width -= 8; + width -= height > 3664 ? 8 : 32; } 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(model,"DSLR-A100")) { if (width == 3880) { height--; width = ++raw_width; } else { + height -= 4; + width -= 4; order = 0x4d4d; load_flags = 2; } diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index f9a7b4463..d5357cc53 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -129,8 +129,9 @@ protected: } tiff_ifd[10]; struct ph1 { - int format, key_off, black, black_off, black_off2, split_col, split_row, tag_21a; - float tag_210; + int format, key_off, tag_21a; + int black, split_col, black_col, split_row, black_row; + float tag_210; } ph1; struct jhead { @@ -281,7 +282,7 @@ void minolta_rd175_load_raw(); void quicktake_100_load_raw(); void kodak_radc_load_raw(); void samsung_load_raw(); - +void samsung2_load_raw(); void kodak_jpeg_load_raw(); void lossy_dng_load_raw(); void kodak_dc120_load_raw(); diff --git a/rtengine/dcraw.patch b/rtengine/dcraw.patch index 03feaca93..526c89e19 100755 --- a/rtengine/dcraw.patch +++ b/rtengine/dcraw.patch @@ -1,5 +1,5 @@ ---- dcraw.c 2014-02-19 17:25:45.051457734 +0100 -+++ dcraw.cc 2014-05-26 14:28:48.785835594 +0200 +--- dcraw.c 2014-06-17 19:24:34 +0000 ++++ dcraw.cc 2014-06-17 19:58:03 +0000 @@ -1,3 +1,15 @@ +/*RT*/#include +/*RT*/#include @@ -52,7 +52,7 @@ #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp -@@ -98,87 +109,38 @@ +@@ -98,88 +109,38 @@ #define LONG_BIT (8 * sizeof (long)) #endif @@ -127,7 +127,8 @@ -} tiff_ifd[10]; - -struct ph1 { -- int format, key_off, black, black_off, split_col, tag_21a; +- int format, key_off, tag_21a; +- int black, split_col, black_col, split_row, black_row; - float tag_210; -} ph1; @@ -156,7 +157,7 @@ #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } /* -@@ -254,6 +216,7 @@ +@@ -255,6 +216,7 @@ if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15]; if (filters == 9) return xtrans[(row+top_margin+6)%6][(col+left_margin+6)%6]; @@ -164,7 +165,7 @@ return FC(row,col); } -@@ -296,6 +259,7 @@ +@@ -297,6 +259,7 @@ fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } data_error++; @@ -172,73 +173,16 @@ } ushort CLASS sget2 (uchar *s) -@@ -369,7 +333,64 @@ +@@ -370,7 +333,7 @@ { if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) - swab (pixel, pixel, count*2); + swab ((char*)pixel, (char*)pixel, count*2); -+} -+ -+/* spline interpolation to 16 bit curve */ -+void CLASS cubic_spline(const int *x_, const int *y_, const int len) -+{ -+ float A[2*len][2*len], b[2*len], c[2*len], d[2*len]; -+ float x[len], y[len]; -+ int i, j; -+ -+ memset(A, 0, sizeof(A)); -+ memset(b, 0, sizeof(b)); -+ memset(c, 0, sizeof(c)); -+ memset(d, 0, sizeof(d)); -+ for (i = 0; i < len; i++) { -+ x[i] = x_[i] / 65535.0; -+ y[i] = y_[i] / 65535.0; -+ } -+ -+ for (i = len-1; i > 0; i--) { -+ b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]); -+ d[i-1] = x[i] - x[i-1]; -+ } -+ for (i = 1; i < len-1; i++) { -+ A[i][i] = 2 * (d[i-1] + d[i]); -+ if (i > 1) { -+ A[i][i-1] = d[i-1]; -+ A[i-1][i] = d[i-1]; -+ } -+ A[i][len-1] = 6 * (b[i+1] - b[i]); -+ } -+ for(i = 1; i < len-2; i++) { -+ float v = A[i+1][i] / A[i][i]; -+ for(j = 1; j <= len-1; j++) { -+ A[i+1][j] -= v * A[i][j]; -+ } -+ } -+ for(i = len-2; i > 0; i--) { -+ float acc = 0; -+ for(j = i; j <= len-2; j++) { -+ acc += A[i][j]*c[j]; -+ } -+ c[i] = (A[i][len-1] - acc) / A[i][i]; -+ } -+ for (i = 0; i < 0x10000; i++) { -+ float x_out = (float)(i / 65535.0); -+ float y_out = 0; -+ for (j = 0; j < len-1; j++) { -+ if (x[j] <= x_out && x_out <= x[j+1]) { -+ float v = x_out - x[j]; -+ y_out = y[j] + -+ ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j]) / 6) * v + -+ (c[j] * 0.5) * v*v + -+ ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v; -+ } -+ } -+ curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 : (ushort)nearbyintf(y_out * 65535.0)); -+ } } - void CLASS canon_600_fixed_wb (int temp) -@@ -541,10 +562,10 @@ + void CLASS cubic_spline (const int *x_, const int *y_, const int len) +@@ -595,10 +558,10 @@ return 0; } @@ -252,7 +196,7 @@ unsigned c; if (nbits > 25) return 0; -@@ -1209,14 +1230,14 @@ +@@ -1263,14 +1226,14 @@ int i, nz; char tail[424]; @@ -269,207 +213,7 @@ void CLASS ppm_thumb() { -@@ -1310,14 +1331,16 @@ - void CLASS phase_one_flat_field (int is_float, int nc) - { - ushort head[8]; -- unsigned wide, y, x, c, rend, cend, row, col; -+ unsigned wide, high, y, x, c, rend, cend, row, col; - float *mrow, num, mult[4]; - - read_shorts (head, 8); -- wide = head[2] / head[4]; -+ if (head[2] == 0 || head[3] == 0 || head[4] == 0 || head[5] == 0) return; // RT: should not really happen, but when reverse-engineering IIQ files zero'd calibration data was used, so it's nice if not crashing. -+ wide = head[2] / head[4] + (head[2] % head[4] != 0); -+ high = head[3] / head[5] + (head[3] % head[5] != 0); - mrow = (float *) calloc (nc*wide, sizeof *mrow); - merror (mrow, "phase_one_flat_field()"); -- for (y=0; y < head[3] / head[5]; y++) { -+ for (y=0; y < high; y++) { - for (x=0; x < wide; x++) - for (c=0; c < nc; c+=2) { - num = is_float ? getreal(11) : get2()/32768.0; -@@ -1326,14 +1349,14 @@ - } - if (y==0) continue; - rend = head[1] + y*head[5]; -- for (row = rend-head[5]; row < raw_height && row < rend; row++) { -+ for (row = rend-head[5]; row < raw_height && row < rend && row < head[1]+head[3]-head[5]; row++) { - for (x=1; x < wide; x++) { - for (c=0; c < nc; c+=2) { - mult[c] = mrow[c*wide+x-1]; - mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; - } - cend = head[0] + x*head[4]; -- for (col = cend-head[4]; col < raw_width && col < cend; col++) { -+ for (col = cend-head[4]; col < raw_width && col < cend && col < head[0]+head[2]-head[4]; col++) { - c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0; - if (!(c & 1)) { - c = RAW(row,col) * mult[c]; -@@ -1361,6 +1384,7 @@ - {-2,-2}, {-2,2}, {2,-2}, {2,2} }; - float poly[8], num, cfrac, frac, mult[2], *yval[2]; - ushort *xval[2]; -+ int qmult_applied = 0, qlin_applied = 0; - - if (half_size || !meta_length) return; - if (verbose) fprintf (stderr,_("Phase One correction...\n")); -@@ -1437,6 +1461,154 @@ - mindiff = diff; - off_412 = ftell(ifp) - 38; - } -+ } else if (tag == 0x41f && !qlin_applied) { /* Per quadrant linearization, P40+/P65+ */ -+ ushort lc[2][2][16], ref[16]; -+ int qr, qc; -+ /* Get curves for each quadrant (ordered top left, top right, bottom left, bottom right) */ -+ for (qr = 0; qr < 2; qr++) { -+ for (qc = 0; qc < 2; qc++) { -+ for (i = 0; i < 16; i++) { -+ lc[qr][qc][i] = (ushort)get4(); -+ } -+ } -+ } -+ /* -+ Each curve hold values along some exponential function, from ~20 to about ~50000, example: -+ 28 41 64 106 172 282 462 762 1240 2353 5111 10127 17867 27385 39122 58451 -+ */ -+ -+ /* Derive a reference curve, by taking the average value in each column. Note: seems to work well, -+ but not 100% sure this is how the reference curve should be derived. */ -+ for (i = 0; i < 16; i++) { -+ int v = 0; -+ for (qr = 0; qr < 2; qr++) { -+ for (qc = 0; qc < 2; qc++) { -+ v += lc[qr][qc][i]; -+ } -+ } -+ ref[i] = (v + 2) >> 2; -+ } -+ -+ /* Interpolate full calibration curves and apply. Spline interpolation used here, -+ as the curves are so coarsely specified and would get sharp corners if linearly -+ interpolated. */ -+ for (qr = 0; qr < 2; qr++) { -+ for (qc = 0; qc < 2; qc++) { -+ int cx[18]; -+ int cf[18]; -+ for (i = 0; i < 16; i++) { -+ cx[1+i] = lc[qr][qc][i]; -+ cf[1+i] = ref[i]; -+ } -+ cx[0] = cf[0] = 0; -+ cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15]; -+ cubic_spline(cx, cf, 18); -+ /* Apply curve in designated quadrant */ -+ for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { -+ for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) { -+ RAW(row,col) = curve[RAW(row,col)]; -+ } -+ } -+ } -+ } -+ /* By some unknown reason some backs provide more than one copy of this tag, make sure -+ that we only apply this once. */ -+ qlin_applied = 1; -+ } else if (tag == 0x41e && !qmult_applied) { /* Per quadrant multipliers P40+/P65+ */ -+ float qmult[2][2] = { { 1, 1 }, { 1, 1 } }; -+ -+ /* -+ This tag has not been fully reverse-engineered, seems to be used only on P40+ and P65+ backs, -+ and will then have most values set to zero. -+ -+ Layout: -+ -+ - First 4 bytes contains 'II' (or 'MM' I guess if file is big endian, but don't think there are -+ any such backs produced) plus short integer 1 -+ - The remaining 80 bytes seems to be 20 floats, most of them always zero. Example contents, -+ with map: -+ -+ 0.000000, 0.000000, 0.080410, 0.078530, -+ 0.000000, 0.000000, 0.000000, 0.000000, -+ 0.104100, 0.103500, 0.000000, 0.000000, -+ 0.000000, 0.000000, 0.000000, 0.000000, -+ 0.089540, 0.092230, 0.000000, 0.000000 -+ -+ noeffect, noeffect, noeffect, topleft , -+ noeffect, TL++ , global , noeffect, -+ noeffect, topright, , TR++ , -+ , bottmlft, , BL++ , -+ noeffect, bottmrgt, , BR++ , -+ -+ 'noeffect' tested with no effect, empty not tested, the ++ versions are stronger effect -+ multpliers that doesn't seem to be used, the global multiplier seems to unused as well. -+ -+ It seems like one quadrant always is generally used as reference, (ie value 0 => multiplier 1.0), -+ but it's not always the same quadrant for different backs. -+ -+ The 'noeffect' fields which actually have values are suspicious, maybe these multipliers are -+ used in Sensor+ or at some different ISO or something? They seem to be close to the ordinary -+ multipliers though so using the 'wrong' ones in some special case should yield quite good -+ result still. -+ */ -+ -+ /* We only read out the multipliers that are used and seem to have any effect and are used */ -+ get4(); get4(); get4(); get4(); -+ qmult[0][0] = 1.0 + getreal(11); -+ get4(); get4(); get4(); get4(); get4(); -+ qmult[0][1] = 1.0 + getreal(11); -+ get4(); get4(); get4(); -+ qmult[1][0] = 1.0 + getreal(11); -+ get4(); get4(); get4(); -+ qmult[1][1] = 1.0 + getreal(11); -+ for (row=0; row < raw_height; row++) { -+ for (col=0; col < raw_width; col++) { -+ i = qmult[row >= ph1.split_row][col >= ph1.split_col] * RAW(row,col); -+ RAW(row,col) = LIM(i,0,65535); -+ } -+ } -+ /* By some unknown reason some backs provide more than one copy of this tag, make sure -+ that we only apply this once. */ -+ qmult_applied = 1; -+ } else if (tag == 0x431 && !qmult_applied) { /* Per quadrant multiplication and linearization, IQ series backs */ -+ ushort lc[2][2][7], ref[7]; -+ int qr, qc; -+ -+ /* Read reference curve */ -+ for (i = 0; i < 7; i++) { -+ ref[i] = (ushort)get4(); -+ } -+ -+ /* Get multipliers for each quadrant */ -+ for (qr = 0; qr < 2; qr++) { -+ for (qc = 0; qc < 2; qc++) { -+ for (i = 0; i < 7; i++) { -+ lc[qr][qc][i] = (ushort)get4(); -+ } -+ } -+ } -+ /* Spline interpolation and apply in each quadrant */ -+ for (qr = 0; qr < 2; qr++) { -+ for (qc = 0; qc < 2; qc++) { -+ int cx[9]; -+ int cf[9]; -+ for (i = 0; i < 7; i++) { -+ cx[1+i] = ref[i]; -+ cf[1+i] = ((unsigned int)ref[i] * lc[qr][qc][i]) / 10000; -+ } -+ cx[0] = cf[0] = 0; -+ cx[8] = cf[8] = 65535; -+ cubic_spline(cx, cf, 9); -+ for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { -+ for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) { -+ RAW(row,col) = curve[RAW(row,col)]; -+ } -+ } -+ } -+ } -+ /* not seen any backs that have this tag multiplied, but just to make sure */ -+ qmult_applied = 1; -+ qlin_applied = 1; - } - fseek (ifp, save, SEEK_SET); - } -@@ -1494,10 +1666,10 @@ +@@ -1632,10 +1595,10 @@ } } @@ -483,43 +227,7 @@ unsigned c; if (nbits == -1) -@@ -1523,8 +1695,10 @@ - static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; - int *offset, len[2], pred[2], row, col, i, j; - ushort *pixel; -- short (*black)[2]; -+ short (*black)[2], (*black2)[2]; - -+ black2 = (short (*)[2]) calloc (raw_width*2, 2); -+ merror (black2, "phase_one_load_raw_c()"); - pixel = (ushort *) calloc (raw_width + raw_height*4, 2); - merror (pixel, "phase_one_load_raw_c()"); - offset = (int *) (pixel + raw_width); -@@ -1535,6 +1709,9 @@ - fseek (ifp, ph1.black_off, SEEK_SET); - if (ph1.black_off) - read_shorts ((ushort *) black[0], raw_height*2); -+ fseek (ifp, ph1.black_off2, SEEK_SET); -+ if (ph1.black_off2) -+ read_shorts ((ushort *) black2[0], raw_width*2); - for (i=0; i < 256; i++) - curve[i] = i*i / 3.969 + 0.5; - for (row=0; row < raw_height; row++) { -@@ -1558,11 +1735,12 @@ - pixel[col] = curve[pixel[col]]; - } - for (col=0; col < raw_width; col++) { -- i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col]; -+ i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col] + black2[col][row >= ph1.split_row]; - if (i > 0) RAW(row,col) = i; - } - } - free (pixel); -+ free (black2); - maximum = 0xfffc - ph1.black; - } - -@@ -1757,10 +1935,10 @@ +@@ -1901,10 +1864,10 @@ maximum = curve[0x3ff]; } @@ -533,7 +241,7 @@ int byte; if (!nbits) return vbits=0; -@@ -2049,11 +2227,11 @@ +@@ -2193,11 +2156,11 @@ METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { @@ -547,7 +255,7 @@ cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; -@@ -2371,10 +2549,9 @@ +@@ -2522,10 +2485,9 @@ maximum = (1 << (thumb_misc & 31)) - 1; } @@ -560,7 +268,7 @@ if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; -@@ -2462,11 +2639,13 @@ +@@ -2610,11 +2572,13 @@ bit += 7; } for (i=0; i < 16; i++, col+=2) @@ -575,7 +283,7 @@ } void CLASS samsung_load_raw() -@@ -2691,7 +2870,7 @@ +@@ -2861,7 +2825,7 @@ void CLASS foveon_decoder (unsigned size, unsigned code) { @@ -584,7 +292,7 @@ struct decode *cur; int i, len; -@@ -3414,10 +3593,13 @@ +@@ -3584,10 +3548,13 @@ } } } else { @@ -600,7 +308,7 @@ if (mask[0][3] > 0) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { -@@ -4011,239 +4193,8 @@ +@@ -4183,239 +4150,8 @@ } } @@ -609,8 +317,7 @@ - int code[16][16][32], size=16, *ip, sum[4]; - int f, c, i, x, y, row, col, shift, color; - ushort *pix; -+/* RT: delete interpolation functions */ - +- - if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); - if (filters == 9) size = 6; - border_interpolate(1); @@ -652,7 +359,8 @@ - This algorithm is officially called: - - "Interpolation using a Threshold-based variable number of gradients" -- ++/* RT: delete interpolation functions */ + - 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. @@ -841,7 +549,7 @@ void CLASS cielab (ushort rgb[3], short lab[3]) { -@@ -4504,112 +4455,7 @@ +@@ -4676,112 +4412,7 @@ } #undef fcol @@ -859,7 +567,7 @@ - char (*homo)[TS][TS], *buffer; - - if (verbose) fprintf (stderr,_("AHD interpolation...\n")); - +- - cielab (0,0); - border_interpolate(5); - buffer = (char *) malloc (26*TS*TS); @@ -867,7 +575,7 @@ - rgb = (ushort(*)[TS][TS][3]) buffer; - lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); - homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); -- + - for (top=2; top < height-5; top += TS-6) - for (left=2; left < width-5; left += TS-6) { - @@ -954,7 +662,7 @@ #undef TS void CLASS median_filter() -@@ -4779,7 +4625,7 @@ +@@ -4951,7 +4582,7 @@ } } @@ -963,7 +671,7 @@ void CLASS parse_makernote (int base, int uptag) { -@@ -4936,7 +4782,8 @@ +@@ -5108,7 +4739,8 @@ cam_mul[2] = get4() << 2; } } @@ -973,7 +681,7 @@ fread (model, 64, 1, ifp); if (strstr(make,"PENTAX")) { if (tag == 0x1b) tag = 0x1018; -@@ -5187,7 +5034,7 @@ +@@ -5359,7 +4991,7 @@ { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7", @@ -982,7 +690,7 @@ "","","","","Aptus-II 10R","Aptus-II 8","","Aptus-II 12","","AFi-II 12" }; float romm_cam[3][3]; -@@ -5276,6 +5123,8 @@ +@@ -5448,6 +5080,8 @@ wbi = -2; } if (tag == 2118) wbtemp = getint(type); @@ -991,7 +699,7 @@ if (tag == 2130 + wbi) FORC3 mul[c] = getreal(type); if (tag == 2140 + wbi && wbi >= 0) -@@ -5295,8 +5144,8 @@ +@@ -5467,8 +5101,8 @@ } } @@ -1002,7 +710,7 @@ int CLASS parse_tiff_ifd (int base) { -@@ -5309,7 +5158,7 @@ +@@ -5481,7 +5115,7 @@ unsigned sony_curve[] = { 0,0,0,0,0,4095 }; unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; struct jhead jh; @@ -1011,7 +719,7 @@ if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) return 1; -@@ -5379,7 +5228,8 @@ +@@ -5555,7 +5189,8 @@ fgets (make, 64, ifp); break; case 272: /* Model */ @@ -1021,7 +729,7 @@ break; case 280: /* Panasonic RW2 offset */ if (type != 4) break; -@@ -5435,6 +5285,9 @@ +@@ -5611,6 +5246,9 @@ case 315: /* Artist */ fread (artist, 64, 1, ifp); break; @@ -1031,7 +739,7 @@ case 322: /* TileWidth */ tiff_ifd[ifd].tile_width = getint(type); break; -@@ -5448,6 +5301,9 @@ +@@ -5626,6 +5264,9 @@ is_raw = 5; } break; @@ -1041,7 +749,7 @@ case 330: /* SubIFDs */ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { load_raw = &CLASS sony_arw_load_raw; -@@ -5461,6 +5317,9 @@ +@@ -5639,6 +5280,9 @@ fseek (ifp, i+4, SEEK_SET); } break; @@ -1051,7 +759,7 @@ case 400: strcpy (make, "Sarnoff"); maximum = 0xfff; -@@ -5630,6 +5489,9 @@ +@@ -5820,6 +5464,9 @@ if (!make[0]) strcpy (make, "DNG"); is_raw = 1; break; @@ -1059,9 +767,9 @@ + fgets (model3, 64, ifp); + break; case 50710: /* CFAPlaneColor */ + if (filters == 9) break; if (len > 4) len = 4; - colors = len; -@@ -5660,10 +5522,21 @@ +@@ -5851,10 +5498,21 @@ case 61450: cblack[4] = cblack[5] = MIN(sqrt(len),64); case 50714: /* BlackLevel */ @@ -1087,7 +795,7 @@ case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ for (num=i=0; i < len; i++) -@@ -5741,12 +5614,15 @@ +@@ -5932,12 +5590,15 @@ fread (buf, sony_length, 1, ifp); sony_decrypt (buf, sony_length/4, 1, sony_key); sfp = ifp; @@ -1109,7 +817,7 @@ ifp = sfp; free (buf); } -@@ -5770,6 +5646,7 @@ +@@ -5961,6 +5622,7 @@ int CLASS parse_tiff (int base) { int doff; @@ -1117,7 +825,7 @@ fseek (ifp, base, SEEK_SET); order = get2(); -@@ -5847,7 +5724,7 @@ +@@ -6038,7 +5700,7 @@ case 8: load_raw = &CLASS eight_bit_load_raw; break; case 12: if (tiff_ifd[raw].phint == 2) load_flags = 6; @@ -1126,7 +834,7 @@ case 14: load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; if (!strncmp(make,"OLYMPUS",7) && -@@ -5878,6 +5755,7 @@ +@@ -6071,6 +5733,7 @@ case 32803: load_raw = &CLASS kodak_65000_load_raw; } case 32867: case 34892: break; @@ -1134,7 +842,7 @@ default: is_raw = 0; } if (!dng_version) -@@ -5963,7 +5841,7 @@ +@@ -6156,7 +5819,7 @@ { const char *file, *ext; char *jname, *jfile, *jext; @@ -1143,7 +851,7 @@ ext = strrchr (ifname, '.'); file = strrchr (ifname, '/'); -@@ -5985,13 +5863,14 @@ +@@ -6178,13 +5841,14 @@ } else while (isdigit(*--jext)) { if (*jext != '9') { @@ -1160,16 +868,7 @@ if (verbose) fprintf (stderr,_("Reading metadata from %s ...\n"), jname); parse_tiff (12); -@@ -6256,6 +6135,8 @@ - case 0x21d: ph1.black = data; break; - case 0x222: ph1.split_col = data; break; - case 0x223: ph1.black_off = data+base; break; -+ case 0x224: ph1.split_row = data; break; -+ case 0x225: ph1.black_off2= data+base; break; - case 0x301: - model[63] = 0; - fread (model, 1, 63, ifp); -@@ -6334,7 +6215,11 @@ +@@ -6529,7 +6193,11 @@ order = get2(); hlen = get4(); if (get4() == 0x48454150) /* "HEAP" */ @@ -1181,7 +880,7 @@ if (parse_tiff (save+6)) apply_tiff(); fseek (ifp, save+len, SEEK_SET); } -@@ -6586,7 +6471,8 @@ +@@ -6781,7 +6449,8 @@ { static const struct { const char *prefix; @@ -1191,7 +890,7 @@ } table[] = { { "AgfaPhoto DC-833m", 0, 0, /* DJC */ { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, -@@ -7457,6 +7343,27 @@ +@@ -7668,6 +7337,27 @@ } break; } @@ -1219,7 +918,7 @@ } void CLASS simple_coeff (int index) -@@ -7732,7 +7639,7 @@ +@@ -7945,7 +7635,7 @@ 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; @@ -1228,7 +927,7 @@ iso_speed = shutter = aperture = focal_len = unique_id = 0; tiff_nifds = 0; memset (tiff_ifd, 0, sizeof tiff_ifd); -@@ -7764,13 +7671,20 @@ +@@ -7977,13 +7667,20 @@ fread (head, 1, 32, ifp); fseek (ifp, 0, SEEK_END); flen = fsize = ftell(ifp); @@ -1251,7 +950,7 @@ parse_ciff (hlen, flen-hlen, 0); load_raw = &CLASS canon_load_raw; } else if (parse_tiff(0)) apply_tiff(); -@@ -7816,6 +7730,7 @@ +@@ -8029,6 +7726,7 @@ fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); @@ -1259,7 +958,7 @@ apply_tiff(); } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); -@@ -7925,15 +7840,18 @@ +@@ -8138,15 +7836,18 @@ if (make[0] == 0) parse_smal (0, flen); if (make[0] == 0) { parse_jpeg(0); @@ -1287,7 +986,7 @@ } for (i=0; i < sizeof corp / sizeof *corp; i++) -@@ -7966,7 +7884,7 @@ +@@ -8179,7 +7880,7 @@ if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */ { height = 3124; width = 4688; filters = 0x16161616; } if (width == 4352 && (!strcmp(model,"K-r") || !strcmp(model,"K-x"))) @@ -1296,7 +995,7 @@ if (width >= 4960 && !strncmp(model,"K-5",3)) { left_margin = 10; width = 4950; filters = 0x16161616; } if (width == 4736 && !strcmp(model,"K-7")) -@@ -7985,6 +7903,7 @@ +@@ -8198,6 +7899,7 @@ switch (tiff_compress) { case 1: load_raw = &CLASS packed_dng_load_raw; break; case 7: load_raw = &CLASS lossless_dng_load_raw; break; @@ -1304,7 +1003,7 @@ case 34892: load_raw = &CLASS lossy_dng_load_raw; break; default: load_raw = 0; } -@@ -8112,7 +8031,7 @@ +@@ -8325,7 +8027,7 @@ width -= 44; } else if (!strcmp(model,"D3200") || !strcmp(model,"D600") || @@ -1313,7 +1012,7 @@ width -= 46; } else if (!strcmp(model,"D4") || !strcmp(model,"Df")) { -@@ -8324,6 +8243,7 @@ +@@ -8542,6 +8244,7 @@ if (load_raw == &CLASS lossless_jpeg_load_raw) load_raw = &CLASS hasselblad_load_raw; if (raw_width == 7262) { @@ -1321,7 +1020,7 @@ height = 5444; width = 7248; top_margin = 4; -@@ -8335,13 +8255,31 @@ +@@ -8553,13 +8256,31 @@ top_margin = 4; left_margin = 41; filters = 0x61616161; @@ -1355,7 +1054,7 @@ } else if (raw_width == 4090) { strcpy (model, "V96C"); height -= (top_margin = 6); -@@ -8394,6 +8332,7 @@ +@@ -8612,6 +8333,7 @@ filters = 0x16161616; } } else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) { @@ -1363,7 +1062,7 @@ if ((flen - data_offset) / (raw_width*8/7) == raw_height) load_raw = &CLASS panasonic_load_raw; if (!load_raw) { -@@ -8411,6 +8350,7 @@ +@@ -8629,6 +8351,7 @@ } filters = 0x01010101 * (uchar) "\x94\x61\x49\x16" [((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3]; @@ -1371,7 +1070,7 @@ } else if (!strcmp(model,"C770UZ")) { height = 1718; width = 2304; -@@ -8630,6 +8570,10 @@ +@@ -8856,6 +8579,10 @@ memcpy (rgb_cam, cmatrix, sizeof cmatrix); raw_color = 0; } @@ -1382,7 +1081,7 @@ if (raw_color) adobe_coeff (make, model); if (load_raw == &CLASS kodak_radc_load_raw) if (raw_color) adobe_coeff ("Apple","Quicktake"); -@@ -8646,7 +8590,7 @@ +@@ -8872,7 +8599,7 @@ if (!tiff_bps) tiff_bps = 12; if (!maximum) maximum = (1 << tiff_bps) - 1; if (!load_raw || height < 22 || width < 22 || @@ -1391,7 +1090,7 @@ is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { -@@ -8725,194 +8669,268 @@ +@@ -8951,194 +8678,268 @@ } #endif @@ -1566,8 +1265,13 @@ + } + } + -+} -+ + } + +-void CLASS stretch() +-{ +- ushort newdim, (*img)[4], *pix0, *pix1; +- int row, col, c; +- double rc, frac; +// From DNG SDK dng_utils.h +static inline uint32_t DNG_HalfToFloat(uint16_t halfValue) { + int32_t sign = (halfValue >> 15) & 0x00000001; @@ -1600,14 +1304,8 @@ + mantissa <<= 13; + // Assemble sign, exponent and mantissa. + return (uint32_t) ((sign << 31) | (exponent << 23) | mantissa); - } ++} --void CLASS stretch() --{ -- ushort newdim, (*img)[4], *pix0, *pix1; -- int row, col, c; -- double rc, frac; -- - if (pixel_aspect == 1) return; - if (verbose) fprintf (stderr,_("Stretching the image...\n")); - if (pixel_aspect < 1) { @@ -1835,7 +1533,7 @@ struct tiff_tag { ushort tag, type; -@@ -8935,585 +8953,12 @@ +@@ -9161,585 +8962,12 @@ unsigned gps[26]; char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index c3cd33333..733998daf 100755 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -327,7 +327,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene width += w; width -= left_margin; } else if (w > 0) { - iwidth = width = w; + iwidth = width = min((int)width,w); } if (h < 0) { iheight += h; @@ -335,7 +335,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene height += h; height -= top_margin; } else if (h > 0) { - iheight = height = h; + iheight = height = min((int)height,h); } } if (cc && cc->has_rawMask(0)) { @@ -372,7 +372,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene if (cc) { for (int i = 0; i < 4; i++) { if (RT_blacklevel_from_constant) { - black_c4[i] = cc->get_BlackLevel(i, iso_speed); + black_c4[i] = cblack[i] + cc->get_BlackLevel(i, iso_speed); } // load 4 channel white level here, will be used if available if (RT_whitelevel_from_constant) { @@ -382,7 +382,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene } if (black_c4[0] == -1) { // RT constants not set, bring in the DCRAW single channel black constant - for (int c=0; c < 4; c++) black_c4[c] = black; + for (int c=0; c < 4; c++) black_c4[c] = black + cblack[c]; } else { black_from_cc = true; } @@ -568,30 +568,32 @@ DCraw::dcraw_coeff_overrides(const char make[], const char model[], const int is { 8665,-2247,-762,-2424,10372,2382,-1011,2286,5189 } }, - { "Panasonic DMC-FZ150", 143, 0xfff, /* RT */ - { 10435,-3208,-72,-2293,10506,2067,-486,1725,4682 } }, - { "Panasonic DMC-G10", 15, 0xf3c, /* RT - Colin Walker */ - { 8310,-1811,-960,-4941,12990,2151,-1378,2468,6860 } }, - { "Panasonic DMC-G1", 15, 0xf94, /* RT - Colin Walker*/ - { 7477,-1615,-651,-5016,12769,2506,-1380,2475,7240 } }, - { "Panasonic DMC-G2", 15, 0xf3c, /* RT - Colin Walker */ - { 8310,-1811,-960,-4941,12990,2151,-1378,2468,6860 } }, - { "Panasonic DMC-G3", 143, 0xfff, /* RT - Colin Walker */ - { 6051,-1406,-671,-4015,11505,2868,-1654,2667,6219 } }, - { "Panasonic DMC-G5", 143, 0xfff, /* RT */ - { 7122,-2092,-419,-4643,11769,3283,-1363,2413,5944 } }, - { "Panasonic DMC-GF1", 15, 0xf92, /* RT - Colin Walker */ - { 7863,-2080,-668,-4623,12331,2578,-1020,2066,7266 } }, - { "Panasonic DMC-GF2", 143, 0xfff, /* RT - Colin Walker */ - { 7694,-1791,-745,-4917,12818,2332,-1221,2322,7197 } }, - { "Panasonic DMC-GF3", 143, 0xfff, /* RT - Colin Walker */ - { 8074,-1846,-861,-5026,12999,2239,-1320,2375,7422 } }, - { "Panasonic DMC-GH1", 15, 0xf92, /* RT - Colin Walker */ - { 6360,-1557,-375,-4201,11504,3086,-1378,2518,5843 } }, - { "Panasonic DMC-GH2", 15, 0xf95, /* RT - Colin Walker */ -// { 6855,-1765,-456,-4223,11600,2996,-1450,2602,5761 } }, disabled - { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, // dcraw original + /* since Dcraw_v9.21 Panasonic BlackLevel is read from exif (tags 0x001c BlackLevelRed, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue + and we define here the needed offset of around 15. The total BL is BL + BLoffset (cblack + black) */ + { "Panasonic DMC-FZ150", 15, 0xfd2, /* RT */ + { 10435,-3208,-72,-2293,10506,2067,-486,1725,4682 } }, + { "Panasonic DMC-G10", 15, 0xf50, /* RT - Colin Walker - variable WL 3920 - 4080 */ + { 8310,-1811,-960,-4941,12990,2151,-1378,2468,6860 } }, + { "Panasonic DMC-G1", 15, 0xf50, /* RT - Colin Walker - variable WL 3920 - 4080 */ + { 7477,-1615,-651,-5016,12769,2506,-1380,2475,7240 } }, + { "Panasonic DMC-G2", 15, 0xf50, /* RT - Colin Walker - variable WL 3920 - 4080 */ + { 8310,-1811,-960,-4941,12990,2151,-1378,2468,6860 } }, + { "Panasonic DMC-G3", 15, 0xfdc, /* RT - Colin Walker - WL 4060 */ + { 6051,-1406,-671,-4015,11505,2868,-1654,2667,6219 } }, + { "Panasonic DMC-G5", 15, 0xfdc, /* RT - WL 4060 */ + { 7122,-2092,-419,-4643,11769,3283,-1363,2413,5944 } }, + { "Panasonic DMC-GF1", 15, 0xf50, /* RT - Colin Walker - Variable WL 3920 - 4080 */ + { 7863,-2080,-668,-4623,12331,2578,-1020,2066,7266 } }, + { "Panasonic DMC-GF2", 15, 0xfd2, /* RT - Colin Walker - WL 4050 */ + { 7694,-1791,-745,-4917,12818,2332,-1221,2322,7197 } }, + { "Panasonic DMC-GF3", 15, 0xfd2, /* RT - Colin Walker - WL 4050 */ + { 8074,-1846,-861,-5026,12999,2239,-1320,2375,7422 } }, + { "Panasonic DMC-GH1", 15, 0xf5a, /* RT - Colin Walker - variable WL 3930 - 4080 */ + { 6360,-1557,-375,-4201,11504,3086,-1378,2518,5843 } }, + { "Panasonic DMC-GH2", 15, 0xf5a, /* RT - Colin Walker - variable WL 3930 - 4080 */ +// { 6855,-1765,-456,-4223,11600,2996,-1450,2602,5761 } }, disabled due to problems with underwater WB + { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, // dcraw original { "Pentax K200D", -1, -1, /* RT */ { 10962,-4428,-542,-5486,13023,2748,-569,842,8390 } },