pngwrite.c 47.6 KB
Newer Older
1

A
Andreas Dilger 已提交
2
/* pngwrite.c - general routines to write a PNG file
3
 *
4
 * Last changed in libpng 1.2.24 November 20, 2007
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2007 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 13

/* get internal access to png.h */
#define PNG_INTERNAL
#include "png.h"
14
#ifdef PNG_WRITE_SUPPORTED
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 394 395
   png_write_IEND(png_ptr);
}

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

411
void PNGAPI
G
Guy Schalnat 已提交
412
png_convert_from_time_t(png_timep ptime, time_t ttime)
G
Guy Schalnat 已提交
413 414 415
{
   struct tm *tbuf;

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

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

/* Alternate initialize png_ptr structure, and allocate any memory needed */
434
png_structp PNGAPI
435 436 437 438 439
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 已提交
440
   png_structp png_ptr;
441
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
442 443
#ifdef USE_FAR_KEYWORD
   jmp_buf jmpbuf;
444
#endif
A
Andreas Dilger 已提交
445
#endif
446
   int i;
A
Andreas Dilger 已提交
447
   png_debug(1, "in png_create_write_struct\n");
448
#ifdef PNG_USER_MEM_SUPPORTED
449 450
   png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
      (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
451
#else
452
   png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
453
#endif /* PNG_USER_MEM_SUPPORTED */
454
   if (png_ptr == NULL)
455
      return (NULL);
456

457 458 459 460 461 462
   /* 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

463
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
464 465 466
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmpbuf))
#else
G
Guy Schalnat 已提交
467
   if (setjmp(png_ptr->jmpbuf))
A
Andreas Dilger 已提交
468
#endif
G
Guy Schalnat 已提交
469
   {
A
Andreas Dilger 已提交
470
      png_free(png_ptr, png_ptr->zbuf);
471
      png_ptr->zbuf=NULL;
G
Guy Schalnat 已提交
472
      png_destroy_struct(png_ptr);
473
      return (NULL);
G
Guy Schalnat 已提交
474
   }
A
Andreas Dilger 已提交
475
#ifdef USE_FAR_KEYWORD
476
   png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
A
Andreas Dilger 已提交
477
#endif
478 479
#endif

480 481 482
#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 已提交
483
   png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
G
Guy Schalnat 已提交
484

485 486
   i=0;
   do
G
Guy Schalnat 已提交
487
   {
488 489 490
     if(user_png_ver[i] != png_libpng_ver[i])
        png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
   } while (png_libpng_ver[i++]);
491

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

G
Guy Schalnat 已提交
525 526
   /* initialize zbuf - compression buffer */
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
527 528
   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
      (png_uint_32)png_ptr->zbuf_size);
G
Guy Schalnat 已提交
529

530 531
   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
      png_flush_ptr_NULL);
G
Guy Schalnat 已提交
532

533 534
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
535
      1, png_doublep_NULL, png_doublep_NULL);
536 537
#endif

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

A
Andreas Dilger 已提交
554
/* Initialize png_ptr structure, and allocate any memory needed */
555
#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
556
/* Deprecated. */
557
#undef png_write_init
558
void PNGAPI
G
Guy Schalnat 已提交
559
png_write_init(png_structp png_ptr)
560 561
{
   /* We only come here via pre-1.0.7-compiled applications */
562
   png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
563 564
}

565
void PNGAPI
566 567
png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
   png_size_t png_struct_size, png_size_t png_info_size)
G
Guy Schalnat 已提交
568
{
569
   /* We only come here via pre-1.0.12-compiled applications */
570
   if(png_ptr == NULL) return;
571
#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
572 573
   if(png_sizeof(png_struct) > png_struct_size ||
      png_sizeof(png_info) > png_info_size)
574 575
   {
      char msg[80];
576
      png_ptr->warning_fn=NULL;
577 578
      if (user_png_ver)
      {
579 580
        png_snprintf(msg, 80,
           "Application was compiled with png.h from libpng-%.20s",
581 582 583
           user_png_ver);
        png_warning(png_ptr, msg);
      }
584 585
      png_snprintf(msg, 80,
         "Application  is  running with png.c from libpng-%.20s",
586 587 588 589
         png_libpng_ver);
      png_warning(png_ptr, msg);
   }
#endif
590
   if(png_sizeof(png_struct) > png_struct_size)
591
     {
592
       png_ptr->error_fn=NULL;
593 594 595
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
       png_ptr->flags=0;
#endif
596
       png_error(png_ptr,
597
       "The png struct allocated by the application for writing is too small.");
598
     }
599
   if(png_sizeof(png_info) > png_info_size)
600
     {
601
       png_ptr->error_fn=NULL;
602 603 604
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
       png_ptr->flags=0;
#endif
605
       png_error(png_ptr,
606
       "The info struct allocated by the application for writing is too small.");
607 608 609
     }
   png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
}
610
#endif /* PNG_1_0_X || PNG_1_2_X */
611 612 613 614 615 616 617


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;
618
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
619
   jmp_buf tmp_jmp; /* to save current jump buffer */
620
#endif
621

622 623
   int i = 0;

624 625 626
   if (png_ptr == NULL)
      return;

627 628 629 630
   do
   {
     if (user_png_ver[i] != png_libpng_ver[i])
     {
631 632 633
#ifdef PNG_LEGACY_SUPPORTED
       png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
#else
634
       png_ptr->warning_fn=NULL;
635 636 637
       png_warning(png_ptr,
     "Application uses deprecated png_write_init() and should be recompiled.");
       break;
638
#endif
639 640
     }
   } while (png_libpng_ver[i++]);
641

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

644
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
645
   /* save jump buffer and error functions */
646
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
647
#endif
G
Guy Schalnat 已提交
648

649
   if (png_sizeof(png_struct) > png_struct_size)
650 651 652 653 654 655
     {
       png_destroy_struct(png_ptr);
       png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
       *ptr_ptr = png_ptr;
     }

G
Guy Schalnat 已提交
656
   /* reset all variables to 0 */
657
   png_memset(png_ptr, 0, png_sizeof (png_struct));
G
Guy Schalnat 已提交
658

659 660 661 662 663 664
   /* 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

665
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
666
   /* restore jump buffer */
667
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
668
#endif
G
Guy Schalnat 已提交
669

670 671
   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
      png_flush_ptr_NULL);
672

G
Guy Schalnat 已提交
673 674
   /* initialize zbuf - compression buffer */
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
675 676
   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
      (png_uint_32)png_ptr->zbuf_size);
A
Andreas Dilger 已提交
677 678 679

#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
680
      1, png_doublep_NULL, png_doublep_NULL);
A
Andreas Dilger 已提交
681
#endif
G
Guy Schalnat 已提交
682 683
}

684 685 686 687 688
/* 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.
 */
689
void PNGAPI
G
Guy Schalnat 已提交
690
png_write_rows(png_structp png_ptr, png_bytepp row,
G
Guy Schalnat 已提交
691 692 693
   png_uint_32 num_rows)
{
   png_uint_32 i; /* row counter */
G
Guy Schalnat 已提交
694
   png_bytepp rp; /* row pointer */
G
Guy Schalnat 已提交
695

A
Andreas Dilger 已提交
696
   png_debug(1, "in png_write_rows\n");
697 698 699 700

   if (png_ptr == NULL)
      return;

G
Guy Schalnat 已提交
701 702 703 704 705 706 707
   /* loop through the rows */
   for (i = 0, rp = row; i < num_rows; i++, rp++)
   {
      png_write_row(png_ptr, *rp);
   }
}

708 709 710
/* Write the image.  You only need to call this function once, even
 * if you are writing an interlaced image.
 */
711
void PNGAPI
G
Guy Schalnat 已提交
712
png_write_image(png_structp png_ptr, png_bytepp image)
G
Guy Schalnat 已提交
713 714 715
{
   png_uint_32 i; /* row index */
   int pass, num_pass; /* pass variables */
G
Guy Schalnat 已提交
716
   png_bytepp rp; /* points to current row */
G
Guy Schalnat 已提交
717

718 719 720
   if (png_ptr == NULL)
      return;

A
Andreas Dilger 已提交
721
   png_debug(1, "in png_write_image\n");
722
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
723 724 725
   /* intialize interlace handling.  If image is not interlaced,
      this will set pass to 1 */
   num_pass = png_set_interlace_handling(png_ptr);
726 727 728
#else
   num_pass = 1;
#endif
G
Guy Schalnat 已提交
729 730 731 732 733 734 735 736 737 738 739
   /* 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 已提交
740
/* called by user to write a row of image data */
741
void PNGAPI
G
Guy Schalnat 已提交
742
png_write_row(png_structp png_ptr, png_bytep row)
G
Guy Schalnat 已提交
743
{
744 745
   if (png_ptr == NULL)
      return;
746 747
   png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
      png_ptr->row_number, png_ptr->pass);
748

G
Guy Schalnat 已提交
749
   /* initialize transformations and other stuff if first time */
G
Guy Schalnat 已提交
750
   if (png_ptr->row_number == 0 && png_ptr->pass == 0)
G
Guy Schalnat 已提交
751
   {
752 753 754 755 756
   /* 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.");

757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
   /* 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 已提交
787 788 789
      png_write_start_row(png_ptr);
   }

G
Guy Schalnat 已提交
790
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
791 792 793 794 795
   /* if interlaced and not interested in row, return */
   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
   {
      switch (png_ptr->pass)
      {
G
Guy Schalnat 已提交
796
         case 0:
797
            if (png_ptr->row_number & 0x07)
G
Guy Schalnat 已提交
798 799 800 801 802 803
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 1:
804
            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
G
Guy Schalnat 已提交
805 806 807 808 809 810
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 2:
811
            if ((png_ptr->row_number & 0x07) != 4)
G
Guy Schalnat 已提交
812 813
            {
               png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
814
               return;
G
Guy Schalnat 已提交
815 816 817
            }
            break;
         case 3:
818
            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
G
Guy Schalnat 已提交
819 820 821 822 823 824
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 4:
825
            if ((png_ptr->row_number & 0x03) != 2)
G
Guy Schalnat 已提交
826 827 828 829 830 831
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 5:
832
            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
G
Guy Schalnat 已提交
833 834 835 836 837 838
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 6:
839
            if (!(png_ptr->row_number & 0x01))
G
Guy Schalnat 已提交
840 841 842 843 844 845 846
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
      }
   }
G
Guy Schalnat 已提交
847
#endif
G
Guy Schalnat 已提交
848 849

   /* set up row info for transformations */
G
Guy Schalnat 已提交
850
   png_ptr->row_info.color_type = png_ptr->color_type;
G
Guy Schalnat 已提交
851 852 853
   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 已提交
854 855
   png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
      png_ptr->row_info.channels);
856

857 858
   png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
      png_ptr->row_info.width);
G
Guy Schalnat 已提交
859

860
   png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
861
   png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
862 863 864
   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);
865
   png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
A
Andreas Dilger 已提交
866 867

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

G
Guy Schalnat 已提交
871
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
872 873 874 875 876
   /* 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 已提交
877
         png_ptr->row_buf + 1, png_ptr->pass);
G
Guy Schalnat 已提交
878 879 880 881 882 883 884
      /* this should always get caught above, but still ... */
      if (!(png_ptr->row_info.width))
      {
         png_write_finish_row(png_ptr);
         return;
      }
   }
G
Guy Schalnat 已提交
885
#endif
G
Guy Schalnat 已提交
886 887 888 889 890

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

891
#if defined(PNG_MNG_FEATURES_SUPPORTED)
892 893 894 895 896 897 898 899 900
   /* 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
    */
901 902 903 904 905 906 907 908
   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 已提交
909
   /* Find a filter if necessary, filter the row and write it out. */
G
Guy Schalnat 已提交
910
   png_write_find_filter(png_ptr, &(png_ptr->row_info));
911 912 913

   if (png_ptr->write_row_fn != NULL)
      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
G
Guy Schalnat 已提交
914 915 916 917
}

#if defined(PNG_WRITE_FLUSH_SUPPORTED)
/* Set the automatic flush interval or 0 to turn flushing off */
918
void PNGAPI
G
Guy Schalnat 已提交
919
png_set_flush(png_structp png_ptr, int nrows)
G
Guy Schalnat 已提交
920
{
A
Andreas Dilger 已提交
921
   png_debug(1, "in png_set_flush\n");
922 923
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
924
   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
G
Guy Schalnat 已提交
925 926 927
}

/* flush the current output buffers now */
928
void PNGAPI
G
Guy Schalnat 已提交
929
png_write_flush(png_structp png_ptr)
G
Guy Schalnat 已提交
930
{
G
Guy Schalnat 已提交
931 932
   int wrote_IDAT;

A
Andreas Dilger 已提交
933
   png_debug(1, "in png_write_flush\n");
934 935
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
936 937
   /* We have already written out all of the data */
   if (png_ptr->row_number >= png_ptr->num_rows)
G
Guy Schalnat 已提交
938 939 940 941 942 943 944
     return;

   do
   {
      int ret;

      /* compress the data */
A
Andreas Dilger 已提交
945
      ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
G
Guy Schalnat 已提交
946 947 948 949 950
      wrote_IDAT = 0;

      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
951
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
952
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
953 954 955 956
         else
            png_error(png_ptr, "zlib error");
      }

A
Andreas Dilger 已提交
957
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
958 959 960 961
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf,
                        png_ptr->zbuf_size);
A
Andreas Dilger 已提交
962 963
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
964 965 966 967 968
         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 已提交
969
   if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
G
Guy Schalnat 已提交
970 971 972
   {
      /* write the IDAT and reset the zlib output buffer */
      png_write_IDAT(png_ptr, png_ptr->zbuf,
A
Andreas Dilger 已提交
973 974 975
                     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 已提交
976 977 978
   }
   png_ptr->flush_rows = 0;
   png_flush(png_ptr);
G
Guy Schalnat 已提交
979
}
G
Guy Schalnat 已提交
980
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
G
Guy Schalnat 已提交
981

G
Guy Schalnat 已提交
982
/* free all memory used by the write */
983
void PNGAPI
A
Andreas Dilger 已提交
984
png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
G
Guy Schalnat 已提交
985
{
A
Andreas Dilger 已提交
986 987
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL;
988 989
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn = NULL;
990
   png_voidp mem_ptr = NULL;
991
#endif
A
Andreas Dilger 已提交
992

A
Andreas Dilger 已提交
993 994
   png_debug(1, "in png_destroy_write_struct\n");
   if (png_ptr_ptr != NULL)
995
   {
A
Andreas Dilger 已提交
996
      png_ptr = *png_ptr_ptr;
997 998
#ifdef PNG_USER_MEM_SUPPORTED
      free_fn = png_ptr->free_fn;
999
      mem_ptr = png_ptr->mem_ptr;
1000 1001
#endif
   }
A
Andreas Dilger 已提交
1002

A
Andreas Dilger 已提交
1003
   if (info_ptr_ptr != NULL)
A
Andreas Dilger 已提交
1004 1005
      info_ptr = *info_ptr_ptr;

A
Andreas Dilger 已提交
1006
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
1007
   {
1008 1009
      png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);

1010
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1011 1012 1013
      if (png_ptr->num_chunk_list)
      {
         png_free(png_ptr, png_ptr->chunk_list);
1014
         png_ptr->chunk_list=NULL;
1015 1016
         png_ptr->num_chunk_list=0;
      }
1017
#endif
1018

1019
#ifdef PNG_USER_MEM_SUPPORTED
1020 1021
      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
1022
#else
A
Andreas Dilger 已提交
1023
      png_destroy_struct((png_voidp)info_ptr);
1024
#endif
1025
      *info_ptr_ptr = NULL;
G
Guy Schalnat 已提交
1026 1027
   }

A
Andreas Dilger 已提交
1028
   if (png_ptr != NULL)
G
Guy Schalnat 已提交
1029
   {
A
Andreas Dilger 已提交
1030
      png_write_destroy(png_ptr);
1031
#ifdef PNG_USER_MEM_SUPPORTED
1032 1033
      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
1034
#else
A
Andreas Dilger 已提交
1035
      png_destroy_struct((png_voidp)png_ptr);
1036
#endif
1037
      *png_ptr_ptr = NULL;
G
Guy Schalnat 已提交
1038 1039 1040
   }
}

G
Guy Schalnat 已提交
1041

A
Andreas Dilger 已提交
1042
/* Free any memory used in png_ptr struct (old method) */
1043
void /* PRIVATE */
G
Guy Schalnat 已提交
1044
png_write_destroy(png_structp png_ptr)
G
Guy Schalnat 已提交
1045
{
1046
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
1047
   jmp_buf tmp_jmp; /* save jump buffer */
1048
#endif
G
Guy Schalnat 已提交
1049 1050 1051
   png_error_ptr error_fn;
   png_error_ptr warning_fn;
   png_voidp error_ptr;
1052 1053 1054
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn;
#endif
G
Guy Schalnat 已提交
1055

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

G
Guy Schalnat 已提交
1060
   /* free our memory.  png_free checks NULL for us. */
A
Andreas Dilger 已提交
1061 1062
   png_free(png_ptr, png_ptr->zbuf);
   png_free(png_ptr, png_ptr->row_buf);
1063
#ifndef PNG_NO_WRITE_FILTERING
A
Andreas Dilger 已提交
1064 1065 1066 1067 1068
   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);
1069
#endif
1070

1071
#if defined(PNG_TIME_RFC1123_SUPPORTED)
1072
   png_free(png_ptr, png_ptr->time_buffer);
1073 1074
#endif

A
Andreas Dilger 已提交
1075 1076 1077 1078 1079 1080
#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);
1081
#endif
G
Guy Schalnat 已提交
1082

1083
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
1084
   /* reset structure */
1085
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
1086
#endif
G
Guy Schalnat 已提交
1087 1088 1089 1090

   error_fn = png_ptr->error_fn;
   warning_fn = png_ptr->warning_fn;
   error_ptr = png_ptr->error_ptr;
1091 1092 1093
#ifdef PNG_USER_MEM_SUPPORTED
   free_fn = png_ptr->free_fn;
#endif
G
Guy Schalnat 已提交
1094

1095
   png_memset(png_ptr, 0, png_sizeof (png_struct));
G
Guy Schalnat 已提交
1096 1097 1098 1099

   png_ptr->error_fn = error_fn;
   png_ptr->warning_fn = warning_fn;
   png_ptr->error_ptr = error_ptr;
1100 1101 1102
#ifdef PNG_USER_MEM_SUPPORTED
   png_ptr->free_fn = free_fn;
#endif
G
Guy Schalnat 已提交
1103

1104
#ifdef PNG_SETJMP_SUPPORTED
1105
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
1106
#endif
G
Guy Schalnat 已提交
1107
}
G
Guy Schalnat 已提交
1108

A
Andreas Dilger 已提交
1109
/* Allow the application to select one or more row filters to use. */
1110
void PNGAPI
G
Guy Schalnat 已提交
1111
png_set_filter(png_structp png_ptr, int method, int filters)
G
Guy Schalnat 已提交
1112
{
A
Andreas Dilger 已提交
1113
   png_debug(1, "in png_set_filter\n");
1114 1115
   if (png_ptr == NULL)
      return;
1116
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1117
   if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
1118 1119 1120
      (method == PNG_INTRAPIXEL_DIFFERENCING))
         method = PNG_FILTER_TYPE_BASE;
#endif
A
Andreas Dilger 已提交
1121
   if (method == PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
1122 1123 1124
   {
      switch (filters & (PNG_ALL_FILTERS | 0x07))
      {
1125
#ifndef PNG_NO_WRITE_FILTER
G
Guy Schalnat 已提交
1126 1127
         case 5:
         case 6:
A
Andreas Dilger 已提交
1128
         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
#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 已提交
1141
         default: png_ptr->do_filter = (png_byte)filters; break;
1142 1143 1144
#else
         default: png_warning(png_ptr, "Unknown row filter for method 0");
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
1145 1146
      }

A
Andreas Dilger 已提交
1147 1148 1149 1150 1151 1152 1153 1154
      /* 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 已提交
1155
       */
A
Andreas Dilger 已提交
1156
      if (png_ptr->row_buf != NULL)
G
Guy Schalnat 已提交
1157
      {
1158
#ifndef PNG_NO_WRITE_FILTER
1159
         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
G
Guy Schalnat 已提交
1160
         {
A
Andreas Dilger 已提交
1161
            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1162
              (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1163
            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1164 1165
         }

1166
         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
G
Guy Schalnat 已提交
1167
         {
A
Andreas Dilger 已提交
1168
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1169
            {
A
Andreas Dilger 已提交
1170
               png_warning(png_ptr, "Can't add Up filter after starting");
G
Guy Schalnat 已提交
1171 1172 1173 1174
               png_ptr->do_filter &= ~PNG_FILTER_UP;
            }
            else
            {
A
Andreas Dilger 已提交
1175
               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1176
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1177
               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1178 1179 1180
            }
         }

1181
         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
G
Guy Schalnat 已提交
1182
         {
A
Andreas Dilger 已提交
1183
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1184
            {
A
Andreas Dilger 已提交
1185
               png_warning(png_ptr, "Can't add Average filter after starting");
G
Guy Schalnat 已提交
1186 1187 1188 1189
               png_ptr->do_filter &= ~PNG_FILTER_AVG;
            }
            else
            {
A
Andreas Dilger 已提交
1190
               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1191
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1192
               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1193 1194 1195
            }
         }

1196
         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
A
Andreas Dilger 已提交
1197
             png_ptr->paeth_row == NULL)
G
Guy Schalnat 已提交
1198
         {
A
Andreas Dilger 已提交
1199
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1200 1201
            {
               png_warning(png_ptr, "Can't add Paeth filter after starting");
1202
               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
G
Guy Schalnat 已提交
1203 1204 1205
            }
            else
            {
1206
               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1207
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1208
               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1209 1210 1211 1212
            }
         }

         if (png_ptr->do_filter == PNG_NO_FILTERS)
1213
#endif /* PNG_NO_WRITE_FILTER */
G
Guy Schalnat 已提交
1214 1215 1216 1217
            png_ptr->do_filter = PNG_FILTER_NONE;
      }
   }
   else
A
Andreas Dilger 已提交
1218 1219 1220 1221 1222 1223 1224 1225
      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
1226 1227
 * better compression.
 */
A
Andreas Dilger 已提交
1228
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
1229
void PNGAPI
A
Andreas Dilger 已提交
1230 1231 1232 1233 1234 1235 1236
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");
1237 1238
   if (png_ptr == NULL)
      return;
A
Andreas Dilger 已提交
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
   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;
   }

1256 1257
   png_ptr->num_prev_filters = (png_byte)num_weights;
   png_ptr->heuristic_method = (png_byte)heuristic_method;
A
Andreas Dilger 已提交
1258 1259 1260 1261 1262 1263

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

1266 1267
         /* To make sure that the weighting starts out fairly */
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1268
         {
1269
            png_ptr->prev_filters[i] = 255;
A
Andreas Dilger 已提交
1270 1271 1272 1273 1274
         }
      }

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

1278
         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
1279
            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
1280
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1281
         {
1282 1283
            png_ptr->inv_filter_weights[i] =
            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
1284
         }
A
Andreas Dilger 已提交
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
      }

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

1312
      png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
1313
         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
A
Andreas Dilger 已提交
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343

      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 已提交
1344
}
A
Andreas Dilger 已提交
1345
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
G
Guy Schalnat 已提交
1346

1347
void PNGAPI
G
Guy Schalnat 已提交
1348
png_set_compression_level(png_structp png_ptr, int level)
G
Guy Schalnat 已提交
1349
{
A
Andreas Dilger 已提交
1350
   png_debug(1, "in png_set_compression_level\n");
1351 1352
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1353
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
G
Guy Schalnat 已提交
1354 1355 1356
   png_ptr->zlib_level = level;
}

1357
void PNGAPI
G
Guy Schalnat 已提交
1358
png_set_compression_mem_level(png_structp png_ptr, int mem_level)
G
Guy Schalnat 已提交
1359
{
A
Andreas Dilger 已提交
1360
   png_debug(1, "in png_set_compression_mem_level\n");
1361 1362
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1363
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
G
Guy Schalnat 已提交
1364
   png_ptr->zlib_mem_level = mem_level;
G
Guy Schalnat 已提交
1365 1366
}

1367
void PNGAPI
G
Guy Schalnat 已提交
1368
png_set_compression_strategy(png_structp png_ptr, int strategy)
G
Guy Schalnat 已提交
1369
{
A
Andreas Dilger 已提交
1370
   png_debug(1, "in png_set_compression_strategy\n");
1371 1372
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1373
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
G
Guy Schalnat 已提交
1374 1375 1376
   png_ptr->zlib_strategy = strategy;
}

1377
void PNGAPI
G
Guy Schalnat 已提交
1378
png_set_compression_window_bits(png_structp png_ptr, int window_bits)
G
Guy Schalnat 已提交
1379
{
1380 1381
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1382 1383
   if (window_bits > 15)
      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1384 1385
   else if (window_bits < 8)
      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1386 1387 1388 1389 1390 1391 1392 1393
#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 已提交
1394
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
G
Guy Schalnat 已提交
1395 1396 1397
   png_ptr->zlib_window_bits = window_bits;
}

1398
void PNGAPI
G
Guy Schalnat 已提交
1399
png_set_compression_method(png_structp png_ptr, int method)
G
Guy Schalnat 已提交
1400
{
A
Andreas Dilger 已提交
1401
   png_debug(1, "in png_set_compression_method\n");
1402 1403
   if (png_ptr == NULL)
      return;
G
Guy Schalnat 已提交
1404 1405 1406
   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 已提交
1407
   png_ptr->zlib_method = method;
G
Guy Schalnat 已提交
1408 1409
}

1410
void PNGAPI
1411 1412
png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
{
1413 1414
   if (png_ptr == NULL)
      return;
1415 1416 1417 1418
   png_ptr->write_row_fn = write_row_fn;
}

#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1419
void PNGAPI
1420 1421 1422 1423
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");
1424 1425
   if (png_ptr == NULL)
      return;
1426 1427 1428 1429
   png_ptr->transformations |= PNG_USER_TRANSFORM;
   png_ptr->write_user_transform_fn = write_user_transform_fn;
}
#endif
1430 1431 1432


#if defined(PNG_INFO_IMAGE_SUPPORTED)
1433 1434
void PNGAPI
png_write_png(png_structp png_ptr, png_infop info_ptr,
1435
              int transforms, voidp params)
1436
{
1437 1438
   if (png_ptr == NULL || info_ptr == NULL)
      return;
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
#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);
1511

1512 1513
   transforms = transforms; /* quiet compiler warnings */
   params = params;
1514 1515
}
#endif
1516
#endif /* PNG_WRITE_SUPPORTED */