Coverage Report

Created: 2026-05-11 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjpeg-turbo.main/src/wrpng.c
Line
Count
Source
1
/*
2
 * wrpng.c
3
 *
4
 * This file was part of the Independent JPEG Group's software:
5
 * Copyright (C) 1991-1996, Thomas G. Lane.
6
 * libjpeg-turbo Modifications:
7
 * Copyright (C) 2017, 2019-2020, 2022, 2024, 2026, D. R. Commander.
8
 * For conditions of distribution and use, see the accompanying README.ijg
9
 * file.
10
 *
11
 * This file contains routines to write output images in 8-bit-per-channel or
12
 * 16-bit-per-channel PNG format.  libspng is required to compile this
13
 * software.
14
 */
15
16
#ifdef _MSC_VER
17
#define _CRT_SECURE_NO_DEPRECATE
18
#endif
19
20
#include "cmyk.h"
21
#include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
22
#include "spng/spng.h"
23
24
#if defined(PNG_SUPPORTED) && \
25
    (BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED))
26
27
28
#if BITS_IN_JSAMPLE == 8
29
0
#define PNG_BIT_DEPTH  8
30
0
#define BYTESPERSAMPLE  1
31
typedef unsigned char PNGSAMPLE;
32
#else
33
0
#define PNG_BIT_DEPTH  16
34
0
#define BYTESPERSAMPLE  2
35
typedef unsigned short PNGSAMPLE;
36
#endif
37
38
0
#define TRY_SPNG(f) { \
39
0
  int __spng_error = (f); \
40
0
  if (__spng_error) \
41
0
    ERREXITS(cinfo, JERR_PNG_LIBSPNG, spng_strerror(__spng_error)); \
42
0
}
43
44
45
/* Private version of data destination object */
46
47
typedef struct {
48
  struct djpeg_dest_struct pub; /* public fields */
49
50
  spng_ctx *ctx;
51
  struct spng_iccp iccp;
52
53
  /* Usually these two pointers point to the same place: */
54
  PNGSAMPLE *iobuffer;          /* libspng's I/O buffer */
55
  _JSAMPROW pixrow;             /* decompressor output buffer */
56
  size_t buffer_width;          /* width of I/O buffer */
57
  PNGSAMPLE *rescale;           /* data precision => PNG bit depth remapping
58
                                   array, or NULL */
59
} png_dest_struct;
60
61
typedef png_dest_struct *png_dest_ptr;
62
63
64
/*
65
 * Write some pixel data.
66
 * In this module rows_supplied will always be 1.
67
 *
68
 * put_pixel_rows() is used when the pixel format is JCS_EXT_RGB/JCS_RGB or
69
 * JCS_GRAYSCALE and cinfo->data_precision is 8 or 16, so we can write the
70
 * pixels directly to the PNG file.
71
 */
72
73
METHODDEF(void)
74
put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
75
               JDIMENSION rows_supplied)
76
0
{
77
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
78
0
  int spng_error;
79
80
0
  spng_error = spng_encode_row(dest->ctx, dest->iobuffer, dest->buffer_width);
81
0
  if (spng_error && spng_error != SPNG_EOI)
82
0
    ERREXITS(cinfo, JERR_PNG_LIBSPNG, spng_strerror(spng_error)); \
83
0
}
Unexecuted instantiation: wrpng-8.c:put_pixel_rows
Unexecuted instantiation: wrpng-12.c:put_pixel_rows
Unexecuted instantiation: wrpng-16.c:put_pixel_rows
84
85
86
/*
87
 * Convert extended RGB to RGB.
88
 */
89
90
METHODDEF(void)
91
put_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, JDIMENSION rows_supplied)
92
0
{
93
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
94
0
  register PNGSAMPLE *bufferptr, *rescale = dest->rescale;
95
0
  register _JSAMPROW ptr;
96
0
  register JDIMENSION col;
97
0
  register int rindex = rgb_red[cinfo->out_color_space];
98
0
  register int gindex = rgb_green[cinfo->out_color_space];
99
0
  register int bindex = rgb_blue[cinfo->out_color_space];
100
0
  register int ps = rgb_pixelsize[cinfo->out_color_space];
101
102
0
  ptr = dest->pub._buffer[0];
103
0
  bufferptr = dest->iobuffer;
104
#if BITS_IN_JSAMPLE == PNG_BIT_DEPTH
105
0
  if (cinfo->data_precision == PNG_BIT_DEPTH) {
106
0
    for (col = cinfo->output_width; col > 0; col--) {
107
0
      *bufferptr++ = ptr[rindex];
108
0
      *bufferptr++ = ptr[gindex];
109
0
      *bufferptr++ = ptr[bindex];
110
0
      ptr += ps;
111
0
    }
112
0
  } else
113
0
#endif
114
0
  {
115
0
    unsigned int maxval = (1 << cinfo->data_precision) - 1;
116
0
    for (col = cinfo->output_width; col > 0; col--) {
117
0
      PNGSAMPLE r = (PNGSAMPLE)ptr[rindex];
118
0
      PNGSAMPLE g = (PNGSAMPLE)ptr[gindex];
119
0
      PNGSAMPLE b = (PNGSAMPLE)ptr[bindex];
120
0
      if (r > maxval || g > maxval || b > maxval)
121
0
        ERREXIT(cinfo, JERR_PNG_OUTOFRANGE);
122
0
      *bufferptr++ = rescale[r];
123
0
      *bufferptr++ = rescale[g];
124
0
      *bufferptr++ = rescale[b];
125
0
      ptr += ps;
126
0
    }
127
0
  }
128
0
  put_pixel_rows(cinfo, dinfo, rows_supplied);
129
0
}
Unexecuted instantiation: wrpng-8.c:put_rgb
Unexecuted instantiation: wrpng-12.c:put_rgb
Unexecuted instantiation: wrpng-16.c:put_rgb
130
131
132
/*
133
 * Convert CMYK to RGB.
134
 */
135
136
METHODDEF(void)
137
put_cmyk(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
138
         JDIMENSION rows_supplied)
139
0
{
140
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
141
0
  register PNGSAMPLE *bufferptr, *rescale = dest->rescale;
142
0
  register _JSAMPROW ptr;
143
0
  register JDIMENSION col;
144
145
0
  ptr = dest->pub._buffer[0];
146
0
  bufferptr = dest->iobuffer;
147
#if BITS_IN_JSAMPLE == PNG_BIT_DEPTH
148
0
  if (cinfo->data_precision == PNG_BIT_DEPTH) {
149
0
    for (col = cinfo->output_width; col > 0; col--) {
150
0
      _JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
151
0
      cmyk_to_rgb((1 << cinfo->data_precision) - 1, c, m, y, k, &r, &g, &b);
152
0
      *bufferptr++ = r;
153
0
      *bufferptr++ = g;
154
0
      *bufferptr++ = b;
155
0
    }
156
0
  } else
157
0
#endif
158
0
  {
159
0
    unsigned int maxval = (1 << cinfo->data_precision) - 1;
160
0
    for (col = cinfo->output_width; col > 0; col--) {
161
0
      _JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
162
0
      cmyk_to_rgb((1 << cinfo->data_precision) - 1, c, m, y, k, &r, &g, &b);
163
0
      if ((PNGSAMPLE)r > maxval || (PNGSAMPLE)g > maxval ||
164
0
          (PNGSAMPLE)b > maxval)
165
0
        ERREXIT(cinfo, JERR_PNG_OUTOFRANGE);
166
0
      *bufferptr++ = rescale[r];
167
0
      *bufferptr++ = rescale[g];
168
0
      *bufferptr++ = rescale[b];
169
0
    }
170
0
  }
171
0
  put_pixel_rows(cinfo, dinfo, rows_supplied);
172
0
}
Unexecuted instantiation: wrpng-8.c:put_cmyk
Unexecuted instantiation: wrpng-12.c:put_cmyk
Unexecuted instantiation: wrpng-16.c:put_cmyk
173
174
175
/*
176
 * Convert N-bit grayscale to 8-bit or 16-bit grayscale
177
 */
178
179
METHODDEF(void)
180
put_gray(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
181
         JDIMENSION rows_supplied)
182
0
{
183
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
184
0
  register PNGSAMPLE *bufferptr, *rescale = dest->rescale;
185
0
  register _JSAMPROW ptr;
186
0
  register JDIMENSION col;
187
0
  unsigned int maxval = (1 << cinfo->data_precision) - 1;
188
189
0
  ptr = dest->pub._buffer[0];
190
0
  bufferptr = dest->iobuffer;
191
0
  for (col = cinfo->output_width; col > 0; col--) {
192
0
    PNGSAMPLE gray = (PNGSAMPLE)(*ptr++);
193
0
    if (gray > maxval)
194
0
      ERREXIT(cinfo, JERR_PNG_OUTOFRANGE);
195
0
    *bufferptr++ = rescale[gray];
196
0
  }
197
0
  put_pixel_rows(cinfo, dinfo, rows_supplied);
198
0
}
Unexecuted instantiation: wrpng-8.c:put_gray
Unexecuted instantiation: wrpng-12.c:put_gray
Unexecuted instantiation: wrpng-16.c:put_gray
199
200
201
/*
202
 * Write some pixel data when color quantization is in effect.
203
 * We have to demap the color index values to straight data.
204
 */
205
206
METHODDEF(void)
207
put_demapped_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
208
                 JDIMENSION rows_supplied)
209
0
{
210
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
211
0
  register int pixval;
212
0
  register PNGSAMPLE *bufferptr, *rescale = dest->rescale;
213
0
  register _JSAMPROW ptr;
214
0
  register _JSAMPROW color_map0 =
215
0
    ((_JSAMPARRAY)cinfo->colormap)[rgb_red[cinfo->out_color_space]];
216
0
  register _JSAMPROW color_map1 =
217
0
    ((_JSAMPARRAY)cinfo->colormap)[rgb_green[cinfo->out_color_space]];
218
0
  register _JSAMPROW color_map2 =
219
0
    ((_JSAMPARRAY)cinfo->colormap)[rgb_blue[cinfo->out_color_space]];
220
0
  register JDIMENSION col;
221
222
0
  ptr = dest->pub._buffer[0];
223
0
  bufferptr = dest->iobuffer;
224
#if BITS_IN_JSAMPLE == PNG_BIT_DEPTH
225
0
  if (cinfo->data_precision == PNG_BIT_DEPTH) {
226
0
    for (col = cinfo->output_width; col > 0; col--) {
227
0
      pixval = *ptr++;
228
0
      *bufferptr++ = color_map0[pixval];
229
0
      *bufferptr++ = color_map1[pixval];
230
0
      *bufferptr++ = color_map2[pixval];
231
0
    }
232
0
  } else
233
0
#endif
234
0
  {
235
0
    unsigned int maxval = (1 << cinfo->data_precision) - 1;
236
0
    for (col = cinfo->output_width; col > 0; col--) {
237
0
      PNGSAMPLE r, g, b;
238
0
      pixval = *ptr++;
239
0
      r = (PNGSAMPLE)color_map0[pixval];
240
0
      g = (PNGSAMPLE)color_map1[pixval];
241
0
      b = (PNGSAMPLE)color_map2[pixval];
242
0
      if (r > maxval || g > maxval || b > maxval)
243
0
        ERREXIT(cinfo, JERR_PNG_OUTOFRANGE);
244
0
      *bufferptr++ = rescale[r];
245
0
      *bufferptr++ = rescale[g];
246
0
      *bufferptr++ = rescale[b];
247
0
    }
248
0
  }
249
0
  put_pixel_rows(cinfo, dinfo, rows_supplied);
250
0
}
Unexecuted instantiation: wrpng-8.c:put_demapped_rgb
Unexecuted instantiation: wrpng-12.c:put_demapped_rgb
Unexecuted instantiation: wrpng-16.c:put_demapped_rgb
251
252
253
METHODDEF(void)
254
put_demapped_gray(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
255
                  JDIMENSION rows_supplied)
256
0
{
257
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
258
0
  register PNGSAMPLE *bufferptr, *rescale = dest->rescale;
259
0
  register _JSAMPROW ptr;
260
0
  register _JSAMPROW color_map = ((_JSAMPARRAY)cinfo->colormap)[0];
261
0
  register JDIMENSION col;
262
263
0
  ptr = dest->pub._buffer[0];
264
0
  bufferptr = dest->iobuffer;
265
#if BITS_IN_JSAMPLE == PNG_BIT_DEPTH
266
0
  if (cinfo->data_precision == PNG_BIT_DEPTH) {
267
0
    for (col = cinfo->output_width; col > 0; col--) {
268
0
      *bufferptr++ = color_map[*ptr++];
269
0
    }
270
0
  } else
271
0
#endif
272
0
  {
273
0
    unsigned int maxval = (1 << cinfo->data_precision) - 1;
274
0
    for (col = cinfo->output_width; col > 0; col--) {
275
0
      PNGSAMPLE gray = (PNGSAMPLE)color_map[*ptr++];
276
0
      if (gray > maxval)
277
0
        ERREXIT(cinfo, JERR_PNG_OUTOFRANGE);
278
0
      *bufferptr++ = rescale[gray];
279
0
    }
280
0
  }
281
0
  put_pixel_rows(cinfo, dinfo, rows_supplied);
282
0
}
Unexecuted instantiation: wrpng-8.c:put_demapped_gray
Unexecuted instantiation: wrpng-12.c:put_demapped_gray
Unexecuted instantiation: wrpng-16.c:put_demapped_gray
283
284
285
/*
286
 * Embed an ICC profile in the PNG image.
287
 *
288
 * NOTE: The pointer passed to this function will be freed in the body of
289
 * finish_output_png().
290
 */
291
292
METHODDEF(void)
293
write_icc_profile_png(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
294
                      const JOCTET *icc_data_ptr, unsigned int icc_data_len)
295
0
{
296
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
297
298
0
  if (!icc_data_ptr || !icc_data_len)
299
0
    ERREXIT(cinfo, JERR_INPUT_EMPTY);
300
301
0
  SNPRINTF(dest->iccp.profile_name, 80, "ICC Profile");
302
0
  dest->iccp.profile_len = icc_data_len;
303
0
  dest->iccp.profile = (char *)icc_data_ptr;
304
0
  TRY_SPNG(spng_set_iccp(dest->ctx, &dest->iccp));
305
0
}
Unexecuted instantiation: wrpng-8.c:write_icc_profile_png
Unexecuted instantiation: wrpng-12.c:write_icc_profile_png
Unexecuted instantiation: wrpng-16.c:write_icc_profile_png
306
307
308
/*
309
 * Startup: write the file header.
310
 */
311
312
METHODDEF(void)
313
start_output_png(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
314
0
{
315
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
316
0
  struct spng_ihdr ihdr;
317
0
  uint8_t color_type = 0;
318
319
0
  switch (cinfo->out_color_space) {
320
0
  case JCS_GRAYSCALE:
321
0
    color_type = SPNG_COLOR_TYPE_GRAYSCALE;
322
0
    break;
323
0
  case JCS_RGB:
324
0
  case JCS_EXT_RGB:
325
0
  case JCS_EXT_RGBX:
326
0
  case JCS_EXT_BGR:
327
0
  case JCS_EXT_BGRX:
328
0
  case JCS_EXT_XBGR:
329
0
  case JCS_EXT_XRGB:
330
0
  case JCS_EXT_RGBA:
331
0
  case JCS_EXT_BGRA:
332
0
  case JCS_EXT_ABGR:
333
0
  case JCS_EXT_ARGB:
334
0
  case JCS_CMYK:
335
0
    if (!IsExtRGB(cinfo->out_color_space) && cinfo->quantize_colors)
336
0
      ERREXIT(cinfo, JERR_PNG_COLORSPACE);
337
#if PNG_BIT_DEPTH == 8
338
0
    if (cinfo->quantize_colors && cinfo->data_precision == PNG_BIT_DEPTH &&
339
0
        IsExtRGB(cinfo->out_color_space))
340
0
      color_type = SPNG_COLOR_TYPE_INDEXED;
341
0
    else
342
0
#endif
343
0
      color_type = SPNG_COLOR_TYPE_TRUECOLOR;
344
0
    break;
345
0
  default:
346
0
    ERREXIT(cinfo, JERR_PNG_COLORSPACE);
347
0
  }
348
349
0
  TRY_SPNG(spng_set_png_file(dest->ctx, dinfo->output_file));
350
351
0
  memset(&ihdr, 0, sizeof(struct spng_ihdr));
352
0
  ihdr.width = (uint32_t)cinfo->output_width;
353
0
  ihdr.height = (uint32_t)cinfo->output_height;
354
0
  ihdr.bit_depth = PNG_BIT_DEPTH;
355
0
  ihdr.color_type = color_type;
356
0
  TRY_SPNG(spng_set_ihdr(dest->ctx, &ihdr));
357
358
#if PNG_BIT_DEPTH == 8
359
0
  if (cinfo->quantize_colors && cinfo->data_precision == PNG_BIT_DEPTH &&
360
0
      IsExtRGB(cinfo->out_color_space)) {
361
0
    struct spng_plte palette;
362
0
    unsigned int i;
363
364
0
    palette.n_entries = cinfo->actual_number_of_colors;
365
0
    for (i = 0; i < palette.n_entries; i++) {
366
0
      palette.entries[i].red =
367
0
        cinfo->colormap[rgb_red[cinfo->out_color_space]][i];
368
0
      palette.entries[i].green =
369
0
        cinfo->colormap[rgb_green[cinfo->out_color_space]][i];
370
0
      palette.entries[i].blue =
371
0
        cinfo->colormap[rgb_blue[cinfo->out_color_space]][i];
372
0
    }
373
0
    TRY_SPNG(spng_set_plte(dest->ctx, &palette));
374
0
  }
375
#endif
376
377
0
  TRY_SPNG(spng_encode_image(dest->ctx, NULL, 0, SPNG_FMT_PNG,
378
0
                             SPNG_ENCODE_PROGRESSIVE));
379
0
}
Unexecuted instantiation: wrpng-8.c:start_output_png
Unexecuted instantiation: wrpng-12.c:start_output_png
Unexecuted instantiation: wrpng-16.c:start_output_png
380
381
382
/*
383
 * Finish up at the end of the file.
384
 */
385
386
METHODDEF(void)
387
finish_output_png(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
388
0
{
389
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
390
391
0
  if (dest->ctx) {
392
0
    spng_encode_chunks(dest->ctx);
393
0
    free(dest->iccp.profile);
394
0
    spng_ctx_free(dest->ctx);
395
0
    dest->ctx = NULL;
396
0
  }
397
398
  /* Make sure we wrote the output file OK */
399
0
  fflush(dinfo->output_file);
400
0
  if (ferror(dinfo->output_file))
401
0
    ERREXIT(cinfo, JERR_FILE_WRITE);
402
0
}
Unexecuted instantiation: wrpng-8.c:finish_output_png
Unexecuted instantiation: wrpng-12.c:finish_output_png
Unexecuted instantiation: wrpng-16.c:finish_output_png
403
404
405
/*
406
 * Re-calculate buffer dimensions based on output dimensions.
407
 */
408
409
METHODDEF(void)
410
calc_buffer_dimensions_png(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
411
0
{
412
0
  png_dest_ptr dest = (png_dest_ptr)dinfo;
413
0
  JDIMENSION samples_per_row;
414
415
0
  if (cinfo->out_color_space == JCS_GRAYSCALE)
416
0
    samples_per_row = cinfo->output_width * cinfo->out_color_components;
417
0
  else
418
#if PNG_BIT_DEPTH == 8
419
0
  if (cinfo->quantize_colors && cinfo->data_precision == PNG_BIT_DEPTH &&
420
0
      IsExtRGB(cinfo->out_color_space))
421
0
    samples_per_row = cinfo->output_width * cinfo->output_components;
422
0
  else
423
0
#endif
424
0
    samples_per_row = cinfo->output_width * 3;
425
0
  dest->buffer_width = samples_per_row * BYTESPERSAMPLE;
426
0
}
Unexecuted instantiation: wrpng-8.c:calc_buffer_dimensions_png
Unexecuted instantiation: wrpng-12.c:calc_buffer_dimensions_png
Unexecuted instantiation: wrpng-16.c:calc_buffer_dimensions_png
427
428
429
/*
430
 * The module selection routine for PNG format output.
431
 */
432
433
GLOBAL(djpeg_dest_ptr)
434
_jinit_write_png(j_decompress_ptr cinfo)
435
0
{
436
0
  png_dest_ptr dest;
437
0
  boolean use_raw_buffer = FALSE;
438
439
#if BITS_IN_JSAMPLE == 8
440
0
  if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
441
#else
442
0
  if (cinfo->data_precision > BITS_IN_JSAMPLE ||
443
0
      cinfo->data_precision < BITS_IN_JSAMPLE - 3)
444
0
#endif
445
0
    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
446
447
  /* Create module interface object, fill in method pointers */
448
0
  dest = (png_dest_ptr)
449
0
      (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
450
0
                                  sizeof(png_dest_struct));
451
0
  dest->pub.start_output = start_output_png;
452
0
  dest->pub.write_icc_profile = write_icc_profile_png;
453
0
  dest->pub.finish_output = finish_output_png;
454
0
  dest->pub.calc_buffer_dimensions = calc_buffer_dimensions_png;
455
0
  memset(&dest->iccp, 0, sizeof(struct spng_iccp));
456
457
  /* Calculate output image dimensions so we can allocate space */
458
0
  if (cinfo->image_width > JPEG_MAX_DIMENSION ||
459
0
      cinfo->image_height > JPEG_MAX_DIMENSION)
460
0
    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, JPEG_MAX_DIMENSION);
461
0
  jpeg_calc_output_dimensions(cinfo);
462
463
  /* Create physical I/O buffer */
464
0
  dest->pub.calc_buffer_dimensions(cinfo, (djpeg_dest_ptr)dest);
465
0
  dest->iobuffer = (PNGSAMPLE *)(*cinfo->mem->alloc_small)
466
0
    ((j_common_ptr)cinfo, JPOOL_IMAGE, dest->buffer_width);
467
468
#if PNG_BIT_DEPTH == 8
469
0
  if (cinfo->quantize_colors && cinfo->data_precision == PNG_BIT_DEPTH &&
470
0
      IsExtRGB(cinfo->out_color_space))
471
0
    use_raw_buffer = TRUE;
472
0
  else
473
0
#endif
474
0
  if (!cinfo->quantize_colors && cinfo->data_precision == PNG_BIT_DEPTH &&
475
0
      (cinfo->out_color_space == JCS_EXT_RGB ||
476
0
#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
477
0
       cinfo->out_color_space == JCS_RGB ||
478
0
#endif
479
0
       cinfo->out_color_space == JCS_GRAYSCALE))
480
0
    use_raw_buffer = TRUE;
481
482
0
  if (use_raw_buffer) {
483
    /* We will write directly from decompressor output buffer. */
484
    /* Synthesize a _JSAMPARRAY pointer structure */
485
0
    dest->pixrow = (_JSAMPROW)dest->iobuffer;
486
0
    dest->pub._buffer = &dest->pixrow;
487
0
    dest->pub.buffer_height = 1;
488
0
    dest->pub.put_pixel_rows = put_pixel_rows;
489
0
  } else {
490
    /* When quantizing, we need an output buffer for colormap indexes
491
     * that's separate from the physical I/O buffer.  We also need a
492
     * separate buffer if pixel format translation must take place.
493
     */
494
0
    dest->pub._buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
495
0
      ((j_common_ptr)cinfo, JPOOL_IMAGE,
496
0
       cinfo->output_width * cinfo->output_components, (JDIMENSION)1);
497
0
    dest->pub.buffer_height = 1;
498
0
    if (!cinfo->quantize_colors) {
499
0
      if (IsExtRGB(cinfo->out_color_space))
500
0
        dest->pub.put_pixel_rows = put_rgb;
501
0
      else if (cinfo->out_color_space == JCS_CMYK)
502
0
        dest->pub.put_pixel_rows = put_cmyk;
503
0
      else
504
0
        dest->pub.put_pixel_rows = put_gray;
505
0
    } else if (cinfo->out_color_space == JCS_GRAYSCALE)
506
0
      dest->pub.put_pixel_rows = put_demapped_gray;
507
0
    else
508
0
      dest->pub.put_pixel_rows = put_demapped_rgb;
509
510
    /* Scale up samples with 2-7 or 9-15 bits of data precision so they can be
511
     * stored in, respectively, 8-bit-per-channel and 16-bit-per-channel PNG
512
     * files.  This scaling algorithm is fully reversible, i.e. you can get
513
     * back the same samples with 2-7 or 9-15 bits of data precision, if you
514
     * similarly scale down the 8-bit or 16-bit samples from the PNG file
515
     * (which our PNG reader does.)
516
     */
517
0
    if (cinfo->data_precision != PNG_BIT_DEPTH) {
518
0
      unsigned int maxval = (1 << cinfo->data_precision) - 1;
519
0
      long val, half_maxval = maxval / 2;
520
521
      /* Compute the rescaling array. */
522
0
      dest->rescale = (PNGSAMPLE *)
523
0
        (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
524
0
                                    (size_t)(((long)maxval + 1L) *
525
0
                                             sizeof(PNGSAMPLE)));
526
0
      memset(dest->rescale, 0, (size_t)(((long)maxval + 1L) *
527
0
                                        sizeof(PNGSAMPLE)));
528
0
      half_maxval = maxval / 2;
529
0
      for (val = 0; val <= (long)maxval; val++) {
530
        /* The multiplication here must be done in 32 bits to avoid overflow */
531
0
        dest->rescale[val] =
532
0
          (PNGSAMPLE)((val * ((1 << PNG_BIT_DEPTH) - 1) + half_maxval) /
533
0
                      maxval);
534
0
      }
535
0
    }
536
0
  }
537
538
0
  dest->ctx = spng_ctx_new(SPNG_CTX_ENCODER);
539
0
  if (!dest->ctx)
540
0
    ERREXITS(cinfo, JERR_PNG_LIBSPNG, "Could not create context");
541
542
0
  return (djpeg_dest_ptr)dest;
543
0
}
Unexecuted instantiation: jinit_write_png
Unexecuted instantiation: j12init_write_png
Unexecuted instantiation: j16init_write_png
544
545
#endif /* defined(PNG_SUPPORTED) &&
546
          (BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)) */