1
2/* pngwrite.c - general routines to write a PNG file
3 *
4 * Last changed in libpng 1.2.15 January 5, 2007
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1998-2007 Glenn Randers-Pehrson
7 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9 */
10
11/* get internal access to png.h */
12#define PNG_INTERNAL
13#include "png.h"
14#ifdef PNG_WRITE_SUPPORTED
15
16/* Writes all the PNG information.  This is the suggested way to use the
17 * library.  If you have a new chunk to add, make a function to write it,
18 * 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
20 * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
21 * the chunk, as that will keep the code from breaking if you want to just
22 * write a plain PNG file.  If you have long comments, I suggest writing
23 * them in png_write_end(), and compressing them.
24 */
25void PNGAPI
26png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
27{
28   png_debug(1, "in png_write_info_before_PLTE\n");
29   if (png_ptr == NULL || info_ptr == NULL)
30      return;
31   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
32   {
33   png_write_sig(png_ptr); /* write PNG signature */
34#if defined(PNG_MNG_FEATURES_SUPPORTED)
35   if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
36   {
37      png_warning(png_ptr,"MNG features are not allowed in a PNG datastream");
38      png_ptr->mng_features_permitted=0;
39   }
40#endif
41   /* write IHDR information. */
42   png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
43      info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
44      info_ptr->filter_type,
45#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
46      info_ptr->interlace_type);
47#else
48      0);
49#endif
50   /* the rest of these check to see if the valid field has the appropriate
51      flag set, and if it does, writes the chunk. */
52#if defined(PNG_WRITE_gAMA_SUPPORTED)
53   if (info_ptr->valid & PNG_INFO_gAMA)
54   {
55#  ifdef PNG_FLOATING_POINT_SUPPORTED
56      png_write_gAMA(png_ptr, info_ptr->gamma);
57#else
58#ifdef PNG_FIXED_POINT_SUPPORTED
59      png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
60#  endif
61#endif
62   }
63#endif
64#if defined(PNG_WRITE_sRGB_SUPPORTED)
65   if (info_ptr->valid & PNG_INFO_sRGB)
66      png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
67#endif
68#if defined(PNG_WRITE_iCCP_SUPPORTED)
69   if (info_ptr->valid & PNG_INFO_iCCP)
70      png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
71                     info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
72#endif
73#if defined(PNG_WRITE_sBIT_SUPPORTED)
74   if (info_ptr->valid & PNG_INFO_sBIT)
75      png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
76#endif
77#if defined(PNG_WRITE_cHRM_SUPPORTED)
78   if (info_ptr->valid & PNG_INFO_cHRM)
79   {
80#ifdef PNG_FLOATING_POINT_SUPPORTED
81      png_write_cHRM(png_ptr,
82         info_ptr->x_white, info_ptr->y_white,
83         info_ptr->x_red, info_ptr->y_red,
84         info_ptr->x_green, info_ptr->y_green,
85         info_ptr->x_blue, info_ptr->y_blue);
86#else
87#  ifdef PNG_FIXED_POINT_SUPPORTED
88      png_write_cHRM_fixed(png_ptr,
89         info_ptr->int_x_white, info_ptr->int_y_white,
90         info_ptr->int_x_red, info_ptr->int_y_red,
91         info_ptr->int_x_green, info_ptr->int_y_green,
92         info_ptr->int_x_blue, info_ptr->int_y_blue);
93#  endif
94#endif
95   }
96#endif
97#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
98   if (info_ptr->unknown_chunks_num)
99   {
100       png_unknown_chunk *up;
101
102       png_debug(5, "writing extra chunks\n");
103
104       for (up = info_ptr->unknown_chunks;
105            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
106            up++)
107       {
108         int keep=png_handle_as_unknown(png_ptr, up->name);
109         if (keep != PNG_HANDLE_CHUNK_NEVER &&
110            up->location && !(up->location & PNG_HAVE_PLTE) &&
111            !(up->location & PNG_HAVE_IDAT) &&
112            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
113            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
114         {
115            png_write_chunk(png_ptr, up->name, up->data, up->size);
116         }
117       }
118   }
119#endif
120      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
121   }
122}
123
124void PNGAPI
125png_write_info(png_structp png_ptr, png_infop info_ptr)
126{
127#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
128   int i;
129#endif
130
131   png_debug(1, "in png_write_info\n");
132
133   if (png_ptr == NULL || info_ptr == NULL)
134      return;
135
136   png_write_info_before_PLTE(png_ptr, info_ptr);
137
138   if (info_ptr->valid & PNG_INFO_PLTE)
139      png_write_PLTE(png_ptr, info_ptr->palette,
140         (png_uint_32)info_ptr->num_palette);
141   else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
142      png_error(png_ptr, "Valid palette required for paletted images");
143
144#if defined(PNG_WRITE_tRNS_SUPPORTED)
145   if (info_ptr->valid & PNG_INFO_tRNS)
146      {
147#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
148         /* invert the alpha channel (in tRNS) */
149         if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
150            info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
151         {
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
157      png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
158         info_ptr->num_trans, info_ptr->color_type);
159      }
160#endif
161#if defined(PNG_WRITE_bKGD_SUPPORTED)
162   if (info_ptr->valid & PNG_INFO_bKGD)
163      png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
164#endif
165#if defined(PNG_WRITE_hIST_SUPPORTED)
166   if (info_ptr->valid & PNG_INFO_hIST)
167      png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
168#endif
169#if defined(PNG_WRITE_oFFs_SUPPORTED)
170   if (info_ptr->valid & PNG_INFO_oFFs)
171      png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
172         info_ptr->offset_unit_type);
173#endif
174#if defined(PNG_WRITE_pCAL_SUPPORTED)
175   if (info_ptr->valid & PNG_INFO_pCAL)
176      png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
177         info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
178         info_ptr->pcal_units, info_ptr->pcal_params);
179#endif
180#if defined(PNG_WRITE_sCAL_SUPPORTED)
181   if (info_ptr->valid & PNG_INFO_sCAL)
182#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
183      png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
184          info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
185#else
186#ifdef PNG_FIXED_POINT_SUPPORTED
187      png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
188          info_ptr->scal_s_width, info_ptr->scal_s_height);
189#else
190      png_warning(png_ptr,
191          "png_write_sCAL not supported; sCAL chunk not written.");
192#endif
193#endif
194#endif
195#if defined(PNG_WRITE_pHYs_SUPPORTED)
196   if (info_ptr->valid & PNG_INFO_pHYs)
197      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
198         info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
199#endif
200#if defined(PNG_WRITE_tIME_SUPPORTED)
201   if (info_ptr->valid & PNG_INFO_tIME)
202   {
203      png_write_tIME(png_ptr, &(info_ptr->mod_time));
204      png_ptr->mode |= PNG_WROTE_tIME;
205   }
206#endif
207#if defined(PNG_WRITE_sPLT_SUPPORTED)
208   if (info_ptr->valid & PNG_INFO_sPLT)
209     for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
210       png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
211#endif
212#if defined(PNG_WRITE_TEXT_SUPPORTED)
213   /* Check to see if we need to write text chunks */
214   for (i = 0; i < info_ptr->num_text; i++)
215   {
216      png_debug2(2, "Writing header text chunk %d, type %d\n", i,
217         info_ptr->text[i].compression);
218      /* an internationalized chunk? */
219      if (info_ptr->text[i].compression > 0)
220      {
221#if defined(PNG_WRITE_iTXt_SUPPORTED)
222          /* write international chunk */
223          png_write_iTXt(png_ptr,
224                         info_ptr->text[i].compression,
225                         info_ptr->text[i].key,
226                         info_ptr->text[i].lang,
227                         info_ptr->text[i].lang_key,
228                         info_ptr->text[i].text);
229#else
230          png_warning(png_ptr, "Unable to write international text");
231#endif
232          /* Mark this chunk as written */
233          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
234      }
235      /* If we want a compressed text chunk */
236      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
237      {
238#if defined(PNG_WRITE_zTXt_SUPPORTED)
239         /* write compressed chunk */
240         png_write_zTXt(png_ptr, info_ptr->text[i].key,
241            info_ptr->text[i].text, 0,
242            info_ptr->text[i].compression);
243#else
244         png_warning(png_ptr, "Unable to write compressed text");
245#endif
246         /* Mark this chunk as written */
247         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
248      }
249      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
250      {
251#if defined(PNG_WRITE_tEXt_SUPPORTED)
252         /* write uncompressed chunk */
253         png_write_tEXt(png_ptr, info_ptr->text[i].key,
254                         info_ptr->text[i].text,
255                         0);
256#else
257         png_warning(png_ptr, "Unable to write uncompressed text");
258#endif
259         /* Mark this chunk as written */
260         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
261      }
262   }
263#endif
264#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
265   if (info_ptr->unknown_chunks_num)
266   {
267       png_unknown_chunk *up;
268
269       png_debug(5, "writing extra chunks\n");
270
271       for (up = info_ptr->unknown_chunks;
272            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
273            up++)
274       {
275         int keep=png_handle_as_unknown(png_ptr, up->name);
276         if (keep != PNG_HANDLE_CHUNK_NEVER &&
277            up->location && (up->location & PNG_HAVE_PLTE) &&
278            !(up->location & PNG_HAVE_IDAT) &&
279            ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
280            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
281         {
282            png_write_chunk(png_ptr, up->name, up->data, up->size);
283         }
284       }
285   }
286#endif
287}
288
289/* Writes the end of the PNG file.  If you don't want to write comments or
290 * time information, you can pass NULL for info.  If you already wrote these
291 * in png_write_info(), do not write them again here.  If you have long
292 * comments, I suggest writing them here, and compressing them.
293 */
294void PNGAPI
295png_write_end(png_structp png_ptr, png_infop info_ptr)
296{
297   png_debug(1, "in png_write_end\n");
298   if (png_ptr == NULL)
299      return;
300   if (!(png_ptr->mode & PNG_HAVE_IDAT))
301      png_error(png_ptr, "No IDATs written into file");
302
303   /* see if user wants us to write information chunks */
304   if (info_ptr != NULL)
305   {
306#if defined(PNG_WRITE_TEXT_SUPPORTED)
307      int i; /* local index variable */
308#endif
309#if defined(PNG_WRITE_tIME_SUPPORTED)
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))
313         png_write_tIME(png_ptr, &(info_ptr->mod_time));
314#endif
315#if defined(PNG_WRITE_TEXT_SUPPORTED)
316      /* loop through comment chunks */
317      for (i = 0; i < info_ptr->num_text; i++)
318      {
319         png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
320            info_ptr->text[i].compression);
321         /* an internationalized chunk? */
322         if (info_ptr->text[i].compression > 0)
323         {
324#if defined(PNG_WRITE_iTXt_SUPPORTED)
325             /* write international chunk */
326             png_write_iTXt(png_ptr,
327                         info_ptr->text[i].compression,
328                         info_ptr->text[i].key,
329                         info_ptr->text[i].lang,
330                         info_ptr->text[i].lang_key,
331                         info_ptr->text[i].text);
332#else
333             png_warning(png_ptr, "Unable to write international text");
334#endif
335             /* Mark this chunk as written */
336             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
337         }
338         else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
339         {
340#if defined(PNG_WRITE_zTXt_SUPPORTED)
341            /* write compressed chunk */
342            png_write_zTXt(png_ptr, info_ptr->text[i].key,
343               info_ptr->text[i].text, 0,
344               info_ptr->text[i].compression);
345#else
346            png_warning(png_ptr, "Unable to write compressed text");
347#endif
348            /* Mark this chunk as written */
349            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
350         }
351         else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
352         {
353#if defined(PNG_WRITE_tEXt_SUPPORTED)
354            /* write uncompressed chunk */
355            png_write_tEXt(png_ptr, info_ptr->text[i].key,
356               info_ptr->text[i].text, 0);
357#else
358            png_warning(png_ptr, "Unable to write uncompressed text");
359#endif
360
361            /* Mark this chunk as written */
362            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
363         }
364      }
365#endif
366#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
367   if (info_ptr->unknown_chunks_num)
368   {
369       png_unknown_chunk *up;
370
371       png_debug(5, "writing extra chunks\n");
372
373       for (up = info_ptr->unknown_chunks;
374            up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
375            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            (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
382         {
383            png_write_chunk(png_ptr, up->name, up->data, up->size);
384         }
385       }
386   }
387#endif
388   }
389
390   png_ptr->mode |= PNG_AFTER_IDAT;
391
392   /* write end of PNG file */
393   png_write_IEND(png_ptr);
394}
395
396#if defined(PNG_WRITE_tIME_SUPPORTED)
397#if !defined(_WIN32_WCE)
398/* "time.h" functions are not supported on WindowsCE */
399void PNGAPI
400png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
401{
402   png_debug(1, "in png_convert_from_struct_tm\n");
403   ptime->year = (png_uint_16)(1900 + ttime->tm_year);
404   ptime->month = (png_byte)(ttime->tm_mon + 1);
405   ptime->day = (png_byte)ttime->tm_mday;
406   ptime->hour = (png_byte)ttime->tm_hour;
407   ptime->minute = (png_byte)ttime->tm_min;
408   ptime->second = (png_byte)ttime->tm_sec;
409}
410
411void PNGAPI
412png_convert_from_time_t(png_timep ptime, time_t ttime)
413{
414   struct tm *tbuf;
415
416   png_debug(1, "in png_convert_from_time_t\n");
417   tbuf = gmtime(&ttime);
418   png_convert_from_struct_tm(ptime, tbuf);
419}
420#endif
421#endif
422
423/* Initialize png_ptr structure, and allocate any memory needed */
424png_structp PNGAPI
425png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
426   png_error_ptr error_fn, png_error_ptr warn_fn)
427{
428#ifdef PNG_USER_MEM_SUPPORTED
429   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 */
434png_structp PNGAPI
435png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
436   png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
437   png_malloc_ptr malloc_fn, png_free_ptr free_fn)
438{
439#endif /* PNG_USER_MEM_SUPPORTED */
440   png_structp png_ptr;
441#ifdef PNG_SETJMP_SUPPORTED
442#ifdef USE_FAR_KEYWORD
443   jmp_buf jmpbuf;
444#endif
445#endif
446   int i;
447   png_debug(1, "in png_create_write_struct\n");
448#ifdef PNG_USER_MEM_SUPPORTED
449   png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
450      (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#if !defined(PNG_1_0_X)
458#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
459#ifdef PNG_MMX_CODE_SUPPORTED
460   png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
461#endif
462#endif
463#endif /* PNG_1_0_X */
464
465   /* added at libpng-1.2.6 */
466#ifdef PNG_SET_USER_LIMITS_SUPPORTED
467   png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
468   png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
469#endif
470
471#ifdef PNG_SETJMP_SUPPORTED
472#ifdef USE_FAR_KEYWORD
473   if (setjmp(jmpbuf))
474#else
475   if (setjmp(png_ptr->jmpbuf))
476#endif
477   {
478      png_free(png_ptr, png_ptr->zbuf);
479      png_ptr->zbuf=NULL;
480      png_destroy_struct(png_ptr);
481      return (NULL);
482   }
483#ifdef USE_FAR_KEYWORD
484   png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
485#endif
486#endif
487
488#ifdef PNG_USER_MEM_SUPPORTED
489   png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
490#endif /* PNG_USER_MEM_SUPPORTED */
491   png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
492
493   i=0;
494   do
495   {
496     if(user_png_ver[i] != png_libpng_ver[i])
497        png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
498   } while (png_libpng_ver[i++]);
499
500   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
501   {
502     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
503      * we must recompile any applications that use any older library version.
504      * For versions after libpng 1.0, we will be compatible, so we need
505      * only check the first digit.
506      */
507     if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
508         (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
509         (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
510     {
511#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
512        char msg[80];
513        if (user_png_ver)
514        {
515          png_snprintf(msg, 80,
516             "Application was compiled with png.h from libpng-%.20s",
517             user_png_ver);
518          png_warning(png_ptr, msg);
519        }
520        png_snprintf(msg, 80,
521           "Application  is  running with png.c from libpng-%.20s",
522           png_libpng_ver);
523        png_warning(png_ptr, msg);
524#endif
525#ifdef PNG_ERROR_NUMBERS_SUPPORTED
526        png_ptr->flags=0;
527#endif
528        png_error(png_ptr,
529           "Incompatible libpng version in application and library");
530     }
531   }
532
533   /* initialize zbuf - compression buffer */
534   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
535   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
536      (png_uint_32)png_ptr->zbuf_size);
537
538   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
539      png_flush_ptr_NULL);
540
541#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
542   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
543      1, png_doublep_NULL, png_doublep_NULL);
544#endif
545
546#ifdef PNG_SETJMP_SUPPORTED
547/* Applications that neglect to set up their own setjmp() and then encounter
548   a png_error() will longjmp here.  Since the jmpbuf is then meaningless we
549   abort instead of returning. */
550#ifdef USE_FAR_KEYWORD
551   if (setjmp(jmpbuf))
552      PNG_ABORT();
553   png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
554#else
555   if (setjmp(png_ptr->jmpbuf))
556      PNG_ABORT();
557#endif
558#endif
559   return (png_ptr);
560}
561
562/* Initialize png_ptr structure, and allocate any memory needed */
563#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
564/* Deprecated. */
565#undef png_write_init
566void PNGAPI
567png_write_init(png_structp png_ptr)
568{
569   /* We only come here via pre-1.0.7-compiled applications */
570   png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
571}
572
573void PNGAPI
574png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
575   png_size_t png_struct_size, png_size_t png_info_size)
576{
577   /* We only come here via pre-1.0.12-compiled applications */
578   if(png_ptr == NULL) return;
579#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
580   if(png_sizeof(png_struct) > png_struct_size ||
581      png_sizeof(png_info) > png_info_size)
582   {
583      char msg[80];
584      png_ptr->warning_fn=NULL;
585      if (user_png_ver)
586      {
587        png_snprintf(msg, 80,
588           "Application was compiled with png.h from libpng-%.20s",
589           user_png_ver);
590        png_warning(png_ptr, msg);
591      }
592      png_snprintf(msg, 80,
593         "Application  is  running with png.c from libpng-%.20s",
594         png_libpng_ver);
595      png_warning(png_ptr, msg);
596   }
597#endif
598   if(png_sizeof(png_struct) > png_struct_size)
599     {
600       png_ptr->error_fn=NULL;
601#ifdef PNG_ERROR_NUMBERS_SUPPORTED
602       png_ptr->flags=0;
603#endif
604       png_error(png_ptr,
605       "The png struct allocated by the application for writing is too small.");
606     }
607   if(png_sizeof(png_info) > png_info_size)
608     {
609       png_ptr->error_fn=NULL;
610#ifdef PNG_ERROR_NUMBERS_SUPPORTED
611       png_ptr->flags=0;
612#endif
613       png_error(png_ptr,
614       "The info struct allocated by the application for writing is too small.");
615     }
616   png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
617}
618#endif /* PNG_1_0_X || PNG_1_2_X */
619
620
621void PNGAPI
622png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
623   png_size_t png_struct_size)
624{
625   png_structp png_ptr=*ptr_ptr;
626#ifdef PNG_SETJMP_SUPPORTED
627   jmp_buf tmp_jmp; /* to save current jump buffer */
628#endif
629
630   int i = 0;
631
632   if (png_ptr == NULL)
633      return;
634
635   do
636   {
637     if (user_png_ver[i] != png_libpng_ver[i])
638     {
639#ifdef PNG_LEGACY_SUPPORTED
640       png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
641#else
642       png_ptr->warning_fn=NULL;
643       png_warning(png_ptr,
644     "Application uses deprecated png_write_init() and should be recompiled.");
645       break;
646#endif
647     }
648   } while (png_libpng_ver[i++]);
649
650   png_debug(1, "in png_write_init_3\n");
651
652#ifdef PNG_SETJMP_SUPPORTED
653   /* save jump buffer and error functions */
654   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
655#endif
656
657   if (png_sizeof(png_struct) > png_struct_size)
658     {
659       png_destroy_struct(png_ptr);
660       png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
661       *ptr_ptr = png_ptr;
662     }
663
664   /* reset all variables to 0 */
665   png_memset(png_ptr, 0, png_sizeof (png_struct));
666
667   /* added at libpng-1.2.6 */
668#ifdef PNG_SET_USER_LIMITS_SUPPORTED
669   png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
670   png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
671#endif
672
673#if !defined(PNG_1_0_X)
674#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
675#ifdef PNG_MMX_CODE_SUPPORTED
676   png_init_mmx_flags(png_ptr);   /* 1.2.0 addition */
677#endif
678#endif
679#endif /* PNG_1_0_X */
680
681#ifdef PNG_SETJMP_SUPPORTED
682   /* restore jump buffer */
683   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
684#endif
685
686   png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
687      png_flush_ptr_NULL);
688
689   /* initialize zbuf - compression buffer */
690   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
691   png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
692      (png_uint_32)png_ptr->zbuf_size);
693
694#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
695   png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
696      1, png_doublep_NULL, png_doublep_NULL);
697#endif
698}
699
700/* Write a few rows of image data.  If the image is interlaced,
701 * either you will have to write the 7 sub images, or, if you
702 * have called png_set_interlace_handling(), you will have to
703 * "write" the image seven times.
704 */
705void PNGAPI
706png_write_rows(png_structp png_ptr, png_bytepp row,
707   png_uint_32 num_rows)
708{
709   png_uint_32 i; /* row counter */
710   png_bytepp rp; /* row pointer */
711
712   png_debug(1, "in png_write_rows\n");
713
714   if (png_ptr == NULL)
715      return;
716
717   /* loop through the rows */
718   for (i = 0, rp = row; i < num_rows; i++, rp++)
719   {
720      png_write_row(png_ptr, *rp);
721   }
722}
723
724/* Write the image.  You only need to call this function once, even
725 * if you are writing an interlaced image.
726 */
727void PNGAPI
728png_write_image(png_structp png_ptr, png_bytepp image)
729{
730   png_uint_32 i; /* row index */
731   int pass, num_pass; /* pass variables */
732   png_bytepp rp; /* points to current row */
733
734   if (png_ptr == NULL)
735      return;
736
737   png_debug(1, "in png_write_image\n");
738#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
739   /* intialize interlace handling.  If image is not interlaced,
740      this will set pass to 1 */
741   num_pass = png_set_interlace_handling(png_ptr);
742#else
743   num_pass = 1;
744#endif
745   /* loop through passes */
746   for (pass = 0; pass < num_pass; pass++)
747   {
748      /* loop through image */
749      for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
750      {
751         png_write_row(png_ptr, *rp);
752      }
753   }
754}
755
756/* called by user to write a row of image data */
757void PNGAPI
758png_write_row(png_structp png_ptr, png_bytep row)
759{
760   if (png_ptr == NULL)
761      return;
762   png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
763      png_ptr->row_number, png_ptr->pass);
764
765   /* initialize transformations and other stuff if first time */
766   if (png_ptr->row_number == 0 && png_ptr->pass == 0)
767   {
768   /* make sure we wrote the header info */
769   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
770      png_error(png_ptr,
771         "png_write_info was never called before png_write_row.");
772
773   /* check for transforms that have been set but were defined out */
774#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
775   if (png_ptr->transformations & PNG_INVERT_MONO)
776      png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
777#endif
778#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
779   if (png_ptr->transformations & PNG_FILLER)
780      png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
781#endif
782#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
783   if (png_ptr->transformations & PNG_PACKSWAP)
784      png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
785#endif
786#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
787   if (png_ptr->transformations & PNG_PACK)
788      png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
789#endif
790#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
791   if (png_ptr->transformations & PNG_SHIFT)
792      png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
793#endif
794#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
795   if (png_ptr->transformations & PNG_BGR)
796      png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
797#endif
798#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
799   if (png_ptr->transformations & PNG_SWAP_BYTES)
800      png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
801#endif
802
803      png_write_start_row(png_ptr);
804   }
805
806#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
807   /* if interlaced and not interested in row, return */
808   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
809   {
810      switch (png_ptr->pass)
811      {
812         case 0:
813            if (png_ptr->row_number & 0x07)
814            {
815               png_write_finish_row(png_ptr);
816               return;
817            }
818            break;
819         case 1:
820            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
821            {
822               png_write_finish_row(png_ptr);
823               return;
824            }
825            break;
826         case 2:
827            if ((png_ptr->row_number & 0x07) != 4)
828            {
829               png_write_finish_row(png_ptr);
830               return;
831            }
832            break;
833         case 3:
834            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
835            {
836               png_write_finish_row(png_ptr);
837               return;
838            }
839            break;
840         case 4:
841            if ((png_ptr->row_number & 0x03) != 2)
842            {
843               png_write_finish_row(png_ptr);
844               return;
845            }
846            break;
847         case 5:
848            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
849            {
850               png_write_finish_row(png_ptr);
851               return;
852            }
853            break;
854         case 6:
855            if (!(png_ptr->row_number & 0x01))
856            {
857               png_write_finish_row(png_ptr);
858               return;
859            }
860            break;
861      }
862   }
863#endif
864
865   /* set up row info for transformations */
866   png_ptr->row_info.color_type = png_ptr->color_type;
867   png_ptr->row_info.width = png_ptr->usr_width;
868   png_ptr->row_info.channels = png_ptr->usr_channels;
869   png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
870   png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
871      png_ptr->row_info.channels);
872
873   png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
874      png_ptr->row_info.width);
875
876   png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
877   png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
878   png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
879   png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
880   png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
881   png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
882
883   /* Copy user's row into buffer, leaving room for filter byte. */
884   png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
885      png_ptr->row_info.rowbytes);
886
887#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
888   /* handle interlacing */
889   if (png_ptr->interlaced && png_ptr->pass < 6 &&
890      (png_ptr->transformations & PNG_INTERLACE))
891   {
892      png_do_write_interlace(&(png_ptr->row_info),
893         png_ptr->row_buf + 1, png_ptr->pass);
894      /* this should always get caught above, but still ... */
895      if (!(png_ptr->row_info.width))
896      {
897         png_write_finish_row(png_ptr);
898         return;
899      }
900   }
901#endif
902
903   /* handle other transformations */
904   if (png_ptr->transformations)
905      png_do_write_transformations(png_ptr);
906
907#if defined(PNG_MNG_FEATURES_SUPPORTED)
908   /* Write filter_method 64 (intrapixel differencing) only if
909    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
910    * 2. Libpng did not write a PNG signature (this filter_method is only
911    *    used in PNG datastreams that are embedded in MNG datastreams) and
912    * 3. The application called png_permit_mng_features with a mask that
913    *    included PNG_FLAG_MNG_FILTER_64 and
914    * 4. The filter_method is 64 and
915    * 5. The color_type is RGB or RGBA
916    */
917   if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
918      (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
919   {
920      /* Intrapixel differencing */
921      png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
922   }
923#endif
924
925   /* Find a filter if necessary, filter the row and write it out. */
926   png_write_find_filter(png_ptr, &(png_ptr->row_info));
927
928   if (png_ptr->write_row_fn != NULL)
929      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
930}
931
932#if defined(PNG_WRITE_FLUSH_SUPPORTED)
933/* Set the automatic flush interval or 0 to turn flushing off */
934void PNGAPI
935png_set_flush(png_structp png_ptr, int nrows)
936{
937   png_debug(1, "in png_set_flush\n");
938   if (png_ptr == NULL)
939      return;
940   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
941}
942
943/* flush the current output buffers now */
944void PNGAPI
945png_write_flush(png_structp png_ptr)
946{
947   int wrote_IDAT;
948
949   png_debug(1, "in png_write_flush\n");
950   if (png_ptr == NULL)
951      return;
952   /* We have already written out all of the data */
953   if (png_ptr->row_number >= png_ptr->num_rows)
954     return;
955
956   do
957   {
958      int ret;
959
960      /* compress the data */
961      ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
962      wrote_IDAT = 0;
963
964      /* check for compression errors */
965      if (ret != Z_OK)
966      {
967         if (png_ptr->zstream.msg != NULL)
968            png_error(png_ptr, png_ptr->zstream.msg);
969         else
970            png_error(png_ptr, "zlib error");
971      }
972
973      if (!(png_ptr->zstream.avail_out))
974      {
975         /* write the IDAT and reset the zlib output buffer */
976         png_write_IDAT(png_ptr, png_ptr->zbuf,
977                        png_ptr->zbuf_size);
978         png_ptr->zstream.next_out = png_ptr->zbuf;
979         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
980         wrote_IDAT = 1;
981      }
982   } while(wrote_IDAT == 1);
983
984   /* If there is any data left to be output, write it into a new IDAT */
985   if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
986   {
987      /* write the IDAT and reset the zlib output buffer */
988      png_write_IDAT(png_ptr, png_ptr->zbuf,
989                     png_ptr->zbuf_size - png_ptr->zstream.avail_out);
990      png_ptr->zstream.next_out = png_ptr->zbuf;
991      png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
992   }
993   png_ptr->flush_rows = 0;
994   png_flush(png_ptr);
995}
996#endif /* PNG_WRITE_FLUSH_SUPPORTED */
997
998/* free all memory used by the write */
999void PNGAPI
1000png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
1001{
1002   png_structp png_ptr = NULL;
1003   png_infop info_ptr = NULL;
1004#ifdef PNG_USER_MEM_SUPPORTED
1005   png_free_ptr free_fn = NULL;
1006   png_voidp mem_ptr = NULL;
1007#endif
1008
1009   png_debug(1, "in png_destroy_write_struct\n");
1010   if (png_ptr_ptr != NULL)
1011   {
1012      png_ptr = *png_ptr_ptr;
1013#ifdef PNG_USER_MEM_SUPPORTED
1014      free_fn = png_ptr->free_fn;
1015      mem_ptr = png_ptr->mem_ptr;
1016#endif
1017   }
1018
1019   if (info_ptr_ptr != NULL)
1020      info_ptr = *info_ptr_ptr;
1021
1022   if (info_ptr != NULL)
1023   {
1024      png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
1025
1026#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1027      if (png_ptr->num_chunk_list)
1028      {
1029         png_free(png_ptr, png_ptr->chunk_list);
1030         png_ptr->chunk_list=NULL;
1031         png_ptr->num_chunk_list=0;
1032      }
1033#endif
1034
1035#ifdef PNG_USER_MEM_SUPPORTED
1036      png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
1037         (png_voidp)mem_ptr);
1038#else
1039      png_destroy_struct((png_voidp)info_ptr);
1040#endif
1041      *info_ptr_ptr = NULL;
1042   }
1043
1044   if (png_ptr != NULL)
1045   {
1046      png_write_destroy(png_ptr);
1047#ifdef PNG_USER_MEM_SUPPORTED
1048      png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
1049         (png_voidp)mem_ptr);
1050#else
1051      png_destroy_struct((png_voidp)png_ptr);
1052#endif
1053      *png_ptr_ptr = NULL;
1054   }
1055}
1056
1057
1058/* Free any memory used in png_ptr struct (old method) */
1059void /* PRIVATE */
1060png_write_destroy(png_structp png_ptr)
1061{
1062#ifdef PNG_SETJMP_SUPPORTED
1063   jmp_buf tmp_jmp; /* save jump buffer */
1064#endif
1065   png_error_ptr error_fn;
1066   png_error_ptr warning_fn;
1067   png_voidp error_ptr;
1068#ifdef PNG_USER_MEM_SUPPORTED
1069   png_free_ptr free_fn;
1070#endif
1071
1072   png_debug(1, "in png_write_destroy\n");
1073   /* free any memory zlib uses */
1074   deflateEnd(&png_ptr->zstream);
1075
1076   /* free our memory.  png_free checks NULL for us. */
1077   png_free(png_ptr, png_ptr->zbuf);
1078   png_free(png_ptr, png_ptr->row_buf);
1079   png_free(png_ptr, png_ptr->prev_row);
1080   png_free(png_ptr, png_ptr->sub_row);
1081   png_free(png_ptr, png_ptr->up_row);
1082   png_free(png_ptr, png_ptr->avg_row);
1083   png_free(png_ptr, png_ptr->paeth_row);
1084
1085#if defined(PNG_TIME_RFC1123_SUPPORTED)
1086   png_free(png_ptr, png_ptr->time_buffer);
1087#endif
1088
1089#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1090   png_free(png_ptr, png_ptr->prev_filters);
1091   png_free(png_ptr, png_ptr->filter_weights);
1092   png_free(png_ptr, png_ptr->inv_filter_weights);
1093   png_free(png_ptr, png_ptr->filter_costs);
1094   png_free(png_ptr, png_ptr->inv_filter_costs);
1095#endif
1096
1097#ifdef PNG_SETJMP_SUPPORTED
1098   /* reset structure */
1099   png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
1100#endif
1101
1102   error_fn = png_ptr->error_fn;
1103   warning_fn = png_ptr->warning_fn;
1104   error_ptr = png_ptr->error_ptr;
1105#ifdef PNG_USER_MEM_SUPPORTED
1106   free_fn = png_ptr->free_fn;
1107#endif
1108
1109   png_memset(png_ptr, 0, png_sizeof (png_struct));
1110
1111   png_ptr->error_fn = error_fn;
1112   png_ptr->warning_fn = warning_fn;
1113   png_ptr->error_ptr = error_ptr;
1114#ifdef PNG_USER_MEM_SUPPORTED
1115   png_ptr->free_fn = free_fn;
1116#endif
1117
1118#ifdef PNG_SETJMP_SUPPORTED
1119   png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
1120#endif
1121}
1122
1123/* Allow the application to select one or more row filters to use. */
1124void PNGAPI
1125png_set_filter(png_structp png_ptr, int method, int filters)
1126{
1127   png_debug(1, "in png_set_filter\n");
1128   if (png_ptr == NULL)
1129      return;
1130#if defined(PNG_MNG_FEATURES_SUPPORTED)
1131   if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
1132      (method == PNG_INTRAPIXEL_DIFFERENCING))
1133         method = PNG_FILTER_TYPE_BASE;
1134#endif
1135   if (method == PNG_FILTER_TYPE_BASE)
1136   {
1137      switch (filters & (PNG_ALL_FILTERS | 0x07))
1138      {
1139#ifndef PNG_NO_WRITE_FILTER
1140         case 5:
1141         case 6:
1142         case 7: png_warning(png_ptr, "Unknown row filter for method 0");
1143#endif /* PNG_NO_WRITE_FILTER */
1144         case PNG_FILTER_VALUE_NONE:
1145              png_ptr->do_filter=PNG_FILTER_NONE; break;
1146#ifndef PNG_NO_WRITE_FILTER
1147         case PNG_FILTER_VALUE_SUB:
1148              png_ptr->do_filter=PNG_FILTER_SUB; break;
1149         case PNG_FILTER_VALUE_UP:
1150              png_ptr->do_filter=PNG_FILTER_UP; break;
1151         case PNG_FILTER_VALUE_AVG:
1152              png_ptr->do_filter=PNG_FILTER_AVG; break;
1153         case PNG_FILTER_VALUE_PAETH:
1154              png_ptr->do_filter=PNG_FILTER_PAETH; break;
1155         default: png_ptr->do_filter = (png_byte)filters; break;
1156#else
1157         default: png_warning(png_ptr, "Unknown row filter for method 0");
1158#endif /* PNG_NO_WRITE_FILTER */
1159      }
1160
1161      /* If we have allocated the row_buf, this means we have already started
1162       * with the image and we should have allocated all of the filter buffers
1163       * that have been selected.  If prev_row isn't already allocated, then
1164       * it is too late to start using the filters that need it, since we
1165       * will be missing the data in the previous row.  If an application
1166       * wants to start and stop using particular filters during compression,
1167       * it should start out with all of the filters, and then add and
1168       * remove them after the start of compression.
1169       */
1170      if (png_ptr->row_buf != NULL)
1171      {
1172#ifndef PNG_NO_WRITE_FILTER
1173         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
1174         {
1175            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1176              (png_ptr->rowbytes + 1));
1177            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
1178         }
1179
1180         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
1181         {
1182            if (png_ptr->prev_row == NULL)
1183            {
1184               png_warning(png_ptr, "Can't add Up filter after starting");
1185               png_ptr->do_filter &= ~PNG_FILTER_UP;
1186            }
1187            else
1188            {
1189               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
1190                  (png_ptr->rowbytes + 1));
1191               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
1192            }
1193         }
1194
1195         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
1196         {
1197            if (png_ptr->prev_row == NULL)
1198            {
1199               png_warning(png_ptr, "Can't add Average filter after starting");
1200               png_ptr->do_filter &= ~PNG_FILTER_AVG;
1201            }
1202            else
1203            {
1204               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1205                  (png_ptr->rowbytes + 1));
1206               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
1207            }
1208         }
1209
1210         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
1211             png_ptr->paeth_row == NULL)
1212         {
1213            if (png_ptr->prev_row == NULL)
1214            {
1215               png_warning(png_ptr, "Can't add Paeth filter after starting");
1216               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
1217            }
1218            else
1219            {
1220               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
1221                  (png_ptr->rowbytes + 1));
1222               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
1223            }
1224         }
1225
1226         if (png_ptr->do_filter == PNG_NO_FILTERS)
1227#endif /* PNG_NO_WRITE_FILTER */
1228            png_ptr->do_filter = PNG_FILTER_NONE;
1229      }
1230   }
1231   else
1232      png_error(png_ptr, "Unknown custom filter method");
1233}
1234
1235/* This allows us to influence the way in which libpng chooses the "best"
1236 * filter for the current scanline.  While the "minimum-sum-of-absolute-
1237 * differences metric is relatively fast and effective, there is some
1238 * question as to whether it can be improved upon by trying to keep the
1239 * filtered data going to zlib more consistent, hopefully resulting in
1240 * better compression.
1241 */
1242#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
1243void PNGAPI
1244png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
1245   int num_weights, png_doublep filter_weights,
1246   png_doublep filter_costs)
1247{
1248   int i;
1249
1250   png_debug(1, "in png_set_filter_heuristics\n");
1251   if (png_ptr == NULL)
1252      return;
1253   if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
1254   {
1255      png_warning(png_ptr, "Unknown filter heuristic method");
1256      return;
1257   }
1258
1259   if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
1260   {
1261      heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
1262   }
1263
1264   if (num_weights < 0 || filter_weights == NULL ||
1265      heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
1266   {
1267      num_weights = 0;
1268   }
1269
1270   png_ptr->num_prev_filters = (png_byte)num_weights;
1271   png_ptr->heuristic_method = (png_byte)heuristic_method;
1272
1273   if (num_weights > 0)
1274   {
1275      if (png_ptr->prev_filters == NULL)
1276      {
1277         png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
1278            (png_uint_32)(png_sizeof(png_byte) * num_weights));
1279
1280         /* To make sure that the weighting starts out fairly */
1281         for (i = 0; i < num_weights; i++)
1282         {
1283            png_ptr->prev_filters[i] = 255;
1284         }
1285      }
1286
1287      if (png_ptr->filter_weights == NULL)
1288      {
1289         png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
1290            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
1291
1292         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
1293            (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
1294         for (i = 0; i < num_weights; i++)
1295         {
1296            png_ptr->inv_filter_weights[i] =
1297            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
1298         }
1299      }
1300
1301      for (i = 0; i < num_weights; i++)
1302      {
1303         if (filter_weights[i] < 0.0)
1304         {
1305            png_ptr->inv_filter_weights[i] =
1306            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
1307         }
1308         else
1309         {
1310            png_ptr->inv_filter_weights[i] =
1311               (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
1312            png_ptr->filter_weights[i] =
1313               (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
1314         }
1315      }
1316   }
1317
1318   /* If, in the future, there are other filter methods, this would
1319    * need to be based on png_ptr->filter.
1320    */
1321   if (png_ptr->filter_costs == NULL)
1322   {
1323      png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
1324         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
1325
1326      png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
1327         (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
1328
1329      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
1330      {
1331         png_ptr->inv_filter_costs[i] =
1332         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
1333      }
1334   }
1335
1336   /* Here is where we set the relative costs of the different filters.  We
1337    * should take the desired compression level into account when setting
1338    * the costs, so that Paeth, for instance, has a high relative cost at low
1339    * compression levels, while it has a lower relative cost at higher
1340    * compression settings.  The filter types are in order of increasing
1341    * relative cost, so it would be possible to do this with an algorithm.
1342    */
1343   for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
1344   {
1345      if (filter_costs == NULL || filter_costs[i] < 0.0)
1346      {
1347         png_ptr->inv_filter_costs[i] =
1348         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
1349      }
1350      else if (filter_costs[i] >= 1.0)
1351      {
1352         png_ptr->inv_filter_costs[i] =
1353            (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
1354         png_ptr->filter_costs[i] =
1355            (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
1356      }
1357   }
1358}
1359#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
1360
1361void PNGAPI
1362png_set_compression_level(png_structp png_ptr, int level)
1363{
1364   png_debug(1, "in png_set_compression_level\n");
1365   if (png_ptr == NULL)
1366      return;
1367   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
1368   png_ptr->zlib_level = level;
1369}
1370
1371void PNGAPI
1372png_set_compression_mem_level(png_structp png_ptr, int mem_level)
1373{
1374   png_debug(1, "in png_set_compression_mem_level\n");
1375   if (png_ptr == NULL)
1376      return;
1377   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
1378   png_ptr->zlib_mem_level = mem_level;
1379}
1380
1381void PNGAPI
1382png_set_compression_strategy(png_structp png_ptr, int strategy)
1383{
1384   png_debug(1, "in png_set_compression_strategy\n");
1385   if (png_ptr == NULL)
1386      return;
1387   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
1388   png_ptr->zlib_strategy = strategy;
1389}
1390
1391void PNGAPI
1392png_set_compression_window_bits(png_structp png_ptr, int window_bits)
1393{
1394   if (png_ptr == NULL)
1395      return;
1396   if (window_bits > 15)
1397      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
1398   else if (window_bits < 8)
1399      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
1400#ifndef WBITS_8_OK
1401   /* avoid libpng bug with 256-byte windows */
1402   if (window_bits == 8)
1403     {
1404       png_warning(png_ptr, "Compression window is being reset to 512");
1405       window_bits=9;
1406     }
1407#endif
1408   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
1409   png_ptr->zlib_window_bits = window_bits;
1410}
1411
1412void PNGAPI
1413png_set_compression_method(png_structp png_ptr, int method)
1414{
1415   png_debug(1, "in png_set_compression_method\n");
1416   if (png_ptr == NULL)
1417      return;
1418   if (method != 8)
1419      png_warning(png_ptr, "Only compression method 8 is supported by PNG");
1420   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
1421   png_ptr->zlib_method = method;
1422}
1423
1424void PNGAPI
1425png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
1426{
1427   if (png_ptr == NULL)
1428      return;
1429   png_ptr->write_row_fn = write_row_fn;
1430}
1431
1432#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1433void PNGAPI
1434png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
1435   write_user_transform_fn)
1436{
1437   png_debug(1, "in png_set_write_user_transform_fn\n");
1438   if (png_ptr == NULL)
1439      return;
1440   png_ptr->transformations |= PNG_USER_TRANSFORM;
1441   png_ptr->write_user_transform_fn = write_user_transform_fn;
1442}
1443#endif
1444
1445
1446#if defined(PNG_INFO_IMAGE_SUPPORTED)
1447void PNGAPI
1448png_write_png(png_structp png_ptr, png_infop info_ptr,
1449              int transforms, voidp params)
1450{
1451   if (png_ptr == NULL || info_ptr == NULL)
1452      return;
1453#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
1454   /* invert the alpha channel from opacity to transparency */
1455   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
1456       png_set_invert_alpha(png_ptr);
1457#endif
1458
1459   /* Write the file header information. */
1460   png_write_info(png_ptr, info_ptr);
1461
1462   /* ------ these transformations don't touch the info structure ------- */
1463
1464#if defined(PNG_WRITE_INVERT_SUPPORTED)
1465   /* invert monochrome pixels */
1466   if (transforms & PNG_TRANSFORM_INVERT_MONO)
1467       png_set_invert_mono(png_ptr);
1468#endif
1469
1470#if defined(PNG_WRITE_SHIFT_SUPPORTED)
1471   /* Shift the pixels up to a legal bit depth and fill in
1472    * as appropriate to correctly scale the image.
1473    */
1474   if ((transforms & PNG_TRANSFORM_SHIFT)
1475               && (info_ptr->valid & PNG_INFO_sBIT))
1476       png_set_shift(png_ptr, &info_ptr->sig_bit);
1477#endif
1478
1479#if defined(PNG_WRITE_PACK_SUPPORTED)
1480   /* pack pixels into bytes */
1481   if (transforms & PNG_TRANSFORM_PACKING)
1482       png_set_packing(png_ptr);
1483#endif
1484
1485#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
1486   /* swap location of alpha bytes from ARGB to RGBA */
1487   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
1488       png_set_swap_alpha(png_ptr);
1489#endif
1490
1491#if defined(PNG_WRITE_FILLER_SUPPORTED)
1492   /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
1493    * RGB (4 channels -> 3 channels). The second parameter is not used.
1494    */
1495   if (transforms & PNG_TRANSFORM_STRIP_FILLER)
1496       png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
1497#endif
1498
1499#if defined(PNG_WRITE_BGR_SUPPORTED)
1500   /* flip BGR pixels to RGB */
1501   if (transforms & PNG_TRANSFORM_BGR)
1502       png_set_bgr(png_ptr);
1503#endif
1504
1505#if defined(PNG_WRITE_SWAP_SUPPORTED)
1506   /* swap bytes of 16-bit files to most significant byte first */
1507   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
1508       png_set_swap(png_ptr);
1509#endif
1510
1511#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
1512   /* swap bits of 1, 2, 4 bit packed pixel formats */
1513   if (transforms & PNG_TRANSFORM_PACKSWAP)
1514       png_set_packswap(png_ptr);
1515#endif
1516
1517   /* ----------------------- end of transformations ------------------- */
1518
1519   /* write the bits */
1520   if (info_ptr->valid & PNG_INFO_IDAT)
1521       png_write_image(png_ptr, info_ptr->row_pointers);
1522
1523   /* It is REQUIRED to call this to finish writing the rest of the file */
1524   png_write_end(png_ptr, info_ptr);
1525
1526   transforms = transforms; /* quiet compiler warnings */
1527   params = params;
1528}
1529#endif
1530#endif /* PNG_WRITE_SUPPORTED */
1531