/src/libraw/src/postprocessing/postprocessing_utils_dcrdefs.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2026 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 | 2.45k | { |
23 | 2.45k | float out_cam[3][4]; |
24 | 2.45k | double num, inverse[3][3]; |
25 | 2.45k | static const double(*out_rgb[])[3] = { |
26 | 2.45k | LibRaw_constants::rgb_rgb, LibRaw_constants::adobe_rgb, |
27 | 2.45k | LibRaw_constants::wide_rgb, LibRaw_constants::prophoto_rgb, |
28 | 2.45k | LibRaw_constants::xyz_rgb, LibRaw_constants::aces_rgb, |
29 | 2.45k | LibRaw_constants::dcip3d65_rgb, LibRaw_constants::rec2020_rgb}; |
30 | 2.45k | static const char *name[] = {"sRGB", "Adobe RGB (1998)", |
31 | 2.45k | "WideGamut D65", "ProPhoto D65", |
32 | 2.45k | "XYZ", "ACES", |
33 | 2.45k | "DCI-P3 D65", "Rec. 2020"}; |
34 | 2.45k | static const unsigned phead[] = { |
35 | 2.45k | 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, |
36 | 2.45k | 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, |
37 | 2.45k | 0, 0, 0, 0xf6d6, 0x10000, 0xd32d}; |
38 | 2.45k | unsigned pbody[] = {10, 0x63707274, 0, 36, /* cprt */ |
39 | 2.45k | 0x64657363, 0, 60, /* desc, len is strlen(longest_string) + 12 */ |
40 | 2.45k | 0x77747074, 0, 20, /* wtpt */ |
41 | 2.45k | 0x626b7074, 0, 20, /* bkpt */ |
42 | 2.45k | 0x72545243, 0, 14, /* rTRC */ |
43 | 2.45k | 0x67545243, 0, 14, /* gTRC */ |
44 | 2.45k | 0x62545243, 0, 14, /* bTRC */ |
45 | 2.45k | 0x7258595a, 0, 20, /* rXYZ */ |
46 | 2.45k | 0x6758595a, 0, 20, /* gXYZ */ |
47 | 2.45k | 0x6258595a, 0, 20}; /* bXYZ */ |
48 | 2.45k | static const unsigned pwhite[] = {0xf351, 0x10000, 0x116cc}; |
49 | 2.45k | unsigned pcurve[] = {0x63757276, 0, 1, 0x1000000}; |
50 | | |
51 | 2.45k | RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 0, 2); |
52 | | |
53 | 2.45k | gamma_curve(gamm[0], gamm[1], 0, 0); |
54 | 2.45k | memcpy(out_cam, rgb_cam, sizeof out_cam); |
55 | 2.45k | raw_color |= colors == 1 || output_color < 1 || output_color > 8; |
56 | 2.45k | if (!raw_color) |
57 | 244 | { |
58 | 244 | size_t prof_desc_len; |
59 | 244 | std::vector<char> prof_desc; |
60 | 244 | int i, j, k; |
61 | 244 | prof_desc_len = snprintf(NULL, 0, "%s gamma %g toe slope %g", name[output_color - 1], |
62 | 244 | floor(1000. / gamm[0] + .5) / 1000., floor(gamm[1] * 1000.0 + .5) / 1000.) + |
63 | 244 | 1; |
64 | 244 | prof_desc.resize(prof_desc_len); |
65 | 244 | sprintf(prof_desc.data(), "%s gamma %g toe slope %g", name[output_color - 1], floor(1000. / gamm[0] + .5) / 1000., |
66 | 244 | floor(gamm[1] * 1000.0 + .5) / 1000.); |
67 | | |
68 | 244 | oprof = (unsigned *)calloc(phead[0], 1); |
69 | 244 | memcpy(oprof, phead, sizeof phead); |
70 | 244 | if (output_color == 5) |
71 | 0 | oprof[4] = oprof[5]; |
72 | 244 | oprof[0] = 132 + 12 * pbody[0]; |
73 | 2.68k | for (i = 0; i < (int)pbody[0]; i++) |
74 | 2.44k | { |
75 | 2.44k | oprof[oprof[0] / 4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; |
76 | 2.44k | pbody[i * 3 + 2] = oprof[0]; |
77 | 2.44k | oprof[0] += (pbody[i * 3 + 3] + 3) & -4; |
78 | 2.44k | } |
79 | 244 | memcpy(oprof + 32, pbody, sizeof pbody); |
80 | 244 | oprof[pbody[5] / 4 + 2] = unsigned(prof_desc_len + 1); |
81 | 244 | memcpy((char *)oprof + pbody[8] + 8, pwhite, sizeof pwhite); |
82 | 244 | pcurve[3] = (short)(256 / gamm[5] + 0.5) << 16; |
83 | 976 | for (i = 4; i < 7; i++) |
84 | 732 | memcpy((char *)oprof + pbody[i * 3 + 2], pcurve, sizeof pcurve); |
85 | 244 | pseudoinverse((double(*)[3])out_rgb[output_color - 1], inverse, 3); |
86 | 976 | for (i = 0; i < 3; i++) |
87 | 2.92k | for (j = 0; j < 3; j++) |
88 | 2.19k | { |
89 | 8.78k | for (num = k = 0; k < 3; k++) |
90 | 6.58k | num += LibRaw_constants::xyzd50_srgb[i][k] * inverse[j][k]; |
91 | 2.19k | oprof[pbody[j * 3 + 23] / 4 + i + 2] = unsigned(num * 0x10000 + 0.5); |
92 | 2.19k | } |
93 | 62.7k | for (i = 0; i < (int)phead[0] / 4; i++) |
94 | 62.4k | oprof[i] = htonl(oprof[i]); |
95 | 244 | strcpy((char *)oprof + pbody[2] + 8, "auto-generated by dcraw"); |
96 | 244 | if (pbody[5] + 12 + prof_desc.size() < phead[0]) |
97 | 244 | strcpy((char *)oprof + pbody[5] + 12, prof_desc.data()); |
98 | 976 | for (i = 0; i < 3; i++) |
99 | 3.07k | for (j = 0; j < colors; j++) |
100 | 9.37k | for (out_cam[i][j] = 0.f, k = 0; k < 3; k++) |
101 | 7.02k | out_cam[i][j] += float(out_rgb[output_color - 1][i][k] * rgb_cam[k][j]); |
102 | 244 | } |
103 | 2.45k | convert_to_rgb_loop(out_cam); |
104 | | |
105 | 2.45k | if (colors == 4 && output_color) |
106 | 235 | colors = 3; |
107 | | |
108 | 2.45k | RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 1, 2); |
109 | 2.45k | } |
110 | | |
111 | | void LibRaw::scale_colors() |
112 | 2.49k | { |
113 | 2.49k | unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; |
114 | 2.49k | int val; |
115 | 2.49k | double dsum[8], dmin, dmax; |
116 | 2.49k | float scale_mul[4], fr, fc; |
117 | 2.49k | ushort *img = 0, *pix; |
118 | | |
119 | 2.49k | RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 0, 2); |
120 | | |
121 | 2.49k | if (user_mul[0]) |
122 | 0 | memcpy(pre_mul, user_mul, sizeof pre_mul); |
123 | 2.49k | if (use_auto_wb || (use_camera_wb && |
124 | 2.49k | (cam_mul[0] < -0.5 // LibRaw 0.19 and older: fallback to auto only if cam_mul[0] is set to -1 |
125 | 2.49k | || (cam_mul[0] <= 0.00001f // New default: fallback to auto if no cam_mul parsed from metadata |
126 | 2.48k | && !(imgdata.rawparams.options & LIBRAW_RAWOPTIONS_CAMERAWB_FALLBACK_TO_DAYLIGHT)) |
127 | 2.49k | ))) |
128 | 2.49k | { |
129 | 2.49k | memset(dsum, 0, sizeof dsum); |
130 | 2.49k | bottom = MIN(greybox[1] + greybox[3], height); |
131 | 2.49k | right = MIN(greybox[0] + greybox[2], width); |
132 | 111k | for (row = greybox[1]; row < bottom; row += 8) |
133 | 4.50M | for (col = greybox[0]; col < right; col += 8) |
134 | 4.39M | { |
135 | 4.39M | memset(sum, 0, sizeof sum); |
136 | 27.5M | for (y = row; y < row + 8 && y < bottom; y++) |
137 | 208M | for (x = col; x < col + 8 && x < right; x++) |
138 | 184M | FORC4 |
139 | 237M | { |
140 | 237M | if (filters) |
141 | 167M | { |
142 | 167M | c = fcol(y, x); |
143 | 167M | val = BAYER2(y, x); |
144 | 167M | } |
145 | 70.6M | else |
146 | 70.6M | val = image[y * width + x][c]; |
147 | 237M | if (val > (int)maximum - 25) |
148 | 1.52M | goto skip_block; |
149 | 236M | if ((val -= cblack[c]) < 0) |
150 | 0 | val = 0; |
151 | 236M | sum[c] += val; |
152 | 236M | sum[c + 4]++; |
153 | 236M | if (filters) |
154 | 165M | break; |
155 | 236M | } |
156 | 22.9M | FORC(8) dsum[c] += sum[c]; |
157 | 4.39M | skip_block:; |
158 | 4.39M | } |
159 | 9.96k | FORC4 if (dsum[c]) pre_mul[c] = float(dsum[c + 4] / dsum[c]); |
160 | 2.49k | } |
161 | 2.49k | if (use_camera_wb && cam_mul[0] > 0.00001f) |
162 | 8 | { |
163 | 8 | memset(sum, 0, sizeof sum); |
164 | 72 | for (row = 0; row < 8; row++) |
165 | 576 | for (col = 0; col < 8; col++) |
166 | 512 | { |
167 | 512 | c = FC(row, col); |
168 | 512 | if ((val = white[row][col] - cblack[c]) > 0) |
169 | 0 | sum[c] += val; |
170 | 512 | sum[c + 4]++; |
171 | 512 | } |
172 | 8 | if (imgdata.color.as_shot_wb_applied & LIBRAW_ASWB_APPLIED) |
173 | 2 | { |
174 | | // sRAW with baked WB: |
175 | 2 | if (imgdata.color.as_shot_wb_applied & LIBRAW_ASWB_USE_CORRECTION) |
176 | 0 | FORC4 pre_mul[c] = imgdata.color.as_shot_wb_corr[c]; |
177 | 2 | else |
178 | 2 | pre_mul[0] = pre_mul[1] = pre_mul[2] = pre_mul[3] = 1.0; |
179 | 2 | } |
180 | 6 | else if (sum[0] && sum[1] && sum[2] && sum[3]) |
181 | 0 | FORC4 pre_mul[c] = (float)sum[c + 4] / sum[c]; |
182 | 6 | else if (cam_mul[0] > 0.00001f && cam_mul[2] > 0.00001f) |
183 | 6 | memcpy(pre_mul, cam_mul, sizeof pre_mul); |
184 | 0 | else |
185 | 0 | { |
186 | 0 | imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB; |
187 | 0 | } |
188 | 8 | } |
189 | | // sRAW with baked WB, daylight |
190 | 2.49k | if ((imgdata.color.as_shot_wb_applied & LIBRAW_ASWB_APPLIED) && !use_camera_wb && !use_auto_wb && |
191 | 0 | cam_mul[0] > 0.00001f && cam_mul[1] > 0.00001f && cam_mul[2] > 0.00001f) |
192 | 0 | { |
193 | 0 | if (imgdata.color.as_shot_wb_applied & LIBRAW_ASWB_USE_CORRECTION) |
194 | 0 | { |
195 | 0 | for (c = 0; c < 3; c++) |
196 | 0 | pre_mul[c] = pre_mul[c] / cam_mul[c] * imgdata.color.as_shot_wb_corr[c]; |
197 | 0 | } |
198 | 0 | else |
199 | 0 | { |
200 | 0 | for (c = 0; c < 3; c++) |
201 | 0 | pre_mul[c] /= cam_mul[c]; |
202 | 0 | } |
203 | 0 | } |
204 | 2.49k | if (pre_mul[1] == 0) |
205 | 18 | pre_mul[1] = 1; |
206 | 2.49k | if (pre_mul[3] == 0) |
207 | 1.27k | pre_mul[3] = colors < 4 ? pre_mul[1] : 1; |
208 | 2.49k | if (threshold) |
209 | 0 | wavelet_denoise(); |
210 | 2.49k | maximum -= black; |
211 | 12.4k | for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++) |
212 | 9.99k | { |
213 | 9.99k | if (dmin > pre_mul[c]) |
214 | 4.19k | dmin = pre_mul[c]; |
215 | 9.99k | if (dmax < pre_mul[c]) |
216 | 3.97k | dmax = pre_mul[c]; |
217 | 9.99k | } |
218 | 2.49k | if (!highlight) |
219 | 2.49k | dmax = dmin; |
220 | 2.49k | if (dmax > 0.00001 && maximum > 0) |
221 | 9.98k | FORC4 scale_mul[c] = (pre_mul[c] /= float(dmax)) * 65535.f / maximum; |
222 | 2 | else |
223 | 8 | FORC4 scale_mul[c] = 1.0; |
224 | | |
225 | 2.49k | if (filters > 1000 && (cblack[4] + 1) / 2 == 1 && (cblack[5] + 1) / 2 == 1) |
226 | 0 | { |
227 | 0 | FORC4 cblack[FC(c / 2, c % 2)] += |
228 | 0 | cblack[6 + c / 2 % cblack[4] * cblack[5] + c % 2 % cblack[5]]; |
229 | 0 | cblack[4] = cblack[5] = 0; |
230 | 0 | } |
231 | 2.49k | size = iheight * iwidth; |
232 | 2.49k | scale_colors_loop(scale_mul); |
233 | 2.49k | if ((aber[0] != 1 || aber[2] != 1) && colors == 3) |
234 | 0 | { |
235 | 0 | for (c = 0; c < 4; c += 2) |
236 | 0 | { |
237 | 0 | if (aber[c] == 1) |
238 | 0 | continue; |
239 | 0 | img = (ushort *)malloc(size * sizeof *img); |
240 | 0 | for (i = 0; i < size; i++) |
241 | 0 | img[i] = image[i][c]; |
242 | 0 | for (row = 0; row < iheight; row++) |
243 | 0 | { |
244 | 0 | fr = float((row - iheight * 0.5) * aber[c] + iheight * 0.5); |
245 | 0 | ur = unsigned(fr); |
246 | 0 | if (ur > (unsigned)iheight - 2) |
247 | 0 | continue; |
248 | 0 | fr -= ur; |
249 | 0 | for (col = 0; col < iwidth; col++) |
250 | 0 | { |
251 | 0 | fc = float((col - iwidth * 0.5) * aber[c] + iwidth * 0.5); |
252 | 0 | uc = unsigned(fc); |
253 | 0 | if (uc > (unsigned)iwidth - 2) |
254 | 0 | continue; |
255 | 0 | fc -= uc; |
256 | 0 | pix = img + ur * iwidth + uc; |
257 | 0 | image[row * iwidth + col][c] = |
258 | 0 | ushort( |
259 | 0 | (pix[0] * (1 - fc) + pix[1] * fc) * (1 - fr) + |
260 | 0 | (pix[iwidth] * (1 - fc) + pix[iwidth + 1] * fc) * fr |
261 | 0 | ); |
262 | 0 | } |
263 | 0 | } |
264 | 0 | free(img); |
265 | 0 | } |
266 | 0 | } |
267 | 2.49k | RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 1, 2); |
268 | 2.49k | } |
269 | | |
270 | | // green equilibration |
271 | | void LibRaw::green_matching() |
272 | 0 | { |
273 | 0 | int i, j; |
274 | 0 | double m1, m2, c1, c2; |
275 | 0 | int o1_1, o1_2, o1_3, o1_4; |
276 | 0 | int o2_1, o2_2, o2_3, o2_4; |
277 | 0 | ushort(*img)[4]; |
278 | 0 | const int margin = 3; |
279 | 0 | int oj = 2, oi = 2; |
280 | 0 | float f; |
281 | 0 | const float thr = 0.01f; |
282 | 0 | if (half_size || shrink) |
283 | 0 | return; |
284 | 0 | if (FC(oj, oi) != 3) |
285 | 0 | oj++; |
286 | 0 | if (FC(oj, oi) != 3) |
287 | 0 | oi++; |
288 | 0 | if (FC(oj, oi) != 3) |
289 | 0 | oj--; |
290 | |
|
291 | 0 | img = (ushort(*)[4])calloc(height * width, sizeof *image); |
292 | 0 | memcpy(img, image, height * width * sizeof *image); |
293 | |
|
294 | 0 | for (j = oj; j < height - margin; j += 2) |
295 | 0 | for (i = oi; i < width - margin; i += 2) |
296 | 0 | { |
297 | 0 | o1_1 = img[(j - 1) * width + i - 1][1]; |
298 | 0 | o1_2 = img[(j - 1) * width + i + 1][1]; |
299 | 0 | o1_3 = img[(j + 1) * width + i - 1][1]; |
300 | 0 | o1_4 = img[(j + 1) * width + i + 1][1]; |
301 | 0 | o2_1 = img[(j - 2) * width + i][3]; |
302 | 0 | o2_2 = img[(j + 2) * width + i][3]; |
303 | 0 | o2_3 = img[j * width + i - 2][3]; |
304 | 0 | o2_4 = img[j * width + i + 2][3]; |
305 | |
|
306 | 0 | m1 = (o1_1 + o1_2 + o1_3 + o1_4) / 4.0; |
307 | 0 | m2 = (o2_1 + o2_2 + o2_3 + o2_4) / 4.0; |
308 | |
|
309 | 0 | c1 = (abs(o1_1 - o1_2) + abs(o1_1 - o1_3) + abs(o1_1 - o1_4) + |
310 | 0 | abs(o1_2 - o1_3) + abs(o1_3 - o1_4) + abs(o1_2 - o1_4)) / |
311 | 0 | 6.0; |
312 | 0 | c2 = (abs(o2_1 - o2_2) + abs(o2_1 - o2_3) + abs(o2_1 - o2_4) + |
313 | 0 | abs(o2_2 - o2_3) + abs(o2_3 - o2_4) + abs(o2_2 - o2_4)) / |
314 | 0 | 6.0; |
315 | 0 | if ((img[j * width + i][3] < maximum * 0.95) && (c1 < maximum * thr) && |
316 | 0 | (c2 < maximum * thr)) |
317 | 0 | { |
318 | 0 | f = float(image[j * width + i][3] * m1 / m2); |
319 | 0 | image[j * width + i][3] = f > 65535.f ? 0xffff : ushort(f); |
320 | 0 | } |
321 | 0 | } |
322 | 0 | free(img); |
323 | 0 | } |