Coverage Report

Created: 2026-10-27 06:57

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
2.62k
{
23
2.62k
  float out_cam[3][4];
24
2.62k
  double num, inverse[3][3];
25
2.62k
  static const double(*out_rgb[])[3] = {
26
2.62k
      LibRaw_constants::rgb_rgb,  LibRaw_constants::adobe_rgb,
27
2.62k
      LibRaw_constants::wide_rgb, LibRaw_constants::prophoto_rgb,
28
2.62k
      LibRaw_constants::xyz_rgb,  LibRaw_constants::aces_rgb,
29
2.62k
      LibRaw_constants::dcip3d65_rgb,  LibRaw_constants::rec2020_rgb};
30
2.62k
  static const char *name[] = {"sRGB",          "Adobe RGB (1998)",
31
2.62k
                               "WideGamut D65", "ProPhoto D65",
32
2.62k
                               "XYZ",           "ACES",
33
2.62k
                               "DCI-P3 D65",    "Rec. 2020"};
34
2.62k
  static const unsigned phead[] = {
35
2.62k
      1024, 0, 0x2100000,  0x6d6e7472, 0x52474220, 0x58595a20, 0,
36
2.62k
      0,    0, 0x61637370, 0,          0,          0x6e6f6e65, 0,
37
2.62k
      0,    0, 0,          0xf6d6,     0x10000,    0xd32d};
38
2.62k
  unsigned pbody[] = {10,         0x63707274, 0,  36, /* cprt */
39
2.62k
                      0x64657363, 0,          60,     /* desc, len is strlen(longest_string) + 12 */
40
2.62k
                      0x77747074, 0,          20,     /* wtpt */
41
2.62k
                      0x626b7074, 0,          20,     /* bkpt */
42
2.62k
                      0x72545243, 0,          14,     /* rTRC */
43
2.62k
                      0x67545243, 0,          14,     /* gTRC */
44
2.62k
                      0x62545243, 0,          14,     /* bTRC */
45
2.62k
                      0x7258595a, 0,          20,     /* rXYZ */
46
2.62k
                      0x6758595a, 0,          20,     /* gXYZ */
47
2.62k
                      0x6258595a, 0,          20};    /* bXYZ */
48
2.62k
  static const unsigned pwhite[] = {0xf351, 0x10000, 0x116cc};
49
2.62k
  unsigned pcurve[] = {0x63757276, 0, 1, 0x1000000};
50
51
2.62k
  RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 0, 2);
52
53
2.62k
  gamma_curve(gamm[0], gamm[1], 0, 0);
54
2.62k
  memcpy(out_cam, rgb_cam, sizeof out_cam);
55
2.62k
  raw_color |= colors == 1 || output_color < 1 || output_color > 8;
56
2.62k
  if (!raw_color)
57
616
  {
58
616
  size_t prof_desc_len;
59
616
  std::vector<char> prof_desc;
60
616
    int i, j, k;
61
616
    prof_desc_len = snprintf(NULL, 0, "%s gamma %g toe slope %g", name[output_color - 1],
62
616
                             floor(1000. / gamm[0] + .5) / 1000., floor(gamm[1] * 1000.0 + .5) / 1000.) +
63
616
                    1;
64
616
    prof_desc.resize(prof_desc_len);
65
616
    sprintf(prof_desc.data(), "%s gamma %g toe slope %g", name[output_color - 1], floor(1000. / gamm[0] + .5) / 1000.,
66
616
            floor(gamm[1] * 1000.0 + .5) / 1000.);
67
68
616
  oprof = (unsigned *)calloc(phead[0], 1);
69
616
    memcpy(oprof, phead, sizeof phead);
70
616
    if (output_color == 5)
71
0
      oprof[4] = oprof[5];
72
616
    oprof[0] = 132 + 12 * pbody[0];
73
6.77k
    for (i = 0; i < (int)pbody[0]; i++)
74
6.16k
    {
75
6.16k
      oprof[oprof[0] / 4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874;
76
6.16k
      pbody[i * 3 + 2] = oprof[0];
77
6.16k
      oprof[0] += (pbody[i * 3 + 3] + 3) & -4;
78
6.16k
    }
79
616
    memcpy(oprof + 32, pbody, sizeof pbody);
80
616
    oprof[pbody[5] / 4 + 2] = unsigned(prof_desc_len + 1);
81
616
    memcpy((char *)oprof + pbody[8] + 8, pwhite, sizeof pwhite);
82
616
    pcurve[3] = (short)(256 / gamm[5] + 0.5) << 16;
83
2.46k
    for (i = 4; i < 7; i++)
84
1.84k
      memcpy((char *)oprof + pbody[i * 3 + 2], pcurve, sizeof pcurve);
85
616
    pseudoinverse((double(*)[3])out_rgb[output_color - 1], inverse, 3);
86
2.46k
    for (i = 0; i < 3; i++)
87
7.39k
      for (j = 0; j < 3; j++)
88
5.54k
      {
89
22.1k
        for (num = k = 0; k < 3; k++)
90
16.6k
          num += LibRaw_constants::xyzd50_srgb[i][k] * inverse[j][k];
91
5.54k
        oprof[pbody[j * 3 + 23] / 4 + i + 2] = unsigned(num * 0x10000 + 0.5);
92
5.54k
      }
93
158k
    for (i = 0; i < (int)phead[0] / 4; i++)
94
157k
      oprof[i] = htonl(oprof[i]);
95
616
    strcpy((char *)oprof + pbody[2] + 8, "auto-generated by dcraw");
96
616
    if (pbody[5] + 12 + prof_desc.size() < phead[0])
97
616
    strcpy((char *)oprof + pbody[5] + 12, prof_desc.data());
98
2.46k
    for (i = 0; i < 3; i++)
99
8.05k
      for (j = 0; j < colors; j++)
100
24.8k
        for (out_cam[i][j] = 0.f, k = 0; k < 3; k++)
101
18.6k
          out_cam[i][j] += float(out_rgb[output_color - 1][i][k] * rgb_cam[k][j]);
102
616
  }
103
2.62k
  convert_to_rgb_loop(out_cam);
104
105
2.62k
  if (colors == 4 && output_color)
106
299
    colors = 3;
107
108
2.62k
  RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 1, 2);
109
2.62k
}
110
111
void LibRaw::scale_colors()
112
2.70k
{
113
2.70k
  unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8];
114
2.70k
  int val;
115
2.70k
  double dsum[8], dmin, dmax;
116
2.70k
  float scale_mul[4], fr, fc;
117
2.70k
  ushort *img = 0, *pix;
118
119
2.70k
  RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 0, 2);
120
121
2.70k
  if (user_mul[0])
122
0
    memcpy(pre_mul, user_mul, sizeof pre_mul);
123
2.70k
  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
2.70k
  {
129
2.70k
    memset(dsum, 0, sizeof dsum);
130
2.70k
    bottom = MIN(greybox[1] + greybox[3], height);
131
2.70k
    right = MIN(greybox[0] + greybox[2], width);
132
814k
    for (row = greybox[1]; row < bottom; row += 8)
133
25.6M
      for (col = greybox[0]; col < right; col += 8)
134
24.8M
      {
135
24.8M
        memset(sum, 0, sizeof sum);
136
103M
        for (y = row; y < row + 8 && y < bottom; y++)
137
716M
          for (x = col; x < col + 8 && x < right; x++)
138
638M
            FORC4
139
854M
            {
140
854M
              if (filters)
141
565M
              {
142
565M
                c = fcol(y, x);
143
565M
                val = BAYER2(y, x);
144
565M
              }
145
288M
              else
146
288M
                val = image[y * width + x][c];
147
854M
              if (val > (int)maximum - 25)
148
15.1M
                goto skip_block;
149
838M
              if ((val -= cblack[c]) < 0)
150
6.10M
                val = 0;
151
838M
              sum[c] += val;
152
838M
              sum[c + 4]++;
153
838M
              if (filters)
154
550M
                break;
155
838M
            }
156
76.9M
        FORC(8) dsum[c] += sum[c];
157
24.8M
      skip_block:;
158
24.8M
      }
159
10.8k
    FORC4 if (dsum[c]) pre_mul[c] = float(dsum[c + 4] / dsum[c]);
160
2.70k
  }
161
2.70k
  if (use_camera_wb && cam_mul[0] > 0.00001f)
162
93
  {
163
93
    memset(sum, 0, sizeof sum);
164
837
    for (row = 0; row < 8; row++)
165
6.69k
      for (col = 0; col < 8; col++)
166
5.95k
      {
167
5.95k
        c = FC(row, col);
168
5.95k
        if ((val = white[row][col] - cblack[c]) > 0)
169
0
          sum[c] += val;
170
5.95k
        sum[c + 4]++;
171
5.95k
      }
172
93
    if (imgdata.color.as_shot_wb_applied)
173
6
    {
174
      // Nikon sRAW: camera WB already applied:
175
6
      pre_mul[0] = pre_mul[1] = pre_mul[2] = pre_mul[3] = 1.0;
176
6
    }
177
87
    else if (sum[0] && sum[1] && sum[2] && sum[3])
178
0
      FORC4 pre_mul[c] = (float)sum[c + 4] / sum[c];
179
87
    else if (cam_mul[0] > 0.00001f && cam_mul[2] > 0.00001f)
180
86
      memcpy(pre_mul, cam_mul, sizeof pre_mul);
181
1
    else
182
1
    {
183
1
      imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB;
184
1
    }
185
93
  }
186
  // Nikon sRAW, daylight
187
2.70k
  if (imgdata.color.as_shot_wb_applied && !use_camera_wb && !use_auto_wb &&
188
0
      cam_mul[0] > 0.00001f && cam_mul[1] > 0.00001f && cam_mul[2] > 0.00001f)
189
0
  {
190
0
    for (c = 0; c < 3; c++)
191
0
      pre_mul[c] /= cam_mul[c];
192
0
  }
193
2.70k
  if (pre_mul[1] == 0)
194
1
    pre_mul[1] = 1;
195
2.70k
  if (pre_mul[3] == 0)
196
1.19k
    pre_mul[3] = colors < 4 ? pre_mul[1] : 1;
197
2.70k
  if (threshold)
198
0
    wavelet_denoise();
199
2.70k
  maximum -= black;
200
13.5k
  for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++)
201
10.8k
  {
202
10.8k
    if (dmin > pre_mul[c])
203
4.82k
      dmin = pre_mul[c];
204
10.8k
    if (dmax < pre_mul[c])
205
4.79k
      dmax = pre_mul[c];
206
10.8k
  }
207
2.70k
  if (!highlight)
208
2.70k
    dmax = dmin;
209
2.70k
  if (dmax > 0.00001 && maximum > 0)
210
10.4k
    FORC4 scale_mul[c] = (pre_mul[c] /= float(dmax)) * 65535.f / maximum;
211
100
  else
212
400
    FORC4 scale_mul[c] = 1.0;
213
214
2.70k
  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
2.70k
  size = iheight * iwidth;
221
2.70k
  scale_colors_loop(scale_mul);
222
2.70k
  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
2.70k
  RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 1, 2);
257
2.70k
}
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
}