Coverage Report

Created: 2026-11-12 07:35

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-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
}