/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)) */ |