pngwrite.c 45.9 KB
Newer Older
1

A
Andreas Dilger 已提交
2
/* pngwrite.c - general routines to write a PNG file
3
 *
4
 * Last changed in libpng 1.4.0 April 20, 2006
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2006 Glenn Randers-Pehrson
7 8
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9
 */
G
Guy Schalnat 已提交
10 11 12

/* get internal access to png.h */
#include "png.h"
13
#ifdef PNG_WRITE_SUPPORTED
14
#include "pngintrn.h"
G
Guy Schalnat 已提交
15

A
Andreas Dilger 已提交
16 17 18
/* 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
19
 * after the image data, put it in png_write_end().  I strongly encourage
A
Andreas Dilger 已提交
20 21 22 23 24
 * 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.
 */
25
void PNGAPI
26
png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
G
Guy Schalnat 已提交
27
{
28
   png_debug(1, "in png_write_info_before_PLTE\n");
29 30
   if (png_ptr == NULL || info_ptr == NULL)
      return;
31 32
   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
   {
G
Guy Schalnat 已提交
33
   png_write_sig(png_ptr); /* write PNG signature */
34 35 36
#if defined(PNG_MNG_FEATURES_SUPPORTED)
   if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
   {
37
      png_warning(png_ptr,"MNG features are not allowed in a PNG datastream");
38 39 40
      png_ptr->mng_features_permitted=0;
   }
#endif
G
Guy Schalnat 已提交
41
   /* write IHDR information. */
A
Andreas Dilger 已提交
42 43
   png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
      info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
44 45 46 47 48 49
      info_ptr->filter_type,
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
      info_ptr->interlace_type);
#else
      0);
#endif
G
Guy Schalnat 已提交
50 51
   /* the rest of these check to see if the valid field has the appropriate
      flag set, and if it does, writes the chunk. */
G
Guy Schalnat 已提交
52
#if defined(PNG_WRITE_gAMA_SUPPORTED)
A
Andreas Dilger 已提交
53
   if (info_ptr->valid & PNG_INFO_gAMA)
54 55
   {
#  ifdef PNG_FLOATING_POINT_SUPPORTED
A
Andreas Dilger 已提交
56
      png_write_gAMA(png_ptr, info_ptr->gamma);
57 58 59
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
      png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
60 61 62
#  endif
#endif
   }
G
Guy Schalnat 已提交
63
#endif
64 65
#if defined(PNG_WRITE_sRGB_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_sRGB)
66
      png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
67
#endif
68 69
#if defined(PNG_WRITE_iCCP_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_iCCP)
70
      png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
71 72
                     info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
#endif
G
Guy Schalnat 已提交
73
#if defined(PNG_WRITE_sBIT_SUPPORTED)
A
Andreas Dilger 已提交
74 75
   if (info_ptr->valid & PNG_INFO_sBIT)
      png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
G
Guy Schalnat 已提交
76 77
#endif
#if defined(PNG_WRITE_cHRM_SUPPORTED)
A
Andreas Dilger 已提交
78
   if (info_ptr->valid & PNG_INFO_cHRM)
79
   {
80
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
81
      png_write_cHRM(png_ptr,
A
Andreas Dilger 已提交
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 87 88 89 90 91 92
#else
#  ifdef PNG_FIXED_POINT_SUPPORTED
      png_write_cHRM_fixed(png_ptr,
         info_ptr->int_x_white, info_ptr->int_y_white,
         info_ptr->int_x_red, info_ptr->int_y_red,
         info_ptr->int_x_green, info_ptr->int_y_green,
         info_ptr->int_x_blue, info_ptr->int_y_blue);
93 94 95 96 97 98 99 100 101 102 103 104 105 106
#  endif
#endif
   }
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   if (info_ptr->unknown_chunks_num)
   {
       png_unknown_chunk *up;

       png_debug(5, "writing extra chunks\n");

       for (up = info_ptr->unknown_chunks;
            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
            up++)
107 108
       {
         int keep=png_handle_as_unknown(png_ptr, up->name);
109
         if (keep != PNG_HANDLE_CHUNK_NEVER &&
110 111
            up->location && !(up->location & PNG_HAVE_PLTE) &&
            !(up->location & PNG_HAVE_IDAT) &&
112
            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
113 114
            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
         {
115
            png_write_chunk(png_ptr, up->name, up->data, up->size);
116 117
         }
       }
118
   }
G
Guy Schalnat 已提交
119
#endif
120 121 122 123
      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
   }
}

124
void PNGAPI
125 126
png_write_info(png_structp png_ptr, png_infop info_ptr)
{
127
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
128 129 130 131 132
   int i;
#endif

   png_debug(1, "in png_write_info\n");

133 134 135
   if (png_ptr == NULL || info_ptr == NULL)
      return;

136 137
   png_write_info_before_PLTE(png_ptr, info_ptr);

A
Andreas Dilger 已提交
138
   if (info_ptr->valid & PNG_INFO_PLTE)
A
Andreas Dilger 已提交
139 140
      png_write_PLTE(png_ptr, info_ptr->palette,
         (png_uint_32)info_ptr->num_palette);
A
Andreas Dilger 已提交
141
   else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
142
      png_error(png_ptr, "Valid palette required for paletted images");
143

G
Guy Schalnat 已提交
144
#if defined(PNG_WRITE_tRNS_SUPPORTED)
A
Andreas Dilger 已提交
145
   if (info_ptr->valid & PNG_INFO_tRNS)
146 147 148
      {
#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
         /* invert the alpha channel (in tRNS) */
149
         if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
150 151
            info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
         {
152
            int j;
153
            for (j=0; j<(int)info_ptr->num_trans; j++)
154
               info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
155 156
         }
#endif
A
Andreas Dilger 已提交
157 158
      png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
         info_ptr->num_trans, info_ptr->color_type);
159
      }
G
Guy Schalnat 已提交
160 161
#endif
#if defined(PNG_WRITE_bKGD_SUPPORTED)
A
Andreas Dilger 已提交
162 163
   if (info_ptr->valid & PNG_INFO_bKGD)
      png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
G
Guy Schalnat 已提交
164 165
#endif
#if defined(PNG_WRITE_hIST_SUPPORTED)
A
Andreas Dilger 已提交
166 167
   if (info_ptr->valid & PNG_INFO_hIST)
      png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
G
Guy Schalnat 已提交
168 169
#endif
#if defined(PNG_WRITE_oFFs_SUPPORTED)
A
Andreas Dilger 已提交
170 171 172
   if (info_ptr->valid & PNG_INFO_oFFs)
      png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
         info_ptr->offset_unit_type);
G
Guy Schalnat 已提交
173
#endif
A
Andreas Dilger 已提交
174 175 176 177 178 179
#if defined(PNG_WRITE_pCAL_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_pCAL)
      png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
         info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
         info_ptr->pcal_units, info_ptr->pcal_params);
#endif
180 181
#if defined(PNG_WRITE_sCAL_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_sCAL)
182
#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
183 184 185 186 187
      png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
          info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
      png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
188
          info_ptr->scal_s_width, info_ptr->scal_s_height);
189 190
#else
      png_warning(png_ptr,
191
          "png_write_sCAL not supported; sCAL chunk not written.");
192
#endif
193 194
#endif
#endif
A
Andreas Dilger 已提交
195 196 197 198 199
#if defined(PNG_WRITE_pHYs_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_pHYs)
      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
         info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
#endif
G
Guy Schalnat 已提交
200
#if defined(PNG_WRITE_tIME_SUPPORTED)
A
Andreas Dilger 已提交
201
   if (info_ptr->valid & PNG_INFO_tIME)
G
Guy Schalnat 已提交
202
   {
A
Andreas Dilger 已提交
203
      png_write_tIME(png_ptr, &(info_ptr->mod_time));
204
      png_ptr->mode |= PNG_WROTE_tIME;
G
Guy Schalnat 已提交
205
   }
G
Guy Schalnat 已提交
206
#endif
207 208 209 210 211
#if defined(PNG_WRITE_sPLT_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_sPLT)
     for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
       png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
#endif
212
#if defined(PNG_WRITE_TEXT_SUPPORTED)
G
Guy Schalnat 已提交
213
   /* Check to see if we need to write text chunks */
A
Andreas Dilger 已提交
214
   for (i = 0; i < info_ptr->num_text; i++)
G
Guy Schalnat 已提交
215
   {
A
Andreas Dilger 已提交
216 217
      png_debug2(2, "Writing header text chunk %d, type %d\n", i,
         info_ptr->text[i].compression);
218
      /* an internationalized chunk? */
219
      if (info_ptr->text[i].compression > 0)
220 221 222 223 224 225
      {
#if defined(PNG_WRITE_iTXt_SUPPORTED)
          /* write international chunk */
          png_write_iTXt(png_ptr,
                         info_ptr->text[i].compression,
                         info_ptr->text[i].key,
226 227
                         info_ptr->text[i].lang,
                         info_ptr->text[i].lang_key,
228 229
                         info_ptr->text[i].text);
#else
230
          png_warning(png_ptr, "Unable to write international text");
231 232 233 234
#endif
          /* Mark this chunk as written */
          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
      }
A
Andreas Dilger 已提交
235
      /* If we want a compressed text chunk */
236
      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
G
Guy Schalnat 已提交
237
      {
G
Guy Schalnat 已提交
238
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
239 240
         /* write compressed chunk */
         png_write_zTXt(png_ptr, info_ptr->text[i].key,
241
            info_ptr->text[i].text, 0,
A
Andreas Dilger 已提交
242
            info_ptr->text[i].compression);
G
Guy Schalnat 已提交
243
#else
244
         png_warning(png_ptr, "Unable to write compressed text");
G
Guy Schalnat 已提交
245
#endif
A
Andreas Dilger 已提交
246 247 248 249 250
         /* Mark this chunk as written */
         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
      }
      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
      {
G
Guy Schalnat 已提交
251
#if defined(PNG_WRITE_tEXt_SUPPORTED)
A
Andreas Dilger 已提交
252 253
         /* write uncompressed chunk */
         png_write_tEXt(png_ptr, info_ptr->text[i].key,
254
                         info_ptr->text[i].text,
255
                         0);
G
Guy Schalnat 已提交
256
#else
257
         png_warning(png_ptr, "Unable to write uncompressed text");
G
Guy Schalnat 已提交
258
#endif
A
Andreas Dilger 已提交
259 260
         /* Mark this chunk as written */
         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
G
Guy Schalnat 已提交
261 262
      }
   }
G
Guy Schalnat 已提交
263
#endif
264 265 266 267 268 269 270 271 272 273
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   if (info_ptr->unknown_chunks_num)
   {
       png_unknown_chunk *up;

       png_debug(5, "writing extra chunks\n");

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

A
Andreas Dilger 已提交
289
/* Writes the end of the PNG file.  If you don't want to write comments or
290 291 292 293
 * 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.
 */
294
void PNGAPI
A
Andreas Dilger 已提交
295
png_write_end(png_structp png_ptr, png_infop info_ptr)
G
Guy Schalnat 已提交
296
{
A
Andreas Dilger 已提交
297
   png_debug(1, "in png_write_end\n");
298 299
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
300 301 302
   if (!(png_ptr->mode & PNG_HAVE_IDAT))
      png_error(png_ptr, "No IDATs written into file");

G
Guy Schalnat 已提交
303
   /* see if user wants us to write information chunks */
A
Andreas Dilger 已提交
304
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
305
   {
306
#if defined(PNG_WRITE_TEXT_SUPPORTED)
A
Andreas Dilger 已提交
307
      int i; /* local index variable */
308
#endif
G
Guy Schalnat 已提交
309
#if defined(PNG_WRITE_tIME_SUPPORTED)
G
Guy Schalnat 已提交
310
      /* check to see if user has supplied a time chunk */
311
      if ((info_ptr->valid & PNG_INFO_tIME) &&
312
         !(png_ptr->mode & PNG_WROTE_tIME))
A
Andreas Dilger 已提交
313
         png_write_tIME(png_ptr, &(info_ptr->mod_time));
G
Guy Schalnat 已提交
314
#endif
315
#if defined(PNG_WRITE_TEXT_SUPPORTED)
A
Andreas Dilger 已提交
316 317
      /* loop through comment chunks */
      for (i = 0; i < info_ptr->num_text; i++)
G
Guy Schalnat 已提交
318
      {
A
Andreas Dilger 已提交
319 320
         png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
            info_ptr->text[i].compression);
321 322 323 324 325 326 327 328 329 330 331 332
         /* an internationalized chunk? */
         if (info_ptr->text[i].compression > 0)
         {
#if defined(PNG_WRITE_iTXt_SUPPORTED)
             /* 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);
#else
333
             png_warning(png_ptr, "Unable to write international text");
334 335 336 337 338
#endif
             /* Mark this chunk as written */
             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
         }
         else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
G
Guy Schalnat 已提交
339
         {
G
Guy Schalnat 已提交
340
#if defined(PNG_WRITE_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
341 342
            /* write compressed chunk */
            png_write_zTXt(png_ptr, info_ptr->text[i].key,
343
               info_ptr->text[i].text, 0,
A
Andreas Dilger 已提交
344 345
               info_ptr->text[i].compression);
#else
346
            png_warning(png_ptr, "Unable to write compressed text");
G
Guy Schalnat 已提交
347
#endif
A
Andreas Dilger 已提交
348 349 350 351 352
            /* Mark this chunk as written */
            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
         }
         else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
         {
G
Guy Schalnat 已提交
353
#if defined(PNG_WRITE_tEXt_SUPPORTED)
A
Andreas Dilger 已提交
354 355
            /* write uncompressed chunk */
            png_write_tEXt(png_ptr, info_ptr->text[i].key,
356
               info_ptr->text[i].text, 0);
A
Andreas Dilger 已提交
357
#else
358
            png_warning(png_ptr, "Unable to write uncompressed text");
G
Guy Schalnat 已提交
359
#endif
A
Andreas Dilger 已提交
360 361 362

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

       png_debug(5, "writing extra chunks\n");

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

   png_ptr->mode |= PNG_AFTER_IDAT;

A
Andreas Dilger 已提交
392
   /* write end of PNG file */
G
Guy Schalnat 已提交
393
   png_write_IEND(png_ptr);
394 395 396
#if 0
/* This flush, added in libpng-1.0.8,  causes some applications to crash
   because they do not set png_ptr->output_flush_fn */
397
   png_flush(png_ptr);
398
#endif
G
Guy Schalnat 已提交
399 400
}

G
Guy Schalnat 已提交
401
#if defined(PNG_WRITE_tIME_SUPPORTED)
402
/* "time.h" functions are not supported on WindowsCE */
403
void PNGAPI
G
Guy Schalnat 已提交
404
png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
G
Guy Schalnat 已提交
405
{
A
Andreas Dilger 已提交
406
   png_debug(1, "in png_convert_from_struct_tm\n");
G
Guy Schalnat 已提交
407 408 409 410 411 412
   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 已提交
413 414
}

415
void PNGAPI
G
Guy Schalnat 已提交
416
png_convert_from_time_t(png_timep ptime, time_t ttime)
G
Guy Schalnat 已提交
417 418 419
{
   struct tm *tbuf;

A
Andreas Dilger 已提交
420
   png_debug(1, "in png_convert_from_time_t\n");
G
Guy Schalnat 已提交
421 422 423
   tbuf = gmtime(&ttime);
   png_convert_from_struct_tm(ptime, tbuf);
}
G
Guy Schalnat 已提交
424
#endif
G
Guy Schalnat 已提交
425

A
Andreas Dilger 已提交
426
/* Initialize png_ptr structure, and allocate any memory needed */
427
png_structp PNGAPI
428
png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
A
Andreas Dilger 已提交
429
   png_error_ptr error_fn, png_error_ptr warn_fn)
G
Guy Schalnat 已提交
430
{
431 432
#ifdef PNG_USER_MEM_SUPPORTED
   return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
433
      warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
434 435 436
}

/* Alternate initialize png_ptr structure, and allocate any memory needed */
437
png_structp PNGAPI
438 439 440 441 442
png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
   png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
   png_malloc_ptr malloc_fn, png_free_ptr free_fn)
{
#endif /* PNG_USER_MEM_SUPPORTED */
G
Guy Schalnat 已提交
443
   png_structp png_ptr;
444
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
445 446
#ifdef USE_FAR_KEYWORD
   jmp_buf jmpbuf;
447
#endif
A
Andreas Dilger 已提交
448
#endif
449
   int i;
A
Andreas Dilger 已提交
450
   png_debug(1, "in png_create_write_struct\n");
451
#ifdef PNG_USER_MEM_SUPPORTED
452 453
   png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
      (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
454
#else
455
   png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
456
#endif /* PNG_USER_MEM_SUPPORTED */
457
   if (png_ptr == NULL)
458
      return (NULL);
459

460
#ifdef PNG_MMX_CODE_SUPPORTED
461 462 463
   png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
#endif

464 465 466 467 468 469
   /* added at libpng-1.2.6 */
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
   png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
   png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
#endif

470
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
471 472 473
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmpbuf))
#else
G
Guy Schalnat 已提交
474
   if (setjmp(png_ptr->jmpbuf))
A
Andreas Dilger 已提交
475
#endif
G
Guy Schalnat 已提交
476
   {
A
Andreas Dilger 已提交
477
      png_free(png_ptr, png_ptr->zbuf);
478
      png_ptr->zbuf=NULL;
G
Guy Schalnat 已提交
479
      png_destroy_struct(png_ptr);
480
      return (NULL);
G
Guy Schalnat 已提交
481
   }
A
Andreas Dilger 已提交
482
#ifdef USE_FAR_KEYWORD
483
   png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
A
Andreas Dilger 已提交
484
#endif
485 486
#endif

487 488 489
#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 已提交
490
   png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
G
Guy Schalnat 已提交
491

492 493
   i=0;
   do
G
Guy Schalnat 已提交
494
   {
495 496 497
     if(user_png_ver[i] != png_libpng_ver[i])
        png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
   } while (png_libpng_ver[i++]);
498

499
   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
500
   {
501 502 503 504 505 506
     /* 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] ||
507
         (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
508 509
         (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
     {
510
#ifndef PNG_NO_STDIO
511 512 513
        char msg[80];
        if (user_png_ver)
        {
514
          png_sprintf(msg, "Application was compiled with png.h from libpng-%.20s",
515 516 517
             user_png_ver);
          png_warning(png_ptr, msg);
        }
518
        png_sprintf(msg, "Application  is  running with png.c from libpng-%.20s",
519 520 521 522 523 524
           png_libpng_ver);
        png_warning(png_ptr, msg);
#endif
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
        png_ptr->flags=0;
#endif
525 526 527 528
        png_error(png_ptr,
           "Incompatible libpng version in application and library");
     }
   }
529

G
Guy Schalnat 已提交
530 531
   /* initialize zbuf - compression buffer */
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
532 533
   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
      (png_uint_32)png_ptr->zbuf_size);
G
Guy Schalnat 已提交
534

535 536
   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
      png_flush_ptr_NULL);
G
Guy Schalnat 已提交
537

538 539
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
540
      1, png_doublep_NULL, png_doublep_NULL);
541 542
#endif

543 544 545 546 547 548 549
#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
   if (setjmp(jmpbuf))
      PNG_ABORT();
550
   png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
551 552 553 554 555 556
#else
   if (setjmp(png_ptr->jmpbuf))
      PNG_ABORT();
#endif
#endif
   return (png_ptr);
G
Guy Schalnat 已提交
557 558
}

559 560 561 562 563
void PNGAPI
png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
   png_size_t png_struct_size)
{
   png_structp png_ptr=*ptr_ptr;
564
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
565
   jmp_buf tmp_jmp; /* to save current jump buffer */
566
#endif
567

568 569
   int i = 0;

570 571 572
   if (png_ptr == NULL)
      return;

573 574 575 576
   do
   {
     if (user_png_ver[i] != png_libpng_ver[i])
     {
577 578 579
#ifdef PNG_LEGACY_SUPPORTED
       png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
#else
580
       png_ptr->warning_fn=NULL;
581 582 583
       png_warning(png_ptr,
     "Application uses deprecated png_write_init() and should be recompiled.");
       break;
584
#endif
585 586
     }
   } while (png_libpng_ver[i++]);
587

588
   png_debug(1, "in png_write_init_3\n");
G
Guy Schalnat 已提交
589

590
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
591
   /* save jump buffer and error functions */
592
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
593
#endif
G
Guy Schalnat 已提交
594

595
   if (png_sizeof(png_struct) > png_struct_size)
596 597 598 599 600 601
     {
       png_destroy_struct(png_ptr);
       png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
       *ptr_ptr = png_ptr;
     }

G
Guy Schalnat 已提交
602
   /* reset all variables to 0 */
603
   png_memset(png_ptr, 0, png_sizeof (png_struct));
G
Guy Schalnat 已提交
604

605 606 607 608 609 610
   /* added at libpng-1.2.6 */
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
   png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
   png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
#endif

611
#ifdef PNG_MMX_CODE_SUPPORTED
612 613 614
   png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
#endif

615
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
616
   /* restore jump buffer */
617
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
618
#endif
G
Guy Schalnat 已提交
619

620 621
   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
      png_flush_ptr_NULL);
622

G
Guy Schalnat 已提交
623 624
   /* initialize zbuf - compression buffer */
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
625 626
   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
      (png_uint_32)png_ptr->zbuf_size);
A
Andreas Dilger 已提交
627 628 629

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
630
      1, png_doublep_NULL, png_doublep_NULL);
A
Andreas Dilger 已提交
631
#endif
G
Guy Schalnat 已提交
632 633
}

634 635 636 637 638
/* 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.
 */
639
void PNGAPI
G
Guy Schalnat 已提交
640
png_write_rows(png_structp png_ptr, png_bytepp row,
G
Guy Schalnat 已提交
641 642 643
   png_uint_32 num_rows)
{
   png_uint_32 i; /* row counter */
G
Guy Schalnat 已提交
644
   png_bytepp rp; /* row pointer */
G
Guy Schalnat 已提交
645

A
Andreas Dilger 已提交
646
   png_debug(1, "in png_write_rows\n");
647 648 649 650

   if (png_ptr == NULL)
      return;

G
Guy Schalnat 已提交
651 652 653 654 655 656 657
   /* loop through the rows */
   for (i = 0, rp = row; i < num_rows; i++, rp++)
   {
      png_write_row(png_ptr, *rp);
   }
}

658 659 660
/* Write the image.  You only need to call this function once, even
 * if you are writing an interlaced image.
 */
661
void PNGAPI
G
Guy Schalnat 已提交
662
png_write_image(png_structp png_ptr, png_bytepp image)
G
Guy Schalnat 已提交
663 664 665
{
   png_uint_32 i; /* row index */
   int pass, num_pass; /* pass variables */
G
Guy Schalnat 已提交
666
   png_bytepp rp; /* points to current row */
G
Guy Schalnat 已提交
667

668 669 670
   if (png_ptr == NULL)
      return;

A
Andreas Dilger 已提交
671
   png_debug(1, "in png_write_image\n");
672
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
673 674 675
   /* intialize interlace handling.  If image is not interlaced,
      this will set pass to 1 */
   num_pass = png_set_interlace_handling(png_ptr);
676 677 678
#else
   num_pass = 1;
#endif
G
Guy Schalnat 已提交
679 680 681 682 683 684 685 686 687 688 689
   /* loop through passes */
   for (pass = 0; pass < num_pass; pass++)
   {
      /* loop through image */
      for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
      {
         png_write_row(png_ptr, *rp);
      }
   }
}

G
Guy Schalnat 已提交
690
/* called by user to write a row of image data */
691
void PNGAPI
G
Guy Schalnat 已提交
692
png_write_row(png_structp png_ptr, png_bytep row)
G
Guy Schalnat 已提交
693
{
694 695
   if (png_ptr == NULL)
      return;
696 697
   png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
      png_ptr->row_number, png_ptr->pass);
698

G
Guy Schalnat 已提交
699
   /* initialize transformations and other stuff if first time */
G
Guy Schalnat 已提交
700
   if (png_ptr->row_number == 0 && png_ptr->pass == 0)
G
Guy Schalnat 已提交
701
   {
702 703 704 705 706
   /* make sure we wrote the header info */
   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
      png_error(png_ptr,
         "png_write_info was never called before png_write_row.");

707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
   /* check for transforms that have been set but were defined out */
#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
   if (png_ptr->transformations & PNG_INVERT_MONO)
      png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
#endif
#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
   if (png_ptr->transformations & PNG_FILLER)
      png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
#endif
#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
   if (png_ptr->transformations & PNG_PACKSWAP)
      png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
#endif
#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
   if (png_ptr->transformations & PNG_PACK)
      png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
#endif
#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
   if (png_ptr->transformations & PNG_SHIFT)
      png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
#endif
#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
   if (png_ptr->transformations & PNG_BGR)
      png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
#endif
#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
   if (png_ptr->transformations & PNG_SWAP_BYTES)
      png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
#endif

G
Guy Schalnat 已提交
737 738 739
      png_write_start_row(png_ptr);
   }

G
Guy Schalnat 已提交
740
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
741 742 743 744 745
   /* if interlaced and not interested in row, return */
   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
   {
      switch (png_ptr->pass)
      {
G
Guy Schalnat 已提交
746
         case 0:
747
            if (png_ptr->row_number & 0x07)
G
Guy Schalnat 已提交
748 749 750 751 752 753
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 1:
754
            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
G
Guy Schalnat 已提交
755 756 757 758 759 760
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 2:
761
            if ((png_ptr->row_number & 0x07) != 4)
G
Guy Schalnat 已提交
762 763
            {
               png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
764
               return;
G
Guy Schalnat 已提交
765 766 767
            }
            break;
         case 3:
768
            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
G
Guy Schalnat 已提交
769 770 771 772 773 774
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 4:
775
            if ((png_ptr->row_number & 0x03) != 2)
G
Guy Schalnat 已提交
776 777 778 779 780 781
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 5:
782
            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
G
Guy Schalnat 已提交
783 784 785 786 787 788
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 6:
789
            if (!(png_ptr->row_number & 0x01))
G
Guy Schalnat 已提交
790 791 792 793 794 795 796
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
      }
   }
G
Guy Schalnat 已提交
797
#endif
G
Guy Schalnat 已提交
798 799

   /* set up row info for transformations */
G
Guy Schalnat 已提交
800
   png_ptr->row_info.color_type = png_ptr->color_type;
G
Guy Schalnat 已提交
801 802 803
   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 已提交
804 805
   png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
      png_ptr->row_info.channels);
806

807 808
   png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
      png_ptr->row_info.width);
G
Guy Schalnat 已提交
809

810
   png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
811 812
   png_debug1(3, "row_info->width = %lu\n",
     (unsigned long) png_ptr->row_info.width);
813 814 815
   png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
   png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
   png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
816 817
   png_debug1(3, "row_info->rowbytes = %lu\n",
     (unsigned long) png_ptr->row_info.rowbytes);
A
Andreas Dilger 已提交
818 819

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

G
Guy Schalnat 已提交
823
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
824 825 826 827 828
   /* handle interlacing */
   if (png_ptr->interlaced && png_ptr->pass < 6 &&
      (png_ptr->transformations & PNG_INTERLACE))
   {
      png_do_write_interlace(&(png_ptr->row_info),
G
Guy Schalnat 已提交
829
         png_ptr->row_buf + 1, png_ptr->pass);
G
Guy Schalnat 已提交
830 831 832 833 834 835 836
      /* this should always get caught above, but still ... */
      if (!(png_ptr->row_info.width))
      {
         png_write_finish_row(png_ptr);
         return;
      }
   }
G
Guy Schalnat 已提交
837
#endif
G
Guy Schalnat 已提交
838 839 840 841 842

   /* handle other transformations */
   if (png_ptr->transformations)
      png_do_write_transformations(png_ptr);

843
#if defined(PNG_MNG_FEATURES_SUPPORTED)
844 845 846 847 848 849 850 851 852
   /* 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
    */
853 854 855 856 857 858 859 860
   if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
      (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
   {
      /* Intrapixel differencing */
      png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
   }
#endif

A
Andreas Dilger 已提交
861
   /* Find a filter if necessary, filter the row and write it out. */
G
Guy Schalnat 已提交
862
   png_write_find_filter(png_ptr, &(png_ptr->row_info));
863 864 865

   if (png_ptr->write_row_fn != NULL)
      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
G
Guy Schalnat 已提交
866 867 868 869
}

#if defined(PNG_WRITE_FLUSH_SUPPORTED)
/* Set the automatic flush interval or 0 to turn flushing off */
870
void PNGAPI
G
Guy Schalnat 已提交
871
png_set_flush(png_structp png_ptr, int nrows)
G
Guy Schalnat 已提交
872
{
A
Andreas Dilger 已提交
873
   png_debug(1, "in png_set_flush\n");
874 875
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
876
   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
G
Guy Schalnat 已提交
877 878 879
}

/* flush the current output buffers now */
880
void PNGAPI
G
Guy Schalnat 已提交
881
png_write_flush(png_structp png_ptr)
G
Guy Schalnat 已提交
882
{
G
Guy Schalnat 已提交
883 884
   int wrote_IDAT;

A
Andreas Dilger 已提交
885
   png_debug(1, "in png_write_flush\n");
886 887
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
888 889
   /* We have already written out all of the data */
   if (png_ptr->row_number >= png_ptr->num_rows)
G
Guy Schalnat 已提交
890 891 892 893 894 895 896
     return;

   do
   {
      int ret;

      /* compress the data */
A
Andreas Dilger 已提交
897
      ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
G
Guy Schalnat 已提交
898 899 900 901 902
      wrote_IDAT = 0;

      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
903
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
904
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
905 906 907 908
         else
            png_error(png_ptr, "zlib error");
      }

A
Andreas Dilger 已提交
909
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
910 911 912 913
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf,
                        png_ptr->zbuf_size);
A
Andreas Dilger 已提交
914 915
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
916 917 918 919 920
         wrote_IDAT = 1;
      }
   } while(wrote_IDAT == 1);

   /* If there is any data left to be output, write it into a new IDAT */
A
Andreas Dilger 已提交
921
   if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
G
Guy Schalnat 已提交
922 923 924
   {
      /* write the IDAT and reset the zlib output buffer */
      png_write_IDAT(png_ptr, png_ptr->zbuf,
A
Andreas Dilger 已提交
925 926 927
                     png_ptr->zbuf_size - png_ptr->zstream.avail_out);
      png_ptr->zstream.next_out = png_ptr->zbuf;
      png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
928 929 930
   }
   png_ptr->flush_rows = 0;
   png_flush(png_ptr);
G
Guy Schalnat 已提交
931
}
G
Guy Schalnat 已提交
932
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
G
Guy Schalnat 已提交
933

G
Guy Schalnat 已提交
934
/* free all memory used by the write */
935
void PNGAPI
A
Andreas Dilger 已提交
936
png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
G
Guy Schalnat 已提交
937
{
A
Andreas Dilger 已提交
938 939
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL;
940 941
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn = NULL;
942
   png_voidp mem_ptr = NULL;
943
#endif
A
Andreas Dilger 已提交
944

A
Andreas Dilger 已提交
945 946
   png_debug(1, "in png_destroy_write_struct\n");
   if (png_ptr_ptr != NULL)
947
   {
A
Andreas Dilger 已提交
948
      png_ptr = *png_ptr_ptr;
949 950
#ifdef PNG_USER_MEM_SUPPORTED
      free_fn = png_ptr->free_fn;
951
      mem_ptr = png_ptr->mem_ptr;
952 953
#endif
   }
A
Andreas Dilger 已提交
954

A
Andreas Dilger 已提交
955
   if (info_ptr_ptr != NULL)
A
Andreas Dilger 已提交
956 957
      info_ptr = *info_ptr_ptr;

A
Andreas Dilger 已提交
958
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
959
   {
960 961
      png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);

962
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
963 964 965
      if (png_ptr->num_chunk_list)
      {
         png_free(png_ptr, png_ptr->chunk_list);
966
         png_ptr->chunk_list=NULL;
967 968
         png_ptr->num_chunk_list=0;
      }
969
#endif
970

971
#ifdef PNG_USER_MEM_SUPPORTED
972 973
      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
974
#else
A
Andreas Dilger 已提交
975
      png_destroy_struct((png_voidp)info_ptr);
976
#endif
977
      *info_ptr_ptr = NULL;
G
Guy Schalnat 已提交
978 979
   }

A
Andreas Dilger 已提交
980
   if (png_ptr != NULL)
G
Guy Schalnat 已提交
981
   {
A
Andreas Dilger 已提交
982
      png_write_destroy(png_ptr);
983
#ifdef PNG_USER_MEM_SUPPORTED
984 985
      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
986
#else
A
Andreas Dilger 已提交
987
      png_destroy_struct((png_voidp)png_ptr);
988
#endif
989
      *png_ptr_ptr = NULL;
G
Guy Schalnat 已提交
990 991 992
   }
}

G
Guy Schalnat 已提交
993

A
Andreas Dilger 已提交
994
/* Free any memory used in png_ptr struct (old method) */
995
void /* PRIVATE */
G
Guy Schalnat 已提交
996
png_write_destroy(png_structp png_ptr)
G
Guy Schalnat 已提交
997
{
998
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
999
   jmp_buf tmp_jmp; /* save jump buffer */
1000
#endif
G
Guy Schalnat 已提交
1001 1002 1003
   png_error_ptr error_fn;
   png_error_ptr warning_fn;
   png_voidp error_ptr;
1004 1005 1006
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn;
#endif
G
Guy Schalnat 已提交
1007

A
Andreas Dilger 已提交
1008
   png_debug(1, "in png_write_destroy\n");
G
Guy Schalnat 已提交
1009
   /* free any memory zlib uses */
A
Andreas Dilger 已提交
1010
   deflateEnd(&png_ptr->zstream);
G
Guy Schalnat 已提交
1011

G
Guy Schalnat 已提交
1012
   /* free our memory.  png_free checks NULL for us. */
A
Andreas Dilger 已提交
1013 1014 1015 1016 1017 1018 1019
   png_free(png_ptr, png_ptr->zbuf);
   png_free(png_ptr, png_ptr->row_buf);
   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);
1020

1021
#if defined(PNG_TIME_RFC1123_SUPPORTED)
1022
   png_free(png_ptr, png_ptr->time_buffer);
1023 1024
#endif

A
Andreas Dilger 已提交
1025 1026 1027 1028 1029 1030
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   png_free(png_ptr, png_ptr->prev_filters);
   png_free(png_ptr, png_ptr->filter_weights);
   png_free(png_ptr, png_ptr->inv_filter_weights);
   png_free(png_ptr, png_ptr->filter_costs);
   png_free(png_ptr, png_ptr->inv_filter_costs);
1031
#endif
G
Guy Schalnat 已提交
1032

1033
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
1034
   /* reset structure */
1035
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
1036
#endif
G
Guy Schalnat 已提交
1037 1038 1039 1040

   error_fn = png_ptr->error_fn;
   warning_fn = png_ptr->warning_fn;
   error_ptr = png_ptr->error_ptr;
1041 1042 1043
#ifdef PNG_USER_MEM_SUPPORTED
   free_fn = png_ptr->free_fn;
#endif
G
Guy Schalnat 已提交
1044

1045
   png_memset(png_ptr, 0, png_sizeof (png_struct));
G
Guy Schalnat 已提交
1046 1047 1048 1049

   png_ptr->error_fn = error_fn;
   png_ptr->warning_fn = warning_fn;
   png_ptr->error_ptr = error_ptr;
1050 1051 1052
#ifdef PNG_USER_MEM_SUPPORTED
   png_ptr->free_fn = free_fn;
#endif
G
Guy Schalnat 已提交
1053

1054
#ifdef PNG_SETJMP_SUPPORTED
1055
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
1056
#endif
G
Guy Schalnat 已提交
1057
}
G
Guy Schalnat 已提交
1058

A
Andreas Dilger 已提交
1059
/* Allow the application to select one or more row filters to use. */
1060
void PNGAPI
G
Guy Schalnat 已提交
1061
png_set_filter(png_structp png_ptr, int method, int filters)
G
Guy Schalnat 已提交
1062
{
A
Andreas Dilger 已提交
1063
   png_debug(1, "in png_set_filter\n");
1064 1065
   if (png_ptr == NULL)
      return;
1066
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1067
   if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
1068 1069 1070
      (method == PNG_INTRAPIXEL_DIFFERENCING))
         method = PNG_FILTER_TYPE_BASE;
#endif
A
Andreas Dilger 已提交
1071
   if (method == PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
1072 1073 1074 1075 1076
   {
      switch (filters & (PNG_ALL_FILTERS | 0x07))
      {
         case 5:
         case 6:
A
Andreas Dilger 已提交
1077 1078 1079 1080 1081 1082
         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
         case PNG_FILTER_VALUE_NONE:  png_ptr->do_filter=PNG_FILTER_NONE; break;
         case PNG_FILTER_VALUE_SUB:   png_ptr->do_filter=PNG_FILTER_SUB;  break;
         case PNG_FILTER_VALUE_UP:    png_ptr->do_filter=PNG_FILTER_UP;   break;
         case PNG_FILTER_VALUE_AVG:   png_ptr->do_filter=PNG_FILTER_AVG;  break;
         case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
G
Guy Schalnat 已提交
1083 1084 1085
         default: png_ptr->do_filter = (png_byte)filters; break;
      }

A
Andreas Dilger 已提交
1086 1087 1088 1089 1090 1091 1092 1093
      /* 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 已提交
1094
       */
A
Andreas Dilger 已提交
1095
      if (png_ptr->row_buf != NULL)
G
Guy Schalnat 已提交
1096
      {
1097
         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
G
Guy Schalnat 已提交
1098
         {
A
Andreas Dilger 已提交
1099
            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1100
              (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1101
            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1102 1103
         }

1104
         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
G
Guy Schalnat 已提交
1105
         {
A
Andreas Dilger 已提交
1106
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1107
            {
A
Andreas Dilger 已提交
1108
               png_warning(png_ptr, "Can't add Up filter after starting");
G
Guy Schalnat 已提交
1109 1110 1111 1112
               png_ptr->do_filter &= ~PNG_FILTER_UP;
            }
            else
            {
A
Andreas Dilger 已提交
1113
               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1114
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1115
               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1116 1117 1118
            }
         }

1119
         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
G
Guy Schalnat 已提交
1120
         {
A
Andreas Dilger 已提交
1121
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1122
            {
A
Andreas Dilger 已提交
1123
               png_warning(png_ptr, "Can't add Average filter after starting");
G
Guy Schalnat 已提交
1124 1125 1126 1127
               png_ptr->do_filter &= ~PNG_FILTER_AVG;
            }
            else
            {
A
Andreas Dilger 已提交
1128
               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1129
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1130
               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1131 1132 1133
            }
         }

1134
         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
A
Andreas Dilger 已提交
1135
             png_ptr->paeth_row == NULL)
G
Guy Schalnat 已提交
1136
         {
A
Andreas Dilger 已提交
1137
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1138 1139
            {
               png_warning(png_ptr, "Can't add Paeth filter after starting");
1140
               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
G
Guy Schalnat 已提交
1141 1142 1143
            }
            else
            {
1144
               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1145
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1146
               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1147 1148 1149 1150 1151 1152 1153 1154
            }
         }

         if (png_ptr->do_filter == PNG_NO_FILTERS)
            png_ptr->do_filter = PNG_FILTER_NONE;
      }
   }
   else
A
Andreas Dilger 已提交
1155 1156 1157 1158 1159 1160 1161 1162
      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
1163 1164
 * better compression.
 */
A
Andreas Dilger 已提交
1165
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
1166
void PNGAPI
A
Andreas Dilger 已提交
1167 1168 1169 1170 1171 1172 1173
png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
   int num_weights, png_doublep filter_weights,
   png_doublep filter_costs)
{
   int i;

   png_debug(1, "in png_set_filter_heuristics\n");
1174 1175
   if (png_ptr == NULL)
      return;
A
Andreas Dilger 已提交
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
   if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
   {
      png_warning(png_ptr, "Unknown filter heuristic method");
      return;
   }

   if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
   {
      heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
   }

   if (num_weights < 0 || filter_weights == NULL ||
      heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
   {
      num_weights = 0;
   }

1193 1194
   png_ptr->num_prev_filters = (png_byte)num_weights;
   png_ptr->heuristic_method = (png_byte)heuristic_method;
A
Andreas Dilger 已提交
1195 1196 1197 1198 1199 1200

   if (num_weights > 0)
   {
      if (png_ptr->prev_filters == NULL)
      {
         png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
1201
            (png_uint_32)(png_sizeof(png_byte) * num_weights));
A
Andreas Dilger 已提交
1202

1203 1204
         /* To make sure that the weighting starts out fairly */
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1205
         {
1206
            png_ptr->prev_filters[i] = 255;
A
Andreas Dilger 已提交
1207 1208 1209 1210 1211
         }
      }

      if (png_ptr->filter_weights == NULL)
      {
1212
         png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
1213
            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
A
Andreas Dilger 已提交
1214

1215
         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
1216
            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
1217
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1218
         {
1219 1220
            png_ptr->inv_filter_weights[i] =
            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
1221
         }
A
Andreas Dilger 已提交
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
      }

      for (i = 0; i < num_weights; i++)
      {
         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)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
            png_ptr->filter_weights[i] =
               (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
         }
      }
   }

   /* 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)
   {
1246
      png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
1247
         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
A
Andreas Dilger 已提交
1248

1249
      png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
1250
         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
A
Andreas Dilger 已提交
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280

      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
      {
         png_ptr->inv_filter_costs[i] =
         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
      }
   }

   /* 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 == NULL || filter_costs[i] < 0.0)
      {
         png_ptr->inv_filter_costs[i] =
         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
      }
      else if (filter_costs[i] >= 1.0)
      {
         png_ptr->inv_filter_costs[i] =
            (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
         png_ptr->filter_costs[i] =
            (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
      }
   }
G
Guy Schalnat 已提交
1281
}
A
Andreas Dilger 已提交
1282
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
G
Guy Schalnat 已提交
1283

1284
void PNGAPI
G
Guy Schalnat 已提交
1285
png_set_compression_level(png_structp png_ptr, int level)
G
Guy Schalnat 已提交
1286
{
A
Andreas Dilger 已提交
1287
   png_debug(1, "in png_set_compression_level\n");
1288 1289
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1290
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
G
Guy Schalnat 已提交
1291 1292 1293
   png_ptr->zlib_level = level;
}

1294
void PNGAPI
G
Guy Schalnat 已提交
1295
png_set_compression_mem_level(png_structp png_ptr, int mem_level)
G
Guy Schalnat 已提交
1296
{
A
Andreas Dilger 已提交
1297
   png_debug(1, "in png_set_compression_mem_level\n");
1298 1299
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1300
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
G
Guy Schalnat 已提交
1301
   png_ptr->zlib_mem_level = mem_level;
G
Guy Schalnat 已提交
1302 1303
}

1304
void PNGAPI
G
Guy Schalnat 已提交
1305
png_set_compression_strategy(png_structp png_ptr, int strategy)
G
Guy Schalnat 已提交
1306
{
A
Andreas Dilger 已提交
1307
   png_debug(1, "in png_set_compression_strategy\n");
1308 1309
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1310
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
G
Guy Schalnat 已提交
1311 1312 1313
   png_ptr->zlib_strategy = strategy;
}

1314
void PNGAPI
G
Guy Schalnat 已提交
1315
png_set_compression_window_bits(png_structp png_ptr, int window_bits)
G
Guy Schalnat 已提交
1316
{
1317 1318
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1319 1320
   if (window_bits > 15)
      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1321 1322
   else if (window_bits < 8)
      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1323 1324 1325 1326 1327 1328 1329 1330
#ifndef WBITS_8_OK
   /* avoid libpng bug with 256-byte windows */
   if (window_bits == 8)
     {
       png_warning(png_ptr, "Compression window is being reset to 512");
       window_bits=9;
     }
#endif
G
Guy Schalnat 已提交
1331
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
G
Guy Schalnat 已提交
1332 1333 1334
   png_ptr->zlib_window_bits = window_bits;
}

1335
void PNGAPI
G
Guy Schalnat 已提交
1336
png_set_compression_method(png_structp png_ptr, int method)
G
Guy Schalnat 已提交
1337
{
A
Andreas Dilger 已提交
1338
   png_debug(1, "in png_set_compression_method\n");
1339 1340
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1341 1342 1343
   if (method != 8)
      png_warning(png_ptr, "Only compression method 8 is supported by PNG");
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
G
Guy Schalnat 已提交
1344
   png_ptr->zlib_method = method;
G
Guy Schalnat 已提交
1345 1346
}

1347
void PNGAPI
1348 1349
png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
{
1350 1351
   if (png_ptr == NULL)
      return;
1352 1353 1354 1355
   png_ptr->write_row_fn = write_row_fn;
}

#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1356
void PNGAPI
1357 1358 1359 1360
png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
   write_user_transform_fn)
{
   png_debug(1, "in png_set_write_user_transform_fn\n");
1361 1362
   if (png_ptr == NULL)
      return;
1363 1364 1365 1366
   png_ptr->transformations |= PNG_USER_TRANSFORM;
   png_ptr->write_user_transform_fn = write_user_transform_fn;
}
#endif
1367 1368 1369


#if defined(PNG_INFO_IMAGE_SUPPORTED)
1370 1371
void PNGAPI
png_write_png(png_structp png_ptr, png_infop info_ptr,
1372
              int transforms, voidp params)
1373
{
1374 1375
   if (png_ptr == NULL || info_ptr == NULL)
      return;
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
   /* invert the alpha channel from opacity to transparency */
   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
       png_set_invert_alpha(png_ptr);
#endif

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

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

#if defined(PNG_WRITE_INVERT_SUPPORTED)
   /* invert monochrome pixels */
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
       png_set_invert_mono(png_ptr);
#endif

#if defined(PNG_WRITE_SHIFT_SUPPORTED)
   /* Shift the pixels up to a legal bit depth and fill in
    * as appropriate to correctly scale the image.
    */
   if ((transforms & PNG_TRANSFORM_SHIFT)
               && (info_ptr->valid & PNG_INFO_sBIT))
       png_set_shift(png_ptr, &info_ptr->sig_bit);
#endif

#if defined(PNG_WRITE_PACK_SUPPORTED)
   /* pack pixels into bytes */
   if (transforms & PNG_TRANSFORM_PACKING)
       png_set_packing(png_ptr);
#endif

#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
   /* swap location of alpha bytes from ARGB to RGBA */
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
       png_set_swap_alpha(png_ptr);
#endif

#if defined(PNG_WRITE_FILLER_SUPPORTED)
   /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
    * RGB (4 channels -> 3 channels). The second parameter is not used.
    */
   if (transforms & PNG_TRANSFORM_STRIP_FILLER)
       png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
#endif

#if defined(PNG_WRITE_BGR_SUPPORTED)
   /* flip BGR pixels to RGB */
   if (transforms & PNG_TRANSFORM_BGR)
       png_set_bgr(png_ptr);
#endif

#if defined(PNG_WRITE_SWAP_SUPPORTED)
   /* swap bytes of 16-bit files to most significant byte first */
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
       png_set_swap(png_ptr);
#endif

#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
   /* swap bits of 1, 2, 4 bit packed pixel formats */
   if (transforms & PNG_TRANSFORM_PACKSWAP)
       png_set_packswap(png_ptr);
#endif

   /* ----------------------- end of transformations ------------------- */

   /* write the bits */
   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);
1448

1449
   if(transforms == 0 || params == NULL)
1450
      /* quiet compiler warnings */ return;
1451 1452
}
#endif
1453
#endif /* PNG_WRITE_SUPPORTED */