/src/libraw/src/postprocessing/postprocessing_utils_dcrdefs.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2025 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, |
5 | | dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. |
6 | | LibRaw do not use RESTRICTED code from dcraw.c |
7 | | |
8 | | LibRaw is free software; you can redistribute it and/or modify |
9 | | it under the terms of the one of two licenses as you choose: |
10 | | |
11 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
12 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
13 | | |
14 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
15 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
16 | | |
17 | | */ |
18 | | |
19 | | #include "../../internal/dcraw_defs.h" |
20 | | |
21 | | void LibRaw::convert_to_rgb() |
22 | 31.4k | { |
23 | 31.4k | float out_cam[3][4]; |
24 | 31.4k | double num, inverse[3][3]; |
25 | 31.4k | static const double(*out_rgb[])[3] = { |
26 | 31.4k | LibRaw_constants::rgb_rgb, LibRaw_constants::adobe_rgb, |
27 | 31.4k | LibRaw_constants::wide_rgb, LibRaw_constants::prophoto_rgb, |
28 | 31.4k | LibRaw_constants::xyz_rgb, LibRaw_constants::aces_rgb, |
29 | 31.4k | LibRaw_constants::dcip3d65_rgb, LibRaw_constants::rec2020_rgb}; |
30 | 31.4k | static const char *name[] = {"sRGB", "Adobe RGB (1998)", |
31 | 31.4k | "WideGamut D65", "ProPhoto D65", |
32 | 31.4k | "XYZ", "ACES", |
33 | 31.4k | "DCI-P3 D65", "Rec. 2020"}; |
34 | 31.4k | static const unsigned phead[] = { |
35 | 31.4k | 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, |
36 | 31.4k | 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, |
37 | 31.4k | 0, 0, 0, 0xf6d6, 0x10000, 0xd32d}; |
38 | 31.4k | unsigned pbody[] = {10, 0x63707274, 0, 36, /* cprt */ |
39 | 31.4k | 0x64657363, 0, 60, /* desc, len is strlen(longest_string) + 12 */ |
40 | 31.4k | 0x77747074, 0, 20, /* wtpt */ |
41 | 31.4k | 0x626b7074, 0, 20, /* bkpt */ |
42 | 31.4k | 0x72545243, 0, 14, /* rTRC */ |
43 | 31.4k | 0x67545243, 0, 14, /* gTRC */ |
44 | 31.4k | 0x62545243, 0, 14, /* bTRC */ |
45 | 31.4k | 0x7258595a, 0, 20, /* rXYZ */ |
46 | 31.4k | 0x6758595a, 0, 20, /* gXYZ */ |
47 | 31.4k | 0x6258595a, 0, 20}; /* bXYZ */ |
48 | 31.4k | static const unsigned pwhite[] = {0xf351, 0x10000, 0x116cc}; |
49 | 31.4k | unsigned pcurve[] = {0x63757276, 0, 1, 0x1000000}; |
50 | | |
51 | 31.4k | RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 0, 2); |
52 | | |
53 | 31.4k | gamma_curve(gamm[0], gamm[1], 0, 0); |
54 | 31.4k | memcpy(out_cam, rgb_cam, sizeof out_cam); |
55 | 31.4k | raw_color |= colors == 1 || output_color < 1 || output_color > 8; |
56 | 31.4k | if (!raw_color) |
57 | 4.53k | { |
58 | 4.53k | size_t prof_desc_len; |
59 | 4.53k | std::vector<char> prof_desc; |
60 | 4.53k | int i, j, k; |
61 | 4.53k | prof_desc_len = snprintf(NULL, 0, "%s gamma %g toe slope %g", name[output_color - 1], |
62 | 4.53k | floor(1000. / gamm[0] + .5) / 1000., floor(gamm[1] * 1000.0 + .5) / 1000.) + |
63 | 4.53k | 1; |
64 | 4.53k | prof_desc.resize(prof_desc_len); |
65 | 4.53k | sprintf(prof_desc.data(), "%s gamma %g toe slope %g", name[output_color - 1], floor(1000. / gamm[0] + .5) / 1000., |
66 | 4.53k | floor(gamm[1] * 1000.0 + .5) / 1000.); |
67 | | |
68 | 4.53k | oprof = (unsigned *)calloc(phead[0], 1); |
69 | 4.53k | memcpy(oprof, phead, sizeof phead); |
70 | 4.53k | if (output_color == 5) |
71 | 818 | oprof[4] = oprof[5]; |
72 | 4.53k | oprof[0] = 132 + 12 * pbody[0]; |
73 | 49.9k | for (i = 0; i < (int)pbody[0]; i++) |
74 | 45.3k | { |
75 | 45.3k | oprof[oprof[0] / 4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; |
76 | 45.3k | pbody[i * 3 + 2] = oprof[0]; |
77 | 45.3k | oprof[0] += (pbody[i * 3 + 3] + 3) & -4; |
78 | 45.3k | } |
79 | 4.53k | memcpy(oprof + 32, pbody, sizeof pbody); |
80 | 4.53k | oprof[pbody[5] / 4 + 2] = unsigned(prof_desc_len + 1); |
81 | 4.53k | memcpy((char *)oprof + pbody[8] + 8, pwhite, sizeof pwhite); |
82 | 4.53k | pcurve[3] = (short)(256 / gamm[5] + 0.5) << 16; |
83 | 18.1k | for (i = 4; i < 7; i++) |
84 | 13.6k | memcpy((char *)oprof + pbody[i * 3 + 2], pcurve, sizeof pcurve); |
85 | 4.53k | pseudoinverse((double(*)[3])out_rgb[output_color - 1], inverse, 3); |
86 | 18.1k | for (i = 0; i < 3; i++) |
87 | 54.4k | for (j = 0; j < 3; j++) |
88 | 40.8k | { |
89 | 163k | for (num = k = 0; k < 3; k++) |
90 | 122k | num += LibRaw_constants::xyzd50_srgb[i][k] * inverse[j][k]; |
91 | 40.8k | oprof[pbody[j * 3 + 23] / 4 + i + 2] = unsigned(num * 0x10000 + 0.5); |
92 | 40.8k | } |
93 | 1.16M | for (i = 0; i < (int)phead[0] / 4; i++) |
94 | 1.16M | oprof[i] = htonl(oprof[i]); |
95 | 4.53k | strcpy((char *)oprof + pbody[2] + 8, "auto-generated by dcraw"); |
96 | 4.53k | if (pbody[5] + 12 + prof_desc.size() < phead[0]) |
97 | 4.53k | strcpy((char *)oprof + pbody[5] + 12, prof_desc.data()); |
98 | 18.1k | for (i = 0; i < 3; i++) |
99 | 58.4k | for (j = 0; j < colors; j++) |
100 | 179k | for (out_cam[i][j] = 0.f, k = 0; k < 3; k++) |
101 | 134k | out_cam[i][j] += float(out_rgb[output_color - 1][i][k] * rgb_cam[k][j]); |
102 | 4.53k | } |
103 | 31.4k | convert_to_rgb_loop(out_cam); |
104 | | |
105 | 31.4k | if (colors == 4 && output_color) |
106 | 1.84k | colors = 3; |
107 | | |
108 | 31.4k | RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 1, 2); |
109 | 31.4k | } |
110 | | |
111 | | void LibRaw::scale_colors() |
112 | 32.2k | { |
113 | 32.2k | unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; |
114 | 32.2k | int val; |
115 | 32.2k | double dsum[8], dmin, dmax; |
116 | 32.2k | float scale_mul[4], fr, fc; |
117 | 32.2k | ushort *img = 0, *pix; |
118 | | |
119 | 32.2k | RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 0, 2); |
120 | | |
121 | 32.2k | if (user_mul[0]) |
122 | 31.8k | memcpy(pre_mul, user_mul, sizeof pre_mul); |
123 | 32.2k | if (use_auto_wb || (use_camera_wb && |
124 | 0 | (cam_mul[0] < -0.5 // LibRaw 0.19 and older: fallback to auto only if cam_mul[0] is set to -1 |
125 | 0 | || (cam_mul[0] <= 0.00001f // New default: fallback to auto if no cam_mul parsed from metadata |
126 | 0 | && !(imgdata.rawparams.options & LIBRAW_RAWOPTIONS_CAMERAWB_FALLBACK_TO_DAYLIGHT)) |
127 | 0 | ))) |
128 | 32.0k | { |
129 | 32.0k | memset(dsum, 0, sizeof dsum); |
130 | 32.0k | bottom = MIN(greybox[1] + greybox[3], height); |
131 | 32.0k | right = MIN(greybox[0] + greybox[2], width); |
132 | 1.77M | for (row = greybox[1]; row < bottom; row += 8) |
133 | 27.7M | for (col = greybox[0]; col < right; col += 8) |
134 | 25.9M | { |
135 | 25.9M | memset(sum, 0, sizeof sum); |
136 | 137M | for (y = row; y < row + 8 && y < bottom; y++) |
137 | 988M | for (x = col; x < col + 8 && x < right; x++) |
138 | 877M | FORC4 |
139 | 1.30G | { |
140 | 1.30G | if (filters) |
141 | 735M | { |
142 | 735M | c = fcol(y, x); |
143 | 735M | val = BAYER2(y, x); |
144 | 735M | } |
145 | 565M | else |
146 | 565M | val = image[y * width + x][c]; |
147 | 1.30G | if (val > (int)maximum - 25) |
148 | 11.9M | goto skip_block; |
149 | 1.28G | if ((val -= cblack[c]) < 0) |
150 | 82.7M | val = 0; |
151 | 1.28G | sum[c] += val; |
152 | 1.28G | sum[c + 4]++; |
153 | 1.28G | if (filters) |
154 | 724M | break; |
155 | 1.28G | } |
156 | 112M | FORC(8) dsum[c] += sum[c]; |
157 | 25.9M | skip_block:; |
158 | 25.9M | } |
159 | 128k | FORC4 if (dsum[c]) pre_mul[c] = float(dsum[c + 4] / dsum[c]); |
160 | 32.0k | } |
161 | 32.2k | if (use_camera_wb && cam_mul[0] > 0.00001f) |
162 | 0 | { |
163 | 0 | memset(sum, 0, sizeof sum); |
164 | 0 | for (row = 0; row < 8; row++) |
165 | 0 | for (col = 0; col < 8; col++) |
166 | 0 | { |
167 | 0 | c = FC(row, col); |
168 | 0 | if ((val = white[row][col] - cblack[c]) > 0) |
169 | 0 | sum[c] += val; |
170 | 0 | sum[c + 4]++; |
171 | 0 | } |
172 | 0 | if (imgdata.color.as_shot_wb_applied) |
173 | 0 | { |
174 | | // Nikon sRAW: camera WB already applied: |
175 | 0 | pre_mul[0] = pre_mul[1] = pre_mul[2] = pre_mul[3] = 1.0; |
176 | 0 | } |
177 | 0 | else if (sum[0] && sum[1] && sum[2] && sum[3]) |
178 | 0 | FORC4 pre_mul[c] = (float)sum[c + 4] / sum[c]; |
179 | 0 | else if (cam_mul[0] > 0.00001f && cam_mul[2] > 0.00001f) |
180 | 0 | memcpy(pre_mul, cam_mul, sizeof pre_mul); |
181 | 0 | else |
182 | 0 | { |
183 | 0 | imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB; |
184 | 0 | } |
185 | 0 | } |
186 | | // Nikon sRAW, daylight |
187 | 32.2k | if (imgdata.color.as_shot_wb_applied && !use_camera_wb && !use_auto_wb && |
188 | 49 | cam_mul[0] > 0.00001f && cam_mul[1] > 0.00001f && cam_mul[2] > 0.00001f) |
189 | 21 | { |
190 | 84 | for (c = 0; c < 3; c++) |
191 | 63 | pre_mul[c] /= cam_mul[c]; |
192 | 21 | } |
193 | 32.2k | if (pre_mul[1] == 0) |
194 | 352 | pre_mul[1] = 1; |
195 | 32.2k | if (pre_mul[3] == 0) |
196 | 1.17k | pre_mul[3] = colors < 4 ? pre_mul[1] : 1; |
197 | 32.2k | if (threshold) |
198 | 26.3k | wavelet_denoise(); |
199 | 32.2k | maximum -= black; |
200 | 161k | for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++) |
201 | 128k | { |
202 | 128k | if (dmin > pre_mul[c]) |
203 | 64.8k | dmin = pre_mul[c]; |
204 | 128k | if (dmax < pre_mul[c]) |
205 | 45.8k | dmax = pre_mul[c]; |
206 | 128k | } |
207 | 32.2k | if (!highlight) |
208 | 32.2k | dmax = dmin; |
209 | 32.2k | if (dmax > 0.00001 && maximum > 0) |
210 | 52.2k | FORC4 scale_mul[c] = (pre_mul[c] /= float(dmax)) * 65535.f / maximum; |
211 | 19.1k | else |
212 | 76.7k | FORC4 scale_mul[c] = 1.0; |
213 | | |
214 | 32.2k | if (filters > 1000 && (cblack[4] + 1) / 2 == 1 && (cblack[5] + 1) / 2 == 1) |
215 | 0 | { |
216 | 0 | FORC4 cblack[FC(c / 2, c % 2)] += |
217 | 0 | cblack[6 + c / 2 % cblack[4] * cblack[5] + c % 2 % cblack[5]]; |
218 | 0 | cblack[4] = cblack[5] = 0; |
219 | 0 | } |
220 | 32.2k | size = iheight * iwidth; |
221 | 32.2k | scale_colors_loop(scale_mul); |
222 | 32.2k | if ((aber[0] != 1 || aber[2] != 1) && colors == 3) |
223 | 0 | { |
224 | 0 | for (c = 0; c < 4; c += 2) |
225 | 0 | { |
226 | 0 | if (aber[c] == 1) |
227 | 0 | continue; |
228 | 0 | img = (ushort *)malloc(size * sizeof *img); |
229 | 0 | for (i = 0; i < size; i++) |
230 | 0 | img[i] = image[i][c]; |
231 | 0 | for (row = 0; row < iheight; row++) |
232 | 0 | { |
233 | 0 | fr = float((row - iheight * 0.5) * aber[c] + iheight * 0.5); |
234 | 0 | ur = unsigned(fr); |
235 | 0 | if (ur > (unsigned)iheight - 2) |
236 | 0 | continue; |
237 | 0 | fr -= ur; |
238 | 0 | for (col = 0; col < iwidth; col++) |
239 | 0 | { |
240 | 0 | fc = float((col - iwidth * 0.5) * aber[c] + iwidth * 0.5); |
241 | 0 | uc = unsigned(fc); |
242 | 0 | if (uc > (unsigned)iwidth - 2) |
243 | 0 | continue; |
244 | 0 | fc -= uc; |
245 | 0 | pix = img + ur * iwidth + uc; |
246 | 0 | image[row * iwidth + col][c] = |
247 | 0 | ushort( |
248 | 0 | (pix[0] * (1 - fc) + pix[1] * fc) * (1 - fr) + |
249 | 0 | (pix[iwidth] * (1 - fc) + pix[iwidth + 1] * fc) * fr |
250 | 0 | ); |
251 | 0 | } |
252 | 0 | } |
253 | 0 | free(img); |
254 | 0 | } |
255 | 0 | } |
256 | 32.2k | RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 1, 2); |
257 | 32.2k | } |
258 | | |
259 | | // green equilibration |
260 | | void LibRaw::green_matching() |
261 | 0 | { |
262 | 0 | int i, j; |
263 | 0 | double m1, m2, c1, c2; |
264 | 0 | int o1_1, o1_2, o1_3, o1_4; |
265 | 0 | int o2_1, o2_2, o2_3, o2_4; |
266 | 0 | ushort(*img)[4]; |
267 | 0 | const int margin = 3; |
268 | 0 | int oj = 2, oi = 2; |
269 | 0 | float f; |
270 | 0 | const float thr = 0.01f; |
271 | 0 | if (half_size || shrink) |
272 | 0 | return; |
273 | 0 | if (FC(oj, oi) != 3) |
274 | 0 | oj++; |
275 | 0 | if (FC(oj, oi) != 3) |
276 | 0 | oi++; |
277 | 0 | if (FC(oj, oi) != 3) |
278 | 0 | oj--; |
279 | |
|
280 | 0 | img = (ushort(*)[4])calloc(height * width, sizeof *image); |
281 | 0 | memcpy(img, image, height * width * sizeof *image); |
282 | |
|
283 | 0 | for (j = oj; j < height - margin; j += 2) |
284 | 0 | for (i = oi; i < width - margin; i += 2) |
285 | 0 | { |
286 | 0 | o1_1 = img[(j - 1) * width + i - 1][1]; |
287 | 0 | o1_2 = img[(j - 1) * width + i + 1][1]; |
288 | 0 | o1_3 = img[(j + 1) * width + i - 1][1]; |
289 | 0 | o1_4 = img[(j + 1) * width + i + 1][1]; |
290 | 0 | o2_1 = img[(j - 2) * width + i][3]; |
291 | 0 | o2_2 = img[(j + 2) * width + i][3]; |
292 | 0 | o2_3 = img[j * width + i - 2][3]; |
293 | 0 | o2_4 = img[j * width + i + 2][3]; |
294 | |
|
295 | 0 | m1 = (o1_1 + o1_2 + o1_3 + o1_4) / 4.0; |
296 | 0 | m2 = (o2_1 + o2_2 + o2_3 + o2_4) / 4.0; |
297 | |
|
298 | 0 | c1 = (abs(o1_1 - o1_2) + abs(o1_1 - o1_3) + abs(o1_1 - o1_4) + |
299 | 0 | abs(o1_2 - o1_3) + abs(o1_3 - o1_4) + abs(o1_2 - o1_4)) / |
300 | 0 | 6.0; |
301 | 0 | c2 = (abs(o2_1 - o2_2) + abs(o2_1 - o2_3) + abs(o2_1 - o2_4) + |
302 | 0 | abs(o2_2 - o2_3) + abs(o2_3 - o2_4) + abs(o2_2 - o2_4)) / |
303 | 0 | 6.0; |
304 | 0 | if ((img[j * width + i][3] < maximum * 0.95) && (c1 < maximum * thr) && |
305 | 0 | (c2 < maximum * thr)) |
306 | 0 | { |
307 | 0 | f = float(image[j * width + i][3] * m1 / m2); |
308 | 0 | image[j * width + i][3] = f > 65535.f ? 0xffff : ushort(f); |
309 | 0 | } |
310 | 0 | } |
311 | 0 | free(img); |
312 | 0 | } |