Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libpng/pngwrite.c
9833 views
1
/* pngwrite.c - general routines to write a PNG file
2
*
3
* Copyright (c) 2018-2025 Cosmin Truta
4
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
5
* Copyright (c) 1996-1997 Andreas Dilger
6
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
7
*
8
* This code is released under the libpng license.
9
* For conditions of distribution and use, see the disclaimer
10
* and license in png.h
11
*/
12
13
#include "pngpriv.h"
14
#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
15
# include <errno.h>
16
#endif /* SIMPLIFIED_WRITE_STDIO */
17
18
#ifdef PNG_WRITE_SUPPORTED
19
20
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
21
/* Write out all the unknown chunks for the current given location */
22
static void
23
write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
24
unsigned int where)
25
{
26
if (info_ptr->unknown_chunks_num != 0)
27
{
28
png_const_unknown_chunkp up;
29
30
png_debug(5, "writing extra chunks");
31
32
for (up = info_ptr->unknown_chunks;
33
up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
34
++up)
35
if ((up->location & where) != 0)
36
{
37
/* If per-chunk unknown chunk handling is enabled use it, otherwise
38
* just write the chunks the application has set.
39
*/
40
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
41
int keep = png_handle_as_unknown(png_ptr, up->name);
42
43
/* NOTE: this code is radically different from the read side in the
44
* matter of handling an ancillary unknown chunk. In the read side
45
* the default behavior is to discard it, in the code below the default
46
* behavior is to write it. Critical chunks are, however, only
47
* written if explicitly listed or if the default is set to write all
48
* unknown chunks.
49
*
50
* The default handling is also slightly weird - it is not possible to
51
* stop the writing of all unsafe-to-copy chunks!
52
*
53
* TODO: REVIEW: this would seem to be a bug.
54
*/
55
if (keep != PNG_HANDLE_CHUNK_NEVER &&
56
((up->name[3] & 0x20) /* safe-to-copy overrides everything */ ||
57
keep == PNG_HANDLE_CHUNK_ALWAYS ||
58
(keep == PNG_HANDLE_CHUNK_AS_DEFAULT &&
59
png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS)))
60
#endif
61
{
62
/* TODO: review, what is wrong with a zero length unknown chunk? */
63
if (up->size == 0)
64
png_warning(png_ptr, "Writing zero-length unknown chunk");
65
66
png_write_chunk(png_ptr, up->name, up->data, up->size);
67
}
68
}
69
}
70
}
71
#endif /* WRITE_UNKNOWN_CHUNKS */
72
73
/* Writes all the PNG information. This is the suggested way to use the
74
* library. If you have a new chunk to add, make a function to write it,
75
* and put it in the correct location here. If you want the chunk written
76
* after the image data, put it in png_write_end(). I strongly encourage
77
* you to supply a PNG_INFO_<chunk> flag, and check info_ptr->valid before
78
* writing the chunk, as that will keep the code from breaking if you want
79
* to just write a plain PNG file. If you have long comments, I suggest
80
* writing them in png_write_end(), and compressing them.
81
*/
82
void PNGAPI
83
png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
84
{
85
png_debug(1, "in png_write_info_before_PLTE");
86
87
if (png_ptr == NULL || info_ptr == NULL)
88
return;
89
90
if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
91
{
92
/* Write PNG signature */
93
png_write_sig(png_ptr);
94
95
#ifdef PNG_MNG_FEATURES_SUPPORTED
96
if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \
97
png_ptr->mng_features_permitted != 0)
98
{
99
png_warning(png_ptr,
100
"MNG features are not allowed in a PNG datastream");
101
png_ptr->mng_features_permitted = 0;
102
}
103
#endif
104
105
/* Write IHDR information. */
106
png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
107
info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
108
info_ptr->filter_type,
109
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
110
info_ptr->interlace_type
111
#else
112
0
113
#endif
114
);
115
116
/* The rest of these check to see if the valid field has the appropriate
117
* flag set, and if it does, writes the chunk.
118
*
119
* 1.6.0: COLORSPACE support controls the writing of these chunks too, and
120
* the chunks will be written if the WRITE routine is there and
121
* information * is available in the COLORSPACE. (See
122
* png_colorspace_sync_info in png.c for where the valid flags get set.)
123
*
124
* Under certain circumstances the colorspace can be invalidated without
125
* syncing the info_struct 'valid' flags; this happens if libpng detects
126
* an error and calls png_error while the color space is being set, yet
127
* the application continues writing the PNG. So check the 'invalid'
128
* flag here too.
129
*/
130
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
131
/* Write unknown chunks first; PNG v3 establishes a precedence order
132
* for colourspace chunks. It is certain therefore that new
133
* colourspace chunks will have a precedence and very likely it will be
134
* higher than all known so far. Writing the unknown chunks here is
135
* most likely to present the chunks in the most convenient order.
136
*
137
* FUTURE: maybe write chunks in the order the app calls png_set_chnk
138
* to give the app control.
139
*/
140
write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
141
#endif
142
143
#ifdef PNG_WRITE_sBIT_SUPPORTED
144
/* PNG v3: a streaming app will need to see this before cICP because
145
* the information is helpful in handling HLG encoding (which is
146
* natively 10 bits but gets expanded to 16 in PNG.)
147
*
148
* The app shouldn't care about the order ideally, but it might have
149
* no choice. In PNG v3, apps are allowed to reject PNGs where the
150
* APNG chunks are out of order so it behooves libpng to be nice here.
151
*/
152
if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
153
png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
154
#endif
155
156
/* PNG v3: the July 2004 version of the TR introduced the concept of colour
157
* space priority. As above it therefore behooves libpng to write the colour
158
* space chunks in the priority order so that a streaming app need not buffer
159
* them.
160
*
161
* PNG v3: Chunks mDCV and cLLI provide ancillary information for the
162
* interpretation of the colourspace chunkgs but do not require support for
163
* those chunks so are outside the "COLORSPACE" check but before the write of
164
* the colourspace chunks themselves.
165
*/
166
#ifdef PNG_WRITE_cLLI_SUPPORTED
167
if ((info_ptr->valid & PNG_INFO_cLLI) != 0)
168
{
169
png_write_cLLI_fixed(png_ptr, info_ptr->maxCLL, info_ptr->maxFALL);
170
}
171
#endif
172
#ifdef PNG_WRITE_mDCV_SUPPORTED
173
if ((info_ptr->valid & PNG_INFO_mDCV) != 0)
174
{
175
png_write_mDCV_fixed(png_ptr,
176
info_ptr->mastering_red_x, info_ptr->mastering_red_y,
177
info_ptr->mastering_green_x, info_ptr->mastering_green_y,
178
info_ptr->mastering_blue_x, info_ptr->mastering_blue_y,
179
info_ptr->mastering_white_x, info_ptr->mastering_white_y,
180
info_ptr->mastering_maxDL, info_ptr->mastering_minDL);
181
}
182
#endif
183
184
# ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */
185
if ((info_ptr->valid & PNG_INFO_cICP) != 0)
186
{
187
png_write_cICP(png_ptr,
188
info_ptr->cicp_colour_primaries,
189
info_ptr->cicp_transfer_function,
190
info_ptr->cicp_matrix_coefficients,
191
info_ptr->cicp_video_full_range_flag);
192
}
193
# endif
194
195
# ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */
196
if ((info_ptr->valid & PNG_INFO_iCCP) != 0)
197
{
198
png_write_iCCP(png_ptr, info_ptr->iccp_name,
199
info_ptr->iccp_profile, info_ptr->iccp_proflen);
200
}
201
# endif
202
203
# ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */
204
if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
205
png_write_sRGB(png_ptr, info_ptr->rendering_intent);
206
# endif /* WRITE_sRGB */
207
208
# ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */
209
if ((info_ptr->valid & PNG_INFO_gAMA) != 0)
210
png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
211
# endif
212
213
# ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */
214
if ((info_ptr->valid & PNG_INFO_cHRM) != 0)
215
png_write_cHRM_fixed(png_ptr, &info_ptr->cHRM);
216
# endif
217
218
png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
219
}
220
}
221
222
void PNGAPI
223
png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
224
{
225
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
226
int i;
227
#endif
228
229
png_debug(1, "in png_write_info");
230
231
if (png_ptr == NULL || info_ptr == NULL)
232
return;
233
234
png_write_info_before_PLTE(png_ptr, info_ptr);
235
236
if ((info_ptr->valid & PNG_INFO_PLTE) != 0)
237
png_write_PLTE(png_ptr, info_ptr->palette,
238
(png_uint_32)info_ptr->num_palette);
239
240
else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
241
png_error(png_ptr, "Valid palette required for paletted images");
242
243
#ifdef PNG_WRITE_tRNS_SUPPORTED
244
if ((info_ptr->valid & PNG_INFO_tRNS) !=0)
245
{
246
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
247
/* Invert the alpha channel (in tRNS) */
248
if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 &&
249
info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
250
{
251
int j, jend;
252
253
jend = info_ptr->num_trans;
254
if (jend > PNG_MAX_PALETTE_LENGTH)
255
jend = PNG_MAX_PALETTE_LENGTH;
256
257
for (j = 0; j<jend; ++j)
258
info_ptr->trans_alpha[j] =
259
(png_byte)(255 - info_ptr->trans_alpha[j]);
260
}
261
#endif
262
png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color),
263
info_ptr->num_trans, info_ptr->color_type);
264
}
265
#endif
266
#ifdef PNG_WRITE_bKGD_SUPPORTED
267
if ((info_ptr->valid & PNG_INFO_bKGD) != 0)
268
png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
269
#endif
270
271
#ifdef PNG_WRITE_eXIf_SUPPORTED
272
if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
273
{
274
png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
275
png_ptr->mode |= PNG_WROTE_eXIf;
276
}
277
#endif
278
279
#ifdef PNG_WRITE_hIST_SUPPORTED
280
if ((info_ptr->valid & PNG_INFO_hIST) != 0)
281
png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
282
#endif
283
284
#ifdef PNG_WRITE_oFFs_SUPPORTED
285
if ((info_ptr->valid & PNG_INFO_oFFs) != 0)
286
png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
287
info_ptr->offset_unit_type);
288
#endif
289
290
#ifdef PNG_WRITE_pCAL_SUPPORTED
291
if ((info_ptr->valid & PNG_INFO_pCAL) != 0)
292
png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
293
info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
294
info_ptr->pcal_units, info_ptr->pcal_params);
295
#endif
296
297
#ifdef PNG_WRITE_sCAL_SUPPORTED
298
if ((info_ptr->valid & PNG_INFO_sCAL) != 0)
299
png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
300
info_ptr->scal_s_width, info_ptr->scal_s_height);
301
#endif /* sCAL */
302
303
#ifdef PNG_WRITE_pHYs_SUPPORTED
304
if ((info_ptr->valid & PNG_INFO_pHYs) != 0)
305
png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
306
info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
307
#endif /* pHYs */
308
309
#ifdef PNG_WRITE_tIME_SUPPORTED
310
if ((info_ptr->valid & PNG_INFO_tIME) != 0)
311
{
312
png_write_tIME(png_ptr, &(info_ptr->mod_time));
313
png_ptr->mode |= PNG_WROTE_tIME;
314
}
315
#endif /* tIME */
316
317
#ifdef PNG_WRITE_sPLT_SUPPORTED
318
if ((info_ptr->valid & PNG_INFO_sPLT) != 0)
319
for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
320
png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
321
#endif /* sPLT */
322
323
#ifdef PNG_WRITE_TEXT_SUPPORTED
324
/* Check to see if we need to write text chunks */
325
for (i = 0; i < info_ptr->num_text; i++)
326
{
327
png_debug2(2, "Writing header text chunk %d, type %d", i,
328
info_ptr->text[i].compression);
329
/* An internationalized chunk? */
330
if (info_ptr->text[i].compression > 0)
331
{
332
#ifdef PNG_WRITE_iTXt_SUPPORTED
333
/* Write international chunk */
334
png_write_iTXt(png_ptr,
335
info_ptr->text[i].compression,
336
info_ptr->text[i].key,
337
info_ptr->text[i].lang,
338
info_ptr->text[i].lang_key,
339
info_ptr->text[i].text);
340
/* Mark this chunk as written */
341
if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
342
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
343
else
344
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
345
#else
346
png_warning(png_ptr, "Unable to write international text");
347
#endif
348
}
349
350
/* If we want a compressed text chunk */
351
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
352
{
353
#ifdef PNG_WRITE_zTXt_SUPPORTED
354
/* Write compressed chunk */
355
png_write_zTXt(png_ptr, info_ptr->text[i].key,
356
info_ptr->text[i].text, info_ptr->text[i].compression);
357
/* Mark this chunk as written */
358
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
359
#else
360
png_warning(png_ptr, "Unable to write compressed text");
361
#endif
362
}
363
364
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
365
{
366
#ifdef PNG_WRITE_tEXt_SUPPORTED
367
/* Write uncompressed chunk */
368
png_write_tEXt(png_ptr, info_ptr->text[i].key,
369
info_ptr->text[i].text,
370
0);
371
/* Mark this chunk as written */
372
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
373
#else
374
/* Can't get here */
375
png_warning(png_ptr, "Unable to write uncompressed text");
376
#endif
377
}
378
}
379
#endif /* tEXt */
380
381
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
382
write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE);
383
#endif
384
}
385
386
/* Writes the end of the PNG file. If you don't want to write comments or
387
* time information, you can pass NULL for info. If you already wrote these
388
* in png_write_info(), do not write them again here. If you have long
389
* comments, I suggest writing them here, and compressing them.
390
*/
391
void PNGAPI
392
png_write_end(png_structrp png_ptr, png_inforp info_ptr)
393
{
394
png_debug(1, "in png_write_end");
395
396
if (png_ptr == NULL)
397
return;
398
399
if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
400
png_error(png_ptr, "No IDATs written into file");
401
402
#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
403
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
404
png_ptr->num_palette_max >= png_ptr->num_palette)
405
png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
406
#endif
407
408
/* See if user wants us to write information chunks */
409
if (info_ptr != NULL)
410
{
411
#ifdef PNG_WRITE_TEXT_SUPPORTED
412
int i; /* local index variable */
413
#endif
414
#ifdef PNG_WRITE_tIME_SUPPORTED
415
/* Check to see if user has supplied a time chunk */
416
if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&
417
(png_ptr->mode & PNG_WROTE_tIME) == 0)
418
png_write_tIME(png_ptr, &(info_ptr->mod_time));
419
420
#endif
421
#ifdef PNG_WRITE_TEXT_SUPPORTED
422
/* Loop through comment chunks */
423
for (i = 0; i < info_ptr->num_text; i++)
424
{
425
png_debug2(2, "Writing trailer text chunk %d, type %d", i,
426
info_ptr->text[i].compression);
427
/* An internationalized chunk? */
428
if (info_ptr->text[i].compression > 0)
429
{
430
#ifdef PNG_WRITE_iTXt_SUPPORTED
431
/* Write international chunk */
432
png_write_iTXt(png_ptr,
433
info_ptr->text[i].compression,
434
info_ptr->text[i].key,
435
info_ptr->text[i].lang,
436
info_ptr->text[i].lang_key,
437
info_ptr->text[i].text);
438
/* Mark this chunk as written */
439
if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
440
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
441
else
442
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
443
#else
444
png_warning(png_ptr, "Unable to write international text");
445
#endif
446
}
447
448
else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
449
{
450
#ifdef PNG_WRITE_zTXt_SUPPORTED
451
/* Write compressed chunk */
452
png_write_zTXt(png_ptr, info_ptr->text[i].key,
453
info_ptr->text[i].text, info_ptr->text[i].compression);
454
/* Mark this chunk as written */
455
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
456
#else
457
png_warning(png_ptr, "Unable to write compressed text");
458
#endif
459
}
460
461
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
462
{
463
#ifdef PNG_WRITE_tEXt_SUPPORTED
464
/* Write uncompressed chunk */
465
png_write_tEXt(png_ptr, info_ptr->text[i].key,
466
info_ptr->text[i].text, 0);
467
/* Mark this chunk as written */
468
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
469
#else
470
png_warning(png_ptr, "Unable to write uncompressed text");
471
#endif
472
}
473
}
474
#endif
475
476
#ifdef PNG_WRITE_eXIf_SUPPORTED
477
if ((info_ptr->valid & PNG_INFO_eXIf) != 0 &&
478
(png_ptr->mode & PNG_WROTE_eXIf) == 0)
479
png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
480
#endif
481
482
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
483
write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);
484
#endif
485
}
486
487
png_ptr->mode |= PNG_AFTER_IDAT;
488
489
/* Write end of PNG file */
490
png_write_IEND(png_ptr);
491
492
/* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
493
* and restored again in libpng-1.2.30, may cause some applications that
494
* do not set png_ptr->output_flush_fn to crash. If your application
495
* experiences a problem, please try building libpng with
496
* PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
497
* png-mng-implement at lists.sf.net .
498
*/
499
#ifdef PNG_WRITE_FLUSH_SUPPORTED
500
# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
501
png_flush(png_ptr);
502
# endif
503
#endif
504
}
505
506
#ifdef PNG_CONVERT_tIME_SUPPORTED
507
void PNGAPI
508
png_convert_from_struct_tm(png_timep ptime, const struct tm * ttime)
509
{
510
png_debug(1, "in png_convert_from_struct_tm");
511
512
ptime->year = (png_uint_16)(1900 + ttime->tm_year);
513
ptime->month = (png_byte)(ttime->tm_mon + 1);
514
ptime->day = (png_byte)ttime->tm_mday;
515
ptime->hour = (png_byte)ttime->tm_hour;
516
ptime->minute = (png_byte)ttime->tm_min;
517
ptime->second = (png_byte)ttime->tm_sec;
518
}
519
520
void PNGAPI
521
png_convert_from_time_t(png_timep ptime, time_t ttime)
522
{
523
struct tm *tbuf;
524
525
png_debug(1, "in png_convert_from_time_t");
526
527
tbuf = gmtime(&ttime);
528
if (tbuf == NULL)
529
{
530
/* TODO: add a safe function which takes a png_ptr argument and raises
531
* a png_error if the ttime argument is invalid and the call to gmtime
532
* fails as a consequence.
533
*/
534
memset(ptime, 0, sizeof(*ptime));
535
return;
536
}
537
538
png_convert_from_struct_tm(ptime, tbuf);
539
}
540
#endif
541
542
/* Initialize png_ptr structure, and allocate any memory needed */
543
PNG_FUNCTION(png_structp,PNGAPI
544
png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
545
png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
546
{
547
#ifndef PNG_USER_MEM_SUPPORTED
548
png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
549
error_fn, warn_fn, NULL, NULL, NULL);
550
#else
551
return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
552
warn_fn, NULL, NULL, NULL);
553
}
554
555
/* Alternate initialize png_ptr structure, and allocate any memory needed */
556
PNG_FUNCTION(png_structp,PNGAPI
557
png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
558
png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
559
png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
560
{
561
png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
562
error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
563
#endif /* USER_MEM */
564
if (png_ptr != NULL)
565
{
566
/* Set the zlib control values to defaults; they can be overridden by the
567
* application after the struct has been created.
568
*/
569
png_ptr->zbuffer_size = PNG_ZBUF_SIZE;
570
571
/* The 'zlib_strategy' setting is irrelevant because png_default_claim in
572
* pngwutil.c defaults it according to whether or not filters will be
573
* used, and ignores this setting.
574
*/
575
png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY;
576
png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION;
577
png_ptr->zlib_mem_level = 8;
578
png_ptr->zlib_window_bits = 15;
579
png_ptr->zlib_method = 8;
580
581
#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
582
png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY;
583
png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION;
584
png_ptr->zlib_text_mem_level = 8;
585
png_ptr->zlib_text_window_bits = 15;
586
png_ptr->zlib_text_method = 8;
587
#endif /* WRITE_COMPRESSED_TEXT */
588
589
/* This is a highly dubious configuration option; by default it is off,
590
* but it may be appropriate for private builds that are testing
591
* extensions not conformant to the current specification, or of
592
* applications that must not fail to write at all costs!
593
*/
594
#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED
595
/* In stable builds only warn if an application error can be completely
596
* handled.
597
*/
598
png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
599
#endif
600
601
/* App warnings are warnings in release (or release candidate) builds but
602
* are errors during development.
603
*/
604
#if PNG_RELEASE_BUILD
605
png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
606
#endif
607
608
/* TODO: delay this, it can be done in png_init_io() (if the app doesn't
609
* do it itself) avoiding setting the default function if it is not
610
* required.
611
*/
612
png_set_write_fn(png_ptr, NULL, NULL, NULL);
613
}
614
615
return png_ptr;
616
}
617
618
619
/* Write a few rows of image data. If the image is interlaced,
620
* either you will have to write the 7 sub images, or, if you
621
* have called png_set_interlace_handling(), you will have to
622
* "write" the image seven times.
623
*/
624
void PNGAPI
625
png_write_rows(png_structrp png_ptr, png_bytepp row,
626
png_uint_32 num_rows)
627
{
628
png_uint_32 i; /* row counter */
629
png_bytepp rp; /* row pointer */
630
631
png_debug(1, "in png_write_rows");
632
633
if (png_ptr == NULL)
634
return;
635
636
/* Loop through the rows */
637
for (i = 0, rp = row; i < num_rows; i++, rp++)
638
{
639
png_write_row(png_ptr, *rp);
640
}
641
}
642
643
/* Write the image. You only need to call this function once, even
644
* if you are writing an interlaced image.
645
*/
646
void PNGAPI
647
png_write_image(png_structrp png_ptr, png_bytepp image)
648
{
649
png_uint_32 i; /* row index */
650
int pass, num_pass; /* pass variables */
651
png_bytepp rp; /* points to current row */
652
653
if (png_ptr == NULL)
654
return;
655
656
png_debug(1, "in png_write_image");
657
658
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
659
/* Initialize interlace handling. If image is not interlaced,
660
* this will set pass to 1
661
*/
662
num_pass = png_set_interlace_handling(png_ptr);
663
#else
664
num_pass = 1;
665
#endif
666
/* Loop through passes */
667
for (pass = 0; pass < num_pass; pass++)
668
{
669
/* Loop through image */
670
for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
671
{
672
png_write_row(png_ptr, *rp);
673
}
674
}
675
}
676
677
#ifdef PNG_MNG_FEATURES_SUPPORTED
678
/* Performs intrapixel differencing */
679
static void
680
png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
681
{
682
png_debug(1, "in png_do_write_intrapixel");
683
684
if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
685
{
686
int bytes_per_pixel;
687
png_uint_32 row_width = row_info->width;
688
if (row_info->bit_depth == 8)
689
{
690
png_bytep rp;
691
png_uint_32 i;
692
693
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
694
bytes_per_pixel = 3;
695
696
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
697
bytes_per_pixel = 4;
698
699
else
700
return;
701
702
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
703
{
704
*(rp) = (png_byte)(*rp - *(rp + 1));
705
*(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1));
706
}
707
}
708
709
#ifdef PNG_WRITE_16BIT_SUPPORTED
710
else if (row_info->bit_depth == 16)
711
{
712
png_bytep rp;
713
png_uint_32 i;
714
715
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
716
bytes_per_pixel = 6;
717
718
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
719
bytes_per_pixel = 8;
720
721
else
722
return;
723
724
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
725
{
726
png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1);
727
png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
728
png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
729
png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL);
730
png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
731
*(rp ) = (png_byte)(red >> 8);
732
*(rp + 1) = (png_byte)red;
733
*(rp + 4) = (png_byte)(blue >> 8);
734
*(rp + 5) = (png_byte)blue;
735
}
736
}
737
#endif /* WRITE_16BIT */
738
}
739
}
740
#endif /* MNG_FEATURES */
741
742
/* Called by user to write a row of image data */
743
void PNGAPI
744
png_write_row(png_structrp png_ptr, png_const_bytep row)
745
{
746
/* 1.5.6: moved from png_struct to be a local structure: */
747
png_row_info row_info;
748
749
png_debug2(1, "in png_write_row (row %u, pass %d)",
750
png_ptr->row_number, png_ptr->pass);
751
752
if (png_ptr == NULL)
753
return;
754
755
/* Initialize transformations and other stuff if first time */
756
if (png_ptr->row_number == 0 && png_ptr->pass == 0)
757
{
758
/* Make sure we wrote the header info */
759
if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
760
png_error(png_ptr,
761
"png_write_info was never called before png_write_row");
762
763
/* Check for transforms that have been set but were defined out */
764
#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
765
if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
766
png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
767
#endif
768
769
#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
770
if ((png_ptr->transformations & PNG_FILLER) != 0)
771
png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
772
#endif
773
#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
774
defined(PNG_READ_PACKSWAP_SUPPORTED)
775
if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
776
png_warning(png_ptr,
777
"PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
778
#endif
779
780
#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
781
if ((png_ptr->transformations & PNG_PACK) != 0)
782
png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
783
#endif
784
785
#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
786
if ((png_ptr->transformations & PNG_SHIFT) != 0)
787
png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
788
#endif
789
790
#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
791
if ((png_ptr->transformations & PNG_BGR) != 0)
792
png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
793
#endif
794
795
#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
796
if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
797
png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
798
#endif
799
800
png_write_start_row(png_ptr);
801
}
802
803
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
804
/* If interlaced and not interested in row, return */
805
if (png_ptr->interlaced != 0 &&
806
(png_ptr->transformations & PNG_INTERLACE) != 0)
807
{
808
switch (png_ptr->pass)
809
{
810
case 0:
811
if ((png_ptr->row_number & 0x07) != 0)
812
{
813
png_write_finish_row(png_ptr);
814
return;
815
}
816
break;
817
818
case 1:
819
if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5)
820
{
821
png_write_finish_row(png_ptr);
822
return;
823
}
824
break;
825
826
case 2:
827
if ((png_ptr->row_number & 0x07) != 4)
828
{
829
png_write_finish_row(png_ptr);
830
return;
831
}
832
break;
833
834
case 3:
835
if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3)
836
{
837
png_write_finish_row(png_ptr);
838
return;
839
}
840
break;
841
842
case 4:
843
if ((png_ptr->row_number & 0x03) != 2)
844
{
845
png_write_finish_row(png_ptr);
846
return;
847
}
848
break;
849
850
case 5:
851
if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2)
852
{
853
png_write_finish_row(png_ptr);
854
return;
855
}
856
break;
857
858
case 6:
859
if ((png_ptr->row_number & 0x01) == 0)
860
{
861
png_write_finish_row(png_ptr);
862
return;
863
}
864
break;
865
866
default: /* error: ignore it */
867
break;
868
}
869
}
870
#endif
871
872
/* Set up row info for transformations */
873
row_info.color_type = png_ptr->color_type;
874
row_info.width = png_ptr->usr_width;
875
row_info.channels = png_ptr->usr_channels;
876
row_info.bit_depth = png_ptr->usr_bit_depth;
877
row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels);
878
row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);
879
880
png_debug1(3, "row_info->color_type = %d", row_info.color_type);
881
png_debug1(3, "row_info->width = %u", row_info.width);
882
png_debug1(3, "row_info->channels = %d", row_info.channels);
883
png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth);
884
png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth);
885
png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes);
886
887
/* Copy user's row into buffer, leaving room for filter byte. */
888
memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes);
889
890
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
891
/* Handle interlacing */
892
if (png_ptr->interlaced && png_ptr->pass < 6 &&
893
(png_ptr->transformations & PNG_INTERLACE) != 0)
894
{
895
png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);
896
/* This should always get caught above, but still ... */
897
if (row_info.width == 0)
898
{
899
png_write_finish_row(png_ptr);
900
return;
901
}
902
}
903
#endif
904
905
#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
906
/* Handle other transformations */
907
if (png_ptr->transformations != 0)
908
png_do_write_transformations(png_ptr, &row_info);
909
#endif
910
911
/* At this point the row_info pixel depth must match the 'transformed' depth,
912
* which is also the output depth.
913
*/
914
if (row_info.pixel_depth != png_ptr->pixel_depth ||
915
row_info.pixel_depth != png_ptr->transformed_pixel_depth)
916
png_error(png_ptr, "internal write transform logic error");
917
918
#ifdef PNG_MNG_FEATURES_SUPPORTED
919
/* Write filter_method 64 (intrapixel differencing) only if
920
* 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
921
* 2. Libpng did not write a PNG signature (this filter_method is only
922
* used in PNG datastreams that are embedded in MNG datastreams) and
923
* 3. The application called png_permit_mng_features with a mask that
924
* included PNG_FLAG_MNG_FILTER_64 and
925
* 4. The filter_method is 64 and
926
* 5. The color_type is RGB or RGBA
927
*/
928
if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
929
(png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
930
{
931
/* Intrapixel differencing */
932
png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1);
933
}
934
#endif
935
936
/* Added at libpng-1.5.10 */
937
#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
938
/* Check for out-of-range palette index */
939
if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&
940
png_ptr->num_palette_max >= 0)
941
png_do_check_palette_indexes(png_ptr, &row_info);
942
#endif
943
944
/* Find a filter if necessary, filter the row and write it out. */
945
png_write_find_filter(png_ptr, &row_info);
946
947
if (png_ptr->write_row_fn != NULL)
948
(*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
949
}
950
951
#ifdef PNG_WRITE_FLUSH_SUPPORTED
952
/* Set the automatic flush interval or 0 to turn flushing off */
953
void PNGAPI
954
png_set_flush(png_structrp png_ptr, int nrows)
955
{
956
png_debug(1, "in png_set_flush");
957
958
if (png_ptr == NULL)
959
return;
960
961
png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows);
962
}
963
964
/* Flush the current output buffers now */
965
void PNGAPI
966
png_write_flush(png_structrp png_ptr)
967
{
968
png_debug(1, "in png_write_flush");
969
970
if (png_ptr == NULL)
971
return;
972
973
/* We have already written out all of the data */
974
if (png_ptr->row_number >= png_ptr->num_rows)
975
return;
976
977
png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH);
978
png_ptr->flush_rows = 0;
979
png_flush(png_ptr);
980
}
981
#endif /* WRITE_FLUSH */
982
983
/* Free any memory used in png_ptr struct without freeing the struct itself. */
984
static void
985
png_write_destroy(png_structrp png_ptr)
986
{
987
png_debug(1, "in png_write_destroy");
988
989
/* Free any memory zlib uses */
990
if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
991
deflateEnd(&png_ptr->zstream);
992
993
/* Free our memory. png_free checks NULL for us. */
994
png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
995
png_free(png_ptr, png_ptr->row_buf);
996
png_ptr->row_buf = NULL;
997
#ifdef PNG_WRITE_FILTER_SUPPORTED
998
png_free(png_ptr, png_ptr->prev_row);
999
png_free(png_ptr, png_ptr->try_row);
1000
png_free(png_ptr, png_ptr->tst_row);
1001
png_ptr->prev_row = NULL;
1002
png_ptr->try_row = NULL;
1003
png_ptr->tst_row = NULL;
1004
#endif
1005
1006
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
1007
png_free(png_ptr, png_ptr->chunk_list);
1008
png_ptr->chunk_list = NULL;
1009
#endif
1010
1011
/* The error handling and memory handling information is left intact at this
1012
* point: the jmp_buf may still have to be freed. See png_destroy_png_struct
1013
* for how this happens.
1014
*/
1015
}
1016
1017
/* Free all memory used by the write.
1018
* In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for
1019
* *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free
1020
* the passed in info_structs but it would quietly fail to free any of the data
1021
* inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it
1022
* has no png_ptr.)
1023
*/
1024
void PNGAPI
1025
png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
1026
{
1027
png_debug(1, "in png_destroy_write_struct");
1028
1029
if (png_ptr_ptr != NULL)
1030
{
1031
png_structrp png_ptr = *png_ptr_ptr;
1032
1033
if (png_ptr != NULL) /* added in libpng 1.6.0 */
1034
{
1035
png_destroy_info_struct(png_ptr, info_ptr_ptr);
1036
1037
*png_ptr_ptr = NULL;
1038
png_write_destroy(png_ptr);
1039
png_destroy_png_struct(png_ptr);
1040
}
1041
}
1042
}
1043
1044
/* Allow the application to select one or more row filters to use. */
1045
void PNGAPI
1046
png_set_filter(png_structrp png_ptr, int method, int filters)
1047
{
1048
png_debug(1, "in png_set_filter");
1049
1050
if (png_ptr == NULL)
1051
return;
1052
1053
#ifdef PNG_MNG_FEATURES_SUPPORTED
1054
if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
1055
(method == PNG_INTRAPIXEL_DIFFERENCING))
1056
method = PNG_FILTER_TYPE_BASE;
1057
1058
#endif
1059
if (method == PNG_FILTER_TYPE_BASE)
1060
{
1061
switch (filters & (PNG_ALL_FILTERS | 0x07))
1062
{
1063
#ifdef PNG_WRITE_FILTER_SUPPORTED
1064
case 5:
1065
case 6:
1066
case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
1067
#endif /* WRITE_FILTER */
1068
/* FALLTHROUGH */
1069
case PNG_FILTER_VALUE_NONE:
1070
png_ptr->do_filter = PNG_FILTER_NONE; break;
1071
1072
#ifdef PNG_WRITE_FILTER_SUPPORTED
1073
case PNG_FILTER_VALUE_SUB:
1074
png_ptr->do_filter = PNG_FILTER_SUB; break;
1075
1076
case PNG_FILTER_VALUE_UP:
1077
png_ptr->do_filter = PNG_FILTER_UP; break;
1078
1079
case PNG_FILTER_VALUE_AVG:
1080
png_ptr->do_filter = PNG_FILTER_AVG; break;
1081
1082
case PNG_FILTER_VALUE_PAETH:
1083
png_ptr->do_filter = PNG_FILTER_PAETH; break;
1084
1085
default:
1086
png_ptr->do_filter = (png_byte)filters; break;
1087
#else
1088
default:
1089
png_app_error(png_ptr, "Unknown row filter for method 0");
1090
#endif /* WRITE_FILTER */
1091
}
1092
1093
#ifdef PNG_WRITE_FILTER_SUPPORTED
1094
/* If we have allocated the row_buf, this means we have already started
1095
* with the image and we should have allocated all of the filter buffers
1096
* that have been selected. If prev_row isn't already allocated, then
1097
* it is too late to start using the filters that need it, since we
1098
* will be missing the data in the previous row. If an application
1099
* wants to start and stop using particular filters during compression,
1100
* it should start out with all of the filters, and then remove them
1101
* or add them back after the start of compression.
1102
*
1103
* NOTE: this is a nasty constraint on the code, because it means that the
1104
* prev_row buffer must be maintained even if there are currently no
1105
* 'prev_row' requiring filters active.
1106
*/
1107
if (png_ptr->row_buf != NULL)
1108
{
1109
int num_filters;
1110
png_alloc_size_t buf_size;
1111
1112
/* Repeat the checks in png_write_start_row; 1 pixel high or wide
1113
* images cannot benefit from certain filters. If this isn't done here
1114
* the check below will fire on 1 pixel high images.
1115
*/
1116
if (png_ptr->height == 1)
1117
filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
1118
1119
if (png_ptr->width == 1)
1120
filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
1121
1122
if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0
1123
&& png_ptr->prev_row == NULL)
1124
{
1125
/* This is the error case, however it is benign - the previous row
1126
* is not available so the filter can't be used. Just warn here.
1127
*/
1128
png_app_warning(png_ptr,
1129
"png_set_filter: UP/AVG/PAETH cannot be added after start");
1130
filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
1131
}
1132
1133
num_filters = 0;
1134
1135
if (filters & PNG_FILTER_SUB)
1136
num_filters++;
1137
1138
if (filters & PNG_FILTER_UP)
1139
num_filters++;
1140
1141
if (filters & PNG_FILTER_AVG)
1142
num_filters++;
1143
1144
if (filters & PNG_FILTER_PAETH)
1145
num_filters++;
1146
1147
/* Allocate needed row buffers if they have not already been
1148
* allocated.
1149
*/
1150
buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth,
1151
png_ptr->width) + 1;
1152
1153
if (png_ptr->try_row == NULL)
1154
png_ptr->try_row = png_voidcast(png_bytep,
1155
png_malloc(png_ptr, buf_size));
1156
1157
if (num_filters > 1)
1158
{
1159
if (png_ptr->tst_row == NULL)
1160
png_ptr->tst_row = png_voidcast(png_bytep,
1161
png_malloc(png_ptr, buf_size));
1162
}
1163
}
1164
png_ptr->do_filter = (png_byte)filters;
1165
#endif
1166
}
1167
else
1168
png_error(png_ptr, "Unknown custom filter method");
1169
}
1170
1171
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
1172
/* Provide floating and fixed point APIs */
1173
#ifdef PNG_FLOATING_POINT_SUPPORTED
1174
void PNGAPI
1175
png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method,
1176
int num_weights, png_const_doublep filter_weights,
1177
png_const_doublep filter_costs)
1178
{
1179
PNG_UNUSED(png_ptr)
1180
PNG_UNUSED(heuristic_method)
1181
PNG_UNUSED(num_weights)
1182
PNG_UNUSED(filter_weights)
1183
PNG_UNUSED(filter_costs)
1184
}
1185
#endif /* FLOATING_POINT */
1186
1187
#ifdef PNG_FIXED_POINT_SUPPORTED
1188
void PNGAPI
1189
png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method,
1190
int num_weights, png_const_fixed_point_p filter_weights,
1191
png_const_fixed_point_p filter_costs)
1192
{
1193
PNG_UNUSED(png_ptr)
1194
PNG_UNUSED(heuristic_method)
1195
PNG_UNUSED(num_weights)
1196
PNG_UNUSED(filter_weights)
1197
PNG_UNUSED(filter_costs)
1198
}
1199
#endif /* FIXED_POINT */
1200
#endif /* WRITE_WEIGHTED_FILTER */
1201
1202
#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
1203
void PNGAPI
1204
png_set_compression_level(png_structrp png_ptr, int level)
1205
{
1206
png_debug(1, "in png_set_compression_level");
1207
1208
if (png_ptr == NULL)
1209
return;
1210
1211
png_ptr->zlib_level = level;
1212
}
1213
1214
void PNGAPI
1215
png_set_compression_mem_level(png_structrp png_ptr, int mem_level)
1216
{
1217
png_debug(1, "in png_set_compression_mem_level");
1218
1219
if (png_ptr == NULL)
1220
return;
1221
1222
png_ptr->zlib_mem_level = mem_level;
1223
}
1224
1225
void PNGAPI
1226
png_set_compression_strategy(png_structrp png_ptr, int strategy)
1227
{
1228
png_debug(1, "in png_set_compression_strategy");
1229
1230
if (png_ptr == NULL)
1231
return;
1232
1233
/* The flag setting here prevents the libpng dynamic selection of strategy.
1234
*/
1235
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
1236
png_ptr->zlib_strategy = strategy;
1237
}
1238
1239
/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
1240
* smaller value of window_bits if it can do so safely.
1241
*/
1242
void PNGAPI
1243
png_set_compression_window_bits(png_structrp png_ptr, int window_bits)
1244
{
1245
png_debug(1, "in png_set_compression_window_bits");
1246
1247
if (png_ptr == NULL)
1248
return;
1249
1250
/* Prior to 1.6.0 this would warn but then set the window_bits value. This
1251
* meant that negative window bits values could be selected that would cause
1252
* libpng to write a non-standard PNG file with raw deflate or gzip
1253
* compressed IDAT or ancillary chunks. Such files can be read and there is
1254
* no warning on read, so this seems like a very bad idea.
1255
*/
1256
if (window_bits > 15)
1257
{
1258
png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1259
window_bits = 15;
1260
}
1261
1262
else if (window_bits < 8)
1263
{
1264
png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1265
window_bits = 8;
1266
}
1267
1268
png_ptr->zlib_window_bits = window_bits;
1269
}
1270
1271
void PNGAPI
1272
png_set_compression_method(png_structrp png_ptr, int method)
1273
{
1274
png_debug(1, "in png_set_compression_method");
1275
1276
if (png_ptr == NULL)
1277
return;
1278
1279
/* This would produce an invalid PNG file if it worked, but it doesn't and
1280
* deflate will fault it, so it is harmless to just warn here.
1281
*/
1282
if (method != 8)
1283
png_warning(png_ptr, "Only compression method 8 is supported by PNG");
1284
1285
png_ptr->zlib_method = method;
1286
}
1287
#endif /* WRITE_CUSTOMIZE_COMPRESSION */
1288
1289
/* The following were added to libpng-1.5.4 */
1290
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
1291
void PNGAPI
1292
png_set_text_compression_level(png_structrp png_ptr, int level)
1293
{
1294
png_debug(1, "in png_set_text_compression_level");
1295
1296
if (png_ptr == NULL)
1297
return;
1298
1299
png_ptr->zlib_text_level = level;
1300
}
1301
1302
void PNGAPI
1303
png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level)
1304
{
1305
png_debug(1, "in png_set_text_compression_mem_level");
1306
1307
if (png_ptr == NULL)
1308
return;
1309
1310
png_ptr->zlib_text_mem_level = mem_level;
1311
}
1312
1313
void PNGAPI
1314
png_set_text_compression_strategy(png_structrp png_ptr, int strategy)
1315
{
1316
png_debug(1, "in png_set_text_compression_strategy");
1317
1318
if (png_ptr == NULL)
1319
return;
1320
1321
png_ptr->zlib_text_strategy = strategy;
1322
}
1323
1324
/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
1325
* smaller value of window_bits if it can do so safely.
1326
*/
1327
void PNGAPI
1328
png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)
1329
{
1330
png_debug(1, "in png_set_text_compression_window_bits");
1331
1332
if (png_ptr == NULL)
1333
return;
1334
1335
if (window_bits > 15)
1336
{
1337
png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1338
window_bits = 15;
1339
}
1340
1341
else if (window_bits < 8)
1342
{
1343
png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1344
window_bits = 8;
1345
}
1346
1347
png_ptr->zlib_text_window_bits = window_bits;
1348
}
1349
1350
void PNGAPI
1351
png_set_text_compression_method(png_structrp png_ptr, int method)
1352
{
1353
png_debug(1, "in png_set_text_compression_method");
1354
1355
if (png_ptr == NULL)
1356
return;
1357
1358
if (method != 8)
1359
png_warning(png_ptr, "Only compression method 8 is supported by PNG");
1360
1361
png_ptr->zlib_text_method = method;
1362
}
1363
#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
1364
/* end of API added to libpng-1.5.4 */
1365
1366
void PNGAPI
1367
png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)
1368
{
1369
png_debug(1, "in png_set_write_status_fn");
1370
1371
if (png_ptr == NULL)
1372
return;
1373
1374
png_ptr->write_row_fn = write_row_fn;
1375
}
1376
1377
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1378
void PNGAPI
1379
png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
1380
write_user_transform_fn)
1381
{
1382
png_debug(1, "in png_set_write_user_transform_fn");
1383
1384
if (png_ptr == NULL)
1385
return;
1386
1387
png_ptr->transformations |= PNG_USER_TRANSFORM;
1388
png_ptr->write_user_transform_fn = write_user_transform_fn;
1389
}
1390
#endif
1391
1392
1393
#ifdef PNG_INFO_IMAGE_SUPPORTED
1394
void PNGAPI
1395
png_write_png(png_structrp png_ptr, png_inforp info_ptr,
1396
int transforms, voidp params)
1397
{
1398
png_debug(1, "in png_write_png");
1399
1400
if (png_ptr == NULL || info_ptr == NULL)
1401
return;
1402
1403
if ((info_ptr->valid & PNG_INFO_IDAT) == 0)
1404
{
1405
png_app_error(png_ptr, "no rows for png_write_image to write");
1406
return;
1407
}
1408
1409
/* Write the file header information. */
1410
png_write_info(png_ptr, info_ptr);
1411
1412
/* ------ these transformations don't touch the info structure ------- */
1413
1414
/* Invert monochrome pixels */
1415
if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)
1416
#ifdef PNG_WRITE_INVERT_SUPPORTED
1417
png_set_invert_mono(png_ptr);
1418
#else
1419
png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");
1420
#endif
1421
1422
/* Shift the pixels up to a legal bit depth and fill in
1423
* as appropriate to correctly scale the image.
1424
*/
1425
if ((transforms & PNG_TRANSFORM_SHIFT) != 0)
1426
#ifdef PNG_WRITE_SHIFT_SUPPORTED
1427
if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
1428
png_set_shift(png_ptr, &info_ptr->sig_bit);
1429
#else
1430
png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");
1431
#endif
1432
1433
/* Pack pixels into bytes */
1434
if ((transforms & PNG_TRANSFORM_PACKING) != 0)
1435
#ifdef PNG_WRITE_PACK_SUPPORTED
1436
png_set_packing(png_ptr);
1437
#else
1438
png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");
1439
#endif
1440
1441
/* Swap location of alpha bytes from ARGB to RGBA */
1442
if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)
1443
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
1444
png_set_swap_alpha(png_ptr);
1445
#else
1446
png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");
1447
#endif
1448
1449
/* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into
1450
* RGB, note that the code expects the input color type to be G or RGB; no
1451
* alpha channel.
1452
*/
1453
if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER|
1454
PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0)
1455
{
1456
#ifdef PNG_WRITE_FILLER_SUPPORTED
1457
if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0)
1458
{
1459
if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
1460
png_app_error(png_ptr,
1461
"PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported");
1462
1463
/* Continue if ignored - this is the pre-1.6.10 behavior */
1464
png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
1465
}
1466
1467
else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
1468
png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
1469
#else
1470
png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported");
1471
#endif
1472
}
1473
1474
/* Flip BGR pixels to RGB */
1475
if ((transforms & PNG_TRANSFORM_BGR) != 0)
1476
#ifdef PNG_WRITE_BGR_SUPPORTED
1477
png_set_bgr(png_ptr);
1478
#else
1479
png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");
1480
#endif
1481
1482
/* Swap bytes of 16-bit files to most significant byte first */
1483
if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)
1484
#ifdef PNG_WRITE_SWAP_SUPPORTED
1485
png_set_swap(png_ptr);
1486
#else
1487
png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");
1488
#endif
1489
1490
/* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */
1491
if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)
1492
#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
1493
png_set_packswap(png_ptr);
1494
#else
1495
png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");
1496
#endif
1497
1498
/* Invert the alpha channel from opacity to transparency */
1499
if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)
1500
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
1501
png_set_invert_alpha(png_ptr);
1502
#else
1503
png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");
1504
#endif
1505
1506
/* ----------------------- end of transformations ------------------- */
1507
1508
/* Write the bits */
1509
png_write_image(png_ptr, info_ptr->row_pointers);
1510
1511
/* It is REQUIRED to call this to finish writing the rest of the file */
1512
png_write_end(png_ptr, info_ptr);
1513
1514
PNG_UNUSED(params)
1515
}
1516
#endif
1517
1518
1519
#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
1520
/* Initialize the write structure - general purpose utility. */
1521
static int
1522
png_image_write_init(png_imagep image)
1523
{
1524
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,
1525
png_safe_error, png_safe_warning);
1526
1527
if (png_ptr != NULL)
1528
{
1529
png_infop info_ptr = png_create_info_struct(png_ptr);
1530
1531
if (info_ptr != NULL)
1532
{
1533
png_controlp control = png_voidcast(png_controlp,
1534
png_malloc_warn(png_ptr, (sizeof *control)));
1535
1536
if (control != NULL)
1537
{
1538
memset(control, 0, (sizeof *control));
1539
1540
control->png_ptr = png_ptr;
1541
control->info_ptr = info_ptr;
1542
control->for_write = 1;
1543
1544
image->opaque = control;
1545
return 1;
1546
}
1547
1548
/* Error clean up */
1549
png_destroy_info_struct(png_ptr, &info_ptr);
1550
}
1551
1552
png_destroy_write_struct(&png_ptr, NULL);
1553
}
1554
1555
return png_image_error(image, "png_image_write_: out of memory");
1556
}
1557
1558
/* Arguments to png_image_write_main: */
1559
typedef struct
1560
{
1561
/* Arguments: */
1562
png_imagep image;
1563
png_const_voidp buffer;
1564
png_int_32 row_stride;
1565
png_const_voidp colormap;
1566
int convert_to_8bit;
1567
/* Local variables: */
1568
png_const_voidp first_row;
1569
ptrdiff_t row_bytes;
1570
png_voidp local_row;
1571
/* Byte count for memory writing */
1572
png_bytep memory;
1573
png_alloc_size_t memory_bytes; /* not used for STDIO */
1574
png_alloc_size_t output_bytes; /* running total */
1575
} png_image_write_control;
1576
1577
/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to
1578
* do any necessary byte swapping. The component order is defined by the
1579
* png_image format value.
1580
*/
1581
static int
1582
png_write_image_16bit(png_voidp argument)
1583
{
1584
png_image_write_control *display = png_voidcast(png_image_write_control*,
1585
argument);
1586
png_imagep image = display->image;
1587
png_structrp png_ptr = image->opaque->png_ptr;
1588
1589
png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
1590
display->first_row);
1591
png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);
1592
png_uint_16p row_end;
1593
unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
1594
3 : 1;
1595
int aindex = 0;
1596
png_uint_32 y = image->height;
1597
1598
if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
1599
{
1600
# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
1601
if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
1602
{
1603
aindex = -1;
1604
++input_row; /* To point to the first component */
1605
++output_row;
1606
}
1607
else
1608
aindex = (int)channels;
1609
# else
1610
aindex = (int)channels;
1611
# endif
1612
}
1613
1614
else
1615
png_error(png_ptr, "png_write_image: internal call error");
1616
1617
/* Work out the output row end and count over this, note that the increment
1618
* above to 'row' means that row_end can actually be beyond the end of the
1619
* row; this is correct.
1620
*/
1621
row_end = output_row + image->width * (channels+1);
1622
1623
for (; y > 0; --y)
1624
{
1625
png_const_uint_16p in_ptr = input_row;
1626
png_uint_16p out_ptr = output_row;
1627
1628
while (out_ptr < row_end)
1629
{
1630
png_uint_16 alpha = in_ptr[aindex];
1631
png_uint_32 reciprocal = 0;
1632
int c;
1633
1634
out_ptr[aindex] = alpha;
1635
1636
/* Calculate a reciprocal. The correct calculation is simply
1637
* component/alpha*65535 << 15. (I.e. 15 bits of precision); this
1638
* allows correct rounding by adding .5 before the shift. 'reciprocal'
1639
* is only initialized when required.
1640
*/
1641
if (alpha > 0 && alpha < 65535)
1642
reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;
1643
1644
c = (int)channels;
1645
do /* always at least one channel */
1646
{
1647
png_uint_16 component = *in_ptr++;
1648
1649
/* The following gives 65535 for an alpha of 0, which is fine,
1650
* otherwise if 0/0 is represented as some other value there is more
1651
* likely to be a discontinuity which will probably damage
1652
* compression when moving from a fully transparent area to a
1653
* nearly transparent one. (The assumption here is that opaque
1654
* areas tend not to be 0 intensity.)
1655
*/
1656
if (component >= alpha)
1657
component = 65535;
1658
1659
/* component<alpha, so component/alpha is less than one and
1660
* component*reciprocal is less than 2^31.
1661
*/
1662
else if (component > 0 && alpha < 65535)
1663
{
1664
png_uint_32 calc = component * reciprocal;
1665
calc += 16384; /* round to nearest */
1666
component = (png_uint_16)(calc >> 15);
1667
}
1668
1669
*out_ptr++ = component;
1670
}
1671
while (--c > 0);
1672
1673
/* Skip to next component (skip the intervening alpha channel) */
1674
++in_ptr;
1675
++out_ptr;
1676
}
1677
1678
png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));
1679
input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
1680
}
1681
1682
return 1;
1683
}
1684
1685
/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel
1686
* is present it must be removed from the components, the components are then
1687
* written in sRGB encoding. No components are added or removed.
1688
*
1689
* Calculate an alpha reciprocal to reverse pre-multiplication. As above the
1690
* calculation can be done to 15 bits of accuracy; however, the output needs to
1691
* be scaled in the range 0..255*65535, so include that scaling here.
1692
*/
1693
# define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+((alpha)>>1))/(alpha))
1694
1695
static png_byte
1696
png_unpremultiply(png_uint_32 component, png_uint_32 alpha,
1697
png_uint_32 reciprocal/*from the above macro*/)
1698
{
1699
/* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0
1700
* is represented as some other value there is more likely to be a
1701
* discontinuity which will probably damage compression when moving from a
1702
* fully transparent area to a nearly transparent one. (The assumption here
1703
* is that opaque areas tend not to be 0 intensity.)
1704
*
1705
* There is a rounding problem here; if alpha is less than 128 it will end up
1706
* as 0 when scaled to 8 bits. To avoid introducing spurious colors into the
1707
* output change for this too.
1708
*/
1709
if (component >= alpha || alpha < 128)
1710
return 255;
1711
1712
/* component<alpha, so component/alpha is less than one and
1713
* component*reciprocal is less than 2^31.
1714
*/
1715
else if (component > 0)
1716
{
1717
/* The test is that alpha/257 (rounded) is less than 255, the first value
1718
* that becomes 255 is 65407.
1719
* NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,
1720
* be exact!) [Could also test reciprocal != 0]
1721
*/
1722
if (alpha < 65407)
1723
{
1724
component *= reciprocal;
1725
component += 64; /* round to nearest */
1726
component >>= 7;
1727
}
1728
1729
else
1730
component *= 255;
1731
1732
/* Convert the component to sRGB. */
1733
return (png_byte)PNG_sRGB_FROM_LINEAR(component);
1734
}
1735
1736
else
1737
return 0;
1738
}
1739
1740
static int
1741
png_write_image_8bit(png_voidp argument)
1742
{
1743
png_image_write_control *display = png_voidcast(png_image_write_control*,
1744
argument);
1745
png_imagep image = display->image;
1746
png_structrp png_ptr = image->opaque->png_ptr;
1747
1748
png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
1749
display->first_row);
1750
png_bytep output_row = png_voidcast(png_bytep, display->local_row);
1751
png_uint_32 y = image->height;
1752
unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
1753
3 : 1;
1754
1755
if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
1756
{
1757
png_bytep row_end;
1758
int aindex;
1759
1760
# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
1761
if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
1762
{
1763
aindex = -1;
1764
++input_row; /* To point to the first component */
1765
++output_row;
1766
}
1767
1768
else
1769
# endif
1770
aindex = (int)channels;
1771
1772
/* Use row_end in place of a loop counter: */
1773
row_end = output_row + image->width * (channels+1);
1774
1775
for (; y > 0; --y)
1776
{
1777
png_const_uint_16p in_ptr = input_row;
1778
png_bytep out_ptr = output_row;
1779
1780
while (out_ptr < row_end)
1781
{
1782
png_uint_16 alpha = in_ptr[aindex];
1783
png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
1784
png_uint_32 reciprocal = 0;
1785
int c;
1786
1787
/* Scale and write the alpha channel. */
1788
out_ptr[aindex] = alphabyte;
1789
1790
if (alphabyte > 0 && alphabyte < 255)
1791
reciprocal = UNP_RECIPROCAL(alpha);
1792
1793
c = (int)channels;
1794
do /* always at least one channel */
1795
*out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);
1796
while (--c > 0);
1797
1798
/* Skip to next component (skip the intervening alpha channel) */
1799
++in_ptr;
1800
++out_ptr;
1801
} /* while out_ptr < row_end */
1802
1803
png_write_row(png_ptr, png_voidcast(png_const_bytep,
1804
display->local_row));
1805
input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
1806
} /* while y */
1807
}
1808
1809
else
1810
{
1811
/* No alpha channel, so the row_end really is the end of the row and it
1812
* is sufficient to loop over the components one by one.
1813
*/
1814
png_bytep row_end = output_row + image->width * channels;
1815
1816
for (; y > 0; --y)
1817
{
1818
png_const_uint_16p in_ptr = input_row;
1819
png_bytep out_ptr = output_row;
1820
1821
while (out_ptr < row_end)
1822
{
1823
png_uint_32 component = *in_ptr++;
1824
1825
component *= 255;
1826
*out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component);
1827
}
1828
1829
png_write_row(png_ptr, output_row);
1830
input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
1831
}
1832
}
1833
1834
return 1;
1835
}
1836
1837
static void
1838
png_image_set_PLTE(png_image_write_control *display)
1839
{
1840
png_imagep image = display->image;
1841
const void *cmap = display->colormap;
1842
int entries = image->colormap_entries > 256 ? 256 :
1843
(int)image->colormap_entries;
1844
1845
/* NOTE: the caller must check for cmap != NULL and entries != 0 */
1846
png_uint_32 format = image->format;
1847
unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);
1848
1849
# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\
1850
defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)
1851
int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
1852
(format & PNG_FORMAT_FLAG_ALPHA) != 0;
1853
# else
1854
# define afirst 0
1855
# endif
1856
1857
# ifdef PNG_FORMAT_BGR_SUPPORTED
1858
int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;
1859
# else
1860
# define bgr 0
1861
# endif
1862
1863
int i, num_trans;
1864
png_color palette[256];
1865
png_byte tRNS[256];
1866
1867
memset(tRNS, 255, (sizeof tRNS));
1868
memset(palette, 0, (sizeof palette));
1869
1870
for (i=num_trans=0; i<entries; ++i)
1871
{
1872
/* This gets automatically converted to sRGB with reversal of the
1873
* pre-multiplication if the color-map has an alpha channel.
1874
*/
1875
if ((format & PNG_FORMAT_FLAG_LINEAR) != 0)
1876
{
1877
png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);
1878
1879
entry += (unsigned int)i * channels;
1880
1881
if ((channels & 1) != 0) /* no alpha */
1882
{
1883
if (channels >= 3) /* RGB */
1884
{
1885
palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
1886
entry[(2 ^ bgr)]);
1887
palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
1888
entry[1]);
1889
palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
1890
entry[bgr]);
1891
}
1892
1893
else /* Gray */
1894
palette[i].blue = palette[i].red = palette[i].green =
1895
(png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry);
1896
}
1897
1898
else /* alpha */
1899
{
1900
png_uint_16 alpha = entry[afirst ? 0 : channels-1];
1901
png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
1902
png_uint_32 reciprocal = 0;
1903
1904
/* Calculate a reciprocal, as in the png_write_image_8bit code above
1905
* this is designed to produce a value scaled to 255*65535 when
1906
* divided by 128 (i.e. asr 7).
1907
*/
1908
if (alphabyte > 0 && alphabyte < 255)
1909
reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;
1910
1911
tRNS[i] = alphabyte;
1912
if (alphabyte < 255)
1913
num_trans = i+1;
1914
1915
if (channels >= 3) /* RGB */
1916
{
1917
palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],
1918
alpha, reciprocal);
1919
palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,
1920
reciprocal);
1921
palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,
1922
reciprocal);
1923
}
1924
1925
else /* gray */
1926
palette[i].blue = palette[i].red = palette[i].green =
1927
png_unpremultiply(entry[afirst], alpha, reciprocal);
1928
}
1929
}
1930
1931
else /* Color-map has sRGB values */
1932
{
1933
png_const_bytep entry = png_voidcast(png_const_bytep, cmap);
1934
1935
entry += (unsigned int)i * channels;
1936
1937
switch (channels)
1938
{
1939
case 4:
1940
tRNS[i] = entry[afirst ? 0 : 3];
1941
if (tRNS[i] < 255)
1942
num_trans = i+1;
1943
/* FALLTHROUGH */
1944
case 3:
1945
palette[i].blue = entry[afirst + (2 ^ bgr)];
1946
palette[i].green = entry[afirst + 1];
1947
palette[i].red = entry[afirst + bgr];
1948
break;
1949
1950
case 2:
1951
tRNS[i] = entry[1 ^ afirst];
1952
if (tRNS[i] < 255)
1953
num_trans = i+1;
1954
/* FALLTHROUGH */
1955
case 1:
1956
palette[i].blue = palette[i].red = palette[i].green =
1957
entry[afirst];
1958
break;
1959
1960
default:
1961
break;
1962
}
1963
}
1964
}
1965
1966
# ifdef afirst
1967
# undef afirst
1968
# endif
1969
# ifdef bgr
1970
# undef bgr
1971
# endif
1972
1973
png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,
1974
entries);
1975
1976
if (num_trans > 0)
1977
png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,
1978
num_trans, NULL);
1979
1980
image->colormap_entries = (png_uint_32)entries;
1981
}
1982
1983
static int
1984
png_image_write_main(png_voidp argument)
1985
{
1986
png_image_write_control *display = png_voidcast(png_image_write_control*,
1987
argument);
1988
png_imagep image = display->image;
1989
png_structrp png_ptr = image->opaque->png_ptr;
1990
png_inforp info_ptr = image->opaque->info_ptr;
1991
png_uint_32 format = image->format;
1992
1993
/* The following four ints are actually booleans */
1994
int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);
1995
int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */
1996
int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);
1997
int write_16bit = linear && (display->convert_to_8bit == 0);
1998
1999
# ifdef PNG_BENIGN_ERRORS_SUPPORTED
2000
/* Make sure we error out on any bad situation */
2001
png_set_benign_errors(png_ptr, 0/*error*/);
2002
# endif
2003
2004
/* Default the 'row_stride' parameter if required, also check the row stride
2005
* and total image size to ensure that they are within the system limits.
2006
*/
2007
{
2008
unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
2009
2010
if (image->width <= 0x7fffffffU/channels) /* no overflow */
2011
{
2012
png_uint_32 check;
2013
png_uint_32 png_row_stride = image->width * channels;
2014
2015
if (display->row_stride == 0)
2016
display->row_stride = (png_int_32)/*SAFE*/png_row_stride;
2017
2018
if (display->row_stride < 0)
2019
check = (png_uint_32)(-display->row_stride);
2020
2021
else
2022
check = (png_uint_32)display->row_stride;
2023
2024
if (check >= png_row_stride)
2025
{
2026
/* Now check for overflow of the image buffer calculation; this
2027
* limits the whole image size to 32 bits for API compatibility with
2028
* the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
2029
*/
2030
if (image->height > 0xffffffffU/png_row_stride)
2031
png_error(image->opaque->png_ptr, "memory image too large");
2032
}
2033
2034
else
2035
png_error(image->opaque->png_ptr, "supplied row stride too small");
2036
}
2037
2038
else
2039
png_error(image->opaque->png_ptr, "image row stride too large");
2040
}
2041
2042
/* Set the required transforms then write the rows in the correct order. */
2043
if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0)
2044
{
2045
if (display->colormap != NULL && image->colormap_entries > 0)
2046
{
2047
png_uint_32 entries = image->colormap_entries;
2048
2049
png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
2050
entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),
2051
PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
2052
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
2053
2054
png_image_set_PLTE(display);
2055
}
2056
2057
else
2058
png_error(image->opaque->png_ptr,
2059
"no color-map for color-mapped image");
2060
}
2061
2062
else
2063
png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
2064
write_16bit ? 16 : 8,
2065
((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +
2066
((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),
2067
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
2068
2069
/* Counter-intuitively the data transformations must be called *after*
2070
* png_write_info, not before as in the read code, but the 'set' functions
2071
* must still be called before. Just set the color space information, never
2072
* write an interlaced image.
2073
*/
2074
2075
if (write_16bit != 0)
2076
{
2077
/* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */
2078
png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);
2079
2080
if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
2081
png_set_cHRM_fixed(png_ptr, info_ptr,
2082
/* color x y */
2083
/* white */ 31270, 32900,
2084
/* red */ 64000, 33000,
2085
/* green */ 30000, 60000,
2086
/* blue */ 15000, 6000
2087
);
2088
}
2089
2090
else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
2091
png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
2092
2093
/* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit
2094
* space must still be gamma encoded.
2095
*/
2096
else
2097
png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
2098
2099
/* Write the file header. */
2100
png_write_info(png_ptr, info_ptr);
2101
2102
/* Now set up the data transformations (*after* the header is written),
2103
* remove the handled transformations from the 'format' flags for checking.
2104
*
2105
* First check for a little endian system if writing 16-bit files.
2106
*/
2107
if (write_16bit != 0)
2108
{
2109
png_uint_16 le = 0x0001;
2110
2111
if ((*(png_const_bytep) & le) != 0)
2112
png_set_swap(png_ptr);
2113
}
2114
2115
# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
2116
if ((format & PNG_FORMAT_FLAG_BGR) != 0)
2117
{
2118
if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0)
2119
png_set_bgr(png_ptr);
2120
format &= ~PNG_FORMAT_FLAG_BGR;
2121
}
2122
# endif
2123
2124
# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
2125
if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
2126
{
2127
if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0)
2128
png_set_swap_alpha(png_ptr);
2129
format &= ~PNG_FORMAT_FLAG_AFIRST;
2130
}
2131
# endif
2132
2133
/* If there are 16 or fewer color-map entries we wrote a lower bit depth
2134
* above, but the application data is still byte packed.
2135
*/
2136
if (colormap != 0 && image->colormap_entries <= 16)
2137
png_set_packing(png_ptr);
2138
2139
/* That should have handled all (both) the transforms. */
2140
if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |
2141
PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0)
2142
png_error(png_ptr, "png_write_image: unsupported transformation");
2143
2144
{
2145
png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);
2146
ptrdiff_t row_bytes = display->row_stride;
2147
2148
if (linear != 0)
2149
row_bytes *= (sizeof (png_uint_16));
2150
2151
if (row_bytes < 0)
2152
row += (image->height-1) * (-row_bytes);
2153
2154
display->first_row = row;
2155
display->row_bytes = row_bytes;
2156
}
2157
2158
/* Apply 'fast' options if the flag is set. */
2159
if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0)
2160
{
2161
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS);
2162
/* NOTE: determined by experiment using pngstest, this reflects some
2163
* balance between the time to write the image once and the time to read
2164
* it about 50 times. The speed-up in pngstest was about 10-20% of the
2165
* total (user) time on a heavily loaded system.
2166
*/
2167
# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
2168
png_set_compression_level(png_ptr, 3);
2169
# endif
2170
}
2171
2172
/* Check for the cases that currently require a pre-transform on the row
2173
* before it is written. This only applies when the input is 16-bit and
2174
* either there is an alpha channel or it is converted to 8-bit.
2175
*/
2176
if ((linear != 0 && alpha != 0 ) ||
2177
(colormap == 0 && display->convert_to_8bit != 0))
2178
{
2179
png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,
2180
png_get_rowbytes(png_ptr, info_ptr)));
2181
int result;
2182
2183
display->local_row = row;
2184
if (write_16bit != 0)
2185
result = png_safe_execute(image, png_write_image_16bit, display);
2186
else
2187
result = png_safe_execute(image, png_write_image_8bit, display);
2188
display->local_row = NULL;
2189
2190
png_free(png_ptr, row);
2191
2192
/* Skip the 'write_end' on error: */
2193
if (result == 0)
2194
return 0;
2195
}
2196
2197
/* Otherwise this is the case where the input is in a format currently
2198
* supported by the rest of the libpng write code; call it directly.
2199
*/
2200
else
2201
{
2202
png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);
2203
ptrdiff_t row_bytes = display->row_bytes;
2204
png_uint_32 y = image->height;
2205
2206
for (; y > 0; --y)
2207
{
2208
png_write_row(png_ptr, row);
2209
row += row_bytes;
2210
}
2211
}
2212
2213
png_write_end(png_ptr, info_ptr);
2214
return 1;
2215
}
2216
2217
2218
static void (PNGCBAPI
2219
image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size)
2220
{
2221
png_image_write_control *display = png_voidcast(png_image_write_control*,
2222
png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/);
2223
png_alloc_size_t ob = display->output_bytes;
2224
2225
/* Check for overflow; this should never happen: */
2226
if (size <= ((png_alloc_size_t)-1) - ob)
2227
{
2228
/* I don't think libpng ever does this, but just in case: */
2229
if (size > 0)
2230
{
2231
if (display->memory_bytes >= ob+size) /* writing */
2232
memcpy(display->memory+ob, data, size);
2233
2234
/* Always update the size: */
2235
display->output_bytes = ob+size;
2236
}
2237
}
2238
2239
else
2240
png_error(png_ptr, "png_image_write_to_memory: PNG too big");
2241
}
2242
2243
static void (PNGCBAPI
2244
image_memory_flush)(png_structp png_ptr)
2245
{
2246
PNG_UNUSED(png_ptr)
2247
}
2248
2249
static int
2250
png_image_write_memory(png_voidp argument)
2251
{
2252
png_image_write_control *display = png_voidcast(png_image_write_control*,
2253
argument);
2254
2255
/* The rest of the memory-specific init and write_main in an error protected
2256
* environment. This case needs to use callbacks for the write operations
2257
* since libpng has no built in support for writing to memory.
2258
*/
2259
png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/,
2260
image_memory_write, image_memory_flush);
2261
2262
return png_image_write_main(display);
2263
}
2264
2265
int PNGAPI
2266
png_image_write_to_memory(png_imagep image, void *memory,
2267
png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit,
2268
const void *buffer, png_int_32 row_stride, const void *colormap)
2269
{
2270
/* Write the image to the given buffer, or count the bytes if it is NULL */
2271
if (image != NULL && image->version == PNG_IMAGE_VERSION)
2272
{
2273
if (memory_bytes != NULL && buffer != NULL)
2274
{
2275
/* This is to give the caller an easier error detection in the NULL
2276
* case and guard against uninitialized variable problems:
2277
*/
2278
if (memory == NULL)
2279
*memory_bytes = 0;
2280
2281
if (png_image_write_init(image) != 0)
2282
{
2283
png_image_write_control display;
2284
int result;
2285
2286
memset(&display, 0, (sizeof display));
2287
display.image = image;
2288
display.buffer = buffer;
2289
display.row_stride = row_stride;
2290
display.colormap = colormap;
2291
display.convert_to_8bit = convert_to_8bit;
2292
display.memory = png_voidcast(png_bytep, memory);
2293
display.memory_bytes = *memory_bytes;
2294
display.output_bytes = 0;
2295
2296
result = png_safe_execute(image, png_image_write_memory, &display);
2297
png_image_free(image);
2298
2299
/* write_memory returns true even if we ran out of buffer. */
2300
if (result)
2301
{
2302
/* On out-of-buffer this function returns '0' but still updates
2303
* memory_bytes:
2304
*/
2305
if (memory != NULL && display.output_bytes > *memory_bytes)
2306
result = 0;
2307
2308
*memory_bytes = display.output_bytes;
2309
}
2310
2311
return result;
2312
}
2313
2314
else
2315
return 0;
2316
}
2317
2318
else
2319
return png_image_error(image,
2320
"png_image_write_to_memory: invalid argument");
2321
}
2322
2323
else if (image != NULL)
2324
return png_image_error(image,
2325
"png_image_write_to_memory: incorrect PNG_IMAGE_VERSION");
2326
2327
else
2328
return 0;
2329
}
2330
2331
#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
2332
int PNGAPI
2333
png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,
2334
const void *buffer, png_int_32 row_stride, const void *colormap)
2335
{
2336
/* Write the image to the given FILE object. */
2337
if (image != NULL && image->version == PNG_IMAGE_VERSION)
2338
{
2339
if (file != NULL && buffer != NULL)
2340
{
2341
if (png_image_write_init(image) != 0)
2342
{
2343
png_image_write_control display;
2344
int result;
2345
2346
/* This is slightly evil, but png_init_io doesn't do anything other
2347
* than this and we haven't changed the standard IO functions so
2348
* this saves a 'safe' function.
2349
*/
2350
image->opaque->png_ptr->io_ptr = file;
2351
2352
memset(&display, 0, (sizeof display));
2353
display.image = image;
2354
display.buffer = buffer;
2355
display.row_stride = row_stride;
2356
display.colormap = colormap;
2357
display.convert_to_8bit = convert_to_8bit;
2358
2359
result = png_safe_execute(image, png_image_write_main, &display);
2360
png_image_free(image);
2361
return result;
2362
}
2363
2364
else
2365
return 0;
2366
}
2367
2368
else
2369
return png_image_error(image,
2370
"png_image_write_to_stdio: invalid argument");
2371
}
2372
2373
else if (image != NULL)
2374
return png_image_error(image,
2375
"png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");
2376
2377
else
2378
return 0;
2379
}
2380
2381
int PNGAPI
2382
png_image_write_to_file(png_imagep image, const char *file_name,
2383
int convert_to_8bit, const void *buffer, png_int_32 row_stride,
2384
const void *colormap)
2385
{
2386
/* Write the image to the named file. */
2387
if (image != NULL && image->version == PNG_IMAGE_VERSION)
2388
{
2389
if (file_name != NULL && buffer != NULL)
2390
{
2391
FILE *fp = fopen(file_name, "wb");
2392
2393
if (fp != NULL)
2394
{
2395
if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,
2396
row_stride, colormap) != 0)
2397
{
2398
int error; /* from fflush/fclose */
2399
2400
/* Make sure the file is flushed correctly. */
2401
if (fflush(fp) == 0 && ferror(fp) == 0)
2402
{
2403
if (fclose(fp) == 0)
2404
return 1;
2405
2406
error = errno; /* from fclose */
2407
}
2408
2409
else
2410
{
2411
error = errno; /* from fflush or ferror */
2412
(void)fclose(fp);
2413
}
2414
2415
(void)remove(file_name);
2416
/* The image has already been cleaned up; this is just used to
2417
* set the error (because the original write succeeded).
2418
*/
2419
return png_image_error(image, strerror(error));
2420
}
2421
2422
else
2423
{
2424
/* Clean up: just the opened file. */
2425
(void)fclose(fp);
2426
(void)remove(file_name);
2427
return 0;
2428
}
2429
}
2430
2431
else
2432
return png_image_error(image, strerror(errno));
2433
}
2434
2435
else
2436
return png_image_error(image,
2437
"png_image_write_to_file: invalid argument");
2438
}
2439
2440
else if (image != NULL)
2441
return png_image_error(image,
2442
"png_image_write_to_file: incorrect PNG_IMAGE_VERSION");
2443
2444
else
2445
return 0;
2446
}
2447
#endif /* SIMPLIFIED_WRITE_STDIO */
2448
#endif /* SIMPLIFIED_WRITE */
2449
#endif /* WRITE */
2450
2451