Coverage Report

Created: 2025-07-18 06:59

/src/libraw/src/postprocessing/mem_image.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- C++ -*-
2
 * Copyright 2019-2024 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
libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *errcode)
18
0
{
19
0
  if (!T.thumb)
20
0
  {
21
0
    if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 &&
22
0
                         load_raw == &LibRaw::broadcom_load_raw) // RPi
23
0
    )
24
0
    {
25
0
      if (errcode)
26
0
        *errcode = LIBRAW_NO_THUMBNAIL;
27
0
    }
28
0
    else
29
0
    {
30
0
      if (errcode)
31
0
        *errcode = LIBRAW_OUT_OF_ORDER_CALL;
32
0
    }
33
0
    return NULL;
34
0
  }
35
36
0
  if (T.tlength < 64u)
37
0
  {
38
0
      if (errcode)
39
0
          *errcode = EINVAL;
40
0
      return NULL;
41
0
  }
42
43
0
  if (INT64(T.tlength) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB)
44
0
  {
45
0
      if (errcode)
46
0
          *errcode = LIBRAW_TOO_BIG;
47
0
      return NULL;
48
0
  }
49
50
0
  if (T.tformat == LIBRAW_THUMBNAIL_BITMAP)
51
0
  {
52
0
    libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
53
0
        sizeof(libraw_processed_image_t) + T.tlength);
54
55
0
    if (!ret)
56
0
    {
57
0
      if (errcode)
58
0
        *errcode = ENOMEM;
59
0
      return NULL;
60
0
    }
61
62
0
    memset(ret, 0, sizeof(libraw_processed_image_t));
63
0
    ret->type = LIBRAW_IMAGE_BITMAP;
64
0
    ret->height = T.theight;
65
0
    ret->width = T.twidth;
66
0
    if (T.tcolors > 0 && T.tcolors < 4)
67
0
        ret->colors = T.tcolors;
68
0
    else
69
0
        ret->colors = 3; // defaults
70
0
    ret->bits = 8;
71
0
    ret->data_size = T.tlength;
72
0
    memmove(ret->data, T.thumb, T.tlength);
73
0
    if (errcode)
74
0
      *errcode = 0;
75
0
    return ret;
76
0
  }
77
0
  else if (T.tformat == LIBRAW_THUMBNAIL_JPEG)
78
0
  {
79
0
    ushort exif[5];
80
0
    int mk_exif = 0;
81
0
    if (strcmp(T.thumb + 6, "Exif"))
82
0
      mk_exif = 1;
83
84
0
    int dsize = T.tlength + mk_exif * (sizeof(exif) + sizeof(tiff_hdr));
85
86
0
    libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
87
0
        sizeof(libraw_processed_image_t) + dsize);
88
89
0
    if (!ret)
90
0
    {
91
0
      if (errcode)
92
0
        *errcode = ENOMEM;
93
0
      return NULL;
94
0
    }
95
96
0
    memset(ret, 0, sizeof(libraw_processed_image_t));
97
98
0
    ret->type = LIBRAW_IMAGE_JPEG;
99
0
    ret->data_size = dsize;
100
101
0
    ret->data[0] = 0xff;
102
0
    ret->data[1] = 0xd8;
103
0
    if (mk_exif)
104
0
    {
105
0
      struct tiff_hdr th;
106
0
      memcpy(exif, "\xff\xe1  Exif\0\0", 10);
107
0
      exif[1] = htons(8 + sizeof th);
108
0
      memmove(ret->data + 2, exif, sizeof(exif));
109
0
      tiff_head(&th, 0);
110
0
      memmove(ret->data + (2 + sizeof(exif)), &th, sizeof(th));
111
0
      memmove(ret->data + (2 + sizeof(exif) + sizeof(th)), T.thumb + 2,
112
0
              T.tlength - 2);
113
0
    }
114
0
    else
115
0
    {
116
0
      memmove(ret->data + 2, T.thumb + 2, T.tlength - 2);
117
0
    }
118
0
    if (errcode)
119
0
      *errcode = 0;
120
0
    return ret;
121
0
  }
122
0
  else if (T.tformat == LIBRAW_THUMBNAIL_H265 || T.tformat == LIBRAW_THUMBNAIL_JPEGXL)
123
0
  {
124
0
    int dsize = T.tlength;
125
0
    libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t) + dsize);
126
0
    if (!ret)
127
0
    {
128
0
      if (errcode)
129
0
        *errcode = ENOMEM;
130
0
      return NULL;
131
0
    }
132
0
    memset(ret, 0, sizeof(libraw_processed_image_t));
133
0
    ret->type = T.tformat == LIBRAW_THUMBNAIL_H265 ? LIBRAW_IMAGE_H265 : LIBRAW_IMAGE_JPEGXL;
134
0
    ret->data_size = dsize;
135
0
    memmove(ret->data, T.thumb, dsize);
136
0
    if (errcode)
137
0
      *errcode = 0;
138
0
    return ret;
139
0
  }
140
0
  else
141
0
  {
142
0
    if (errcode)
143
0
      *errcode = LIBRAW_UNSUPPORTED_THUMBNAIL;
144
0
    return NULL;
145
0
  }
146
0
}
147
148
// jlb
149
// macros for copying pixels to either BGR or RGB formats
150
0
#define FORBGR for (c = P1.colors - 1; c >= 0; c--)
151
0
#define FORRGB for (c = 0; c < P1.colors; c++)
152
153
void LibRaw::get_mem_image_format(int *width, int *height, int *colors,
154
                                  int *bps) const
155
156
0
{
157
0
  *width = S.width;
158
0
  *height = S.height;
159
0
  if (imgdata.progress_flags < LIBRAW_PROGRESS_FUJI_ROTATE)
160
0
  {
161
0
    if (O.use_fuji_rotate)
162
0
    {
163
0
      if (IO.fuji_width)
164
0
      {
165
0
        int fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink;
166
0
        *width = (ushort)(fuji_width / sqrt(0.5));
167
0
        *height = (ushort)((*height - fuji_width) / sqrt(0.5));
168
0
      }
169
0
      else
170
0
      {
171
0
        if (S.pixel_aspect < 0.995)
172
0
          *height = (ushort)(*height / S.pixel_aspect + 0.5);
173
0
        if (S.pixel_aspect > 1.005)
174
0
          *width = (ushort)(*width * S.pixel_aspect + 0.5);
175
0
      }
176
0
    }
177
0
  }
178
0
  if (S.flip & 4)
179
0
  {
180
0
    std::swap(*width, *height);
181
0
  }
182
0
  *colors = P1.colors;
183
0
  *bps = O.output_bps;
184
0
}
185
186
int LibRaw::copy_mem_image(void *scan0, int stride, int bgr)
187
188
0
{
189
  // the image memory pointed to by scan0 is assumed to be in the format
190
  // returned by get_mem_image_format
191
0
  if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) <
192
0
      LIBRAW_PROGRESS_PRE_INTERPOLATE)
193
0
    return LIBRAW_OUT_OF_ORDER_CALL;
194
195
0
  if (libraw_internal_data.output_data.histogram)
196
0
  {
197
0
    int perc, val, total, t_white = 0x2000, c;
198
0
    perc = int(S.width * S.height * O.auto_bright_thr);
199
0
    if (IO.fuji_width)
200
0
      perc /= 2;
201
0
    if (!((O.highlight & ~2) || O.no_auto_bright))
202
0
      for (t_white = c = 0; c < P1.colors; c++)
203
0
      {
204
0
        for (val = 0x2000, total = 0; --val > 32;)
205
0
          if ((total += libraw_internal_data.output_data.histogram[c][val]) >
206
0
              perc)
207
0
            break;
208
0
        if (t_white < val)
209
0
          t_white = val;
210
0
      }
211
0
    gamma_curve(O.gamm[0], O.gamm[1], 2, int((t_white << 3) / O.bright));
212
0
  }
213
214
0
  int s_iheight = S.iheight;
215
0
  int s_iwidth = S.iwidth;
216
0
  int s_width = S.width;
217
0
  int s_hwight = S.height;
218
219
0
  S.iheight = S.height;
220
0
  S.iwidth = S.width;
221
222
0
  if (S.flip & 4)
223
0
    SWAP(S.height, S.width);
224
0
  uchar *ppm;
225
0
  ushort *ppm2;
226
0
  int c, row, col, soff, rstep, cstep;
227
228
0
  soff = flip_index(0, 0);
229
0
  cstep = flip_index(0, 1) - soff;
230
0
  rstep = flip_index(1, 0) - flip_index(0, S.width);
231
232
0
  for (row = 0; row < S.height; row++, soff += rstep)
233
0
  {
234
0
    uchar *bufp = ((uchar *)scan0) + row * stride;
235
0
    ppm2 = (ushort *)(ppm = bufp);
236
    // keep trivial decisions in the outer loop for speed
237
0
    if (bgr)
238
0
    {
239
0
      if (O.output_bps == 8)
240
0
      {
241
0
        for (col = 0; col < S.width; col++, soff += cstep)
242
0
          FORBGR *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8;
243
0
      }
244
0
      else
245
0
      {
246
0
        for (col = 0; col < S.width; col++, soff += cstep)
247
0
          FORBGR *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]];
248
0
      }
249
0
    }
250
0
    else
251
0
    {
252
0
      if (O.output_bps == 8)
253
0
      {
254
0
        for (col = 0; col < S.width; col++, soff += cstep)
255
0
          FORRGB *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8;
256
0
      }
257
0
      else
258
0
      {
259
0
        for (col = 0; col < S.width; col++, soff += cstep)
260
0
          FORRGB *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]];
261
0
      }
262
0
    }
263
264
    //            bufp += stride;           // go to the next line
265
0
  }
266
267
0
  S.iheight = s_iheight;
268
0
  S.iwidth = s_iwidth;
269
0
  S.width = s_width;
270
0
  S.height = s_hwight;
271
272
0
  return 0;
273
0
}
274
#undef FORBGR
275
#undef FORRGB
276
277
libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode)
278
279
0
{
280
0
  int width, height, colors, bps;
281
0
  get_mem_image_format(&width, &height, &colors, &bps);
282
0
  int stride = width * (bps / 8) * colors;
283
0
  unsigned ds = height * stride;
284
0
  libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
285
0
      sizeof(libraw_processed_image_t) + ds);
286
0
  if (!ret)
287
0
  {
288
0
    if (errcode)
289
0
      *errcode = ENOMEM;
290
0
    return NULL;
291
0
  }
292
0
  memset(ret, 0, sizeof(libraw_processed_image_t));
293
294
  // metadata init
295
0
  ret->type = LIBRAW_IMAGE_BITMAP;
296
0
  ret->height = height;
297
0
  ret->width = width;
298
0
  ret->colors = colors;
299
0
  ret->bits = bps;
300
0
  ret->data_size = ds;
301
0
  copy_mem_image(ret->data, stride, 0);
302
303
0
  return ret;
304
0
}
305
306
void LibRaw::dcraw_clear_mem(libraw_processed_image_t *p)
307
0
{
308
0
  if (p)
309
0
    ::free(p);
310
0
}