pngwrite.c 46.8 KB
Newer Older
1

A
Andreas Dilger 已提交
2
/* pngwrite.c - general routines to write a PNG file
3
 *
4
 * libpng 1.2.8rc3 - November 28, 2004
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2004 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 29 30
   png_debug(1, "in png_write_info_before_PLTE\n");
   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
   {
G
Guy Schalnat 已提交
31
   png_write_sig(png_ptr); /* write PNG signature */
32 33 34 35 36 37 38
#if defined(PNG_MNG_FEATURES_SUPPORTED)
   if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
   {
      png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n");
      png_ptr->mng_features_permitted=0;
   }
#endif
G
Guy Schalnat 已提交
39
   /* write IHDR information. */
A
Andreas Dilger 已提交
40 41
   png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
      info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
42 43 44 45 46 47
      info_ptr->filter_type,
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
      info_ptr->interlace_type);
#else
      0);
#endif
G
Guy Schalnat 已提交
48 49
   /* 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 已提交
50
#if defined(PNG_WRITE_gAMA_SUPPORTED)
A
Andreas Dilger 已提交
51
   if (info_ptr->valid & PNG_INFO_gAMA)
52 53
   {
#  ifdef PNG_FLOATING_POINT_SUPPORTED
A
Andreas Dilger 已提交
54
      png_write_gAMA(png_ptr, info_ptr->gamma);
55 56 57
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
      png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
58 59 60
#  endif
#endif
   }
G
Guy Schalnat 已提交
61
#endif
62 63
#if defined(PNG_WRITE_sRGB_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_sRGB)
64
      png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
65
#endif
66 67
#if defined(PNG_WRITE_iCCP_SUPPORTED)
   if (info_ptr->valid & PNG_INFO_iCCP)
68
      png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
69 70
                     info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
#endif
G
Guy Schalnat 已提交
71
#if defined(PNG_WRITE_sBIT_SUPPORTED)
A
Andreas Dilger 已提交
72 73
   if (info_ptr->valid & PNG_INFO_sBIT)
      png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
G
Guy Schalnat 已提交
74 75
#endif
#if defined(PNG_WRITE_cHRM_SUPPORTED)
A
Andreas Dilger 已提交
76
   if (info_ptr->valid & PNG_INFO_cHRM)
77
   {
78
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
79
      png_write_cHRM(png_ptr,
A
Andreas Dilger 已提交
80 81 82 83
         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);
84 85 86 87 88 89 90
#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);
91 92 93 94 95 96 97 98 99 100 101 102 103 104
#  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++)
105 106
       {
         int keep=png_handle_as_unknown(png_ptr, up->name);
107
         if (keep != PNG_HANDLE_CHUNK_NEVER &&
108 109
            up->location && !(up->location & PNG_HAVE_PLTE) &&
            !(up->location & PNG_HAVE_IDAT) &&
110
            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
111 112
            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
         {
113
            png_write_chunk(png_ptr, up->name, up->data, up->size);
114 115
         }
       }
116
   }
G
Guy Schalnat 已提交
117
#endif
118 119 120 121
      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
   }
}

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

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

   png_write_info_before_PLTE(png_ptr, info_ptr);

A
Andreas Dilger 已提交
133
   if (info_ptr->valid & PNG_INFO_PLTE)
A
Andreas Dilger 已提交
134 135
      png_write_PLTE(png_ptr, info_ptr->palette,
         (png_uint_32)info_ptr->num_palette);
A
Andreas Dilger 已提交
136
   else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
G
Guy Schalnat 已提交
137
      png_error(png_ptr, "Valid palette required for paletted images\n");
138

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

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

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

            /* Mark this chunk as written */
            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
G
Guy Schalnat 已提交
356 357
         }
      }
358 359 360 361 362 363 364 365 366 367 368
#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++)
369 370
       {
         int keep=png_handle_as_unknown(png_ptr, up->name);
371
         if (keep != PNG_HANDLE_CHUNK_NEVER &&
372
            up->location && (up->location & PNG_AFTER_IDAT) &&
373
            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
374 375
            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
         {
376
            png_write_chunk(png_ptr, up->name, up->data, up->size);
377 378
         }
       }
379
   }
G
Guy Schalnat 已提交
380
#endif
G
Guy Schalnat 已提交
381
   }
G
Guy Schalnat 已提交
382 383 384

   png_ptr->mode |= PNG_AFTER_IDAT;

A
Andreas Dilger 已提交
385
   /* write end of PNG file */
G
Guy Schalnat 已提交
386
   png_write_IEND(png_ptr);
387 388 389
#if 0
/* This flush, added in libpng-1.0.8,  causes some applications to crash
   because they do not set png_ptr->output_flush_fn */
390
   png_flush(png_ptr);
391
#endif
G
Guy Schalnat 已提交
392 393
}

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

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

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

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

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

455
#if !defined(PNG_1_0_X)
456 457 458
#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
   png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
#endif
459
#endif /* PNG_1_0_X */
460

461 462 463 464 465 466
   /* 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

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

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

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

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

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

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

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

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

A
Andreas Dilger 已提交
556
/* Initialize png_ptr structure, and allocate any memory needed */
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 !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
571 572
   if(png_sizeof(png_struct) > png_struct_size ||
      png_sizeof(png_info) > png_info_size)
573 574
   {
      char msg[80];
575
      png_ptr->warning_fn=NULL;
576 577 578 579 580 581
      if (user_png_ver)
      {
        sprintf(msg, "Application was compiled with png.h from libpng-%.20s",
           user_png_ver);
        png_warning(png_ptr, msg);
      }
582
      sprintf(msg, "Application  is  running with png.c from libpng-%.20s",
583 584 585 586
         png_libpng_ver);
      png_warning(png_ptr, msg);
   }
#endif
587
   if(png_sizeof(png_struct) > png_struct_size)
588
     {
589
       png_ptr->error_fn=NULL;
590 591 592
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
       png_ptr->flags=0;
#endif
593
       png_error(png_ptr,
594
       "The png struct allocated by the application for writing is too small.");
595
     }
596
   if(png_sizeof(png_info) > png_info_size)
597
     {
598
       png_ptr->error_fn=NULL;
599 600 601
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
       png_ptr->flags=0;
#endif
602
       png_error(png_ptr,
603
       "The info struct allocated by the application for writing is too small.");
604 605 606 607 608 609 610 611 612 613
     }
   png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
}


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;
614
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
615
   jmp_buf tmp_jmp; /* to save current jump buffer */
616
#endif
617 618 619 620 621
   int i = 0;
   do
   {
     if (user_png_ver[i] != png_libpng_ver[i])
     {
622 623 624
#ifdef PNG_LEGACY_SUPPORTED
       png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
#else
625
       png_ptr->warning_fn=NULL;
626 627 628
       png_warning(png_ptr,
     "Application uses deprecated png_write_init() and should be recompiled.");
       break;
629
#endif
630 631
     }
   } while (png_libpng_ver[i++]);
632

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

635
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
636
   /* save jump buffer and error functions */
637
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
638
#endif
G
Guy Schalnat 已提交
639

640
   if (png_sizeof(png_struct) > png_struct_size)
641 642 643 644 645 646
     {
       png_destroy_struct(png_ptr);
       png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
       *ptr_ptr = png_ptr;
     }

G
Guy Schalnat 已提交
647
   /* reset all variables to 0 */
648
   png_memset(png_ptr, 0, png_sizeof (png_struct));
G
Guy Schalnat 已提交
649

650 651 652 653 654 655
   /* 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

656
#if !defined(PNG_1_0_X)
657 658 659
#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
   png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
#endif
660
#endif /* PNG_1_0_X */
661

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

667 668
   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
      png_flush_ptr_NULL);
669

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

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

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

A
Andreas Dilger 已提交
693
   png_debug(1, "in png_write_rows\n");
G
Guy Schalnat 已提交
694 695 696 697 698 699 700
   /* loop through the rows */
   for (i = 0, rp = row; i < num_rows; i++, rp++)
   {
      png_write_row(png_ptr, *rp);
   }
}

701 702 703
/* Write the image.  You only need to call this function once, even
 * if you are writing an interlaced image.
 */
704
void PNGAPI
G
Guy Schalnat 已提交
705
png_write_image(png_structp png_ptr, png_bytepp image)
G
Guy Schalnat 已提交
706 707 708
{
   png_uint_32 i; /* row index */
   int pass, num_pass; /* pass variables */
G
Guy Schalnat 已提交
709
   png_bytepp rp; /* points to current row */
G
Guy Schalnat 已提交
710

A
Andreas Dilger 已提交
711
   png_debug(1, "in png_write_image\n");
712
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
713 714 715
   /* intialize interlace handling.  If image is not interlaced,
      this will set pass to 1 */
   num_pass = png_set_interlace_handling(png_ptr);
716 717 718
#else
   num_pass = 1;
#endif
G
Guy Schalnat 已提交
719 720 721 722 723 724 725 726 727 728 729
   /* 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 已提交
730
/* called by user to write a row of image data */
731
void PNGAPI
G
Guy Schalnat 已提交
732
png_write_row(png_structp png_ptr, png_bytep row)
G
Guy Schalnat 已提交
733
{
734 735
   png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
      png_ptr->row_number, png_ptr->pass);
G
Guy Schalnat 已提交
736
   /* initialize transformations and other stuff if first time */
G
Guy Schalnat 已提交
737
   if (png_ptr->row_number == 0 && png_ptr->pass == 0)
G
Guy Schalnat 已提交
738
   {
739 740 741 742 743
   /* 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.");

744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
   /* 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 已提交
774 775 776
      png_write_start_row(png_ptr);
   }

G
Guy Schalnat 已提交
777
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
778 779 780 781 782
   /* if interlaced and not interested in row, return */
   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
   {
      switch (png_ptr->pass)
      {
G
Guy Schalnat 已提交
783
         case 0:
784
            if (png_ptr->row_number & 0x07)
G
Guy Schalnat 已提交
785 786 787 788 789 790
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 1:
791
            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
G
Guy Schalnat 已提交
792 793 794 795 796 797
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 2:
798
            if ((png_ptr->row_number & 0x07) != 4)
G
Guy Schalnat 已提交
799 800
            {
               png_write_finish_row(png_ptr);
G
Guy Schalnat 已提交
801
               return;
G
Guy Schalnat 已提交
802 803 804
            }
            break;
         case 3:
805
            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
G
Guy Schalnat 已提交
806 807 808 809 810 811
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 4:
812
            if ((png_ptr->row_number & 0x03) != 2)
G
Guy Schalnat 已提交
813 814 815 816 817 818
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 5:
819
            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
G
Guy Schalnat 已提交
820 821 822 823 824 825
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
         case 6:
826
            if (!(png_ptr->row_number & 0x01))
G
Guy Schalnat 已提交
827 828 829 830 831 832 833
            {
               png_write_finish_row(png_ptr);
               return;
            }
            break;
      }
   }
G
Guy Schalnat 已提交
834
#endif
G
Guy Schalnat 已提交
835 836

   /* set up row info for transformations */
G
Guy Schalnat 已提交
837
   png_ptr->row_info.color_type = png_ptr->color_type;
G
Guy Schalnat 已提交
838 839 840
   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 已提交
841 842
   png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
      png_ptr->row_info.channels);
843

844 845
   png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
      png_ptr->row_info.width);
G
Guy Schalnat 已提交
846

847
   png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
848
   png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
849 850 851
   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);
852
   png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
A
Andreas Dilger 已提交
853 854

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

G
Guy Schalnat 已提交
858
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
859 860 861 862 863
   /* 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 已提交
864
         png_ptr->row_buf + 1, png_ptr->pass);
G
Guy Schalnat 已提交
865 866 867 868 869 870 871
      /* this should always get caught above, but still ... */
      if (!(png_ptr->row_info.width))
      {
         png_write_finish_row(png_ptr);
         return;
      }
   }
G
Guy Schalnat 已提交
872
#endif
G
Guy Schalnat 已提交
873 874 875 876 877

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

878
#if defined(PNG_MNG_FEATURES_SUPPORTED)
879 880 881 882 883 884 885 886 887
   /* 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
    */
888 889 890 891 892 893 894 895
   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 已提交
896
   /* Find a filter if necessary, filter the row and write it out. */
G
Guy Schalnat 已提交
897
   png_write_find_filter(png_ptr, &(png_ptr->row_info));
898 899 900

   if (png_ptr->write_row_fn != NULL)
      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
G
Guy Schalnat 已提交
901 902 903 904
}

#if defined(PNG_WRITE_FLUSH_SUPPORTED)
/* Set the automatic flush interval or 0 to turn flushing off */
905
void PNGAPI
G
Guy Schalnat 已提交
906
png_set_flush(png_structp png_ptr, int nrows)
G
Guy Schalnat 已提交
907
{
A
Andreas Dilger 已提交
908
   png_debug(1, "in png_set_flush\n");
G
Guy Schalnat 已提交
909
   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
G
Guy Schalnat 已提交
910 911 912
}

/* flush the current output buffers now */
913
void PNGAPI
G
Guy Schalnat 已提交
914
png_write_flush(png_structp png_ptr)
G
Guy Schalnat 已提交
915
{
G
Guy Schalnat 已提交
916 917
   int wrote_IDAT;

A
Andreas Dilger 已提交
918
   png_debug(1, "in png_write_flush\n");
G
Guy Schalnat 已提交
919 920
   /* We have already written out all of the data */
   if (png_ptr->row_number >= png_ptr->num_rows)
G
Guy Schalnat 已提交
921 922 923 924 925 926 927
     return;

   do
   {
      int ret;

      /* compress the data */
A
Andreas Dilger 已提交
928
      ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
G
Guy Schalnat 已提交
929 930 931 932 933
      wrote_IDAT = 0;

      /* check for compression errors */
      if (ret != Z_OK)
      {
A
Andreas Dilger 已提交
934
         if (png_ptr->zstream.msg != NULL)
A
Andreas Dilger 已提交
935
            png_error(png_ptr, png_ptr->zstream.msg);
G
Guy Schalnat 已提交
936 937 938 939
         else
            png_error(png_ptr, "zlib error");
      }

A
Andreas Dilger 已提交
940
      if (!(png_ptr->zstream.avail_out))
G
Guy Schalnat 已提交
941 942 943 944
      {
         /* write the IDAT and reset the zlib output buffer */
         png_write_IDAT(png_ptr, png_ptr->zbuf,
                        png_ptr->zbuf_size);
A
Andreas Dilger 已提交
945 946
         png_ptr->zstream.next_out = png_ptr->zbuf;
         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
947 948 949 950 951
         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 已提交
952
   if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
G
Guy Schalnat 已提交
953 954 955
   {
      /* write the IDAT and reset the zlib output buffer */
      png_write_IDAT(png_ptr, png_ptr->zbuf,
A
Andreas Dilger 已提交
956 957 958
                     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 已提交
959 960 961
   }
   png_ptr->flush_rows = 0;
   png_flush(png_ptr);
G
Guy Schalnat 已提交
962
}
G
Guy Schalnat 已提交
963
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
G
Guy Schalnat 已提交
964

G
Guy Schalnat 已提交
965
/* free all memory used by the write */
966
void PNGAPI
A
Andreas Dilger 已提交
967
png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
G
Guy Schalnat 已提交
968
{
A
Andreas Dilger 已提交
969 970
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL;
971 972
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn = NULL;
973
   png_voidp mem_ptr = NULL;
974
#endif
A
Andreas Dilger 已提交
975

A
Andreas Dilger 已提交
976 977
   png_debug(1, "in png_destroy_write_struct\n");
   if (png_ptr_ptr != NULL)
978
   {
A
Andreas Dilger 已提交
979
      png_ptr = *png_ptr_ptr;
980 981
#ifdef PNG_USER_MEM_SUPPORTED
      free_fn = png_ptr->free_fn;
982
      mem_ptr = png_ptr->mem_ptr;
983 984
#endif
   }
A
Andreas Dilger 已提交
985

A
Andreas Dilger 已提交
986
   if (info_ptr_ptr != NULL)
A
Andreas Dilger 已提交
987 988
      info_ptr = *info_ptr_ptr;

A
Andreas Dilger 已提交
989
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
990
   {
991 992
      png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);

993
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
994 995 996
      if (png_ptr->num_chunk_list)
      {
         png_free(png_ptr, png_ptr->chunk_list);
997
         png_ptr->chunk_list=NULL;
998 999
         png_ptr->num_chunk_list=0;
      }
1000
#endif
1001

1002
#ifdef PNG_USER_MEM_SUPPORTED
1003 1004
      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
1005
#else
A
Andreas Dilger 已提交
1006
      png_destroy_struct((png_voidp)info_ptr);
1007
#endif
1008
      *info_ptr_ptr = NULL;
G
Guy Schalnat 已提交
1009 1010
   }

A
Andreas Dilger 已提交
1011
   if (png_ptr != NULL)
G
Guy Schalnat 已提交
1012
   {
A
Andreas Dilger 已提交
1013
      png_write_destroy(png_ptr);
1014
#ifdef PNG_USER_MEM_SUPPORTED
1015 1016
      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
         (png_voidp)mem_ptr);
1017
#else
A
Andreas Dilger 已提交
1018
      png_destroy_struct((png_voidp)png_ptr);
1019
#endif
1020
      *png_ptr_ptr = NULL;
G
Guy Schalnat 已提交
1021 1022 1023
   }
}

G
Guy Schalnat 已提交
1024

A
Andreas Dilger 已提交
1025
/* Free any memory used in png_ptr struct (old method) */
1026
void /* PRIVATE */
G
Guy Schalnat 已提交
1027
png_write_destroy(png_structp png_ptr)
G
Guy Schalnat 已提交
1028
{
1029
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
1030
   jmp_buf tmp_jmp; /* save jump buffer */
1031
#endif
G
Guy Schalnat 已提交
1032 1033 1034
   png_error_ptr error_fn;
   png_error_ptr warning_fn;
   png_voidp error_ptr;
1035 1036 1037
#ifdef PNG_USER_MEM_SUPPORTED
   png_free_ptr free_fn;
#endif
G
Guy Schalnat 已提交
1038

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

G
Guy Schalnat 已提交
1043
   /* free our memory.  png_free checks NULL for us. */
A
Andreas Dilger 已提交
1044 1045 1046 1047 1048 1049 1050
   png_free(png_ptr, png_ptr->zbuf);
   png_free(png_ptr, png_ptr->row_buf);
   png_free(png_ptr, png_ptr->prev_row);
   png_free(png_ptr, png_ptr->sub_row);
   png_free(png_ptr, png_ptr->up_row);
   png_free(png_ptr, png_ptr->avg_row);
   png_free(png_ptr, png_ptr->paeth_row);
1051

1052
#if defined(PNG_TIME_RFC1123_SUPPORTED)
1053
   png_free(png_ptr, png_ptr->time_buffer);
1054 1055
#endif

A
Andreas Dilger 已提交
1056 1057 1058 1059 1060 1061
#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);
1062
#endif
G
Guy Schalnat 已提交
1063

1064
#ifdef PNG_SETJMP_SUPPORTED
G
Guy Schalnat 已提交
1065
   /* reset structure */
1066
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
1067
#endif
G
Guy Schalnat 已提交
1068 1069 1070 1071

   error_fn = png_ptr->error_fn;
   warning_fn = png_ptr->warning_fn;
   error_ptr = png_ptr->error_ptr;
1072 1073 1074
#ifdef PNG_USER_MEM_SUPPORTED
   free_fn = png_ptr->free_fn;
#endif
G
Guy Schalnat 已提交
1075

1076
   png_memset(png_ptr, 0, png_sizeof (png_struct));
G
Guy Schalnat 已提交
1077 1078 1079 1080

   png_ptr->error_fn = error_fn;
   png_ptr->warning_fn = warning_fn;
   png_ptr->error_ptr = error_ptr;
1081 1082 1083
#ifdef PNG_USER_MEM_SUPPORTED
   png_ptr->free_fn = free_fn;
#endif
G
Guy Schalnat 已提交
1084

1085
#ifdef PNG_SETJMP_SUPPORTED
1086
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
1087
#endif
G
Guy Schalnat 已提交
1088
}
G
Guy Schalnat 已提交
1089

A
Andreas Dilger 已提交
1090
/* Allow the application to select one or more row filters to use. */
1091
void PNGAPI
G
Guy Schalnat 已提交
1092
png_set_filter(png_structp png_ptr, int method, int filters)
G
Guy Schalnat 已提交
1093
{
A
Andreas Dilger 已提交
1094
   png_debug(1, "in png_set_filter\n");
1095
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1096
   if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
1097 1098 1099
      (method == PNG_INTRAPIXEL_DIFFERENCING))
         method = PNG_FILTER_TYPE_BASE;
#endif
A
Andreas Dilger 已提交
1100
   if (method == PNG_FILTER_TYPE_BASE)
G
Guy Schalnat 已提交
1101 1102 1103 1104 1105
   {
      switch (filters & (PNG_ALL_FILTERS | 0x07))
      {
         case 5:
         case 6:
A
Andreas Dilger 已提交
1106 1107 1108 1109 1110 1111
         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
         case PNG_FILTER_VALUE_NONE:  png_ptr->do_filter=PNG_FILTER_NONE; break;
         case PNG_FILTER_VALUE_SUB:   png_ptr->do_filter=PNG_FILTER_SUB;  break;
         case PNG_FILTER_VALUE_UP:    png_ptr->do_filter=PNG_FILTER_UP;   break;
         case PNG_FILTER_VALUE_AVG:   png_ptr->do_filter=PNG_FILTER_AVG;  break;
         case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
G
Guy Schalnat 已提交
1112 1113 1114
         default: png_ptr->do_filter = (png_byte)filters; break;
      }

A
Andreas Dilger 已提交
1115 1116 1117 1118 1119 1120 1121 1122
      /* 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 已提交
1123
       */
A
Andreas Dilger 已提交
1124
      if (png_ptr->row_buf != NULL)
G
Guy Schalnat 已提交
1125
      {
1126
         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
G
Guy Schalnat 已提交
1127
         {
A
Andreas Dilger 已提交
1128
            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1129
              (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1130
            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
G
Guy Schalnat 已提交
1131 1132
         }

1133
         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
G
Guy Schalnat 已提交
1134
         {
A
Andreas Dilger 已提交
1135
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1136
            {
A
Andreas Dilger 已提交
1137
               png_warning(png_ptr, "Can't add Up filter after starting");
G
Guy Schalnat 已提交
1138 1139 1140 1141
               png_ptr->do_filter &= ~PNG_FILTER_UP;
            }
            else
            {
A
Andreas Dilger 已提交
1142
               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1143
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1144
               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
G
Guy Schalnat 已提交
1145 1146 1147
            }
         }

1148
         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
G
Guy Schalnat 已提交
1149
         {
A
Andreas Dilger 已提交
1150
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1151
            {
A
Andreas Dilger 已提交
1152
               png_warning(png_ptr, "Can't add Average filter after starting");
G
Guy Schalnat 已提交
1153 1154 1155 1156
               png_ptr->do_filter &= ~PNG_FILTER_AVG;
            }
            else
            {
A
Andreas Dilger 已提交
1157
               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1158
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1159
               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
G
Guy Schalnat 已提交
1160 1161 1162
            }
         }

1163
         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
A
Andreas Dilger 已提交
1164
             png_ptr->paeth_row == NULL)
G
Guy Schalnat 已提交
1165
         {
A
Andreas Dilger 已提交
1166
            if (png_ptr->prev_row == NULL)
G
Guy Schalnat 已提交
1167 1168
            {
               png_warning(png_ptr, "Can't add Paeth filter after starting");
1169
               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
G
Guy Schalnat 已提交
1170 1171 1172
            }
            else
            {
1173
               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1174
                  (png_ptr->rowbytes + 1));
A
Andreas Dilger 已提交
1175
               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
G
Guy Schalnat 已提交
1176 1177 1178 1179 1180 1181 1182 1183
            }
         }

         if (png_ptr->do_filter == PNG_NO_FILTERS)
            png_ptr->do_filter = PNG_FILTER_NONE;
      }
   }
   else
A
Andreas Dilger 已提交
1184 1185 1186 1187 1188 1189 1190 1191
      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
1192 1193
 * better compression.
 */
A
Andreas Dilger 已提交
1194
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
1195
void PNGAPI
A
Andreas Dilger 已提交
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
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");
   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;
   }

1220 1221
   png_ptr->num_prev_filters = (png_byte)num_weights;
   png_ptr->heuristic_method = (png_byte)heuristic_method;
A
Andreas Dilger 已提交
1222 1223 1224 1225 1226 1227

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

1230 1231
         /* To make sure that the weighting starts out fairly */
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1232
         {
1233
            png_ptr->prev_filters[i] = 255;
A
Andreas Dilger 已提交
1234 1235 1236 1237 1238
         }
      }

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

1242
         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
1243
            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
1244
         for (i = 0; i < num_weights; i++)
A
Andreas Dilger 已提交
1245
         {
1246 1247
            png_ptr->inv_filter_weights[i] =
            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
1248
         }
A
Andreas Dilger 已提交
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
      }

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

1276
      png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
1277
         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
A
Andreas Dilger 已提交
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307

      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 已提交
1308
}
A
Andreas Dilger 已提交
1309
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
G
Guy Schalnat 已提交
1310

1311
void PNGAPI
G
Guy Schalnat 已提交
1312
png_set_compression_level(png_structp png_ptr, int level)
G
Guy Schalnat 已提交
1313
{
A
Andreas Dilger 已提交
1314
   png_debug(1, "in png_set_compression_level\n");
G
Guy Schalnat 已提交
1315
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
G
Guy Schalnat 已提交
1316 1317 1318
   png_ptr->zlib_level = level;
}

1319
void PNGAPI
G
Guy Schalnat 已提交
1320
png_set_compression_mem_level(png_structp png_ptr, int mem_level)
G
Guy Schalnat 已提交
1321
{
A
Andreas Dilger 已提交
1322
   png_debug(1, "in png_set_compression_mem_level\n");
G
Guy Schalnat 已提交
1323
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
G
Guy Schalnat 已提交
1324
   png_ptr->zlib_mem_level = mem_level;
G
Guy Schalnat 已提交
1325 1326
}

1327
void PNGAPI
G
Guy Schalnat 已提交
1328
png_set_compression_strategy(png_structp png_ptr, int strategy)
G
Guy Schalnat 已提交
1329
{
A
Andreas Dilger 已提交
1330
   png_debug(1, "in png_set_compression_strategy\n");
G
Guy Schalnat 已提交
1331
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
G
Guy Schalnat 已提交
1332 1333 1334
   png_ptr->zlib_strategy = strategy;
}

1335
void PNGAPI
G
Guy Schalnat 已提交
1336
png_set_compression_window_bits(png_structp png_ptr, int window_bits)
G
Guy Schalnat 已提交
1337
{
G
Guy Schalnat 已提交
1338 1339
   if (window_bits > 15)
      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1340 1341
   else if (window_bits < 8)
      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1342 1343 1344 1345 1346 1347 1348 1349
#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 已提交
1350
   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
G
Guy Schalnat 已提交
1351 1352 1353
   png_ptr->zlib_window_bits = window_bits;
}

1354
void PNGAPI
G
Guy Schalnat 已提交
1355
png_set_compression_method(png_structp png_ptr, int method)
G
Guy Schalnat 已提交
1356
{
A
Andreas Dilger 已提交
1357
   png_debug(1, "in png_set_compression_method\n");
G
Guy Schalnat 已提交
1358 1359 1360
   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 已提交
1361
   png_ptr->zlib_method = method;
G
Guy Schalnat 已提交
1362 1363
}

1364
void PNGAPI
1365 1366 1367 1368 1369 1370
png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
{
   png_ptr->write_row_fn = write_row_fn;
}

#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1371
void PNGAPI
1372 1373 1374 1375 1376 1377 1378 1379
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");
   png_ptr->transformations |= PNG_USER_TRANSFORM;
   png_ptr->write_user_transform_fn = write_user_transform_fn;
}
#endif
1380 1381 1382


#if defined(PNG_INFO_IMAGE_SUPPORTED)
1383 1384
void PNGAPI
png_write_png(png_structp png_ptr, png_infop info_ptr,
1385
              int transforms, voidp params)
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
{
#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);
1459

1460
   if(transforms == 0 || params == NULL)
1461
      /* quiet compiler warnings */ return;
1462 1463
}
#endif
1464
#endif /* PNG_WRITE_SUPPORTED */