Coverage Report

Created: 2026-02-11 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}