pngwrite.c 48.2 KB
Newer Older
1

A
Andreas Dilger 已提交
2
/* pngwrite.c - general routines to write a PNG file
3
 *
4
 * Last changed in libpng 1.5.1 [February 3, 2011]
5
 * Copyright (c) 1998-2011 Glenn Randers-Pehrson
6 7
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8
 *
9
 * This code is released under the libpng license.
10
 * For conditions of distribution and use, see the disclaimer
11
 * and license in png.h
12
 */
G
Guy Schalnat 已提交
13

14
#include "pngpriv.h"
G
Guy Schalnat 已提交
15

16 17
#ifdef PNG_WRITE_SUPPORTED

A
Andreas Dilger 已提交
18 19 20
/* Writes all the PNG information.  This is the suggested way to use the
 * library.  If you have a new chunk to add, make a function to write it,
 * and put it in the correct location here.  If you want the chunk written
21
 * after the image data, put it in png_write_end().  I strongly encourage
A
Andreas Dilger 已提交
22 23 24 25 26
 * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
 * the chunk, as that will keep the code from breaking if you want to just
 * write a plain PNG file.  If you have long comments, I suggest writing
 * them in png_write_end(), and compressing them.
 */
27
void PNGAPI
28
png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
G
Guy Schalnat 已提交
29
{
30
   png_debug(1, "in png_write_info_before_PLTE");
31

32 33
   if (png_ptr == NULL || info_ptr == NULL)
      return;
34

35 36
   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
   {
37 38
   /* Write PNG signature */
   png_write_sig(png_ptr);
39

40
#ifdef PNG_MNG_FEATURES_SUPPORTED
41
   if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \
42
       (png_ptr->mng_features_permitted))
43
   {
44
      png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
45
      png_ptr->mng_features_permitted = 0;
46 47
   }
#endif
48

49
   /* Write IHDR information. */
A
Andreas Dilger 已提交
50
   png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
51 52
       info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
       info_ptr->filter_type,
53
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
54
       info_ptr->interlace_type);
55
#else
56
       0);
57
#endif
58 59 60
   /* The rest of these check to see if the valid field has the appropriate
    * flag set, and if it does, writes the chunk.
    */
61
#ifdef PNG_WRITE_gAMA_SUPPORTED
A
Andreas Dilger 已提交
62
   if (info_ptr->valid & PNG_INFO_gAMA)
G
[devel]  
Glenn Randers-Pehrson 已提交
63
      png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
G
Guy Schalnat 已提交
64
#endif
65
#ifdef PNG_WRITE_sRGB_SUPPORTED
66
   if (info_ptr->valid & PNG_INFO_sRGB)
67
      png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
68
#endif
69

70
#ifdef PNG_WRITE_iCCP_SUPPORTED
71
   if (info_ptr->valid & PNG_INFO_iCCP)
72
      png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
G
[devel]  
Glenn Randers-Pehrson 已提交
73
          (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
74
#endif
75
#ifdef PNG_WRITE_sBIT_SUPPORTED
A
Andreas Dilger 已提交
76 77
   if (info_ptr->valid & PNG_INFO_sBIT)
      png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
G
Guy Schalnat 已提交
78
#endif
79
#ifdef PNG_WRITE_cHRM_SUPPORTED
A
Andreas Dilger 已提交
80
   if (info_ptr->valid & PNG_INFO_cHRM)
G
[devel]  
Glenn Randers-Pehrson 已提交
81
      png_write_cHRM_fixed(png_ptr,
82 83 84 85
          info_ptr->x_white, info_ptr->y_white,
          info_ptr->x_red, info_ptr->y_red,
          info_ptr->x_green, info_ptr->y_green,
          info_ptr->x_blue, info_ptr->y_blue);
86
#endif
87

88
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
89 90
   if (info_ptr->unknown_chunks_num)
   {
91
      png_unknown_chunk *up;
92

93
      png_debug(5, "writing extra chunks");
94

95 96 97 98
      for (up = info_ptr->unknown_chunks;
           up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
           up++)
      {
99
         int keep = png_handle_as_unknown(png_ptr, up->name);
100

101
         if (keep != PNG_HANDLE_CHUNK_NEVER &&
102 103 104 105
             up->location && !(up->location & PNG_HAVE_PLTE) &&
             !(up->location & PNG_HAVE_IDAT) &&
             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
106
         {
107 108
            if (up->size == 0)
               png_warning(png_ptr, "Writing zero-length unknown chunk");
109

110
            png_write_chunk(png_ptr, up->name, up->data, up->size);
111
         }
112
      }
113
   }
G
Guy Schalnat 已提交
114
#endif
115 116 117 118
      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
   }
}

119
void PNGAPI
120 121
png_write_info(png_structp png_ptr, png_infop info_ptr)
{
122
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
123 124 125
   int i;
#endif

126
   png_debug(1, "in png_write_info");
127

128 129 130
   if (png_ptr == NULL || info_ptr == NULL)
      return;

131 132
   png_write_info_before_PLTE(png_ptr, info_ptr);

A
Andreas Dilger 已提交
133
   if (info_ptr->valid & PNG_INFO_PLTE)
A
Andreas Dilger 已提交
134
      png_write_PLTE(png_ptr, info_ptr->palette,
135
          (png_uint_32)info_ptr->num_palette);
136

A
Andreas Dilger 已提交
137
   else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
138
      png_error(png_ptr, "Valid palette required for paletted images");
139

140
#ifdef PNG_WRITE_tRNS_SUPPORTED
A
Andreas Dilger 已提交
141
   if (info_ptr->valid & PNG_INFO_tRNS)
142
   {
143
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
144
      /* Invert the alpha channel (in tRNS) */
145
      if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
146
          info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
147 148
      {
         int j;
149
         for (j = 0; j<(int)info_ptr->num_trans; j++)
G
[devel]  
Glenn Randers-Pehrson 已提交
150
            info_ptr->trans_alpha[j] =
151
               (png_byte)(255 - info_ptr->trans_alpha[j]);
152
      }
153
#endif
154
      png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color),
155
          info_ptr->num_trans, info_ptr->color_type);
156
   }
G
Guy Schalnat 已提交
157
#endif
158
#ifdef PNG_WRITE_bKGD_SUPPORTED
A
Andreas Dilger 已提交
159 160
   if (info_ptr->valid & PNG_INFO_bKGD)
      png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
G
Guy Schalnat 已提交
161
#endif
162

163
#ifdef PNG_WRITE_hIST_SUPPORTED
A
Andreas Dilger 已提交
164 165
   if (info_ptr->valid & PNG_INFO_hIST)
      png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
G
Guy Schalnat 已提交
166
#endif
167

168
#ifdef PNG_WRITE_oFFs_SUPPORTED
A
Andreas Dilger 已提交
169 170
   if (info_ptr->valid & PNG_INFO_oFFs)
      png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
171
          info_ptr->offset_unit_type);
G
Guy Schalnat 已提交
172
#endif
173

174
#ifdef PNG_WRITE_pCAL_SUPPORTED
A
Andreas Dilger 已提交
175 176
   if (info_ptr->valid & PNG_INFO_pCAL)
      png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
177 178
          info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
          info_ptr->pcal_units, info_ptr->pcal_params);
A
Andreas Dilger 已提交
179
#endif
180

181
#ifdef PNG_WRITE_sCAL_SUPPORTED
G
[devel]  
Glenn Randers-Pehrson 已提交
182
   if (info_ptr->valid & PNG_INFO_sCAL)
183
      png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
184
          info_ptr->scal_s_width, info_ptr->scal_s_height);
185 186
#endif /* sCAL */

187
#ifdef PNG_WRITE_pHYs_SUPPORTED
A
Andreas Dilger 已提交
188 189
   if (info_ptr->valid & PNG_INFO_pHYs)
      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
190
          info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
191 192
#endif /* pHYs */

193
#ifdef PNG_WRITE_tIME_SUPPORTED
A
Andreas Dilger 已提交
194
   if (info_ptr->valid & PNG_INFO_tIME)
G
Guy Schalnat 已提交
195
   {
A
Andreas Dilger 已提交
196
      png_write_tIME(png_ptr, &(info_ptr->mod_time));
197
      png_ptr->mode |= PNG_WROTE_tIME;
G
Guy Schalnat 已提交
198
   }
199 200
#endif /* tIME */

201
#ifdef PNG_WRITE_sPLT_SUPPORTED
202
   if (info_ptr->valid & PNG_INFO_sPLT)
203 204
      for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
         png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
205 206
#endif /* sPLT */

207
#ifdef PNG_WRITE_TEXT_SUPPORTED
G
Guy Schalnat 已提交
208
   /* Check to see if we need to write text chunks */
A
Andreas Dilger 已提交
209
   for (i = 0; i < info_ptr->num_text; i++)
G
Guy Schalnat 已提交
210
   {
211
      png_debug2(2, "Writing header text chunk %d, type %d", i,
212
          info_ptr->text[i].compression);
213
      /* An internationalized chunk? */
214
      if (info_ptr->text[i].compression > 0)
215
      {
216
#ifdef PNG_WRITE_iTXt_SUPPORTED
217 218 219 220 221 222 223
         /* Write international chunk */
         png_write_iTXt(png_ptr,
             info_ptr->text[i].compression,
             info_ptr->text[i].key,
             info_ptr->text[i].lang,
             info_ptr->text[i].lang_key,
             info_ptr->text[i].text);
224
#else
225
          png_warning(png_ptr, "Unable to write international text");
226 227 228 229
#endif
          /* Mark this chunk as written */
          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
      }
230

A
Andreas Dilger 已提交
231
      /* If we want a compressed text chunk */
232
      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
G
Guy Schalnat 已提交
233
      {
234
#ifdef PNG_WRITE_zTXt_SUPPORTED
235
         /* Write compressed chunk */
A
Andreas Dilger 已提交
236
         png_write_zTXt(png_ptr, info_ptr->text[i].key,
237 238
             info_ptr->text[i].text, 0,
             info_ptr->text[i].compression);
G
Guy Schalnat 已提交
239
#else
240
         png_warning(png_ptr, "Unable to write compressed text");
G
Guy Schalnat 已提交
241
#endif
A
Andreas Dilger 已提交
242 243 244
         /* Mark this chunk as written */
         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
      }
245

A
Andreas Dilger 已提交
246 247
      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
      {
248
#ifdef PNG_WRITE_tEXt_SUPPORTED
249
         /* Write uncompressed chunk */
A
Andreas Dilger 已提交
250
         png_write_tEXt(png_ptr, info_ptr->text[i].key,
251 252
             info_ptr->text[i].text,
             0);
253 254
         /* Mark this chunk as written */
         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
G
Guy Schalnat 已提交
255
#else
256
         /* Can't get here */
257
         png_warning(png_ptr, "Unable to write uncompressed text");
G
Guy Schalnat 已提交
258
#endif
G
Guy Schalnat 已提交
259 260
      }
   }
261 262
#endif /* tEXt */

263
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
264 265
   if (info_ptr->unknown_chunks_num)
   {
266
      png_unknown_chunk *up;
267

268
      png_debug(5, "writing extra chunks");
269

270 271 272 273
      for (up = info_ptr->unknown_chunks;
           up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
           up++)
      {
274
         int keep = png_handle_as_unknown(png_ptr, up->name);
275
         if (keep != PNG_HANDLE_CHUNK_NEVER &&
276 277 278 279
             up->location && (up->location & PNG_HAVE_PLTE) &&
             !(up->location & PNG_HAVE_IDAT) &&
             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
280 281 282
         {
            png_write_chunk(png_ptr, up->name, up->data, up->size);
         }
283
      }
284 285
   }
#endif
G
Guy Schalnat 已提交
286 287
}

A
Andreas Dilger 已提交
288
/* Writes the end of the PNG file.  If you don't want to write comments or
289 290 291 292
 * time information, you can pass NULL for info.  If you already wrote these
 * in png_write_info(), do not write them again here.  If you have long
 * comments, I suggest writing them here, and compressing them.
 */
293
void PNGAPI
A
Andreas Dilger 已提交
294
png_write_end(png_structp png_ptr, png_infop info_ptr)
G
Guy Schalnat 已提交
295
{
296
   png_debug(1, "in png_write_end");
297

298 299
   if (png_ptr == NULL)
      return;
300

G
Guy Schalnat 已提交
301 302 303
   if (!(png_ptr->mode & PNG_HAVE_IDAT))
      png_error(png_ptr, "No IDATs written into file");

304
   /* See if user wants us to write information chunks */
A
Andreas Dilger 已提交
305
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
306
   {
307
#ifdef PNG_WRITE_TEXT_SUPPORTED
A
Andreas Dilger 已提交
308
      int i; /* local index variable */
309
#endif
310
#ifdef PNG_WRITE_tIME_SUPPORTED
311
      /* Check to see if user has supplied a time chunk */
312
      if ((info_ptr->valid & PNG_INFO_tIME) &&
313
          !(png_ptr->mode & PNG_WROTE_tIME))
A
Andreas Dilger 已提交
314
         png_write_tIME(png_ptr, &(info_ptr->mod_time));
315

G
Guy Schalnat 已提交
316
#endif
317
#ifdef PNG_WRITE_TEXT_SUPPORTED
318
      /* Loop through comment chunks */
A
Andreas Dilger 已提交
319
      for (i = 0; i < info_ptr->num_text; i++)
G
Guy Schalnat 已提交
320
      {
321
         png_debug2(2, "Writing trailer text chunk %d, type %d", i,
A
Andreas Dilger 已提交
322
            info_ptr->text[i].compression);
323
         /* An internationalized chunk? */
324 325
         if (info_ptr->text[i].compression > 0)
         {
326
#ifdef PNG_WRITE_iTXt_SUPPORTED
327
            /* Write international chunk */
328
            png_write_iTXt(png_ptr,
329 330 331 332 333
                info_ptr->text[i].compression,
                info_ptr->text[i].key,
                info_ptr->text[i].lang,
                info_ptr->text[i].lang_key,
                info_ptr->text[i].text);
334
#else
335
            png_warning(png_ptr, "Unable to write international text");
336
#endif
337 338
            /* Mark this chunk as written */
            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
339
         }
340

341
         else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
G
Guy Schalnat 已提交
342
         {
343
#ifdef PNG_WRITE_zTXt_SUPPORTED
344
            /* Write compressed chunk */
A
Andreas Dilger 已提交
345
            png_write_zTXt(png_ptr, info_ptr->text[i].key,
346 347
                info_ptr->text[i].text, 0,
                info_ptr->text[i].compression);
A
Andreas Dilger 已提交
348
#else
349
            png_warning(png_ptr, "Unable to write compressed text");
G
Guy Schalnat 已提交
350
#endif
A
Andreas Dilger 已提交
351 352 353
            /* Mark this chunk as written */
            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
         }
354

A
Andreas Dilger 已提交
355 356
         else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
         {
357
#ifdef PNG_WRITE_tEXt_SUPPORTED
358
            /* Write uncompressed chunk */
A
Andreas Dilger 已提交
359
            png_write_tEXt(png_ptr, info_ptr->text[i].key,
360
                info_ptr->text[i].text, 0);
A
Andreas Dilger 已提交
361
#else
362
            png_warning(png_ptr, "Unable to write uncompressed text");
G
Guy Schalnat 已提交
363
#endif
A
Andreas Dilger 已提交
364 365 366

            /* Mark this chunk as written */
            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
G
Guy Schalnat 已提交
367 368
         }
      }
369
#endif
370
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
371 372
   if (info_ptr->unknown_chunks_num)
   {
373
      png_unknown_chunk *up;
374

375
      png_debug(5, "writing extra chunks");
376

377 378 379 380
      for (up = info_ptr->unknown_chunks;
           up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
           up++)
      {
381
         int keep = png_handle_as_unknown(png_ptr, up->name);
382
         if (keep != PNG_HANDLE_CHUNK_NEVER &&
383 384 385
             up->location && (up->location & PNG_AFTER_IDAT) &&
             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
386
         {
387
            png_write_chunk(png_ptr, up->name, up->data, up->size);
388
         }
389
      }
390
   }
G
Guy Schalnat 已提交
391
#endif
G
Guy Schalnat 已提交
392
   }
G
Guy Schalnat 已提交
393 394 395

   png_ptr->mode |= PNG_AFTER_IDAT;

396
   /* Write end of PNG file */
G
Guy Schalnat 已提交
397
   png_write_IEND(png_ptr);
398 399 400
   /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
    * and restored again in libpng-1.2.30, may cause some applications that
    * do not set png_ptr->output_flush_fn to crash.  If your application
401 402
    * experiences a problem, please try building libpng with
    * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
403 404
    * png-mng-implement at lists.sf.net .
    */
405
#ifdef PNG_WRITE_FLUSH_SUPPORTED
406
#  ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
407
   png_flush(png_ptr);
408
#  endif
409
#endif
G
Guy Schalnat 已提交
410 411
}

412
#ifdef PNG_CONVERT_tIME_SUPPORTED
413
/* "tm" structure is not supported on WindowsCE */
414
void PNGAPI
415
png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm FAR * ttime)
G
Guy Schalnat 已提交
416
{
417
   png_debug(1, "in png_convert_from_struct_tm");
418

G
Guy Schalnat 已提交
419 420 421 422 423 424
   ptime->year = (png_uint_16)(1900 + ttime->tm_year);
   ptime->month = (png_byte)(ttime->tm_mon + 1);
   ptime->day = (png_byte)ttime->tm_mday;
   ptime->hour = (png_byte)ttime->tm_hour;
   ptime->minute = (png_byte)ttime->tm_min;
   ptime->second = (png_byte)ttime->tm_sec;
G
Guy Schalnat 已提交
425 426
}

427
void PNGAPI
G
Guy Schalnat 已提交
428
png_convert_from_time_t(png_timep ptime, time_t ttime)
G
Guy Schalnat 已提交
429 430 431
{
   struct tm *tbuf;

432
   png_debug(1, "in png_convert_from_time_t");
433

G
Guy Schalnat 已提交
434 435 436
   tbuf = gmtime(&ttime);
   png_convert_from_struct_tm(ptime, tbuf);
}
G
Guy Schalnat 已提交
437
#endif
438

A
Andreas Dilger 已提交
439
/* Initialize png_ptr structure, and allocate any memory needed */
440 441 442
PNG_FUNCTION(png_structp,PNGAPI
png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
    png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
G
Guy Schalnat 已提交
443
{
444 445
#ifdef PNG_USER_MEM_SUPPORTED
   return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
446
       warn_fn, NULL, NULL, NULL));
447 448 449
}

/* Alternate initialize png_ptr structure, and allocate any memory needed */
450 451
static void png_reset_filter_heuristics(png_structp png_ptr); /* forward decl */

452 453
PNG_FUNCTION(png_structp,PNGAPI
png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
454
    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
455
    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
456 457
{
#endif /* PNG_USER_MEM_SUPPORTED */
458
   volatile int png_cleanup_needed = 0;
459
#ifdef PNG_SETJMP_SUPPORTED
460
   volatile
461
#endif
462
   png_structp png_ptr;
463
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
464
#ifdef USE_FAR_KEYWORD
465
   jmp_buf png_jmpbuf;
466
#endif
A
Andreas Dilger 已提交
467
#endif
468
   int i;
469

470
   png_debug(1, "in png_create_write_struct");
471

472
#ifdef PNG_USER_MEM_SUPPORTED
473
   png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
474
       (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
475
#else
476
   png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
477
#endif /* PNG_USER_MEM_SUPPORTED */
478
   if (png_ptr == NULL)
479
      return (NULL);
480

481
   /* Added at libpng-1.2.6 */
482
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
483 484
   png_ptr->user_width_max = PNG_USER_WIDTH_MAX;
   png_ptr->user_height_max = PNG_USER_HEIGHT_MAX;
485 486
#endif

487 488 489 490 491
#ifdef PNG_SETJMP_SUPPORTED
/* Applications that neglect to set up their own setjmp() and then
   encounter a png_error() will longjmp here.  Since the jmpbuf is
   then meaningless we abort instead of returning. */
#ifdef USE_FAR_KEYWORD
492
   if (setjmp(png_jmpbuf))
493
#else
494 495 496
   if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */
#endif
#ifdef USE_FAR_KEYWORD
497
   png_memcpy(png_jmpbuf(png_ptr), png_jmpbuf, png_sizeof(jmp_buf));
498
#endif
499
      PNG_ABORT();
500
#endif
501

502 503 504
#ifdef PNG_USER_MEM_SUPPORTED
   png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
#endif /* PNG_USER_MEM_SUPPORTED */
A
Andreas Dilger 已提交
505
   png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
G
Guy Schalnat 已提交
506

507
   if (user_png_ver)
G
Guy Schalnat 已提交
508
   {
509
      i = 0;
510 511 512 513 514
      do
      {
         if (user_png_ver[i] != png_libpng_ver[i])
            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
      } while (png_libpng_ver[i++]);
515
   }
516

517
   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
518
   {
519 520 521 522 523 524
     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
      * we must recompile any applications that use any older library version.
      * For versions after libpng 1.0, we will be compatible, so we need
      * only check the first digit.
      */
     if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
525
         (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
526 527
         (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
     {
528
#ifdef PNG_CONSOLE_IO_SUPPORTED
529
        char msg[80];
530

531 532
        if (user_png_ver)
        {
533 534 535 536 537 538 539 540 541 542
            png_snprintf2(msg, 80,
                "Application built with libpng-%.20s"
                " but running with %.20s",
                user_png_ver,
                png_libpng_ver);
            png_warning(png_ptr, msg);
         }
#else
         png_warning(png_ptr,
             "Incompatible libpng version in application and library");
543 544
#endif
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
545
        png_ptr->flags = 0;
546
#endif
547
        png_cleanup_needed = 1;
548 549
     }
   }
550

551
   /* Initialize zbuf - compression buffer */
G
Guy Schalnat 已提交
552
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
553

554
   if (!png_cleanup_needed)
555 556
   {
      png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr,
557
          png_ptr->zbuf_size);
558 559 560
      if (png_ptr->zbuf == NULL)
         png_cleanup_needed = 1;
   }
561

562
   if (png_cleanup_needed)
563 564 565 566
   {
       /* Clean up PNG structure and deallocate any memory. */
       png_free(png_ptr, png_ptr->zbuf);
       png_ptr->zbuf = NULL;
567
#ifdef PNG_USER_MEM_SUPPORTED
568
       png_destroy_struct_2((png_voidp)png_ptr,
569
           (png_free_ptr)free_fn, (png_voidp)mem_ptr);
570
#else
571
       png_destroy_struct((png_voidp)png_ptr);
572
#endif
573 574
       return (NULL);
   }
G
Guy Schalnat 已提交
575

576
   png_set_write_fn(png_ptr, NULL, NULL, NULL);
G
Guy Schalnat 已提交
577

578
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
579
   png_reset_filter_heuristics(png_ptr);
580 581
#endif

582
   return (png_ptr);
G
Guy Schalnat 已提交
583 584
}

585

586 587 588 589 590
/* Write a few rows of image data.  If the image is interlaced,
 * either you will have to write the 7 sub images, or, if you
 * have called png_set_interlace_handling(), you will have to
 * "write" the image seven times.
 */
591
void PNGAPI
G
Guy Schalnat 已提交
592
png_write_rows(png_structp png_ptr, png_bytepp row,
593
    png_uint_32 num_rows)
G
Guy Schalnat 已提交
594 595
{
   png_uint_32 i; /* row counter */
G
Guy Schalnat 已提交
596
   png_bytepp rp; /* row pointer */
G
Guy Schalnat 已提交
597

598
   png_debug(1, "in png_write_rows");
599 600 601 602

   if (png_ptr == NULL)
      return;

603
   /* Loop through the rows */
G
Guy Schalnat 已提交
604 605 606 607 608 609
   for (i = 0, rp = row; i < num_rows; i++, rp++)
   {
      png_write_row(png_ptr, *rp);
   }
}

610 611 612
/* Write the image.  You only need to call this function once, even
 * if you are writing an interlaced image.
 */
613
void PNGAPI
G
Guy Schalnat 已提交
614
png_write_image(png_structp png_ptr, png_bytepp image)
G
Guy Schalnat 已提交
615 616 617
{
   png_uint_32 i; /* row index */
   int pass, num_pass; /* pass variables */
G
Guy Schalnat 已提交
618
   png_bytepp rp; /* points to current row */
G
Guy Schalnat 已提交
619

620 621 622
   if (png_ptr == NULL)
      return;

623
   png_debug(1, "in png_write_image");
624

625
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
626
   /* Initialize interlace handling.  If image is not interlaced,
627 628
    * this will set pass to 1
    */
G
Guy Schalnat 已提交
629
   num_pass = png_set_interlace_handling(png_ptr);
630 631 632
#else
   num_pass = 1;
#endif
633
   /* Loop through passes */
G
Guy Schalnat 已提交
634 635
   for (pass = 0; pass < num_pass; pass++)
   {
636
      /* Loop through image */
G
Guy Schalnat 已提交
637 638 639 640 641 642 643
      for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
      {
         png_write_row(png_ptr, *rp);
      }
   }
}

644
/* Called by user to write a row of image data */
645
void PNGAPI
646
png_write_row(png_structp png_ptr, png_const_bytep row)
G
Guy Schalnat 已提交
647
{
648 649
   if (png_ptr == NULL)
      return;
650

651
   png_debug2(1, "in png_write_row (row %u, pass %d)",
652
      png_ptr->row_number, png_ptr->pass);
653

654
   /* Initialize transformations and other stuff if first time */
G
Guy Schalnat 已提交
655
   if (png_ptr->row_number == 0 && png_ptr->pass == 0)
G
Guy Schalnat 已提交
656
   {
657
      /* Make sure we wrote the header info */
658 659
      if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
         png_error(png_ptr,
660
             "png_write_info was never called before png_write_row");
661

662
      /* Check for transforms that have been set but were defined out */
663
#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
664 665
      if (png_ptr->transformations & PNG_INVERT_MONO)
         png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
666
#endif
667

668
#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
669 670
      if (png_ptr->transformations & PNG_FILLER)
         png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
671
#endif
672 673
#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
    defined(PNG_READ_PACKSWAP_SUPPORTED)
674
      if (png_ptr->transformations & PNG_PACKSWAP)
675 676
         png_warning(png_ptr,
             "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
677
#endif
678

679
#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
680 681
      if (png_ptr->transformations & PNG_PACK)
         png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
682
#endif
683

684
#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
685 686
      if (png_ptr->transformations & PNG_SHIFT)
         png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
687
#endif
688

689
#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
690 691
      if (png_ptr->transformations & PNG_BGR)
         png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
692
#endif
693

694
#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
695 696
      if (png_ptr->transformations & PNG_SWAP_BYTES)
         png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
697 698
#endif

G
Guy Schalnat 已提交
699 700 701
      png_write_start_row(png_ptr);
   }

702
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
703
   /* If interlaced and not interested in row, return */
G
Guy Schalnat 已提交
704 705 706 707
   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
   {
      switch (png_ptr->pass)
      {
G
Guy Schalnat 已提交
708
         case 0:
709
            if (png_ptr->row_number & 0x07)
G
Guy Schalnat 已提交
710 711 712 713 714
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
715

G
Guy Schalnat 已提交
716
         case 1:
717
            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
G
Guy Schalnat 已提交
718 719 720 721 722
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
723

G
Guy Schalnat 已提交
724
         case 2:
725
            if ((png_ptr->row_number & 0x07) != 4)
G
Guy Schalnat 已提交
726 727
            {
               png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
728
               return;
G
Guy Schalnat 已提交
729 730
            }
            break;
731

G
Guy Schalnat 已提交
732
         case 3:
733
            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
G
Guy Schalnat 已提交
734 735 736 737 738
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
739

G
Guy Schalnat 已提交
740
         case 4:
741
            if ((png_ptr->row_number & 0x03) != 2)
G
Guy Schalnat 已提交
742 743 744 745 746
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
747

G
Guy Schalnat 已提交
748
         case 5:
749
            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
G
Guy Schalnat 已提交
750 751 752 753 754
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
755

G
Guy Schalnat 已提交
756
         case 6:
757
            if (!(png_ptr->row_number & 0x01))
G
Guy Schalnat 已提交
758 759 760 761 762
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
763 764 765

         default: /* error: ignore it */
            break;
G
Guy Schalnat 已提交
766 767
      }
   }
G
Guy Schalnat 已提交
768
#endif
G
Guy Schalnat 已提交
769

770
   /* Set up row info for transformations */
G
Guy Schalnat 已提交
771
   png_ptr->row_info.color_type = png_ptr->color_type;
G
Guy Schalnat 已提交
772 773 774
   png_ptr->row_info.width = png_ptr->usr_width;
   png_ptr->row_info.channels = png_ptr->usr_channels;
   png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
G
Guy Schalnat 已提交
775 776
   png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
      png_ptr->row_info.channels);
777

778 779
   png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
      png_ptr->row_info.width);
G
Guy Schalnat 已提交
780

781
   png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type);
782
   png_debug1(3, "row_info->width = %u", png_ptr->row_info.width);
783 784 785
   png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels);
   png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth);
   png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth);
786 787
   png_debug1(3, "row_info->rowbytes = %lu",
       (unsigned long)png_ptr->row_info.rowbytes);
A
Andreas Dilger 已提交
788 789

   /* Copy user's row into buffer, leaving room for filter byte. */
790
   png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes);
G
Guy Schalnat 已提交
791

792
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
793
   /* Handle interlacing */
G
Guy Schalnat 已提交
794
   if (png_ptr->interlaced && png_ptr->pass < 6 &&
795
       (png_ptr->transformations & PNG_INTERLACE))
G
Guy Schalnat 已提交
796 797
   {
      png_do_write_interlace(&(png_ptr->row_info),
798
          png_ptr->row_buf + 1, png_ptr->pass);
799
      /* This should always get caught above, but still ... */
G
Guy Schalnat 已提交
800 801 802 803 804 805
      if (!(png_ptr->row_info.width))
      {
         png_write_finish_row(png_ptr);
         return;
      }
   }
G
Guy Schalnat 已提交
806
#endif
G
Guy Schalnat 已提交
807

808
   /* Handle other transformations */
G
Guy Schalnat 已提交
809 810 811
   if (png_ptr->transformations)
      png_do_write_transformations(png_ptr);

812
#ifdef PNG_MNG_FEATURES_SUPPORTED
813 814 815 816 817 818 819 820 821
   /* Write filter_method 64 (intrapixel differencing) only if
    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
    * 2. Libpng did not write a PNG signature (this filter_method is only
    *    used in PNG datastreams that are embedded in MNG datastreams) and
    * 3. The application called png_permit_mng_features with a mask that
    *    included PNG_FLAG_MNG_FILTER_64 and
    * 4. The filter_method is 64 and
    * 5. The color_type is RGB or RGBA
    */
822
   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
823
       (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
824 825 826 827 828 829
   {
      /* Intrapixel differencing */
      png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
   }
#endif

A
Andreas Dilger 已提交
830
   /* Find a filter if necessary, filter the row and write it out. */
G
Guy Schalnat 已提交
831
   png_write_find_filter(png_ptr, &(png_ptr->row_info));
832 833 834

   if (png_ptr->write_row_fn != NULL)
      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
G
Guy Schalnat 已提交
835 836
}

837
#ifdef PNG_WRITE_FLUSH_SUPPORTED
G
Guy Schalnat 已提交
838
/* Set the automatic flush interval or 0 to turn flushing off */
839
void PNGAPI
G
Guy Schalnat 已提交
840
png_set_flush(png_structp png_ptr, int nrows)
G
Guy Schalnat 已提交
841
{
842
   png_debug(1, "in png_set_flush");
843

844 845
   if (png_ptr == NULL)
      return;
846

G
Guy Schalnat 已提交
847
   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
G
Guy Schalnat 已提交
848 849
}

850
/* Flush the current output buffers now */
851
void PNGAPI
G
Guy Schalnat 已提交
852
png_write_flush(png_structp png_ptr)
G
Guy Schalnat 已提交
853
{
G
Guy Schalnat 已提交
854 855
   int wrote_IDAT;

856
   png_debug(1, "in png_write_flush");
857

858 859
   if (png_ptr == NULL)
      return;
860

G
Guy Schalnat 已提交
861 862
   /* We have already written out all of the data */
   if (png_ptr->row_number >= png_ptr->num_rows)
863
      return;
G
Guy Schalnat 已提交
864 865 866 867 868

   do
   {
      int ret;

869
      /* Compress the data */
A
Andreas Dilger 已提交
870
      ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
G
Guy Schalnat 已提交
871 872
      wrote_IDAT = 0;

873
      /* Check for compression errors */
G
Guy Schalnat 已提交
874 875
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
876
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
877
            png_error(png_ptr, png_ptr->zstream.msg);
878

G
Guy Schalnat 已提交
879 880 881 882
         else
            png_error(png_ptr, "zlib error");
      }

A
Andreas Dilger 已提交
883
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
884
      {
885
         /* Write the IDAT and reset the zlib output buffer */
886
         png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
A
Andreas Dilger 已提交
887 888
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
889 890
         wrote_IDAT = 1;
      }
891
   } while (wrote_IDAT == 1);
G
Guy Schalnat 已提交
892 893

   /* If there is any data left to be output, write it into a new IDAT */
A
Andreas Dilger 已提交
894
   if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
G
Guy Schalnat 已提交
895
   {
896
      /* Write the IDAT and reset the zlib output buffer */
G
Guy Schalnat 已提交
897
      png_write_IDAT(png_ptr, png_ptr->zbuf,
898
          png_ptr->zbuf_size - png_ptr->zstream.avail_out);
A
Andreas Dilger 已提交
899 900
      png_ptr->zstream.next_out = png_ptr->zbuf;
      png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
901 902 903
   }
   png_ptr->flush_rows = 0;
   png_flush(png_ptr);
G
Guy Schalnat 已提交
904
}
G
Guy Schalnat 已提交
905
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
G
Guy Schalnat 已提交
906

907
/* Free all memory used by the write */
908
void PNGAPI
A
Andreas Dilger 已提交
909
png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
G
Guy Schalnat 已提交
910
{
A
Andreas Dilger 已提交
911 912
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL;
913 914
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn = NULL;
915
   png_voidp mem_ptr = NULL;
916
#endif
A
Andreas Dilger 已提交
917

918
   png_debug(1, "in png_destroy_write_struct");
919

A
Andreas Dilger 已提交
920
   if (png_ptr_ptr != NULL)
921
   {
A
Andreas Dilger 已提交
922
      png_ptr = *png_ptr_ptr;
923 924
#ifdef PNG_USER_MEM_SUPPORTED
      free_fn = png_ptr->free_fn;
925
      mem_ptr = png_ptr->mem_ptr;
926 927
#endif
   }
A
Andreas Dilger 已提交
928

929 930 931 932 933 934 935 936
#ifdef PNG_USER_MEM_SUPPORTED
   if (png_ptr != NULL)
   {
      free_fn = png_ptr->free_fn;
      mem_ptr = png_ptr->mem_ptr;
   }
#endif

A
Andreas Dilger 已提交
937
   if (info_ptr_ptr != NULL)
A
Andreas Dilger 已提交
938 939
      info_ptr = *info_ptr_ptr;

A
Andreas Dilger 已提交
940
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
941
   {
942 943
      if (png_ptr != NULL)
      {
944
         png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
945

946
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
947 948 949 950 951
         if (png_ptr->num_chunk_list)
         {
            png_free(png_ptr, png_ptr->chunk_list);
            png_ptr->num_chunk_list = 0;
         }
952
#endif
953
      }
954

955
#ifdef PNG_USER_MEM_SUPPORTED
956
      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
957
          (png_voidp)mem_ptr);
958
#else
A
Andreas Dilger 已提交
959
      png_destroy_struct((png_voidp)info_ptr);
960
#endif
961
      *info_ptr_ptr = NULL;
G
Guy Schalnat 已提交
962 963
   }

A
Andreas Dilger 已提交
964
   if (png_ptr != NULL)
G
Guy Schalnat 已提交
965
   {
A
Andreas Dilger 已提交
966
      png_write_destroy(png_ptr);
967
#ifdef PNG_USER_MEM_SUPPORTED
968
      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
969
          (png_voidp)mem_ptr);
970
#else
A
Andreas Dilger 已提交
971
      png_destroy_struct((png_voidp)png_ptr);
972
#endif
973
      *png_ptr_ptr = NULL;
G
Guy Schalnat 已提交
974 975 976
   }
}

G
Guy Schalnat 已提交
977

A
Andreas Dilger 已提交
978
/* Free any memory used in png_ptr struct (old method) */
979
void /* PRIVATE */
G
Guy Schalnat 已提交
980
png_write_destroy(png_structp png_ptr)
G
Guy Schalnat 已提交
981
{
982
#ifdef PNG_SETJMP_SUPPORTED
983
   jmp_buf tmp_jmp; /* Save jump buffer */
984
#endif
G
Guy Schalnat 已提交
985 986 987
   png_error_ptr error_fn;
   png_error_ptr warning_fn;
   png_voidp error_ptr;
988 989 990
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn;
#endif
G
Guy Schalnat 已提交
991

992
   png_debug(1, "in png_write_destroy");
993 994

   /* Free any memory zlib uses */
A
Andreas Dilger 已提交
995
   deflateEnd(&png_ptr->zstream);
G
Guy Schalnat 已提交
996

997
   /* Free our memory.  png_free checks NULL for us. */
A
Andreas Dilger 已提交
998 999
   png_free(png_ptr, png_ptr->zbuf);
   png_free(png_ptr, png_ptr->row_buf);
1000
#ifdef PNG_WRITE_FILTER_SUPPORTED
A
Andreas Dilger 已提交
1001 1002 1003 1004 1005
   png_free(png_ptr, png_ptr->prev_row);
   png_free(png_ptr, png_ptr->sub_row);
   png_free(png_ptr, png_ptr->up_row);
   png_free(png_ptr, png_ptr->avg_row);
   png_free(png_ptr, png_ptr->paeth_row);
1006
#endif
1007

1008
#ifdef PNG_TIME_RFC1123_SUPPORTED
1009
   png_free(png_ptr, png_ptr->time_buffer);
1010 1011
#endif

1012
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
1013 1014
   /* Use this to save a little code space, it doesn't free the filter_costs */
   png_reset_filter_heuristics(png_ptr);
A
Andreas Dilger 已提交
1015 1016
   png_free(png_ptr, png_ptr->filter_costs);
   png_free(png_ptr, png_ptr->inv_filter_costs);
1017
#endif
G
Guy Schalnat 已提交
1018

1019
#ifdef PNG_SETJMP_SUPPORTED
1020
   /* Reset structure */
1021
   png_memcpy(tmp_jmp, png_ptr->png_jmpbuf, png_sizeof(jmp_buf));
1022
#endif
G
Guy Schalnat 已提交
1023 1024 1025 1026

   error_fn = png_ptr->error_fn;
   warning_fn = png_ptr->warning_fn;
   error_ptr = png_ptr->error_ptr;
1027 1028 1029
#ifdef PNG_USER_MEM_SUPPORTED
   free_fn = png_ptr->free_fn;
#endif
G
Guy Schalnat 已提交
1030

1031
   png_memset(png_ptr, 0, png_sizeof(png_struct));
G
Guy Schalnat 已提交
1032 1033 1034 1035

   png_ptr->error_fn = error_fn;
   png_ptr->warning_fn = warning_fn;
   png_ptr->error_ptr = error_ptr;
1036 1037 1038
#ifdef PNG_USER_MEM_SUPPORTED
   png_ptr->free_fn = free_fn;
#endif
G
Guy Schalnat 已提交
1039

1040
#ifdef PNG_SETJMP_SUPPORTED
1041
   png_memcpy(png_ptr->png_jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
1042
#endif
G
Guy Schalnat 已提交
1043
}
G
Guy Schalnat 已提交
1044

A
Andreas Dilger 已提交
1045
/* Allow the application to select one or more row filters to use. */
1046
void PNGAPI
G
Guy Schalnat 已提交
1047
png_set_filter(png_structp png_ptr, int method, int filters)
G
Guy Schalnat 已提交
1048
{
1049
   png_debug(1, "in png_set_filter");
1050

1051 1052
   if (png_ptr == NULL)
      return;
1053

1054
#ifdef PNG_MNG_FEATURES_SUPPORTED
1055
   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
1056 1057
       (method == PNG_INTRAPIXEL_DIFFERENCING))
      method = PNG_FILTER_TYPE_BASE;
1058

1059
#endif
A
Andreas Dilger 已提交
1060
   if (method == PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
1061 1062 1063
   {
      switch (filters & (PNG_ALL_FILTERS | 0x07))
      {
1064
#ifdef PNG_WRITE_FILTER_SUPPORTED
G
Guy Schalnat 已提交
1065 1066
         case 5:
         case 6:
A
Andreas Dilger 已提交
1067
         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
1068
#endif /* PNG_WRITE_FILTER_SUPPORTED */
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 1086
         default:
            png_ptr->do_filter = (png_byte)filters; break;
1087
#else
1088 1089
         default:
            png_warning(png_ptr, "Unknown row filter for method 0");
1090
#endif /* PNG_WRITE_FILTER_SUPPORTED */
G
Guy Schalnat 已提交
1091 1092
      }

A
Andreas Dilger 已提交
1093 1094 1095 1096 1097 1098 1099 1100
      /* If we have allocated the row_buf, this means we have already started
       * with the image and we should have allocated all of the filter buffers
       * that have been selected.  If prev_row isn't already allocated, then
       * it is too late to start using the filters that need it, since we
       * will be missing the data in the previous row.  If an application
       * wants to start and stop using particular filters during compression,
       * it should start out with all of the filters, and then add and
       * remove them after the start of compression.
G
Guy Schalnat 已提交
1101
       */
A
Andreas Dilger 已提交
1102
      if (png_ptr->row_buf != NULL)
G
Guy Schalnat 已提交
1103
      {
1104
#ifdef PNG_WRITE_FILTER_SUPPORTED
1105
         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
G
Guy Schalnat 已提交
1106
         {
A
Andreas Dilger 已提交
1107
            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1108
                (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1109
            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1110 1111
         }

1112
         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
G
Guy Schalnat 已提交
1113
         {
A
Andreas Dilger 已提交
1114
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1115
            {
A
Andreas Dilger 已提交
1116
               png_warning(png_ptr, "Can't add Up filter after starting");
1117 1118
               png_ptr->do_filter = (png_byte)(png_ptr->do_filter &
                   ~PNG_FILTER_UP);
G
Guy Schalnat 已提交
1119
            }
1120

G
Guy Schalnat 已提交
1121 1122
            else
            {
A
Andreas Dilger 已提交
1123
               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1124
                   (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1125
               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1126 1127 1128
            }
         }

1129
         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
G
Guy Schalnat 已提交
1130
         {
A
Andreas Dilger 已提交
1131
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1132
            {
A
Andreas Dilger 已提交
1133
               png_warning(png_ptr, "Can't add Average filter after starting");
1134 1135
               png_ptr->do_filter = (png_byte)(png_ptr->do_filter &
                   ~PNG_FILTER_AVG);
G
Guy Schalnat 已提交
1136
            }
1137

G
Guy Schalnat 已提交
1138 1139
            else
            {
A
Andreas Dilger 已提交
1140
               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1141
                   (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1142
               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1143 1144 1145
            }
         }

1146
         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
A
Andreas Dilger 已提交
1147
             png_ptr->paeth_row == NULL)
G
Guy Schalnat 已提交
1148
         {
A
Andreas Dilger 已提交
1149
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1150 1151
            {
               png_warning(png_ptr, "Can't add Paeth filter after starting");
1152
               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
G
Guy Schalnat 已提交
1153
            }
1154

G
Guy Schalnat 已提交
1155 1156
            else
            {
1157
               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1158
                   (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1159
               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1160 1161 1162 1163
            }
         }

         if (png_ptr->do_filter == PNG_NO_FILTERS)
1164
#endif /* PNG_WRITE_FILTER_SUPPORTED */
G
Guy Schalnat 已提交
1165 1166 1167 1168
            png_ptr->do_filter = PNG_FILTER_NONE;
      }
   }
   else
A
Andreas Dilger 已提交
1169 1170 1171 1172 1173 1174 1175 1176
      png_error(png_ptr, "Unknown custom filter method");
}

/* This allows us to influence the way in which libpng chooses the "best"
 * filter for the current scanline.  While the "minimum-sum-of-absolute-
 * differences metric is relatively fast and effective, there is some
 * question as to whether it can be improved upon by trying to keep the
 * filtered data going to zlib more consistent, hopefully resulting in
1177 1178
 * better compression.
 */
1179
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED      /* GRR 970116 */
1180
/* Convenience reset API. */
1181 1182
static void
png_reset_filter_heuristics(png_structp png_ptr)
A
Andreas Dilger 已提交
1183
{
1184 1185 1186 1187 1188 1189 1190 1191
   /* Clear out any old values in the 'weights' - this must be done because if
    * the app calls set_filter_heuristics multiple times with different
    * 'num_weights' values we would otherwise potentially have wrong sized
    * arrays.
    */
   png_ptr->num_prev_filters = 0;
   png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
   if (png_ptr->prev_filters != NULL)
A
Andreas Dilger 已提交
1192
   {
1193 1194 1195
      png_bytep old = png_ptr->prev_filters;
      png_ptr->prev_filters = NULL;
      png_free(png_ptr, old);
A
Andreas Dilger 已提交
1196
   }
1197
   if (png_ptr->filter_weights != NULL)
A
Andreas Dilger 已提交
1198
   {
1199 1200 1201
      png_uint_16p old = png_ptr->filter_weights;
      png_ptr->filter_weights = NULL;
      png_free(png_ptr, old);
A
Andreas Dilger 已提交
1202 1203
   }

1204
   if (png_ptr->inv_filter_weights != NULL)
A
Andreas Dilger 已提交
1205
   {
1206 1207 1208
      png_uint_16p old = png_ptr->inv_filter_weights;
      png_ptr->inv_filter_weights = NULL;
      png_free(png_ptr, old);
A
Andreas Dilger 已提交
1209 1210
   }

1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
   /* Leave the filter_costs - this array is fixed size. */
}

static int
png_init_filter_heuristics(png_structp png_ptr, int heuristic_method,
   int num_weights)
{
   if (png_ptr == NULL)
      return 0;

   /* Clear out the arrays */
   png_reset_filter_heuristics(png_ptr);
A
Andreas Dilger 已提交
1223

1224 1225 1226 1227 1228
   /* Check arguments; the 'reset' function makes the correct settings for the
    * unweighted case, but we must handle the weight case by initializing the
    * arrays for the caller.
    */
   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
A
Andreas Dilger 已提交
1229
   {
1230 1231 1232
      int i;

      if (num_weights > 0)
A
Andreas Dilger 已提交
1233 1234
      {
         png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
1235
             (png_uint_32)(png_sizeof(png_byte) * num_weights));
A
Andreas Dilger 已提交
1236

1237 1238
         /* To make sure that the weighting starts out fairly */
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1239
         {
1240
            png_ptr->prev_filters[i] = 255;
A
Andreas Dilger 已提交
1241 1242
         }

1243 1244
         png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
A
Andreas Dilger 已提交
1245

1246 1247
         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
1248

1249 1250 1251 1252 1253
         for (i = 0; i < num_weights; i++)
         {
            png_ptr->inv_filter_weights[i] =
            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
         }
1254

1255 1256
         /* Safe to set this now */
         png_ptr->num_prev_filters = (png_byte)num_weights;
A
Andreas Dilger 已提交
1257 1258
      }

1259 1260 1261 1262
      /* If, in the future, there are other filter methods, this would
       * need to be based on png_ptr->filter.
       */
      if (png_ptr->filter_costs == NULL)
A
Andreas Dilger 已提交
1263
      {
1264 1265
         png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
             (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
1266

1267 1268
         png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
             (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
1269
      }
1270

1271 1272
      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
      {
1273 1274
         png_ptr->inv_filter_costs[i] =
         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
A
Andreas Dilger 已提交
1275
      }
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291

      /* All the arrays are inited, safe to set this: */
      png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED;

      /* Return the 'ok' code. */
      return 1;
   }
   else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT ||
      heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
   {
      return 1;
   }
   else
   {
      png_warning(png_ptr, "Unknown filter heuristic method");
      return 0;
A
Andreas Dilger 已提交
1292
   }
1293
}
A
Andreas Dilger 已提交
1294

1295 1296 1297 1298
/* Provide floating and fixed point APIs */
#ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
1299 1300
    int num_weights, png_const_doublep filter_weights,
    png_const_doublep filter_costs)
1301 1302 1303 1304 1305
{
   png_debug(1, "in png_set_filter_heuristics");

   /* The internal API allocates all the arrays and ensures that the elements of
    * those arrays are set to the default value.
A
Andreas Dilger 已提交
1306
    */
1307 1308
   if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
      return;
A
Andreas Dilger 已提交
1309

1310 1311 1312 1313 1314 1315
   /* If using the weighted method copy in the weights. */
   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
   {
      int i;
      for (i = 0; i < num_weights; i++)
      {
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
         if (filter_weights[i] <= 0.0)
         {
            png_ptr->inv_filter_weights[i] =
            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
         }

         else
         {
            png_ptr->inv_filter_weights[i] =
                (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5);

            png_ptr->filter_weights[i] =
                (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5);
         }
1330
      }
A
Andreas Dilger 已提交
1331

1332 1333 1334 1335 1336 1337 1338 1339
      /* Here is where we set the relative costs of the different filters.  We
       * should take the desired compression level into account when setting
       * the costs, so that Paeth, for instance, has a high relative cost at low
       * compression levels, while it has a lower relative cost at higher
       * compression settings.  The filter types are in order of increasing
       * relative cost, so it would be possible to do this with an algorithm.
       */
      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0)
A
Andreas Dilger 已提交
1340
      {
1341 1342
         png_ptr->inv_filter_costs[i] =
             (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5);
1343

1344 1345
         png_ptr->filter_costs[i] =
             (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5);
A
Andreas Dilger 已提交
1346 1347
      }
   }
1348 1349
}
#endif /* FLOATING_POINT */
A
Andreas Dilger 已提交
1350

1351 1352 1353
#ifdef PNG_FIXED_POINT_SUPPORTED
void PNGAPI
png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method,
1354 1355
    int num_weights, png_const_fixed_point_p filter_weights,
    png_const_fixed_point_p filter_costs)
1356 1357 1358 1359 1360
{
   png_debug(1, "in png_set_filter_heuristics_fixed");

   /* The internal API allocates all the arrays and ensures that the elements of
    * those arrays are set to the default value.
A
Andreas Dilger 已提交
1361
    */
1362 1363 1364 1365 1366
   if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
      return;

   /* If using the weighted method copy in the weights. */
   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
A
Andreas Dilger 已提交
1367
   {
1368 1369
      int i;
      for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1370
      {
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
         if (filter_weights[i] <= 0)
         {
            png_ptr->inv_filter_weights[i] =
            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
         }

         else
         {
            png_ptr->inv_filter_weights[i] = (png_uint_16)
               ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1);

            png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR*
               PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]);
         }
A
Andreas Dilger 已提交
1385
      }
1386

1387 1388 1389 1390 1391 1392 1393 1394 1395
      /* Here is where we set the relative costs of the different filters.  We
       * should take the desired compression level into account when setting
       * the costs, so that Paeth, for instance, has a high relative cost at low
       * compression levels, while it has a lower relative cost at higher
       * compression settings.  The filter types are in order of increasing
       * relative cost, so it would be possible to do this with an algorithm.
       */
      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
         if (filter_costs[i] >= PNG_FP_1)
A
Andreas Dilger 已提交
1396
      {
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
         png_uint_32 tmp;

         /* Use a 32 bit unsigned temporary here because otherwise the
          * intermediate value will be a 32 bit *signed* integer (ANSI rules)
          * and this will get the wrong answer on division.
          */
         tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2);
         tmp /= filter_costs[i];

         png_ptr->inv_filter_costs[i] = (png_uint_16)tmp;

         tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF;
         tmp /= PNG_FP_1;
1410

1411
         png_ptr->filter_costs[i] = (png_uint_16)tmp;
A
Andreas Dilger 已提交
1412 1413
      }
   }
G
Guy Schalnat 已提交
1414
}
1415
#endif /* FIXED_POINT */
A
Andreas Dilger 已提交
1416
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
G
Guy Schalnat 已提交
1417

1418
void PNGAPI
G
Guy Schalnat 已提交
1419
png_set_compression_level(png_structp png_ptr, int level)
G
Guy Schalnat 已提交
1420
{
1421
   png_debug(1, "in png_set_compression_level");
1422

1423 1424
   if (png_ptr == NULL)
      return;
1425

G
Guy Schalnat 已提交
1426
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
G
Guy Schalnat 已提交
1427 1428 1429
   png_ptr->zlib_level = level;
}

1430
void PNGAPI
G
Guy Schalnat 已提交
1431
png_set_compression_mem_level(png_structp png_ptr, int mem_level)
G
Guy Schalnat 已提交
1432
{
1433
   png_debug(1, "in png_set_compression_mem_level");
1434

1435 1436
   if (png_ptr == NULL)
      return;
1437

G
Guy Schalnat 已提交
1438
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
G
Guy Schalnat 已提交
1439
   png_ptr->zlib_mem_level = mem_level;
G
Guy Schalnat 已提交
1440 1441
}

1442
void PNGAPI
G
Guy Schalnat 已提交
1443
png_set_compression_strategy(png_structp png_ptr, int strategy)
G
Guy Schalnat 已提交
1444
{
1445
   png_debug(1, "in png_set_compression_strategy");
1446

1447 1448
   if (png_ptr == NULL)
      return;
1449

G
Guy Schalnat 已提交
1450
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
G
Guy Schalnat 已提交
1451 1452 1453
   png_ptr->zlib_strategy = strategy;
}

1454
void PNGAPI
G
Guy Schalnat 已提交
1455
png_set_compression_window_bits(png_structp png_ptr, int window_bits)
G
Guy Schalnat 已提交
1456
{
1457 1458
   if (png_ptr == NULL)
      return;
1459

G
Guy Schalnat 已提交
1460 1461
   if (window_bits > 15)
      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1462

1463 1464
   else if (window_bits < 8)
      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1465

1466
#ifndef WBITS_8_OK
1467
   /* Avoid libpng bug with 256-byte windows */
1468
   if (window_bits == 8)
1469 1470 1471 1472
      {
        png_warning(png_ptr, "Compression window is being reset to 512");
        window_bits = 9;
      }
1473

1474
#endif
G
Guy Schalnat 已提交
1475
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
G
Guy Schalnat 已提交
1476 1477 1478
   png_ptr->zlib_window_bits = window_bits;
}

1479
void PNGAPI
G
Guy Schalnat 已提交
1480
png_set_compression_method(png_structp png_ptr, int method)
G
Guy Schalnat 已提交
1481
{
1482
   png_debug(1, "in png_set_compression_method");
1483

1484 1485
   if (png_ptr == NULL)
      return;
1486

G
Guy Schalnat 已提交
1487 1488
   if (method != 8)
      png_warning(png_ptr, "Only compression method 8 is supported by PNG");
1489

G
Guy Schalnat 已提交
1490
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
G
Guy Schalnat 已提交
1491
   png_ptr->zlib_method = method;
G
Guy Schalnat 已提交
1492 1493
}

1494
void PNGAPI
1495 1496
png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
{
1497 1498
   if (png_ptr == NULL)
      return;
1499

1500 1501 1502
   png_ptr->write_row_fn = write_row_fn;
}

1503
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1504
void PNGAPI
1505
png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
1506
    write_user_transform_fn)
1507
{
1508
   png_debug(1, "in png_set_write_user_transform_fn");
1509

1510 1511
   if (png_ptr == NULL)
      return;
1512

1513 1514 1515 1516
   png_ptr->transformations |= PNG_USER_TRANSFORM;
   png_ptr->write_user_transform_fn = write_user_transform_fn;
}
#endif
1517 1518


1519
#ifdef PNG_INFO_IMAGE_SUPPORTED
1520 1521
void PNGAPI
png_write_png(png_structp png_ptr, png_infop info_ptr,
1522
    int transforms, voidp params)
1523
{
1524 1525
   if (png_ptr == NULL || info_ptr == NULL)
      return;
1526 1527 1528 1529 1530 1531

   /* Write the file header information. */
   png_write_info(png_ptr, info_ptr);

   /* ------ these transformations don't touch the info structure ------- */

1532
#ifdef PNG_WRITE_INVERT_SUPPORTED
1533
   /* Invert monochrome pixels */
1534
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
1535
      png_set_invert_mono(png_ptr);
1536 1537
#endif

1538
#ifdef PNG_WRITE_SHIFT_SUPPORTED
1539 1540 1541 1542
   /* Shift the pixels up to a legal bit depth and fill in
    * as appropriate to correctly scale the image.
    */
   if ((transforms & PNG_TRANSFORM_SHIFT)
1543
       && (info_ptr->valid & PNG_INFO_sBIT))
1544
      png_set_shift(png_ptr, &info_ptr->sig_bit);
1545 1546
#endif

1547
#ifdef PNG_WRITE_PACK_SUPPORTED
1548
   /* Pack pixels into bytes */
1549 1550 1551 1552
   if (transforms & PNG_TRANSFORM_PACKING)
       png_set_packing(png_ptr);
#endif

1553
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
1554
   /* Swap location of alpha bytes from ARGB to RGBA */
1555
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
1556
      png_set_swap_alpha(png_ptr);
1557 1558
#endif

1559
#ifdef PNG_WRITE_FILLER_SUPPORTED
1560
   /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */
1561
   if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER)
1562
      png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
1563

1564
   else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE)
1565
      png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
1566 1567
#endif

1568
#ifdef PNG_WRITE_BGR_SUPPORTED
1569
   /* Flip BGR pixels to RGB */
1570
   if (transforms & PNG_TRANSFORM_BGR)
1571
      png_set_bgr(png_ptr);
1572 1573
#endif

1574
#ifdef PNG_WRITE_SWAP_SUPPORTED
1575
   /* Swap bytes of 16-bit files to most significant byte first */
1576
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
1577
      png_set_swap(png_ptr);
1578 1579
#endif

1580
#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
1581
   /* Swap bits of 1, 2, 4 bit packed pixel formats */
1582
   if (transforms & PNG_TRANSFORM_PACKSWAP)
1583
      png_set_packswap(png_ptr);
1584 1585
#endif

1586
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
1587 1588 1589 1590 1591
   /* Invert the alpha channel from opacity to transparency */
   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
      png_set_invert_alpha(png_ptr);
#endif

1592 1593
   /* ----------------------- end of transformations ------------------- */

1594
   /* Write the bits */
1595 1596 1597 1598 1599
   if (info_ptr->valid & PNG_INFO_IDAT)
       png_write_image(png_ptr, info_ptr->row_pointers);

   /* It is REQUIRED to call this to finish writing the rest of the file */
   png_write_end(png_ptr, info_ptr);
1600

1601 1602
   PNG_UNUSED(transforms)   /* Quiet compiler warnings */
   PNG_UNUSED(params)
1603 1604
}
#endif
1605
#endif /* PNG_WRITE_SUPPORTED */