/src/LibRaw/src/postprocessing/dcraw_process.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2025 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw is free software; you can redistribute it and/or modify |
5 | | it under the terms of the one of two licenses as you choose: |
6 | | |
7 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
8 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
9 | | |
10 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
11 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
12 | | |
13 | | */ |
14 | | |
15 | | #include "../../internal/libraw_cxx_defs.h" |
16 | | |
17 | | int LibRaw::dcraw_process(void) |
18 | 2.49k | { |
19 | 2.49k | int quality, i; |
20 | | |
21 | 2.49k | int iterations = -1, dcb_enhance = 1, noiserd = 0; |
22 | 2.49k | float preser = 0; |
23 | 2.49k | float expos = 1.0; |
24 | | |
25 | 2.49k | CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); |
26 | | // CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE); |
27 | | |
28 | 2.49k | try |
29 | 2.49k | { |
30 | | |
31 | 2.49k | int no_crop = 1; |
32 | | |
33 | 2.49k | if (~O.cropbox[2] && ~O.cropbox[3]) |
34 | 0 | no_crop = 0; |
35 | | |
36 | 12.4k | for(int c = 0; c < 4; c++) |
37 | 9.97k | if (O.aber[c]< 0.001 || O.aber[c] > 1000.f) |
38 | 0 | O.aber[c] = 1.0; |
39 | | |
40 | 2.49k | libraw_decoder_info_t di; |
41 | 2.49k | get_decoder_info(&di); |
42 | | |
43 | 2.49k | bool is_bayer = (imgdata.idata.filters || P1.colors == 1); |
44 | 2.49k | int subtract_inline = |
45 | 2.49k | !O.bad_pixels && !O.dark_frame && is_bayer && !IO.zero_is_bad; |
46 | | |
47 | 2.49k | int rc = raw2image_ex(subtract_inline); // allocate imgdata.image and copy data! |
48 | 2.49k | if (rc != LIBRAW_SUCCESS) |
49 | 141 | return rc; |
50 | | |
51 | | // Adjust sizes |
52 | | |
53 | 2.35k | int save_4color = O.four_color_rgb; |
54 | | |
55 | 2.35k | if (IO.zero_is_bad) |
56 | 136 | { |
57 | 136 | remove_zeroes(); |
58 | 136 | SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES); |
59 | 136 | } |
60 | | |
61 | 2.35k | if (O.bad_pixels && no_crop) |
62 | 0 | { |
63 | 0 | bad_pixels(O.bad_pixels); |
64 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS); |
65 | 0 | } |
66 | | |
67 | 2.35k | if (O.dark_frame && no_crop) |
68 | 0 | { |
69 | 0 | subtract(O.dark_frame); |
70 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME); |
71 | 0 | } |
72 | | /* pre subtract black callback: check for it above to disable subtract |
73 | | * inline */ |
74 | | |
75 | 2.35k | if (callbacks.pre_subtractblack_cb) |
76 | 0 | (callbacks.pre_subtractblack_cb)(this); |
77 | | |
78 | 2.35k | quality = 2 + !IO.fuji_width; |
79 | | |
80 | 2.35k | if (O.user_qual >= 0) |
81 | 2.35k | quality = O.user_qual; |
82 | | |
83 | 2.35k | if (!subtract_inline || !C.data_maximum) |
84 | 707 | { |
85 | 707 | adjust_bl(); |
86 | 707 | subtract_black_internal(); |
87 | 707 | } |
88 | | |
89 | 2.35k | if (!(di.decoder_flags & LIBRAW_DECODER_FIXEDMAXC)) |
90 | 1.69k | adjust_maximum(); |
91 | | |
92 | 2.35k | if (O.user_sat > 0) |
93 | 0 | C.maximum = O.user_sat; |
94 | | |
95 | 2.35k | if (P1.is_foveon) |
96 | 0 | { |
97 | 0 | if (load_raw == &LibRaw::x3f_load_raw) |
98 | 0 | { |
99 | | // Filter out zeroes |
100 | 0 | for (int q = 0; q < S.height * S.width; q++) |
101 | 0 | { |
102 | 0 | for (int c = 0; c < 4; c++) |
103 | 0 | if ((short)imgdata.image[q][c] < 0) |
104 | 0 | imgdata.image[q][c] = 0; |
105 | 0 | } |
106 | 0 | } |
107 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE); |
108 | 0 | } |
109 | | |
110 | 2.35k | if (O.green_matching && !O.half_size) |
111 | 0 | { |
112 | 0 | green_matching(); |
113 | 0 | } |
114 | | |
115 | 2.35k | if (callbacks.pre_scalecolors_cb) |
116 | 0 | (callbacks.pre_scalecolors_cb)(this); |
117 | | |
118 | 2.35k | if (!O.no_auto_scale) |
119 | 2.35k | { |
120 | 2.35k | scale_colors(); |
121 | 2.35k | SET_PROC_FLAG(LIBRAW_PROGRESS_SCALE_COLORS); |
122 | 2.35k | } |
123 | | |
124 | 2.35k | if (callbacks.pre_preinterpolate_cb) |
125 | 0 | (callbacks.pre_preinterpolate_cb)(this); |
126 | | |
127 | 2.35k | pre_interpolate(); |
128 | | |
129 | 2.35k | SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE); |
130 | | |
131 | 2.35k | if (O.dcb_iterations >= 0) |
132 | 2.35k | iterations = O.dcb_iterations; |
133 | 2.35k | if (O.dcb_enhance_fl >= 0) |
134 | 2.35k | dcb_enhance = O.dcb_enhance_fl; |
135 | 2.35k | if (O.fbdd_noiserd >= 0) |
136 | 2.35k | noiserd = O.fbdd_noiserd; |
137 | | |
138 | | /* pre-exposure correction callback */ |
139 | | |
140 | 2.35k | if (O.exp_correc > 0) |
141 | 0 | { |
142 | 0 | expos = O.exp_shift; |
143 | 0 | preser = O.exp_preser; |
144 | 0 | exp_bef(expos, preser); |
145 | 0 | } |
146 | | |
147 | 2.35k | if (callbacks.pre_interpolate_cb) |
148 | 0 | (callbacks.pre_interpolate_cb)(this); |
149 | | |
150 | | /* post-exposure correction fallback */ |
151 | 2.35k | if (P1.filters && !O.no_interpolation) |
152 | 1.88k | { |
153 | 1.88k | int real_colors = P1.colors; |
154 | 1.88k | int bad_bayer = 0; |
155 | 1.88k | if (P1.filters > 1000) |
156 | 8.84k | for (int r = 0; r < 4; r++) |
157 | 63.6k | for (int c = 0; c < 8; c++) |
158 | 56.6k | { |
159 | 56.6k | real_colors = MAX(COLOR(r, c) + 1, real_colors); |
160 | 56.6k | if (P1.filters > 1000) |
161 | 56.6k | { |
162 | | // Normal bayer: adjacent pixels horizontally/vertically have different colors |
163 | 56.6k | bad_bayer += (FC(r, c) == FC(r + 1, c)); |
164 | 56.6k | bad_bayer += (FC(r, c) == FC(r, c + 1)); |
165 | 56.6k | } |
166 | 56.6k | } |
167 | | |
168 | 1.88k | if (noiserd > 0 && P1.colors == 3 && real_colors == 3 && P1.filters > 1000) |
169 | 0 | fbdd(noiserd); |
170 | | |
171 | 1.88k | if (P1.filters > 1000 && callbacks.interpolate_bayer_cb) |
172 | 0 | (callbacks.interpolate_bayer_cb)(this); |
173 | 1.88k | else if (P1.filters == 9 && callbacks.interpolate_xtrans_cb) |
174 | 0 | (callbacks.interpolate_xtrans_cb)(this); |
175 | 1.88k | else if (quality == 0) |
176 | 0 | lin_interpolate(); |
177 | 1.88k | else if (quality == 1 || P1.colors > 3 || real_colors > 3 || bad_bayer || (P1.filters != LIBRAW_XTRANS && P1.filters <= 1000)) |
178 | 284 | vng_interpolate(); |
179 | 1.59k | else if (quality == 2 && P1.filters > 1000) |
180 | 0 | ppg_interpolate(); |
181 | 1.59k | else if (P1.filters == LIBRAW_XTRANS) |
182 | 74 | { |
183 | | // Fuji X-Trans |
184 | 74 | xtrans_interpolate(quality > 2 ? 3 : 1); |
185 | 74 | } |
186 | 1.52k | else if (quality == 3) |
187 | 1.52k | ahd_interpolate(); // really don't need it here due to fallback op |
188 | 0 | else if (quality == 4) |
189 | 0 | dcb(iterations, dcb_enhance); |
190 | | |
191 | 0 | else if (quality == 11) |
192 | 0 | dht_interpolate(); |
193 | 0 | else if (quality == 12) |
194 | 0 | aahd_interpolate(); |
195 | | // fallback to AHD |
196 | 0 | else |
197 | 0 | { |
198 | 0 | ahd_interpolate(); |
199 | 0 | imgdata.process_warnings |= LIBRAW_WARN_FALLBACK_TO_AHD; |
200 | 0 | } |
201 | | |
202 | 1.88k | SET_PROC_FLAG(LIBRAW_PROGRESS_INTERPOLATE); |
203 | 1.88k | } |
204 | 2.35k | if (IO.mix_green) |
205 | 64 | { |
206 | 47.3k | for (P1.colors = 3, i = 0; i < S.height * S.width; i++) |
207 | 47.3k | imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1; |
208 | 64 | SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN); |
209 | 64 | } |
210 | | |
211 | 2.35k | if (callbacks.post_interpolate_cb) |
212 | 0 | (callbacks.post_interpolate_cb)(this); |
213 | 2.35k | else if (!P1.is_foveon && P1.colors == 3 && O.med_passes > 0) |
214 | 0 | { |
215 | 0 | median_filter(); |
216 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER); |
217 | 0 | } |
218 | | |
219 | 2.35k | if (O.highlight == 2) |
220 | 0 | { |
221 | 0 | blend_highlights(); |
222 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); |
223 | 0 | } |
224 | | |
225 | 2.35k | if (O.highlight > 2) |
226 | 0 | { |
227 | 0 | recover_highlights(); |
228 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); |
229 | 0 | } |
230 | | |
231 | 2.35k | if (O.use_fuji_rotate) |
232 | 2.27k | { |
233 | 2.27k | fuji_rotate(); |
234 | 2.27k | SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); |
235 | 2.27k | } |
236 | | |
237 | 2.35k | if (!libraw_internal_data.output_data.histogram) |
238 | 2.27k | { |
239 | 2.27k | libraw_internal_data.output_data.histogram = |
240 | 2.27k | (int(*)[LIBRAW_HISTOGRAM_SIZE])calloc(1, |
241 | 2.27k | sizeof(*libraw_internal_data.output_data.histogram) * 4); |
242 | 2.27k | } |
243 | | #ifndef NO_LCMS |
244 | | if (O.camera_profile) |
245 | | { |
246 | | apply_profile(O.camera_profile, O.output_profile); |
247 | | SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE); |
248 | | } |
249 | | #endif |
250 | | |
251 | 2.35k | if (callbacks.pre_converttorgb_cb) |
252 | 0 | (callbacks.pre_converttorgb_cb)(this); |
253 | | |
254 | 2.35k | convert_to_rgb(); |
255 | 2.35k | SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB); |
256 | | |
257 | 2.35k | if (callbacks.post_converttorgb_cb) |
258 | 0 | (callbacks.post_converttorgb_cb)(this); |
259 | | |
260 | 2.35k | if (O.use_fuji_rotate) |
261 | 2.27k | { |
262 | 2.27k | stretch(); |
263 | 2.27k | SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH); |
264 | 2.27k | } |
265 | 2.35k | O.four_color_rgb = save_4color; // also, restore |
266 | | |
267 | 2.35k | return 0; |
268 | 2.49k | } |
269 | 2.49k | catch (const std::bad_alloc&) |
270 | 2.49k | { |
271 | 0 | recycle(); |
272 | 0 | return LIBRAW_UNSUFFICIENT_MEMORY; |
273 | 0 | } |
274 | 2.49k | catch (const LibRaw_exceptions& err) |
275 | 2.49k | { |
276 | 74 | EXCEPTION_HANDLER(err); |
277 | 74 | } |
278 | 2.49k | } |