Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/LibRaw/src/write/file_write.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
#include <vector>
21
22
int LibRaw::flip_index(int row, int col)
23
0
{
24
0
  if (flip & 4)
25
0
    SWAP(row, col);
26
0
  if (flip & 2)
27
0
    row = iheight - 1 - row;
28
0
  if (flip & 1)
29
0
    col = iwidth - 1 - col;
30
0
  return row * iwidth + col;
31
0
}
32
33
void LibRaw::tiff_set(struct tiff_hdr *th, ushort *ntag, ushort tag,
34
                      ushort type, int count, int val)
35
0
{
36
0
  struct libraw_tiff_tag *tt;
37
0
  int c;
38
39
0
  tt = (struct libraw_tiff_tag *)(ntag + 1) + (*ntag)++;
40
0
  tt->val.i = val;
41
0
  if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_BYTE) && count <= 4)
42
0
    FORC(4) tt->val.c[c] = val >> (c << 3);
43
0
  else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_ASCII))
44
0
  {
45
0
    count = int(strnlen((char *)th + val, count - 1)) + 1;
46
0
    if (count <= 4)
47
0
      FORC(4) tt->val.c[c] = ((char *)th)[val + c];
48
0
  }
49
0
  else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) && count <= 2)
50
0
    FORC(2) tt->val.s[c] = val >> (c << 4);
51
0
  tt->count = count;
52
0
  tt->type = type;
53
0
  tt->tag = tag;
54
0
}
55
56
// local strnlen: we cannot use LibRaw::strnlen b/c it is protected
57
static size_t local_static_strnlen(const char *s, size_t n)
58
0
{
59
0
#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
60
0
  const char *p = (const char *)memchr(s, 0, n);
61
0
  return (p ? p - s : n);
62
#else
63
  return strnlen(s, n);
64
#endif
65
0
}
66
67
68
static void tiff_set_str4(struct tiff_hdr *th, ushort *ntag, ushort tag, ushort type, int count, const uchar* val)
69
0
{
70
0
  struct libraw_tiff_tag *tt;
71
0
  int c;
72
0
  tt = (struct libraw_tiff_tag *)(ntag + 1) + (*ntag)++;
73
0
  count = int(local_static_strnlen((const char*)val, count-1)) + 1;
74
0
  FORC(4) tt->val.c[c] = val[c];
75
0
  tt->count = count;
76
0
  tt->type = type;
77
0
  tt->tag = tag;
78
0
}
79
80
0
#define TOFF(ptr) int((char *)(&(ptr)) - (char *)th)
81
82
void LibRaw::tiff_head(struct tiff_hdr *th, int full)
83
0
{
84
0
  int c, psize = 0;
85
0
  struct tm *t;
86
87
0
  memset(th, 0, sizeof *th);
88
0
  th->t_order = htonl(0x4d4d4949) >> 16;
89
0
  th->magic = 42;
90
0
  th->ifd = 10;
91
0
  th->rat[0] = th->rat[2] = 300;
92
0
  th->rat[1] = th->rat[3] = 1;
93
0
  FORC(6) th->rat[4 + c] = 1000000;
94
0
  th->rat[4] = int(shutter * 1000000.f);
95
0
  th->rat[6] = int(aperture * 1000000.f);
96
0
  th->rat[8] = int(focal_len * 1000000.f);
97
0
  strncpy(th->t_desc, desc, 512);
98
0
  strncpy(th->t_make, make, 64);
99
0
  strncpy(th->t_model, model, 64);
100
0
  strcpy(th->soft, "dcraw v" DCRAW_VERSION);
101
0
  t = localtime(&timestamp);
102
0
  sprintf(th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year + 1900,
103
0
          t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
104
0
  strncpy(th->t_artist, artist, 64);
105
0
  if (full)
106
0
  {
107
0
    tiff_set(th, &th->ntag, 254, 4, 1, 0);
108
0
    tiff_set(th, &th->ntag, 256, 4, 1, width);
109
0
    tiff_set(th, &th->ntag, 257, 4, 1, height);
110
0
    tiff_set(th, &th->ntag, 258, 3, colors, output_bps);
111
0
    if (colors > 2)
112
0
      th->tag[th->ntag - 1].val.i = TOFF(th->bps);
113
0
    FORC4 th->bps[c] = output_bps;
114
0
    tiff_set(th, &th->ntag, 259, 3, 1, 1);
115
0
    tiff_set(th, &th->ntag, 262, 3, 1, 1 + (colors > 1));
116
0
  }
117
0
  tiff_set(th, &th->ntag, 270, 2, 512, TOFF(th->t_desc));
118
0
  tiff_set(th, &th->ntag, 271, 2, 64, TOFF(th->t_make));
119
0
  tiff_set(th, &th->ntag, 272, 2, 64, TOFF(th->t_model));
120
0
  if (full)
121
0
  {
122
0
    if (oprof)
123
0
      psize = ntohl(oprof[0]);
124
0
    tiff_set(th, &th->ntag, 273, 4, 1, sizeof *th + psize);
125
0
    tiff_set(th, &th->ntag, 277, 3, 1, colors);
126
0
    tiff_set(th, &th->ntag, 278, 4, 1, height);
127
0
  INT64 strip_bytes = INT64(height) * INT64(width) * INT64(colors) * INT64(output_bps) / 8LL;
128
0
  if (strip_bytes >= 2147483647LL)
129
0
    throw LIBRAW_EXCEPTION_TOOBIG; // bigtiff is not supported...
130
0
  int strip_bytes_32 = strip_bytes;
131
0
  tiff_set(th, &th->ntag, 279, 4, 1, strip_bytes_32);
132
0
  }
133
0
  else
134
0
    tiff_set(th, &th->ntag, 274, 3, 1, "12435867"[flip] - '0');
135
0
  tiff_set(th, &th->ntag, 282, 5, 1, TOFF(th->rat[0]));
136
0
  tiff_set(th, &th->ntag, 283, 5, 1, TOFF(th->rat[2]));
137
0
  tiff_set(th, &th->ntag, 284, 3, 1, 1);
138
0
  tiff_set(th, &th->ntag, 296, 3, 1, 2);
139
0
  tiff_set(th, &th->ntag, 305, 2, 32, TOFF(th->soft));
140
0
  tiff_set(th, &th->ntag, 306, 2, 20, TOFF(th->date));
141
0
  tiff_set(th, &th->ntag, 315, 2, 64, TOFF(th->t_artist));
142
0
  tiff_set(th, &th->ntag, 34665, 4, 1, TOFF(th->nexif));
143
0
  if (psize)
144
0
    tiff_set(th, &th->ntag, 34675, 7, psize, sizeof *th);
145
0
  tiff_set(th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4]));
146
0
  tiff_set(th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6]));
147
0
  tiff_set(th, &th->nexif, 34855, 3, 1, int(iso_speed));
148
0
  tiff_set(th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8]));
149
0
  if (gpsdata[1])
150
0
  {
151
0
    uchar latref[4] = { (uchar)(gpsdata[29]),0,0,0 },
152
0
          lonref[4] = { (uchar)(gpsdata[30]),0,0,0 };
153
0
    tiff_set(th, &th->ntag, 34853, 4, 1, TOFF(th->ngps));
154
0
    tiff_set(th, &th->ngps, 0, 1, 4, 0x202);
155
0
    tiff_set_str4(th, &th->ngps, 1, 2, 2, latref);
156
0
    tiff_set(th, &th->ngps, 2, 5, 3, TOFF(th->gps[0]));
157
0
    tiff_set_str4(th, &th->ngps, 3, 2, 2, lonref);
158
0
    tiff_set(th, &th->ngps, 4, 5, 3, TOFF(th->gps[6]));
159
0
    tiff_set(th, &th->ngps, 5, 1, 1, gpsdata[31]);
160
0
    tiff_set(th, &th->ngps, 6, 5, 1, TOFF(th->gps[18]));
161
0
    tiff_set(th, &th->ngps, 7, 5, 3, TOFF(th->gps[12]));
162
0
    tiff_set(th, &th->ngps, 18, 2, 12, TOFF(th->gps[20]));
163
0
    tiff_set(th, &th->ngps, 29, 2, 12, TOFF(th->gps[23]));
164
0
    memcpy(th->gps, gpsdata, sizeof th->gps);
165
0
  }
166
0
}
167
168
void LibRaw::jpeg_thumb_writer(FILE *tfp, char *t_humb, int t_humb_length)
169
0
{
170
0
  ushort exif[5];
171
0
  struct tiff_hdr th;
172
0
  fputc(0xff, tfp);
173
0
  fputc(0xd8, tfp);
174
0
  if (memcmp(t_humb + 6, "Exif\0",5))
175
0
  {
176
0
    memcpy(exif, "\xff\xe1  Exif\0\0", 10);
177
0
    exif[1] = htons(8 + sizeof th);
178
0
    fwrite(exif, 1, sizeof exif, tfp);
179
0
    tiff_head(&th, 0);
180
0
    fwrite(&th, 1, sizeof th, tfp);
181
0
  }
182
0
  fwrite(t_humb + 2, 1, t_humb_length - 2, tfp);
183
0
}
184
void LibRaw::write_ppm_tiff()
185
0
{
186
0
    try
187
0
    {
188
0
        struct tiff_hdr th;
189
0
        ushort *ppm2;
190
0
        int c, row, col, soff, rstep, cstep;
191
0
        int perc, val, total, t_white = 0x2000;
192
193
0
        perc = int(width * height * auto_bright_thr);
194
195
0
        if (fuji_width)
196
0
            perc /= 2;
197
0
        if (!((highlight & ~2) || no_auto_bright))
198
0
            for (t_white = c = 0; c < colors; c++)
199
0
            {
200
0
                for (val = 0x2000, total = 0; --val > 32;)
201
0
                    if ((total += histogram[c][val]) > perc)
202
0
                        break;
203
0
                if (t_white < val)
204
0
                    t_white = val;
205
0
            }
206
0
        gamma_curve(gamm[0], gamm[1], 2, int((t_white << 3) / bright));
207
0
        iheight = height;
208
0
        iwidth = width;
209
0
        if (flip & 4)
210
0
            SWAP(height, width);
211
212
0
        std::vector<uchar> ppm(width * colors * output_bps / 8);
213
0
        ppm2 = (ushort *)ppm.data();
214
0
        if (output_tiff)
215
0
        {
216
0
            tiff_head(&th, 1);
217
0
            fwrite(&th, sizeof th, 1, ofp);
218
0
            if (oprof)
219
0
                fwrite(oprof, ntohl(oprof[0]), 1, ofp);
220
0
        }
221
0
        else if (colors > 3)
222
0
  {
223
0
      if(imgdata.params.output_flags & LIBRAW_OUTPUT_FLAGS_PPMMETA)
224
0
        fprintf(ofp,
225
0
              "P7\n# EXPTIME=%0.5f\n# TIMESTAMP=%lld\n# ISOSPEED=%d\n"
226
0
              "# APERTURE=%0.1f\n# FOCALLEN=%0.1f\n# MAKE=%s\n# MODEL=%s\n"
227
0
              "WIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n",
228
0
              shutter, (long long int)timestamp, (int)iso_speed,aperture, 
229
0
        focal_len, make, model,
230
0
        width, height, colors, (1 << output_bps) - 1, cdesc);
231
0
      else
232
0
            fprintf(
233
0
                ofp,
234
0
                "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n",
235
0
                width, height, colors, (1 << output_bps) - 1, cdesc);
236
0
  }
237
0
        else
238
0
  {
239
0
      if(imgdata.params.output_flags & LIBRAW_OUTPUT_FLAGS_PPMMETA)
240
0
        fprintf(ofp, "P%d\n# EXPTIME=%0.5f\n# TIMESTAMP=%lld\n"
241
0
    "# ISOSPEED=%d\n# APERTURE=%0.1f\n# FOCALLEN=%0.1f\n"
242
0
    "# MAKE=%s\n# MODEL=%s\n%d %d\n%d\n",
243
0
                colors/2+5,
244
0
    shutter, (long long int)timestamp, (int)iso_speed,aperture,focal_len,
245
0
    make,model,
246
0
    width, height, (1 << output_bps)-1);
247
0
      else
248
0
             fprintf(ofp, "P%d\n%d %d\n%d\n", colors / 2 + 5, width, height,
249
0
            (1 << output_bps) - 1);
250
0
        }
251
0
        soff = flip_index(0, 0);
252
0
        cstep = flip_index(0, 1) - soff;
253
0
        rstep = flip_index(1, 0) - flip_index(0, width);
254
0
        for (row = 0; row < height; row++, soff += rstep)
255
0
        {
256
0
            for (col = 0; col < width; col++, soff += cstep)
257
0
                if (output_bps == 8)
258
0
                    FORCC ppm[col * colors + c] = curve[image[soff][c]] >> 8;
259
0
                else
260
0
                    FORCC ppm2[col * colors + c] = curve[image[soff][c]];
261
0
            if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa)
262
0
                libraw_swab(ppm2, width * colors * 2);
263
0
            fwrite(ppm.data(), colors * output_bps / 8, width, ofp);
264
0
        }
265
0
    }
266
0
    catch (...)
267
0
    {
268
0
      throw LIBRAW_EXCEPTION_ALLOC; // rethrow
269
0
    }
270
0
}
271
#if 0
272
void LibRaw::ppm_thumb()
273
{
274
    try
275
    {
276
        thumb_length = thumb_width * thumb_height * 3;
277
        std::vector<char> thumb(thumb_length);
278
        fprintf(ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height);
279
        fread(thumb.data(), 1, thumb_length, ifp);
280
        fwrite(thumb.data(), 1, thumb_length, ofp);
281
    }
282
    catch (...)
283
    {
284
      throw LIBRAW_EXCEPTION_ALLOC; // rethrow
285
    }
286
}
287
288
void LibRaw::ppm16_thumb()
289
{
290
    try
291
    {
292
        unsigned i;
293
        thumb_length = thumb_width * thumb_height * 3;
294
        std::vector<char> thumb(thumb_length * 2, 0);
295
        read_shorts((ushort *)thumb.data(), thumb_length);
296
        for (i = 0; i < thumb_length; i++)
297
            thumb[i] = ((ushort *)thumb.data())[i] >> 8;
298
        fprintf(ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height);
299
        fwrite(thumb.data(), 1, thumb_length, ofp);
300
    }
301
    catch (...)
302
    {
303
      throw LIBRAW_EXCEPTION_ALLOC; // rethrow
304
    }
305
}
306
307
void LibRaw::layer_thumb()
308
{
309
    try
310
    {
311
        unsigned int i;
312
        int c;
313
        char map[][4] = { "012", "102" };
314
315
        colors = thumb_misc >> 5 & 7;
316
        thumb_length = thumb_width * thumb_height;
317
        std::vector<char> thumb(colors * thumb_length, 0);
318
        fprintf(ofp, "P%d\n%d %d\n255\n", 5 + (colors >> 1), thumb_width,
319
            thumb_height);
320
        fread(thumb.data(), thumb_length, colors, ifp);
321
        for (i = 0; i < thumb_length; i++)
322
            FORCC putc(thumb[i + thumb_length * (map[thumb_misc >> 8][c] - '0')], ofp);
323
    }
324
    catch (...)
325
    {
326
      throw LIBRAW_EXCEPTION_ALLOC; // rethrow
327
    }
328
}
329
330
void LibRaw::rollei_thumb()
331
{
332
    try
333
    {
334
        unsigned i;
335
        thumb_length = thumb_width * thumb_height;
336
        std::vector<ushort> thumb(thumb_length, 0);
337
        fprintf(ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height);
338
        read_shorts(thumb.data(), thumb_length);
339
        for (i = 0; i < thumb_length; i++)
340
        {
341
            putc(thumb[i] << 3, ofp);
342
            putc(thumb[i] >> 5 << 2, ofp);
343
            putc(thumb[i] >> 11 << 3, ofp);
344
        }
345
    }
346
    catch (...)
347
    {
348
      throw LIBRAW_EXCEPTION_ALLOC; // rethrow
349
    }
350
}
351
352
void LibRaw::jpeg_thumb()
353
{
354
    try
355
    {
356
        std::vector<char> thumb(thumb_length);
357
        fread(thumb.data(), 1, thumb_length, ifp);
358
        jpeg_thumb_writer(ofp, thumb.data(), thumb_length);
359
    }
360
    catch (...)
361
    {
362
      throw LIBRAW_EXCEPTION_ALLOC; // rethrow
363
    }
364
}
365
#endif