pngwrite.c 44.8 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 [May 15, 2009]
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2009 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 "pngpriv.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");
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
#if defined(PNG_MNG_FEATURES_SUPPORTED)
35
   if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
36
   {
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
#  endif
#endif
   }
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   if (info_ptr->unknown_chunks_num)
   {
       png_unknown_chunk *up;

102
       png_debug(5, "writing extra chunks");
103 104 105 106

       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 116
            if (up->size == 0)
               png_warning(png_ptr, "Writing zero-length unknown chunk");
117
            png_write_chunk(png_ptr, up->name, up->data, up->size);
118 119
         }
       }
120
   }
G
Guy Schalnat 已提交
121
#endif
122 123 124 125
      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
   }
}

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

133
   png_debug(1, "in png_write_info");
134

135 136 137
   if (png_ptr == NULL || info_ptr == NULL)
      return;

138 139
   png_write_info_before_PLTE(png_ptr, info_ptr);

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

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

271
       png_debug(5, "writing extra chunks");
272 273 274 275

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

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

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

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

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

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

   png_ptr->mode |= PNG_AFTER_IDAT;

A
Andreas Dilger 已提交
394
   /* write end of PNG file */
G
Guy Schalnat 已提交
395
   png_write_IEND(png_ptr);
396 397 398
   /* 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
399
    * experiences a problem, please report the event to
400 401
    * png-mng-implement at lists.sf.net .
    */
402
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
403
   png_flush(png_ptr);
404
#endif
G
Guy Schalnat 已提交
405 406
}

G
Guy Schalnat 已提交
407
#if defined(PNG_WRITE_tIME_SUPPORTED)
408
/* "time.h" functions are not supported on WindowsCE */
409
void PNGAPI
G
Guy Schalnat 已提交
410
png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
G
Guy Schalnat 已提交
411
{
412
   png_debug(1, "in png_convert_from_struct_tm");
G
Guy Schalnat 已提交
413 414 415 416 417 418
   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 已提交
419 420
}

421
void PNGAPI
G
Guy Schalnat 已提交
422
png_convert_from_time_t(png_timep ptime, time_t ttime)
G
Guy Schalnat 已提交
423 424 425
{
   struct tm *tbuf;

426
   png_debug(1, "in png_convert_from_time_t");
G
Guy Schalnat 已提交
427 428 429
   tbuf = gmtime(&ttime);
   png_convert_from_struct_tm(ptime, tbuf);
}
G
Guy Schalnat 已提交
430
#endif
G
Guy Schalnat 已提交
431

432

A
Andreas Dilger 已提交
433
/* Initialize png_ptr structure, and allocate any memory needed */
434
png_structp PNGAPI
435
png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
A
Andreas Dilger 已提交
436
   png_error_ptr error_fn, png_error_ptr warn_fn)
G
Guy Schalnat 已提交
437
{
438 439
#ifdef PNG_USER_MEM_SUPPORTED
   return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
440
      warn_fn, NULL, NULL, NULL));
441 442 443
}

/* Alternate initialize png_ptr structure, and allocate any memory needed */
444
png_structp PNGAPI
445 446 447 448 449
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 */
450
   int png_cleanup_needed = 0;
451 452 453
#ifdef PNG_SETJMP_SUPPORTED
    volatile
#endif
454
   png_structp png_ptr;
455
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
456 457
#ifdef USE_FAR_KEYWORD
   jmp_buf jmpbuf;
458
#endif
A
Andreas Dilger 已提交
459
#endif
460
   int i;
461
   png_debug(1, "in png_create_write_struct");
462
#ifdef PNG_USER_MEM_SUPPORTED
463
   png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
464
      (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
465
#else
466
   png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
467
#endif /* PNG_USER_MEM_SUPPORTED */
468
   if (png_ptr == NULL)
469
      return (NULL);
470

471 472 473 474 475 476
   /* 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

477 478 479 480 481 482 483 484 485 486 487
#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))
#else
   if (setjmp(png_ptr->jmpbuf))
#endif
   PNG_ABORT();
#endif
488

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

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

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

G
Guy Schalnat 已提交
538 539
   /* initialize zbuf - compression buffer */
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
540 541 542 543 544 545 546 547 548
   if (!png_cleanup_needed)
     {
        png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr,
           png_ptr->zbuf_size);
        if (png_ptr->zbuf == NULL)
          png_cleanup_needed = 1;
     }
   if (png_cleanup_needed)
     {
549 550 551
        /* Clean up PNG structure and deallocate any memory. */
        png_free(png_ptr, png_ptr->zbuf);
        png_ptr->zbuf = NULL;
552
#ifdef PNG_USER_MEM_SUPPORTED
553 554
        png_destroy_struct_2((png_voidp)png_ptr,
           (png_free_ptr)free_fn, (png_voidp)mem_ptr);
555
#else
556
        png_destroy_struct((png_voidp)png_ptr);
557 558 559
#endif
        return (NULL);
     }
G
Guy Schalnat 已提交
560

561
   png_set_write_fn(png_ptr, NULL, NULL, NULL);
G
Guy Schalnat 已提交
562

563 564
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
565
      1, NULL, NULL);
566 567
#endif

568
   return (png_ptr);
G
Guy Schalnat 已提交
569 570
}

571

572 573 574 575 576
/* 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.
 */
577
void PNGAPI
G
Guy Schalnat 已提交
578
png_write_rows(png_structp png_ptr, png_bytepp row,
G
Guy Schalnat 已提交
579 580 581
   png_uint_32 num_rows)
{
   png_uint_32 i; /* row counter */
G
Guy Schalnat 已提交
582
   png_bytepp rp; /* row pointer */
G
Guy Schalnat 已提交
583

584
   png_debug(1, "in png_write_rows");
585 586 587 588

   if (png_ptr == NULL)
      return;

G
Guy Schalnat 已提交
589 590 591 592 593 594 595
   /* loop through the rows */
   for (i = 0, rp = row; i < num_rows; i++, rp++)
   {
      png_write_row(png_ptr, *rp);
   }
}

596 597 598
/* Write the image.  You only need to call this function once, even
 * if you are writing an interlaced image.
 */
599
void PNGAPI
G
Guy Schalnat 已提交
600
png_write_image(png_structp png_ptr, png_bytepp image)
G
Guy Schalnat 已提交
601 602 603
{
   png_uint_32 i; /* row index */
   int pass, num_pass; /* pass variables */
G
Guy Schalnat 已提交
604
   png_bytepp rp; /* points to current row */
G
Guy Schalnat 已提交
605

606 607 608
   if (png_ptr == NULL)
      return;

609
   png_debug(1, "in png_write_image");
610
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
611 612 613
   /* intialize interlace handling.  If image is not interlaced,
      this will set pass to 1 */
   num_pass = png_set_interlace_handling(png_ptr);
614 615 616
#else
   num_pass = 1;
#endif
G
Guy Schalnat 已提交
617 618 619 620 621 622 623 624 625 626 627
   /* 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 已提交
628
/* called by user to write a row of image data */
629
void PNGAPI
G
Guy Schalnat 已提交
630
png_write_row(png_structp png_ptr, png_bytep row)
G
Guy Schalnat 已提交
631
{
632 633
   if (png_ptr == NULL)
      return;
634
   png_debug2(1, "in png_write_row (row %ld, pass %d)",
635
      png_ptr->row_number, png_ptr->pass);
636

G
Guy Schalnat 已提交
637
   /* initialize transformations and other stuff if first time */
G
Guy Schalnat 已提交
638
   if (png_ptr->row_number == 0 && png_ptr->pass == 0)
G
Guy Schalnat 已提交
639
   {
640 641 642
   /* make sure we wrote the header info */
   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
      png_error(png_ptr,
643
         "png_write_info was never called before png_write_row");
644

645 646 647
   /* 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)
648
      png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
649 650 651
#endif
#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
   if (png_ptr->transformations & PNG_FILLER)
652
      png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
653 654 655
#endif
#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
   if (png_ptr->transformations & PNG_PACKSWAP)
656
      png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
657 658 659
#endif
#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
   if (png_ptr->transformations & PNG_PACK)
660
      png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
661 662 663
#endif
#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
   if (png_ptr->transformations & PNG_SHIFT)
664
      png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
665 666 667
#endif
#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
   if (png_ptr->transformations & PNG_BGR)
668
      png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
669 670 671
#endif
#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
   if (png_ptr->transformations & PNG_SWAP_BYTES)
672
      png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
673 674
#endif

G
Guy Schalnat 已提交
675 676 677
      png_write_start_row(png_ptr);
   }

G
Guy Schalnat 已提交
678
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
679 680 681 682 683
   /* if interlaced and not interested in row, return */
   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
   {
      switch (png_ptr->pass)
      {
G
Guy Schalnat 已提交
684
         case 0:
685
            if (png_ptr->row_number & 0x07)
G
Guy Schalnat 已提交
686 687 688 689 690 691
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 1:
692
            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
G
Guy Schalnat 已提交
693 694 695 696 697 698
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 2:
699
            if ((png_ptr->row_number & 0x07) != 4)
G
Guy Schalnat 已提交
700 701
            {
               png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
702
               return;
G
Guy Schalnat 已提交
703 704 705
            }
            break;
         case 3:
706
            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
G
Guy Schalnat 已提交
707 708 709 710 711 712
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 4:
713
            if ((png_ptr->row_number & 0x03) != 2)
G
Guy Schalnat 已提交
714 715 716 717 718 719
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 5:
720
            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
G
Guy Schalnat 已提交
721 722 723 724 725 726
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 6:
727
            if (!(png_ptr->row_number & 0x01))
G
Guy Schalnat 已提交
728 729 730 731 732 733 734
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
      }
   }
G
Guy Schalnat 已提交
735
#endif
G
Guy Schalnat 已提交
736 737

   /* set up row info for transformations */
G
Guy Schalnat 已提交
738
   png_ptr->row_info.color_type = png_ptr->color_type;
G
Guy Schalnat 已提交
739 740 741
   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 已提交
742 743
   png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
      png_ptr->row_info.channels);
744

745 746
   png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
      png_ptr->row_info.width);
G
Guy Schalnat 已提交
747

748 749 750 751 752 753
   png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type);
   png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width);
   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);
   png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes);
A
Andreas Dilger 已提交
754 755

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

G
Guy Schalnat 已提交
758
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
759 760 761 762 763
   /* 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 已提交
764
         png_ptr->row_buf + 1, png_ptr->pass);
G
Guy Schalnat 已提交
765 766 767 768 769 770 771
      /* this should always get caught above, but still ... */
      if (!(png_ptr->row_info.width))
      {
         png_write_finish_row(png_ptr);
         return;
      }
   }
G
Guy Schalnat 已提交
772
#endif
G
Guy Schalnat 已提交
773 774 775 776 777

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

778
#if defined(PNG_MNG_FEATURES_SUPPORTED)
779 780 781 782 783 784 785 786 787
   /* 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
    */
788
   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
789 790 791 792 793 794 795
      (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 已提交
796
   /* Find a filter if necessary, filter the row and write it out. */
G
Guy Schalnat 已提交
797
   png_write_find_filter(png_ptr, &(png_ptr->row_info));
798 799 800

   if (png_ptr->write_row_fn != NULL)
      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
G
Guy Schalnat 已提交
801 802 803 804
}

#if defined(PNG_WRITE_FLUSH_SUPPORTED)
/* Set the automatic flush interval or 0 to turn flushing off */
805
void PNGAPI
G
Guy Schalnat 已提交
806
png_set_flush(png_structp png_ptr, int nrows)
G
Guy Schalnat 已提交
807
{
808
   png_debug(1, "in png_set_flush");
809 810
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
811
   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
G
Guy Schalnat 已提交
812 813 814
}

/* flush the current output buffers now */
815
void PNGAPI
G
Guy Schalnat 已提交
816
png_write_flush(png_structp png_ptr)
G
Guy Schalnat 已提交
817
{
G
Guy Schalnat 已提交
818 819
   int wrote_IDAT;

820
   png_debug(1, "in png_write_flush");
821 822
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
823 824
   /* We have already written out all of the data */
   if (png_ptr->row_number >= png_ptr->num_rows)
G
Guy Schalnat 已提交
825 826 827 828 829 830 831
     return;

   do
   {
      int ret;

      /* compress the data */
A
Andreas Dilger 已提交
832
      ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
G
Guy Schalnat 已提交
833 834 835 836 837
      wrote_IDAT = 0;

      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
838
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
839
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
840 841 842 843
         else
            png_error(png_ptr, "zlib error");
      }

A
Andreas Dilger 已提交
844
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
845 846 847 848
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf,
                        png_ptr->zbuf_size);
A
Andreas Dilger 已提交
849 850
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
851 852 853 854 855
         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 已提交
856
   if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
G
Guy Schalnat 已提交
857 858 859
   {
      /* write the IDAT and reset the zlib output buffer */
      png_write_IDAT(png_ptr, png_ptr->zbuf,
A
Andreas Dilger 已提交
860 861 862
                     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 已提交
863 864 865
   }
   png_ptr->flush_rows = 0;
   png_flush(png_ptr);
G
Guy Schalnat 已提交
866
}
G
Guy Schalnat 已提交
867
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
G
Guy Schalnat 已提交
868

G
Guy Schalnat 已提交
869
/* free all memory used by the write */
870
void PNGAPI
A
Andreas Dilger 已提交
871
png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
G
Guy Schalnat 已提交
872
{
A
Andreas Dilger 已提交
873 874
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL;
875 876
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn = NULL;
877
   png_voidp mem_ptr = NULL;
878
#endif
A
Andreas Dilger 已提交
879

880
   png_debug(1, "in png_destroy_write_struct");
A
Andreas Dilger 已提交
881
   if (png_ptr_ptr != NULL)
882
   {
A
Andreas Dilger 已提交
883
      png_ptr = *png_ptr_ptr;
884 885
#ifdef PNG_USER_MEM_SUPPORTED
      free_fn = png_ptr->free_fn;
886
      mem_ptr = png_ptr->mem_ptr;
887 888
#endif
   }
A
Andreas Dilger 已提交
889

890 891 892 893 894 895 896 897
#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 已提交
898
   if (info_ptr_ptr != NULL)
A
Andreas Dilger 已提交
899 900
      info_ptr = *info_ptr_ptr;

A
Andreas Dilger 已提交
901
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
902
   {
903 904 905
      if (png_ptr != NULL)
      {
        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
906

907
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
908 909 910
        if (png_ptr->num_chunk_list)
        {
           png_free(png_ptr, png_ptr->chunk_list);
911
           png_ptr->num_chunk_list = 0;
912
        }
913
#endif
914
      }
915

916
#ifdef PNG_USER_MEM_SUPPORTED
917 918
      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
919
#else
A
Andreas Dilger 已提交
920
      png_destroy_struct((png_voidp)info_ptr);
921
#endif
922
      *info_ptr_ptr = NULL;
G
Guy Schalnat 已提交
923 924
   }

A
Andreas Dilger 已提交
925
   if (png_ptr != NULL)
G
Guy Schalnat 已提交
926
   {
A
Andreas Dilger 已提交
927
      png_write_destroy(png_ptr);
928
#ifdef PNG_USER_MEM_SUPPORTED
929 930
      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
931
#else
A
Andreas Dilger 已提交
932
      png_destroy_struct((png_voidp)png_ptr);
933
#endif
934
      *png_ptr_ptr = NULL;
G
Guy Schalnat 已提交
935 936 937
   }
}

G
Guy Schalnat 已提交
938

A
Andreas Dilger 已提交
939
/* Free any memory used in png_ptr struct (old method) */
940
void /* PRIVATE */
G
Guy Schalnat 已提交
941
png_write_destroy(png_structp png_ptr)
G
Guy Schalnat 已提交
942
{
943
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
944
   jmp_buf tmp_jmp; /* save jump buffer */
945
#endif
G
Guy Schalnat 已提交
946 947 948
   png_error_ptr error_fn;
   png_error_ptr warning_fn;
   png_voidp error_ptr;
949 950 951
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn;
#endif
G
Guy Schalnat 已提交
952

953
   png_debug(1, "in png_write_destroy");
G
Guy Schalnat 已提交
954
   /* free any memory zlib uses */
A
Andreas Dilger 已提交
955
   deflateEnd(&png_ptr->zstream);
G
Guy Schalnat 已提交
956

G
Guy Schalnat 已提交
957
   /* free our memory.  png_free checks NULL for us. */
A
Andreas Dilger 已提交
958 959
   png_free(png_ptr, png_ptr->zbuf);
   png_free(png_ptr, png_ptr->row_buf);
960
#ifndef PNG_NO_WRITE_FILTER
A
Andreas Dilger 已提交
961 962 963 964 965
   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);
966
#endif
967

968
#if defined(PNG_TIME_RFC1123_SUPPORTED)
969
   png_free(png_ptr, png_ptr->time_buffer);
970 971
#endif

A
Andreas Dilger 已提交
972 973 974 975 976 977
#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);
978
#endif
G
Guy Schalnat 已提交
979

980
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
981
   /* reset structure */
982
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf));
983
#endif
G
Guy Schalnat 已提交
984 985 986 987

   error_fn = png_ptr->error_fn;
   warning_fn = png_ptr->warning_fn;
   error_ptr = png_ptr->error_ptr;
988 989 990
#ifdef PNG_USER_MEM_SUPPORTED
   free_fn = png_ptr->free_fn;
#endif
G
Guy Schalnat 已提交
991

992
   png_memset(png_ptr, 0, png_sizeof(png_struct));
G
Guy Schalnat 已提交
993 994 995 996

   png_ptr->error_fn = error_fn;
   png_ptr->warning_fn = warning_fn;
   png_ptr->error_ptr = error_ptr;
997 998 999
#ifdef PNG_USER_MEM_SUPPORTED
   png_ptr->free_fn = free_fn;
#endif
G
Guy Schalnat 已提交
1000

1001
#ifdef PNG_SETJMP_SUPPORTED
1002
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
1003
#endif
G
Guy Schalnat 已提交
1004
}
G
Guy Schalnat 已提交
1005

A
Andreas Dilger 已提交
1006
/* Allow the application to select one or more row filters to use. */
1007
void PNGAPI
G
Guy Schalnat 已提交
1008
png_set_filter(png_structp png_ptr, int method, int filters)
G
Guy Schalnat 已提交
1009
{
1010
   png_debug(1, "in png_set_filter");
1011 1012
   if (png_ptr == NULL)
      return;
1013
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1014
   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
1015 1016 1017
      (method == PNG_INTRAPIXEL_DIFFERENCING))
         method = PNG_FILTER_TYPE_BASE;
#endif
A
Andreas Dilger 已提交
1018
   if (method == PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
1019 1020 1021
   {
      switch (filters & (PNG_ALL_FILTERS | 0x07))
      {
1022
#ifndef PNG_NO_WRITE_FILTER
G
Guy Schalnat 已提交
1023 1024
         case 5:
         case 6:
A
Andreas Dilger 已提交
1025
         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
#endif /* PNG_NO_WRITE_FILTER */
         case PNG_FILTER_VALUE_NONE:
              png_ptr->do_filter=PNG_FILTER_NONE; break;
#ifndef PNG_NO_WRITE_FILTER
         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 已提交
1038
         default: png_ptr->do_filter = (png_byte)filters; break;
1039 1040 1041
#else
         default: png_warning(png_ptr, "Unknown row filter for method 0");
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
1042 1043
      }

A
Andreas Dilger 已提交
1044 1045 1046 1047 1048 1049 1050 1051
      /* 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 已提交
1052
       */
A
Andreas Dilger 已提交
1053
      if (png_ptr->row_buf != NULL)
G
Guy Schalnat 已提交
1054
      {
1055
#ifndef PNG_NO_WRITE_FILTER
1056
         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
G
Guy Schalnat 已提交
1057
         {
A
Andreas Dilger 已提交
1058
            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1059
              (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1060
            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1061 1062
         }

1063
         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
G
Guy Schalnat 已提交
1064
         {
A
Andreas Dilger 已提交
1065
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1066
            {
A
Andreas Dilger 已提交
1067
               png_warning(png_ptr, "Can't add Up filter after starting");
G
Guy Schalnat 已提交
1068 1069 1070 1071
               png_ptr->do_filter &= ~PNG_FILTER_UP;
            }
            else
            {
A
Andreas Dilger 已提交
1072
               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1073
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1074
               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1075 1076 1077
            }
         }

1078
         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
G
Guy Schalnat 已提交
1079
         {
A
Andreas Dilger 已提交
1080
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1081
            {
A
Andreas Dilger 已提交
1082
               png_warning(png_ptr, "Can't add Average filter after starting");
G
Guy Schalnat 已提交
1083 1084 1085 1086
               png_ptr->do_filter &= ~PNG_FILTER_AVG;
            }
            else
            {
A
Andreas Dilger 已提交
1087
               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1088
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1089
               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1090 1091 1092
            }
         }

1093
         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
A
Andreas Dilger 已提交
1094
             png_ptr->paeth_row == NULL)
G
Guy Schalnat 已提交
1095
         {
A
Andreas Dilger 已提交
1096
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1097 1098
            {
               png_warning(png_ptr, "Can't add Paeth filter after starting");
1099
               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
G
Guy Schalnat 已提交
1100 1101 1102
            }
            else
            {
1103
               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1104
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1105
               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1106 1107 1108 1109
            }
         }

         if (png_ptr->do_filter == PNG_NO_FILTERS)
1110
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
1111 1112 1113 1114
            png_ptr->do_filter = PNG_FILTER_NONE;
      }
   }
   else
A
Andreas Dilger 已提交
1115 1116 1117 1118 1119 1120 1121 1122
      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
1123 1124
 * better compression.
 */
A
Andreas Dilger 已提交
1125
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
1126
void PNGAPI
A
Andreas Dilger 已提交
1127 1128 1129 1130 1131 1132
png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
   int num_weights, png_doublep filter_weights,
   png_doublep filter_costs)
{
   int i;

1133
   png_debug(1, "in png_set_filter_heuristics");
1134 1135
   if (png_ptr == NULL)
      return;
A
Andreas Dilger 已提交
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
   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;
   }

1153 1154
   png_ptr->num_prev_filters = (png_byte)num_weights;
   png_ptr->heuristic_method = (png_byte)heuristic_method;
A
Andreas Dilger 已提交
1155 1156 1157 1158 1159 1160

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

1163 1164
         /* To make sure that the weighting starts out fairly */
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1165
         {
1166
            png_ptr->prev_filters[i] = 255;
A
Andreas Dilger 已提交
1167 1168 1169 1170 1171
         }
      }

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

1175
         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
1176
            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
1177
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1178
         {
1179 1180
            png_ptr->inv_filter_weights[i] =
            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
1181
         }
A
Andreas Dilger 已提交
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
      }

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

1209
      png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
1210
         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
A
Andreas Dilger 已提交
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240

      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 已提交
1241
}
A
Andreas Dilger 已提交
1242
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
G
Guy Schalnat 已提交
1243

1244
void PNGAPI
G
Guy Schalnat 已提交
1245
png_set_compression_level(png_structp png_ptr, int level)
G
Guy Schalnat 已提交
1246
{
1247
   png_debug(1, "in png_set_compression_level");
1248 1249
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1250
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
G
Guy Schalnat 已提交
1251 1252 1253
   png_ptr->zlib_level = level;
}

1254
void PNGAPI
G
Guy Schalnat 已提交
1255
png_set_compression_mem_level(png_structp png_ptr, int mem_level)
G
Guy Schalnat 已提交
1256
{
1257
   png_debug(1, "in png_set_compression_mem_level");
1258 1259
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1260
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
G
Guy Schalnat 已提交
1261
   png_ptr->zlib_mem_level = mem_level;
G
Guy Schalnat 已提交
1262 1263
}

1264
void PNGAPI
G
Guy Schalnat 已提交
1265
png_set_compression_strategy(png_structp png_ptr, int strategy)
G
Guy Schalnat 已提交
1266
{
1267
   png_debug(1, "in png_set_compression_strategy");
1268 1269
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1270
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
G
Guy Schalnat 已提交
1271 1272 1273
   png_ptr->zlib_strategy = strategy;
}

1274
void PNGAPI
G
Guy Schalnat 已提交
1275
png_set_compression_window_bits(png_structp png_ptr, int window_bits)
G
Guy Schalnat 已提交
1276
{
1277 1278
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1279 1280
   if (window_bits > 15)
      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1281 1282
   else if (window_bits < 8)
      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1283 1284 1285 1286 1287 1288 1289 1290
#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 已提交
1291
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
G
Guy Schalnat 已提交
1292 1293 1294
   png_ptr->zlib_window_bits = window_bits;
}

1295
void PNGAPI
G
Guy Schalnat 已提交
1296
png_set_compression_method(png_structp png_ptr, int method)
G
Guy Schalnat 已提交
1297
{
1298
   png_debug(1, "in png_set_compression_method");
1299 1300
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1301 1302 1303
   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 已提交
1304
   png_ptr->zlib_method = method;
G
Guy Schalnat 已提交
1305 1306
}

1307
void PNGAPI
1308 1309
png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
{
1310 1311
   if (png_ptr == NULL)
      return;
1312 1313 1314 1315
   png_ptr->write_row_fn = write_row_fn;
}

#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1316
void PNGAPI
1317 1318 1319
png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
   write_user_transform_fn)
{
1320
   png_debug(1, "in png_set_write_user_transform_fn");
1321 1322
   if (png_ptr == NULL)
      return;
1323 1324 1325 1326
   png_ptr->transformations |= PNG_USER_TRANSFORM;
   png_ptr->write_user_transform_fn = write_user_transform_fn;
}
#endif
1327 1328 1329


#if defined(PNG_INFO_IMAGE_SUPPORTED)
1330 1331
void PNGAPI
png_write_png(png_structp png_ptr, png_infop info_ptr,
1332
              int transforms, voidp params)
1333
{
1334 1335
   if (png_ptr == NULL || info_ptr == NULL)
      return;
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
#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)
1375
   /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */
1376 1377 1378 1379
  if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER)
      png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
  else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE)
      png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
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
#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);
1408

1409 1410
   transforms = transforms; /* quiet compiler warnings */
   params = params;
1411 1412
}
#endif
1413
#endif /* PNG_WRITE_SUPPORTED */