Coverage Report

Created: 2026-02-26 07:48

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