blob: b571b0f783c297f1cf0f4dde09f337c6c8eefb66 [file] [log] [blame]
Andreas Dilger47a0c421997-05-16 02:46:07 -05001
2/* pngwrite.c - general routines to write a PNG file
Guy Schalnat0d580581995-07-20 02:43:20 -05003
Andreas Dilger47a0c421997-05-16 02:46:07 -05004 libpng 1.0 beta 6 - version 0.96
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06006 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
Andreas Dilger47a0c421997-05-16 02:46:07 -05007 Copyright (c) 1996, 1997 Andreas Dilger
8 May 12, 1997
Guy Schalnat0d580581995-07-20 02:43:20 -05009 */
10
11/* get internal access to png.h */
12#define PNG_INTERNAL
13#include "png.h"
14
Andreas Dilger47a0c421997-05-16 02:46:07 -050015/* Writes all the PNG information. This is the suggested way to use the
16 * library. If you have a new chunk to add, make a function to write it,
17 * and put it in the correct location here. If you want the chunk written
18 * after the image data, put it in png_write_end(). I strongly encurage
19 * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
20 * the chunk, as that will keep the code from breaking if you want to just
21 * write a plain PNG file. If you have long comments, I suggest writing
22 * them in png_write_end(), and compressing them.
23 */
Guy Schalnat0d580581995-07-20 02:43:20 -050024void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060025png_write_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -050026{
Andreas Dilger47a0c421997-05-16 02:46:07 -050027 int i;
28
29 png_debug(1, "in png_write_info\n");
Guy Schalnat0d580581995-07-20 02:43:20 -050030 png_write_sig(png_ptr); /* write PNG signature */
31 /* write IHDR information. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060032 png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
33 info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
34 info_ptr->filter_type, info_ptr->interlace_type);
Guy Schalnat0d580581995-07-20 02:43:20 -050035 /* the rest of these check to see if the valid field has the appropriate
36 flag set, and if it does, writes the chunk. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -050037#if defined(PNG_WRITE_gAMA_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060038 if (info_ptr->valid & PNG_INFO_gAMA)
39 png_write_gAMA(png_ptr, info_ptr->gamma);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050040#endif
41#if defined(PNG_WRITE_sBIT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060042 if (info_ptr->valid & PNG_INFO_sBIT)
43 png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050044#endif
45#if defined(PNG_WRITE_cHRM_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060046 if (info_ptr->valid & PNG_INFO_cHRM)
Guy Schalnat0d580581995-07-20 02:43:20 -050047 png_write_cHRM(png_ptr,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060048 info_ptr->x_white, info_ptr->y_white,
49 info_ptr->x_red, info_ptr->y_red,
50 info_ptr->x_green, info_ptr->y_green,
51 info_ptr->x_blue, info_ptr->y_blue);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050052#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060053 if (info_ptr->valid & PNG_INFO_PLTE)
Andreas Dilger47a0c421997-05-16 02:46:07 -050054 png_write_PLTE(png_ptr, info_ptr->palette,
55 (png_uint_32)info_ptr->num_palette);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060056 else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -050057 png_error(png_ptr, "Valid palette required for paletted images\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -050058#if defined(PNG_WRITE_tRNS_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060059 if (info_ptr->valid & PNG_INFO_tRNS)
60 png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
61 info_ptr->num_trans, info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050062#endif
63#if defined(PNG_WRITE_bKGD_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060064 if (info_ptr->valid & PNG_INFO_bKGD)
65 png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050066#endif
67#if defined(PNG_WRITE_hIST_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060068 if (info_ptr->valid & PNG_INFO_hIST)
69 png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050070#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050071#if defined(PNG_WRITE_oFFs_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060072 if (info_ptr->valid & PNG_INFO_oFFs)
73 png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
74 info_ptr->offset_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050075#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -050076#if defined(PNG_WRITE_pCAL_SUPPORTED)
77 if (info_ptr->valid & PNG_INFO_pCAL)
78 png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
79 info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
80 info_ptr->pcal_units, info_ptr->pcal_params);
81#endif
82#if defined(PNG_WRITE_pHYs_SUPPORTED)
83 if (info_ptr->valid & PNG_INFO_pHYs)
84 png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
85 info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
86#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050087#if defined(PNG_WRITE_tIME_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060088 if (info_ptr->valid & PNG_INFO_tIME)
Guy Schalnate5a37791996-06-05 15:50:50 -050089 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060090 png_write_tIME(png_ptr, &(info_ptr->mod_time));
Guy Schalnate5a37791996-06-05 15:50:50 -050091 png_ptr->flags |= PNG_FLAG_WROTE_tIME;
92 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -050093#endif
94#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -050095 /* Check to see if we need to write text chunks */
Andreas Dilger47a0c421997-05-16 02:46:07 -050096 for (i = 0; i < info_ptr->num_text; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -050097 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050098 png_debug2(2, "Writing header text chunk %d, type %d\n", i,
99 info_ptr->text[i].compression);
100 /* If we want a compressed text chunk */
101 if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
102 {
103#if defined(PNG_WRITE_zTXt_SUPPORTED)
104 /* write compressed chunk */
105 png_write_zTXt(png_ptr, info_ptr->text[i].key,
106 info_ptr->text[i].text, info_ptr->text[i].text_length,
107 info_ptr->text[i].compression);
108#else
109 png_warning(png_ptr, "Unable to write compressed text\n");
110#endif
111 /* Mark this chunk as written */
112 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
113 }
114 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
115 {
116#if defined(PNG_WRITE_tEXt_SUPPORTED)
117 /* write uncompressed chunk */
118 png_write_tEXt(png_ptr, info_ptr->text[i].key,
119 info_ptr->text[i].text, info_ptr->text[i].text_length);
120#else
121 png_warning(png_ptr, "Unable to write uncompressed text\n");
122#endif
123 /* Mark this chunk as written */
124 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
125 }
126 }
127#endif
128}
Guy Schalnat0d580581995-07-20 02:43:20 -0500129
Andreas Dilger47a0c421997-05-16 02:46:07 -0500130/* Writes the end of the PNG file. If you don't want to write comments or
131 time information, you can pass NULL for info. If you already wrote these
132 in png_write_info(), do not write them again here. If you have long
133 comments, I suggest writing them here, and compressing them. */
134void
135png_write_end(png_structp png_ptr, png_infop info_ptr)
136{
137 png_debug(1, "in png_write_end\n");
138 if (!(png_ptr->mode & PNG_HAVE_IDAT))
139 png_error(png_ptr, "No IDATs written into file");
140
141 /* see if user wants us to write information chunks */
142 if (info_ptr != NULL)
143 {
144 int i; /* local index variable */
145#if defined(PNG_WRITE_tIME_SUPPORTED)
146 /* check to see if user has supplied a time chunk */
147 if (info_ptr->valid & PNG_INFO_tIME &&
148 !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
149 png_write_tIME(png_ptr, &(info_ptr->mod_time));
150#endif
151#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
152 /* loop through comment chunks */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600153 for (i = 0; i < info_ptr->num_text; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500154 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500155 png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
156 info_ptr->text[i].compression);
157 if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
Guy Schalnat0d580581995-07-20 02:43:20 -0500158 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500159#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600160 /* write compressed chunk */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600161 png_write_zTXt(png_ptr, info_ptr->text[i].key,
162 info_ptr->text[i].text, info_ptr->text[i].text_length,
163 info_ptr->text[i].compression);
Guy Schalnate5a37791996-06-05 15:50:50 -0500164#else
165 png_warning(png_ptr, "Unable to write compressed text\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500166#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500167 /* Mark this chunk as written */
168 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500169 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500170 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500171 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500172#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500173 /* write uncompressed chunk */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600174 png_write_tEXt(png_ptr, info_ptr->text[i].key,
175 info_ptr->text[i].text, info_ptr->text[i].text_length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500176#else
177 png_warning(png_ptr, "Unable to write uncompressed text\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500178#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500179
Andreas Dilger47a0c421997-05-16 02:46:07 -0500180 /* Mark this chunk as written */
181 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500182 }
183 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600184#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500185 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500186
187 png_ptr->mode |= PNG_AFTER_IDAT;
188
Andreas Dilger47a0c421997-05-16 02:46:07 -0500189 /* write end of PNG file */
Guy Schalnat0d580581995-07-20 02:43:20 -0500190 png_write_IEND(png_ptr);
191}
192
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500193#if defined(PNG_WRITE_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500194void
Guy Schalnat6d764711995-12-19 03:22:19 -0600195png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500196{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500197 png_debug(1, "in png_convert_from_struct_tm\n");
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600198 ptime->year = (png_uint_16)(1900 + ttime->tm_year);
199 ptime->month = (png_byte)(ttime->tm_mon + 1);
200 ptime->day = (png_byte)ttime->tm_mday;
201 ptime->hour = (png_byte)ttime->tm_hour;
202 ptime->minute = (png_byte)ttime->tm_min;
203 ptime->second = (png_byte)ttime->tm_sec;
Guy Schalnat0d580581995-07-20 02:43:20 -0500204}
205
206void
Guy Schalnat6d764711995-12-19 03:22:19 -0600207png_convert_from_time_t(png_timep ptime, time_t ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500208{
209 struct tm *tbuf;
210
Andreas Dilger47a0c421997-05-16 02:46:07 -0500211 png_debug(1, "in png_convert_from_time_t\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500212 tbuf = gmtime(&ttime);
213 png_convert_from_struct_tm(ptime, tbuf);
214}
Guy Schalnat6d764711995-12-19 03:22:19 -0600215#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500216
Andreas Dilger47a0c421997-05-16 02:46:07 -0500217/* Initialize png_ptr structure, and allocate any memory needed */
Guy Schalnate5a37791996-06-05 15:50:50 -0500218png_structp
219png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600220 png_error_ptr error_fn, png_error_ptr warn_fn)
Guy Schalnat0d580581995-07-20 02:43:20 -0500221{
Guy Schalnate5a37791996-06-05 15:50:50 -0500222 png_structp png_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600223#ifdef USE_FAR_KEYWORD
224 jmp_buf jmpbuf;
225#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500226 png_debug(1, "in png_create_write_struct\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500227 if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
228 {
229 return (png_structp)NULL;
230 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600231#ifdef USE_FAR_KEYWORD
232 if (setjmp(jmpbuf))
233#else
Guy Schalnate5a37791996-06-05 15:50:50 -0500234 if (setjmp(png_ptr->jmpbuf))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600235#endif
Guy Schalnate5a37791996-06-05 15:50:50 -0500236 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600237 png_free(png_ptr, png_ptr->zbuf);
Guy Schalnate5a37791996-06-05 15:50:50 -0500238 png_destroy_struct(png_ptr);
239 return (png_structp)NULL;
240 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600241#ifdef USE_FAR_KEYWORD
242 png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
243#endif
244 png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
Guy Schalnate5a37791996-06-05 15:50:50 -0500245
Andreas Dilger47a0c421997-05-16 02:46:07 -0500246 /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
247 * we must recompile any applications that use any older library version.
248 * For versions after libpng 1.0, we will be compatible, so we need
249 * only check the first digit.
250 */
251 if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
252 (png_libpng_ver[0] == '0' && user_png_ver[2] < '9'))
Guy Schalnate5a37791996-06-05 15:50:50 -0500253 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500254 png_error(png_ptr,
255 "Incompatible libpng version in application and library");
Guy Schalnate5a37791996-06-05 15:50:50 -0500256 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500257
258 /* initialize zbuf - compression buffer */
259 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600260 png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
Guy Schalnate5a37791996-06-05 15:50:50 -0500261
262 png_set_write_fn(png_ptr, NULL, NULL, NULL);
263
Guy Schalnate5a37791996-06-05 15:50:50 -0500264 return (png_ptr);
265}
266
267
Andreas Dilger47a0c421997-05-16 02:46:07 -0500268/* Initialize png_ptr structure, and allocate any memory needed */
Guy Schalnate5a37791996-06-05 15:50:50 -0500269void
270png_write_init(png_structp png_ptr)
271{
272 jmp_buf tmp_jmp; /* to save current jump buffer */
273
Andreas Dilger47a0c421997-05-16 02:46:07 -0500274 png_debug(1, "in png_write_init\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500275 /* save jump buffer and error functions */
276 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
277
278 /* reset all variables to 0 */
279 png_memset(png_ptr, 0, sizeof (png_struct));
280
281 /* restore jump buffer */
282 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
283
284 /* initialize zbuf - compression buffer */
285 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600286 png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
Guy Schalnate5a37791996-06-05 15:50:50 -0500287 png_set_write_fn(png_ptr, NULL, NULL, NULL);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500288
289#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
290 png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
291 1, NULL, NULL);
292#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500293}
294
295/* write a few rows of image data. If the image is interlaced,
296 either you will have to write the 7 sub images, or, if you
297 have called png_set_interlace_handling(), you will have to
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600298 "write" the image seven times */
Guy Schalnat0d580581995-07-20 02:43:20 -0500299void
Guy Schalnat6d764711995-12-19 03:22:19 -0600300png_write_rows(png_structp png_ptr, png_bytepp row,
Guy Schalnat0d580581995-07-20 02:43:20 -0500301 png_uint_32 num_rows)
302{
303 png_uint_32 i; /* row counter */
Guy Schalnat6d764711995-12-19 03:22:19 -0600304 png_bytepp rp; /* row pointer */
Guy Schalnat0d580581995-07-20 02:43:20 -0500305
Andreas Dilger47a0c421997-05-16 02:46:07 -0500306 png_debug(1, "in png_write_rows\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500307 /* loop through the rows */
308 for (i = 0, rp = row; i < num_rows; i++, rp++)
309 {
310 png_write_row(png_ptr, *rp);
311 }
312}
313
314/* write the image. You only need to call this function once, even
315 if you are writing an interlaced image. */
316void
Guy Schalnat6d764711995-12-19 03:22:19 -0600317png_write_image(png_structp png_ptr, png_bytepp image)
Guy Schalnat0d580581995-07-20 02:43:20 -0500318{
319 png_uint_32 i; /* row index */
320 int pass, num_pass; /* pass variables */
Guy Schalnat6d764711995-12-19 03:22:19 -0600321 png_bytepp rp; /* points to current row */
Guy Schalnat0d580581995-07-20 02:43:20 -0500322
Andreas Dilger47a0c421997-05-16 02:46:07 -0500323 png_debug(1, "in png_write_image\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500324 /* intialize interlace handling. If image is not interlaced,
325 this will set pass to 1 */
326 num_pass = png_set_interlace_handling(png_ptr);
327 /* loop through passes */
328 for (pass = 0; pass < num_pass; pass++)
329 {
330 /* loop through image */
331 for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
332 {
333 png_write_row(png_ptr, *rp);
334 }
335 }
336}
337
Guy Schalnate5a37791996-06-05 15:50:50 -0500338/* called by user to write a row of image data */
Guy Schalnat0d580581995-07-20 02:43:20 -0500339void
Guy Schalnat6d764711995-12-19 03:22:19 -0600340png_write_row(png_structp png_ptr, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500341{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500342 png_debug(1, "in png_write_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500343 /* initialize transformations and other stuff if first time */
Guy Schalnat6d764711995-12-19 03:22:19 -0600344 if (png_ptr->row_number == 0 && png_ptr->pass == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500345 {
346 png_write_start_row(png_ptr);
347 }
348
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500349#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500350 /* if interlaced and not interested in row, return */
351 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
352 {
353 switch (png_ptr->pass)
354 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600355 case 0:
Guy Schalnat0d580581995-07-20 02:43:20 -0500356 if (png_ptr->row_number & 7)
357 {
358 png_write_finish_row(png_ptr);
359 return;
360 }
361 break;
362 case 1:
363 if ((png_ptr->row_number & 7) || png_ptr->width < 5)
364 {
365 png_write_finish_row(png_ptr);
366 return;
367 }
368 break;
369 case 2:
370 if ((png_ptr->row_number & 7) != 4)
371 {
372 png_write_finish_row(png_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600373 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500374 }
375 break;
376 case 3:
377 if ((png_ptr->row_number & 3) || png_ptr->width < 3)
378 {
379 png_write_finish_row(png_ptr);
380 return;
381 }
382 break;
383 case 4:
384 if ((png_ptr->row_number & 3) != 2)
385 {
386 png_write_finish_row(png_ptr);
387 return;
388 }
389 break;
390 case 5:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600391 if ((png_ptr->row_number & 1) || png_ptr->width < 2)
Guy Schalnat0d580581995-07-20 02:43:20 -0500392 {
393 png_write_finish_row(png_ptr);
394 return;
395 }
396 break;
397 case 6:
398 if (!(png_ptr->row_number & 1))
399 {
400 png_write_finish_row(png_ptr);
401 return;
402 }
403 break;
404 }
405 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600406#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500407
408 /* set up row info for transformations */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600409 png_ptr->row_info.color_type = png_ptr->color_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500410 png_ptr->row_info.width = png_ptr->usr_width;
411 png_ptr->row_info.channels = png_ptr->usr_channels;
412 png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600413 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
414 png_ptr->row_info.channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500415 png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
416 (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
417
Andreas Dilger47a0c421997-05-16 02:46:07 -0500418 png_debug1(4, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
419 png_debug1(4, "row_info->width = %d\n", png_ptr->row_info.width);
420 png_debug1(4, "row_info->channels = %d\n", png_ptr->row_info.channels);
421 png_debug1(4, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
422 png_debug1(4, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
423 png_debug1(4, "row_info->rowbytes = %d\n", png_ptr->row_info.rowbytes);
424
425 /* Copy user's row into buffer, leaving room for filter byte. */
426 png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500427
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500428#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500429 /* handle interlacing */
430 if (png_ptr->interlaced && png_ptr->pass < 6 &&
431 (png_ptr->transformations & PNG_INTERLACE))
432 {
433 png_do_write_interlace(&(png_ptr->row_info),
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600434 png_ptr->row_buf + 1, png_ptr->pass);
Guy Schalnat0d580581995-07-20 02:43:20 -0500435 /* this should always get caught above, but still ... */
436 if (!(png_ptr->row_info.width))
437 {
438 png_write_finish_row(png_ptr);
439 return;
440 }
441 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600442#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500443
444 /* handle other transformations */
445 if (png_ptr->transformations)
446 png_do_write_transformations(png_ptr);
447
Andreas Dilger47a0c421997-05-16 02:46:07 -0500448 /* Find a filter if necessary, filter the row and write it out. */
Guy Schalnate5a37791996-06-05 15:50:50 -0500449 png_write_find_filter(png_ptr, &(png_ptr->row_info));
Guy Schalnat0d580581995-07-20 02:43:20 -0500450}
451
Guy Schalnat0f716451995-11-28 11:22:13 -0600452#if defined(PNG_WRITE_FLUSH_SUPPORTED)
453/* Set the automatic flush interval or 0 to turn flushing off */
454void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600455png_set_flush(png_structp png_ptr, int nrows)
Guy Schalnat0f716451995-11-28 11:22:13 -0600456{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500457 png_debug(1, "in png_set_flush\n");
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600458 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
Guy Schalnat0f716451995-11-28 11:22:13 -0600459}
460
461/* flush the current output buffers now */
462void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600463png_write_flush(png_structp png_ptr)
Guy Schalnat0f716451995-11-28 11:22:13 -0600464{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600465 int wrote_IDAT;
Guy Schalnat0f716451995-11-28 11:22:13 -0600466
Andreas Dilger47a0c421997-05-16 02:46:07 -0500467 png_debug(1, "in png_write_flush\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500468 /* We have already written out all of the data */
469 if (png_ptr->row_number >= png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600470 return;
Guy Schalnat0f716451995-11-28 11:22:13 -0600471
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600472 do
473 {
474 int ret;
Guy Schalnat0f716451995-11-28 11:22:13 -0600475
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600476 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600477 ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600478 wrote_IDAT = 0;
Guy Schalnat0f716451995-11-28 11:22:13 -0600479
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600480 /* check for compression errors */
481 if (ret != Z_OK)
482 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500483 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600484 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600485 else
486 png_error(png_ptr, "zlib error");
487 }
Guy Schalnat0f716451995-11-28 11:22:13 -0600488
Andreas Dilger47a0c421997-05-16 02:46:07 -0500489 if (!(png_ptr->zstream.avail_out))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600490 {
491 /* write the IDAT and reset the zlib output buffer */
492 png_write_IDAT(png_ptr, png_ptr->zbuf,
493 png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600494 png_ptr->zstream.next_out = png_ptr->zbuf;
495 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600496 wrote_IDAT = 1;
497 }
498 } while(wrote_IDAT == 1);
Guy Schalnat0f716451995-11-28 11:22:13 -0600499
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600500 /* If there is any data left to be output, write it into a new IDAT */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600501 if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600502 {
503 /* write the IDAT and reset the zlib output buffer */
504 png_write_IDAT(png_ptr, png_ptr->zbuf,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600505 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
506 png_ptr->zstream.next_out = png_ptr->zbuf;
507 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600508 }
509 png_ptr->flush_rows = 0;
510 png_flush(png_ptr);
Guy Schalnat0f716451995-11-28 11:22:13 -0600511}
512#endif /* PNG_WRITE_FLUSH_SUPPORTED */
513
Guy Schalnate5a37791996-06-05 15:50:50 -0500514/* free all memory used by the write */
515void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600516png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
Guy Schalnate5a37791996-06-05 15:50:50 -0500517{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600518 png_structp png_ptr = NULL;
519 png_infop info_ptr = NULL;
520
Andreas Dilger47a0c421997-05-16 02:46:07 -0500521 png_debug(1, "in png_destroy_write_struct\n");
522 if (png_ptr_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600523 png_ptr = *png_ptr_ptr;
524
Andreas Dilger47a0c421997-05-16 02:46:07 -0500525 if (info_ptr_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600526 info_ptr = *info_ptr_ptr;
527
Andreas Dilger47a0c421997-05-16 02:46:07 -0500528 if (info_ptr != NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500529 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600530 png_destroy_struct((png_voidp)info_ptr);
531 *info_ptr_ptr = (png_infop)NULL;
Guy Schalnate5a37791996-06-05 15:50:50 -0500532 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600533
Andreas Dilger47a0c421997-05-16 02:46:07 -0500534 if (png_ptr != NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500535 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600536 png_write_destroy(png_ptr);
537 png_destroy_struct((png_voidp)png_ptr);
538 *png_ptr_ptr = (png_structp)NULL;
Guy Schalnate5a37791996-06-05 15:50:50 -0500539 }
540}
541
542
Andreas Dilger47a0c421997-05-16 02:46:07 -0500543/* Free any memory used in png_ptr struct (old method) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500544void
Guy Schalnat6d764711995-12-19 03:22:19 -0600545png_write_destroy(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500546{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600547 jmp_buf tmp_jmp; /* save jump buffer */
Guy Schalnate5a37791996-06-05 15:50:50 -0500548 png_error_ptr error_fn;
549 png_error_ptr warning_fn;
550 png_voidp error_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500551
Andreas Dilger47a0c421997-05-16 02:46:07 -0500552 png_debug(1, "in png_write_destroy\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500553 /* free any memory zlib uses */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600554 deflateEnd(&png_ptr->zstream);
Guy Schalnate5a37791996-06-05 15:50:50 -0500555
Guy Schalnat0d580581995-07-20 02:43:20 -0500556 /* free our memory. png_free checks NULL for us. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600557 png_free(png_ptr, png_ptr->zbuf);
558 png_free(png_ptr, png_ptr->row_buf);
559 png_free(png_ptr, png_ptr->prev_row);
560 png_free(png_ptr, png_ptr->sub_row);
561 png_free(png_ptr, png_ptr->up_row);
562 png_free(png_ptr, png_ptr->avg_row);
563 png_free(png_ptr, png_ptr->paeth_row);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500564#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
565 png_free(png_ptr, png_ptr->prev_filters);
566 png_free(png_ptr, png_ptr->filter_weights);
567 png_free(png_ptr, png_ptr->inv_filter_weights);
568 png_free(png_ptr, png_ptr->filter_costs);
569 png_free(png_ptr, png_ptr->inv_filter_costs);
570#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -0500571
Guy Schalnat0d580581995-07-20 02:43:20 -0500572 /* reset structure */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500573 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
Guy Schalnate5a37791996-06-05 15:50:50 -0500574
575 error_fn = png_ptr->error_fn;
576 warning_fn = png_ptr->warning_fn;
577 error_ptr = png_ptr->error_ptr;
578
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500579 png_memset(png_ptr, 0, sizeof (png_struct));
Guy Schalnate5a37791996-06-05 15:50:50 -0500580
581 png_ptr->error_fn = error_fn;
582 png_ptr->warning_fn = warning_fn;
583 png_ptr->error_ptr = error_ptr;
584
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500585 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
586}
Guy Schalnate5a37791996-06-05 15:50:50 -0500587
Andreas Dilger47a0c421997-05-16 02:46:07 -0500588/* Allow the application to select one or more row filters to use. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500589void
Guy Schalnate5a37791996-06-05 15:50:50 -0500590png_set_filter(png_structp png_ptr, int method, int filters)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500591{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500592 png_debug(1, "in png_set_filter\n");
593 /* We allow 'method' only for future expansion of the base filter method. */
594 if (method == PNG_FILTER_TYPE_BASE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500595 {
596 switch (filters & (PNG_ALL_FILTERS | 0x07))
597 {
598 case 5:
599 case 6:
Andreas Dilger47a0c421997-05-16 02:46:07 -0500600 case 7: png_warning(png_ptr, "Unknown row filter for method 0");
601 case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break;
602 case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break;
603 case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break;
604 case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break;
605 case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
Guy Schalnate5a37791996-06-05 15:50:50 -0500606 default: png_ptr->do_filter = (png_byte)filters; break;
607 }
608
Andreas Dilger47a0c421997-05-16 02:46:07 -0500609 /* If we have allocated the row_buf, this means we have already started
610 * with the image and we should have allocated all of the filter buffers
611 * that have been selected. If prev_row isn't already allocated, then
612 * it is too late to start using the filters that need it, since we
613 * will be missing the data in the previous row. If an application
614 * wants to start and stop using particular filters during compression,
615 * it should start out with all of the filters, and then add and
616 * remove them after the start of compression.
Guy Schalnate5a37791996-06-05 15:50:50 -0500617 */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500618 if (png_ptr->row_buf != NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500619 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500620 if (png_ptr->do_filter & PNG_FILTER_SUB && png_ptr->sub_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500621 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500622 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500623 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500624 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
Guy Schalnate5a37791996-06-05 15:50:50 -0500625 }
626
Andreas Dilger47a0c421997-05-16 02:46:07 -0500627 if (png_ptr->do_filter & PNG_FILTER_UP && png_ptr->up_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500628 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500629 if (png_ptr->prev_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500630 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500631 png_warning(png_ptr, "Can't add Up filter after starting");
Guy Schalnate5a37791996-06-05 15:50:50 -0500632 png_ptr->do_filter &= ~PNG_FILTER_UP;
633 }
634 else
635 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500636 png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500637 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500638 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
Guy Schalnate5a37791996-06-05 15:50:50 -0500639 }
640 }
641
Andreas Dilger47a0c421997-05-16 02:46:07 -0500642 if (png_ptr->do_filter & PNG_FILTER_AVG && png_ptr->avg_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500643 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500644 if (png_ptr->prev_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500645 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500646 png_warning(png_ptr, "Can't add Average filter after starting");
Guy Schalnate5a37791996-06-05 15:50:50 -0500647 png_ptr->do_filter &= ~PNG_FILTER_AVG;
648 }
649 else
650 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500651 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500652 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500653 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
Guy Schalnate5a37791996-06-05 15:50:50 -0500654 }
655 }
656
Andreas Dilger47a0c421997-05-16 02:46:07 -0500657 if (png_ptr->do_filter & PNG_FILTER_PAETH &&
658 png_ptr->paeth_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500659 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500660 if (png_ptr->prev_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500661 {
662 png_warning(png_ptr, "Can't add Paeth filter after starting");
663 png_ptr->do_filter &= ~PNG_FILTER_PAETH;
664 }
665 else
666 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600667 png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500668 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500669 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
Guy Schalnate5a37791996-06-05 15:50:50 -0500670 }
671 }
672
673 if (png_ptr->do_filter == PNG_NO_FILTERS)
674 png_ptr->do_filter = PNG_FILTER_NONE;
675 }
676 }
677 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500678 png_error(png_ptr, "Unknown custom filter method");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500679}
680
Andreas Dilger47a0c421997-05-16 02:46:07 -0500681/* This allows us to influence the way in which libpng chooses the "best"
682 * filter for the current scanline. While the "minimum-sum-of-absolute-
683 * differences metric is relatively fast and effective, there is some
684 * question as to whether it can be improved upon by trying to keep the
685 * filtered data going to zlib more consistent, hopefully resulting in
686 * better compression. */
687#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
688void
689png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
690 int num_weights, png_doublep filter_weights,
691 png_doublep filter_costs)
692{
693 int i;
694
695 png_debug(1, "in png_set_filter_heuristics\n");
696 if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
697 {
698 png_warning(png_ptr, "Unknown filter heuristic method");
699 return;
700 }
701
702 if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
703 {
704 heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
705 }
706
707 if (num_weights < 0 || filter_weights == NULL ||
708 heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
709 {
710 num_weights = 0;
711 }
712
713 png_ptr->num_prev_filters = num_weights;
714 png_ptr->heuristic_method = heuristic_method;
715
716 if (num_weights > 0)
717 {
718 if (png_ptr->prev_filters == NULL)
719 {
720 png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
721 sizeof(png_byte) * num_weights);
722
723 /* To make sure that the weighting starts out fairly */
724 for (i = 0; i < num_weights; i++)
725 {
726 png_ptr->prev_filters[i] = 255;
727 }
728 }
729
730 if (png_ptr->filter_weights == NULL)
731 {
732 png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
733 sizeof(png_uint_16) * num_weights);
734
735 png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
736 sizeof(png_uint_16) * num_weights);
737
738 for (i = 0; i < num_weights; i++)
739 {
740 png_ptr->inv_filter_weights[i] =
741 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
742 }
743 }
744
745 for (i = 0; i < num_weights; i++)
746 {
747 if (filter_weights[i] < 0.0)
748 {
749 png_ptr->inv_filter_weights[i] =
750 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
751 }
752 else
753 {
754 png_ptr->inv_filter_weights[i] =
755 (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
756 png_ptr->filter_weights[i] =
757 (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
758 }
759 }
760 }
761
762 /* If, in the future, there are other filter methods, this would
763 * need to be based on png_ptr->filter.
764 */
765 if (png_ptr->filter_costs == NULL)
766 {
767 png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
768 sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
769
770 png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
771 sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
772
773 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
774 {
775 png_ptr->inv_filter_costs[i] =
776 png_ptr->filter_costs[i] = PNG_COST_FACTOR;
777 }
778 }
779
780 /* Here is where we set the relative costs of the different filters. We
781 * should take the desired compression level into account when setting
782 * the costs, so that Paeth, for instance, has a high relative cost at low
783 * compression levels, while it has a lower relative cost at higher
784 * compression settings. The filter types are in order of increasing
785 * relative cost, so it would be possible to do this with an algorithm.
786 */
787 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
788 {
789 if (filter_costs == NULL || filter_costs[i] < 0.0)
790 {
791 png_ptr->inv_filter_costs[i] =
792 png_ptr->filter_costs[i] = PNG_COST_FACTOR;
793 }
794 else if (filter_costs[i] >= 1.0)
795 {
796 png_ptr->inv_filter_costs[i] =
797 (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
798 png_ptr->filter_costs[i] =
799 (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
800 }
801 }
802}
803#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
804
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500805void
Guy Schalnat6d764711995-12-19 03:22:19 -0600806png_set_compression_level(png_structp png_ptr, int level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500807{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500808 png_debug(1, "in png_set_compression_level\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500809 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500810 png_ptr->zlib_level = level;
811}
812
813void
Guy Schalnat6d764711995-12-19 03:22:19 -0600814png_set_compression_mem_level(png_structp png_ptr, int mem_level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500815{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500816 png_debug(1, "in png_set_compression_mem_level\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500817 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600818 png_ptr->zlib_mem_level = mem_level;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500819}
820
821void
Guy Schalnat6d764711995-12-19 03:22:19 -0600822png_set_compression_strategy(png_structp png_ptr, int strategy)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500823{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500824 png_debug(1, "in png_set_compression_strategy\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500825 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500826 png_ptr->zlib_strategy = strategy;
827}
828
829void
Guy Schalnat6d764711995-12-19 03:22:19 -0600830png_set_compression_window_bits(png_structp png_ptr, int window_bits)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500831{
Guy Schalnate5a37791996-06-05 15:50:50 -0500832 if (window_bits > 15)
833 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
834 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500835 png_ptr->zlib_window_bits = window_bits;
836}
837
838void
Guy Schalnat6d764711995-12-19 03:22:19 -0600839png_set_compression_method(png_structp png_ptr, int method)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500840{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500841 png_debug(1, "in png_set_compression_method\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500842 if (method != 8)
843 png_warning(png_ptr, "Only compression method 8 is supported by PNG");
844 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500845 png_ptr->zlib_method = method;
Guy Schalnat0d580581995-07-20 02:43:20 -0500846}
847