17dd7cddfSDavid du Colombier
27dd7cddfSDavid du Colombier /* pngwutil.c - utilities to write a PNG file
37dd7cddfSDavid du Colombier *
4*593dc095SDavid du Colombier * libpng version 1.2.8 - December 3, 2004
57dd7cddfSDavid du Colombier * For conditions of distribution and use, see copyright notice in png.h
6*593dc095SDavid du Colombier * Copyright (c) 1998-2004 Glenn Randers-Pehrson
7*593dc095SDavid du Colombier * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8*593dc095SDavid du Colombier * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
97dd7cddfSDavid du Colombier */
107dd7cddfSDavid du Colombier
117dd7cddfSDavid du Colombier #define PNG_INTERNAL
127dd7cddfSDavid du Colombier #include "png.h"
13*593dc095SDavid du Colombier #ifdef PNG_WRITE_SUPPORTED
147dd7cddfSDavid du Colombier
157dd7cddfSDavid du Colombier /* Place a 32-bit number into a buffer in PNG byte order. We work
167dd7cddfSDavid du Colombier * with unsigned numbers for convenience, although one supported
177dd7cddfSDavid du Colombier * ancillary chunk uses signed (two's complement) numbers.
187dd7cddfSDavid du Colombier */
19*593dc095SDavid du Colombier void /* PRIVATE */
png_save_uint_32(png_bytep buf,png_uint_32 i)207dd7cddfSDavid du Colombier png_save_uint_32(png_bytep buf, png_uint_32 i)
217dd7cddfSDavid du Colombier {
227dd7cddfSDavid du Colombier buf[0] = (png_byte)((i >> 24) & 0xff);
237dd7cddfSDavid du Colombier buf[1] = (png_byte)((i >> 16) & 0xff);
247dd7cddfSDavid du Colombier buf[2] = (png_byte)((i >> 8) & 0xff);
257dd7cddfSDavid du Colombier buf[3] = (png_byte)(i & 0xff);
267dd7cddfSDavid du Colombier }
277dd7cddfSDavid du Colombier
28*593dc095SDavid du Colombier #if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
297dd7cddfSDavid du Colombier /* The png_save_int_32 function assumes integers are stored in two's
307dd7cddfSDavid du Colombier * complement format. If this isn't the case, then this routine needs to
317dd7cddfSDavid du Colombier * be modified to write data in two's complement format.
327dd7cddfSDavid du Colombier */
33*593dc095SDavid du Colombier void /* PRIVATE */
png_save_int_32(png_bytep buf,png_int_32 i)347dd7cddfSDavid du Colombier png_save_int_32(png_bytep buf, png_int_32 i)
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier buf[0] = (png_byte)((i >> 24) & 0xff);
377dd7cddfSDavid du Colombier buf[1] = (png_byte)((i >> 16) & 0xff);
387dd7cddfSDavid du Colombier buf[2] = (png_byte)((i >> 8) & 0xff);
397dd7cddfSDavid du Colombier buf[3] = (png_byte)(i & 0xff);
407dd7cddfSDavid du Colombier }
417dd7cddfSDavid du Colombier #endif
427dd7cddfSDavid du Colombier
437dd7cddfSDavid du Colombier /* Place a 16-bit number into a buffer in PNG byte order.
447dd7cddfSDavid du Colombier * The parameter is declared unsigned int, not png_uint_16,
457dd7cddfSDavid du Colombier * just to avoid potential problems on pre-ANSI C compilers.
467dd7cddfSDavid du Colombier */
47*593dc095SDavid du Colombier void /* PRIVATE */
png_save_uint_16(png_bytep buf,unsigned int i)487dd7cddfSDavid du Colombier png_save_uint_16(png_bytep buf, unsigned int i)
497dd7cddfSDavid du Colombier {
507dd7cddfSDavid du Colombier buf[0] = (png_byte)((i >> 8) & 0xff);
517dd7cddfSDavid du Colombier buf[1] = (png_byte)(i & 0xff);
527dd7cddfSDavid du Colombier }
537dd7cddfSDavid du Colombier
547dd7cddfSDavid du Colombier /* Write a PNG chunk all at once. The type is an array of ASCII characters
557dd7cddfSDavid du Colombier * representing the chunk name. The array must be at least 4 bytes in
567dd7cddfSDavid du Colombier * length, and does not need to be null terminated. To be safe, pass the
577dd7cddfSDavid du Colombier * pre-defined chunk names here, and if you need a new one, define it
587dd7cddfSDavid du Colombier * where the others are defined. The length is the length of the data.
597dd7cddfSDavid du Colombier * All the data must be present. If that is not possible, use the
607dd7cddfSDavid du Colombier * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
617dd7cddfSDavid du Colombier * functions instead.
627dd7cddfSDavid du Colombier */
63*593dc095SDavid du Colombier void PNGAPI
png_write_chunk(png_structp png_ptr,png_bytep chunk_name,png_bytep data,png_size_t length)647dd7cddfSDavid du Colombier png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
657dd7cddfSDavid du Colombier png_bytep data, png_size_t length)
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
687dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, data, length);
697dd7cddfSDavid du Colombier png_write_chunk_end(png_ptr);
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier
727dd7cddfSDavid du Colombier /* Write the start of a PNG chunk. The type is the chunk type.
737dd7cddfSDavid du Colombier * The total_length is the sum of the lengths of all the data you will be
747dd7cddfSDavid du Colombier * passing in png_write_chunk_data().
757dd7cddfSDavid du Colombier */
76*593dc095SDavid du Colombier void PNGAPI
png_write_chunk_start(png_structp png_ptr,png_bytep chunk_name,png_uint_32 length)777dd7cddfSDavid du Colombier png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
787dd7cddfSDavid du Colombier png_uint_32 length)
797dd7cddfSDavid du Colombier {
807dd7cddfSDavid du Colombier png_byte buf[4];
81*593dc095SDavid du Colombier png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length);
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier /* write the length */
847dd7cddfSDavid du Colombier png_save_uint_32(buf, length);
857dd7cddfSDavid du Colombier png_write_data(png_ptr, buf, (png_size_t)4);
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier /* write the chunk name */
887dd7cddfSDavid du Colombier png_write_data(png_ptr, chunk_name, (png_size_t)4);
897dd7cddfSDavid du Colombier /* reset the crc and run it over the chunk name */
907dd7cddfSDavid du Colombier png_reset_crc(png_ptr);
917dd7cddfSDavid du Colombier png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier /* Write the data of a PNG chunk started with png_write_chunk_start().
957dd7cddfSDavid du Colombier * Note that multiple calls to this function are allowed, and that the
967dd7cddfSDavid du Colombier * sum of the lengths from these calls *must* add up to the total_length
977dd7cddfSDavid du Colombier * given to png_write_chunk_start().
987dd7cddfSDavid du Colombier */
99*593dc095SDavid du Colombier void PNGAPI
png_write_chunk_data(png_structp png_ptr,png_bytep data,png_size_t length)1007dd7cddfSDavid du Colombier png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier /* write the data, and run the CRC over it */
1037dd7cddfSDavid du Colombier if (data != NULL && length > 0)
1047dd7cddfSDavid du Colombier {
1057dd7cddfSDavid du Colombier png_calculate_crc(png_ptr, data, length);
1067dd7cddfSDavid du Colombier png_write_data(png_ptr, data, length);
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier }
1097dd7cddfSDavid du Colombier
1107dd7cddfSDavid du Colombier /* Finish a chunk started with png_write_chunk_start(). */
111*593dc095SDavid du Colombier void PNGAPI
png_write_chunk_end(png_structp png_ptr)1127dd7cddfSDavid du Colombier png_write_chunk_end(png_structp png_ptr)
1137dd7cddfSDavid du Colombier {
1147dd7cddfSDavid du Colombier png_byte buf[4];
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier /* write the crc */
1177dd7cddfSDavid du Colombier png_save_uint_32(buf, png_ptr->crc);
1187dd7cddfSDavid du Colombier
1197dd7cddfSDavid du Colombier png_write_data(png_ptr, buf, (png_size_t)4);
1207dd7cddfSDavid du Colombier }
1217dd7cddfSDavid du Colombier
1227dd7cddfSDavid du Colombier /* Simple function to write the signature. If we have already written
1237dd7cddfSDavid du Colombier * the magic bytes of the signature, or more likely, the PNG stream is
1247dd7cddfSDavid du Colombier * being embedded into another stream and doesn't need its own signature,
1257dd7cddfSDavid du Colombier * we should call png_set_sig_bytes() to tell libpng how many of the
1267dd7cddfSDavid du Colombier * bytes have already been written.
1277dd7cddfSDavid du Colombier */
128*593dc095SDavid du Colombier void /* PRIVATE */
png_write_sig(png_structp png_ptr)1297dd7cddfSDavid du Colombier png_write_sig(png_structp png_ptr)
1307dd7cddfSDavid du Colombier {
131*593dc095SDavid du Colombier png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
1327dd7cddfSDavid du Colombier /* write the rest of the 8 byte signature */
133*593dc095SDavid du Colombier png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
1347dd7cddfSDavid du Colombier (png_size_t)8 - png_ptr->sig_bytes);
135*593dc095SDavid du Colombier if(png_ptr->sig_bytes < 3)
136*593dc095SDavid du Colombier png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier
139*593dc095SDavid du Colombier #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
140*593dc095SDavid du Colombier /*
141*593dc095SDavid du Colombier * This pair of functions encapsulates the operation of (a) compressing a
142*593dc095SDavid du Colombier * text string, and (b) issuing it later as a series of chunk data writes.
143*593dc095SDavid du Colombier * The compression_state structure is shared context for these functions
144*593dc095SDavid du Colombier * set up by the caller in order to make the whole mess thread-safe.
145*593dc095SDavid du Colombier */
146*593dc095SDavid du Colombier
147*593dc095SDavid du Colombier typedef struct
148*593dc095SDavid du Colombier {
149*593dc095SDavid du Colombier char *input; /* the uncompressed input data */
150*593dc095SDavid du Colombier int input_len; /* its length */
151*593dc095SDavid du Colombier int num_output_ptr; /* number of output pointers used */
152*593dc095SDavid du Colombier int max_output_ptr; /* size of output_ptr */
153*593dc095SDavid du Colombier png_charpp output_ptr; /* array of pointers to output */
154*593dc095SDavid du Colombier } compression_state;
155*593dc095SDavid du Colombier
156*593dc095SDavid du Colombier /* compress given text into storage in the png_ptr structure */
157*593dc095SDavid du Colombier static int /* PRIVATE */
png_text_compress(png_structp png_ptr,png_charp text,png_size_t text_len,int compression,compression_state * comp)158*593dc095SDavid du Colombier png_text_compress(png_structp png_ptr,
159*593dc095SDavid du Colombier png_charp text, png_size_t text_len, int compression,
160*593dc095SDavid du Colombier compression_state *comp)
161*593dc095SDavid du Colombier {
162*593dc095SDavid du Colombier int ret;
163*593dc095SDavid du Colombier
164*593dc095SDavid du Colombier comp->num_output_ptr = comp->max_output_ptr = 0;
165*593dc095SDavid du Colombier comp->output_ptr = NULL;
166*593dc095SDavid du Colombier comp->input = NULL;
167*593dc095SDavid du Colombier
168*593dc095SDavid du Colombier /* we may just want to pass the text right through */
169*593dc095SDavid du Colombier if (compression == PNG_TEXT_COMPRESSION_NONE)
170*593dc095SDavid du Colombier {
171*593dc095SDavid du Colombier comp->input = text;
172*593dc095SDavid du Colombier comp->input_len = text_len;
173*593dc095SDavid du Colombier return((int)text_len);
174*593dc095SDavid du Colombier }
175*593dc095SDavid du Colombier
176*593dc095SDavid du Colombier if (compression >= PNG_TEXT_COMPRESSION_LAST)
177*593dc095SDavid du Colombier {
178*593dc095SDavid du Colombier #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
179*593dc095SDavid du Colombier char msg[50];
180*593dc095SDavid du Colombier sprintf(msg, "Unknown compression type %d", compression);
181*593dc095SDavid du Colombier png_warning(png_ptr, msg);
182*593dc095SDavid du Colombier #else
183*593dc095SDavid du Colombier png_warning(png_ptr, "Unknown compression type");
184*593dc095SDavid du Colombier #endif
185*593dc095SDavid du Colombier }
186*593dc095SDavid du Colombier
187*593dc095SDavid du Colombier /* We can't write the chunk until we find out how much data we have,
188*593dc095SDavid du Colombier * which means we need to run the compressor first and save the
189*593dc095SDavid du Colombier * output. This shouldn't be a problem, as the vast majority of
190*593dc095SDavid du Colombier * comments should be reasonable, but we will set up an array of
191*593dc095SDavid du Colombier * malloc'd pointers to be sure.
192*593dc095SDavid du Colombier *
193*593dc095SDavid du Colombier * If we knew the application was well behaved, we could simplify this
194*593dc095SDavid du Colombier * greatly by assuming we can always malloc an output buffer large
195*593dc095SDavid du Colombier * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
196*593dc095SDavid du Colombier * and malloc this directly. The only time this would be a bad idea is
197*593dc095SDavid du Colombier * if we can't malloc more than 64K and we have 64K of random input
198*593dc095SDavid du Colombier * data, or if the input string is incredibly large (although this
199*593dc095SDavid du Colombier * wouldn't cause a failure, just a slowdown due to swapping).
200*593dc095SDavid du Colombier */
201*593dc095SDavid du Colombier
202*593dc095SDavid du Colombier /* set up the compression buffers */
203*593dc095SDavid du Colombier png_ptr->zstream.avail_in = (uInt)text_len;
204*593dc095SDavid du Colombier png_ptr->zstream.next_in = (Bytef *)text;
205*593dc095SDavid du Colombier png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
206*593dc095SDavid du Colombier png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
207*593dc095SDavid du Colombier
208*593dc095SDavid du Colombier /* this is the same compression loop as in png_write_row() */
209*593dc095SDavid du Colombier do
210*593dc095SDavid du Colombier {
211*593dc095SDavid du Colombier /* compress the data */
212*593dc095SDavid du Colombier ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
213*593dc095SDavid du Colombier if (ret != Z_OK)
214*593dc095SDavid du Colombier {
215*593dc095SDavid du Colombier /* error */
216*593dc095SDavid du Colombier if (png_ptr->zstream.msg != NULL)
217*593dc095SDavid du Colombier png_error(png_ptr, png_ptr->zstream.msg);
218*593dc095SDavid du Colombier else
219*593dc095SDavid du Colombier png_error(png_ptr, "zlib error");
220*593dc095SDavid du Colombier }
221*593dc095SDavid du Colombier /* check to see if we need more room */
222*593dc095SDavid du Colombier if (!(png_ptr->zstream.avail_out))
223*593dc095SDavid du Colombier {
224*593dc095SDavid du Colombier /* make sure the output array has room */
225*593dc095SDavid du Colombier if (comp->num_output_ptr >= comp->max_output_ptr)
226*593dc095SDavid du Colombier {
227*593dc095SDavid du Colombier int old_max;
228*593dc095SDavid du Colombier
229*593dc095SDavid du Colombier old_max = comp->max_output_ptr;
230*593dc095SDavid du Colombier comp->max_output_ptr = comp->num_output_ptr + 4;
231*593dc095SDavid du Colombier if (comp->output_ptr != NULL)
232*593dc095SDavid du Colombier {
233*593dc095SDavid du Colombier png_charpp old_ptr;
234*593dc095SDavid du Colombier
235*593dc095SDavid du Colombier old_ptr = comp->output_ptr;
236*593dc095SDavid du Colombier comp->output_ptr = (png_charpp)png_malloc(png_ptr,
237*593dc095SDavid du Colombier (png_uint_32)(comp->max_output_ptr *
238*593dc095SDavid du Colombier png_sizeof (png_charpp)));
239*593dc095SDavid du Colombier png_memcpy(comp->output_ptr, old_ptr, old_max
240*593dc095SDavid du Colombier * png_sizeof (png_charp));
241*593dc095SDavid du Colombier png_free(png_ptr, old_ptr);
242*593dc095SDavid du Colombier }
243*593dc095SDavid du Colombier else
244*593dc095SDavid du Colombier comp->output_ptr = (png_charpp)png_malloc(png_ptr,
245*593dc095SDavid du Colombier (png_uint_32)(comp->max_output_ptr *
246*593dc095SDavid du Colombier png_sizeof (png_charp)));
247*593dc095SDavid du Colombier }
248*593dc095SDavid du Colombier
249*593dc095SDavid du Colombier /* save the data */
250*593dc095SDavid du Colombier comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
251*593dc095SDavid du Colombier (png_uint_32)png_ptr->zbuf_size);
252*593dc095SDavid du Colombier png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
253*593dc095SDavid du Colombier png_ptr->zbuf_size);
254*593dc095SDavid du Colombier comp->num_output_ptr++;
255*593dc095SDavid du Colombier
256*593dc095SDavid du Colombier /* and reset the buffer */
257*593dc095SDavid du Colombier png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
258*593dc095SDavid du Colombier png_ptr->zstream.next_out = png_ptr->zbuf;
259*593dc095SDavid du Colombier }
260*593dc095SDavid du Colombier /* continue until we don't have any more to compress */
261*593dc095SDavid du Colombier } while (png_ptr->zstream.avail_in);
262*593dc095SDavid du Colombier
263*593dc095SDavid du Colombier /* finish the compression */
264*593dc095SDavid du Colombier do
265*593dc095SDavid du Colombier {
266*593dc095SDavid du Colombier /* tell zlib we are finished */
267*593dc095SDavid du Colombier ret = deflate(&png_ptr->zstream, Z_FINISH);
268*593dc095SDavid du Colombier
269*593dc095SDavid du Colombier if (ret == Z_OK)
270*593dc095SDavid du Colombier {
271*593dc095SDavid du Colombier /* check to see if we need more room */
272*593dc095SDavid du Colombier if (!(png_ptr->zstream.avail_out))
273*593dc095SDavid du Colombier {
274*593dc095SDavid du Colombier /* check to make sure our output array has room */
275*593dc095SDavid du Colombier if (comp->num_output_ptr >= comp->max_output_ptr)
276*593dc095SDavid du Colombier {
277*593dc095SDavid du Colombier int old_max;
278*593dc095SDavid du Colombier
279*593dc095SDavid du Colombier old_max = comp->max_output_ptr;
280*593dc095SDavid du Colombier comp->max_output_ptr = comp->num_output_ptr + 4;
281*593dc095SDavid du Colombier if (comp->output_ptr != NULL)
282*593dc095SDavid du Colombier {
283*593dc095SDavid du Colombier png_charpp old_ptr;
284*593dc095SDavid du Colombier
285*593dc095SDavid du Colombier old_ptr = comp->output_ptr;
286*593dc095SDavid du Colombier /* This could be optimized to realloc() */
287*593dc095SDavid du Colombier comp->output_ptr = (png_charpp)png_malloc(png_ptr,
288*593dc095SDavid du Colombier (png_uint_32)(comp->max_output_ptr *
289*593dc095SDavid du Colombier png_sizeof (png_charpp)));
290*593dc095SDavid du Colombier png_memcpy(comp->output_ptr, old_ptr,
291*593dc095SDavid du Colombier old_max * png_sizeof (png_charp));
292*593dc095SDavid du Colombier png_free(png_ptr, old_ptr);
293*593dc095SDavid du Colombier }
294*593dc095SDavid du Colombier else
295*593dc095SDavid du Colombier comp->output_ptr = (png_charpp)png_malloc(png_ptr,
296*593dc095SDavid du Colombier (png_uint_32)(comp->max_output_ptr *
297*593dc095SDavid du Colombier png_sizeof (png_charp)));
298*593dc095SDavid du Colombier }
299*593dc095SDavid du Colombier
300*593dc095SDavid du Colombier /* save off the data */
301*593dc095SDavid du Colombier comp->output_ptr[comp->num_output_ptr] =
302*593dc095SDavid du Colombier (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
303*593dc095SDavid du Colombier png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
304*593dc095SDavid du Colombier png_ptr->zbuf_size);
305*593dc095SDavid du Colombier comp->num_output_ptr++;
306*593dc095SDavid du Colombier
307*593dc095SDavid du Colombier /* and reset the buffer pointers */
308*593dc095SDavid du Colombier png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
309*593dc095SDavid du Colombier png_ptr->zstream.next_out = png_ptr->zbuf;
310*593dc095SDavid du Colombier }
311*593dc095SDavid du Colombier }
312*593dc095SDavid du Colombier else if (ret != Z_STREAM_END)
313*593dc095SDavid du Colombier {
314*593dc095SDavid du Colombier /* we got an error */
315*593dc095SDavid du Colombier if (png_ptr->zstream.msg != NULL)
316*593dc095SDavid du Colombier png_error(png_ptr, png_ptr->zstream.msg);
317*593dc095SDavid du Colombier else
318*593dc095SDavid du Colombier png_error(png_ptr, "zlib error");
319*593dc095SDavid du Colombier }
320*593dc095SDavid du Colombier } while (ret != Z_STREAM_END);
321*593dc095SDavid du Colombier
322*593dc095SDavid du Colombier /* text length is number of buffers plus last buffer */
323*593dc095SDavid du Colombier text_len = png_ptr->zbuf_size * comp->num_output_ptr;
324*593dc095SDavid du Colombier if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
325*593dc095SDavid du Colombier text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
326*593dc095SDavid du Colombier
327*593dc095SDavid du Colombier return((int)text_len);
328*593dc095SDavid du Colombier }
329*593dc095SDavid du Colombier
330*593dc095SDavid du Colombier /* ship the compressed text out via chunk writes */
331*593dc095SDavid du Colombier static void /* PRIVATE */
png_write_compressed_data_out(png_structp png_ptr,compression_state * comp)332*593dc095SDavid du Colombier png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
333*593dc095SDavid du Colombier {
334*593dc095SDavid du Colombier int i;
335*593dc095SDavid du Colombier
336*593dc095SDavid du Colombier /* handle the no-compression case */
337*593dc095SDavid du Colombier if (comp->input)
338*593dc095SDavid du Colombier {
339*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)comp->input,
340*593dc095SDavid du Colombier (png_size_t)comp->input_len);
341*593dc095SDavid du Colombier return;
342*593dc095SDavid du Colombier }
343*593dc095SDavid du Colombier
344*593dc095SDavid du Colombier /* write saved output buffers, if any */
345*593dc095SDavid du Colombier for (i = 0; i < comp->num_output_ptr; i++)
346*593dc095SDavid du Colombier {
347*593dc095SDavid du Colombier png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
348*593dc095SDavid du Colombier png_ptr->zbuf_size);
349*593dc095SDavid du Colombier png_free(png_ptr, comp->output_ptr[i]);
350*593dc095SDavid du Colombier comp->output_ptr[i]=NULL;
351*593dc095SDavid du Colombier }
352*593dc095SDavid du Colombier if (comp->max_output_ptr != 0)
353*593dc095SDavid du Colombier png_free(png_ptr, comp->output_ptr);
354*593dc095SDavid du Colombier comp->output_ptr=NULL;
355*593dc095SDavid du Colombier /* write anything left in zbuf */
356*593dc095SDavid du Colombier if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
357*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, png_ptr->zbuf,
358*593dc095SDavid du Colombier png_ptr->zbuf_size - png_ptr->zstream.avail_out);
359*593dc095SDavid du Colombier
360*593dc095SDavid du Colombier /* reset zlib for another zTXt/iTXt or image data */
361*593dc095SDavid du Colombier deflateReset(&png_ptr->zstream);
362*593dc095SDavid du Colombier png_ptr->zstream.data_type = Z_BINARY;
363*593dc095SDavid du Colombier }
364*593dc095SDavid du Colombier #endif
365*593dc095SDavid du Colombier
3667dd7cddfSDavid du Colombier /* Write the IHDR chunk, and update the png_struct with the necessary
3677dd7cddfSDavid du Colombier * information. Note that the rest of this code depends upon this
3687dd7cddfSDavid du Colombier * information being correct.
3697dd7cddfSDavid du Colombier */
370*593dc095SDavid du Colombier void /* PRIVATE */
png_write_IHDR(png_structp png_ptr,png_uint_32 width,png_uint_32 height,int bit_depth,int color_type,int compression_type,int filter_type,int interlace_type)3717dd7cddfSDavid du Colombier png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
3727dd7cddfSDavid du Colombier int bit_depth, int color_type, int compression_type, int filter_type,
3737dd7cddfSDavid du Colombier int interlace_type)
3747dd7cddfSDavid du Colombier {
375*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
376*593dc095SDavid du Colombier PNG_IHDR;
377*593dc095SDavid du Colombier #endif
3787dd7cddfSDavid du Colombier png_byte buf[13]; /* buffer to store the IHDR info */
3797dd7cddfSDavid du Colombier
3807dd7cddfSDavid du Colombier png_debug(1, "in png_write_IHDR\n");
3817dd7cddfSDavid du Colombier /* Check that we have valid input data from the application info */
3827dd7cddfSDavid du Colombier switch (color_type)
3837dd7cddfSDavid du Colombier {
3847dd7cddfSDavid du Colombier case PNG_COLOR_TYPE_GRAY:
3857dd7cddfSDavid du Colombier switch (bit_depth)
3867dd7cddfSDavid du Colombier {
3877dd7cddfSDavid du Colombier case 1:
3887dd7cddfSDavid du Colombier case 2:
3897dd7cddfSDavid du Colombier case 4:
3907dd7cddfSDavid du Colombier case 8:
3917dd7cddfSDavid du Colombier case 16: png_ptr->channels = 1; break;
3927dd7cddfSDavid du Colombier default: png_error(png_ptr,"Invalid bit depth for grayscale image");
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier break;
3957dd7cddfSDavid du Colombier case PNG_COLOR_TYPE_RGB:
3967dd7cddfSDavid du Colombier if (bit_depth != 8 && bit_depth != 16)
3977dd7cddfSDavid du Colombier png_error(png_ptr, "Invalid bit depth for RGB image");
3987dd7cddfSDavid du Colombier png_ptr->channels = 3;
3997dd7cddfSDavid du Colombier break;
4007dd7cddfSDavid du Colombier case PNG_COLOR_TYPE_PALETTE:
4017dd7cddfSDavid du Colombier switch (bit_depth)
4027dd7cddfSDavid du Colombier {
4037dd7cddfSDavid du Colombier case 1:
4047dd7cddfSDavid du Colombier case 2:
4057dd7cddfSDavid du Colombier case 4:
4067dd7cddfSDavid du Colombier case 8: png_ptr->channels = 1; break;
4077dd7cddfSDavid du Colombier default: png_error(png_ptr, "Invalid bit depth for paletted image");
4087dd7cddfSDavid du Colombier }
4097dd7cddfSDavid du Colombier break;
4107dd7cddfSDavid du Colombier case PNG_COLOR_TYPE_GRAY_ALPHA:
4117dd7cddfSDavid du Colombier if (bit_depth != 8 && bit_depth != 16)
4127dd7cddfSDavid du Colombier png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
4137dd7cddfSDavid du Colombier png_ptr->channels = 2;
4147dd7cddfSDavid du Colombier break;
4157dd7cddfSDavid du Colombier case PNG_COLOR_TYPE_RGB_ALPHA:
4167dd7cddfSDavid du Colombier if (bit_depth != 8 && bit_depth != 16)
4177dd7cddfSDavid du Colombier png_error(png_ptr, "Invalid bit depth for RGBA image");
4187dd7cddfSDavid du Colombier png_ptr->channels = 4;
4197dd7cddfSDavid du Colombier break;
4207dd7cddfSDavid du Colombier default:
4217dd7cddfSDavid du Colombier png_error(png_ptr, "Invalid image color type specified");
4227dd7cddfSDavid du Colombier }
4237dd7cddfSDavid du Colombier
4247dd7cddfSDavid du Colombier if (compression_type != PNG_COMPRESSION_TYPE_BASE)
4257dd7cddfSDavid du Colombier {
4267dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid compression type specified");
4277dd7cddfSDavid du Colombier compression_type = PNG_COMPRESSION_TYPE_BASE;
4287dd7cddfSDavid du Colombier }
4297dd7cddfSDavid du Colombier
430*593dc095SDavid du Colombier /* Write filter_method 64 (intrapixel differencing) only if
431*593dc095SDavid du Colombier * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
432*593dc095SDavid du Colombier * 2. Libpng did not write a PNG signature (this filter_method is only
433*593dc095SDavid du Colombier * used in PNG datastreams that are embedded in MNG datastreams) and
434*593dc095SDavid du Colombier * 3. The application called png_permit_mng_features with a mask that
435*593dc095SDavid du Colombier * included PNG_FLAG_MNG_FILTER_64 and
436*593dc095SDavid du Colombier * 4. The filter_method is 64 and
437*593dc095SDavid du Colombier * 5. The color_type is RGB or RGBA
438*593dc095SDavid du Colombier */
439*593dc095SDavid du Colombier if (
440*593dc095SDavid du Colombier #if defined(PNG_MNG_FEATURES_SUPPORTED)
441*593dc095SDavid du Colombier !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
442*593dc095SDavid du Colombier ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
443*593dc095SDavid du Colombier (color_type == PNG_COLOR_TYPE_RGB ||
444*593dc095SDavid du Colombier color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
445*593dc095SDavid du Colombier (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
446*593dc095SDavid du Colombier #endif
447*593dc095SDavid du Colombier filter_type != PNG_FILTER_TYPE_BASE)
4487dd7cddfSDavid du Colombier {
4497dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid filter type specified");
4507dd7cddfSDavid du Colombier filter_type = PNG_FILTER_TYPE_BASE;
4517dd7cddfSDavid du Colombier }
4527dd7cddfSDavid du Colombier
4537dd7cddfSDavid du Colombier #ifdef PNG_WRITE_INTERLACING_SUPPORTED
4547dd7cddfSDavid du Colombier if (interlace_type != PNG_INTERLACE_NONE &&
4557dd7cddfSDavid du Colombier interlace_type != PNG_INTERLACE_ADAM7)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid interlace type specified");
4587dd7cddfSDavid du Colombier interlace_type = PNG_INTERLACE_ADAM7;
4597dd7cddfSDavid du Colombier }
4607dd7cddfSDavid du Colombier #else
4617dd7cddfSDavid du Colombier interlace_type=PNG_INTERLACE_NONE;
4627dd7cddfSDavid du Colombier #endif
4637dd7cddfSDavid du Colombier
4647dd7cddfSDavid du Colombier /* save off the relevent information */
4657dd7cddfSDavid du Colombier png_ptr->bit_depth = (png_byte)bit_depth;
4667dd7cddfSDavid du Colombier png_ptr->color_type = (png_byte)color_type;
4677dd7cddfSDavid du Colombier png_ptr->interlaced = (png_byte)interlace_type;
468*593dc095SDavid du Colombier #if defined(PNG_MNG_FEATURES_SUPPORTED)
469*593dc095SDavid du Colombier png_ptr->filter_type = (png_byte)filter_type;
470*593dc095SDavid du Colombier #endif
471*593dc095SDavid du Colombier png_ptr->compression_type = (png_byte)compression_type;
4727dd7cddfSDavid du Colombier png_ptr->width = width;
4737dd7cddfSDavid du Colombier png_ptr->height = height;
4747dd7cddfSDavid du Colombier
4757dd7cddfSDavid du Colombier png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
476*593dc095SDavid du Colombier png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
4777dd7cddfSDavid du Colombier /* set the usr info, so any transformations can modify it */
4787dd7cddfSDavid du Colombier png_ptr->usr_width = png_ptr->width;
4797dd7cddfSDavid du Colombier png_ptr->usr_bit_depth = png_ptr->bit_depth;
4807dd7cddfSDavid du Colombier png_ptr->usr_channels = png_ptr->channels;
4817dd7cddfSDavid du Colombier
4827dd7cddfSDavid du Colombier /* pack the header information into the buffer */
4837dd7cddfSDavid du Colombier png_save_uint_32(buf, width);
4847dd7cddfSDavid du Colombier png_save_uint_32(buf + 4, height);
4857dd7cddfSDavid du Colombier buf[8] = (png_byte)bit_depth;
4867dd7cddfSDavid du Colombier buf[9] = (png_byte)color_type;
4877dd7cddfSDavid du Colombier buf[10] = (png_byte)compression_type;
4887dd7cddfSDavid du Colombier buf[11] = (png_byte)filter_type;
4897dd7cddfSDavid du Colombier buf[12] = (png_byte)interlace_type;
4907dd7cddfSDavid du Colombier
4917dd7cddfSDavid du Colombier /* write the chunk */
492*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
4937dd7cddfSDavid du Colombier
4947dd7cddfSDavid du Colombier /* initialize zlib with PNG info */
4957dd7cddfSDavid du Colombier png_ptr->zstream.zalloc = png_zalloc;
4967dd7cddfSDavid du Colombier png_ptr->zstream.zfree = png_zfree;
4977dd7cddfSDavid du Colombier png_ptr->zstream.opaque = (voidpf)png_ptr;
4987dd7cddfSDavid du Colombier if (!(png_ptr->do_filter))
4997dd7cddfSDavid du Colombier {
5007dd7cddfSDavid du Colombier if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
5017dd7cddfSDavid du Colombier png_ptr->bit_depth < 8)
5027dd7cddfSDavid du Colombier png_ptr->do_filter = PNG_FILTER_NONE;
5037dd7cddfSDavid du Colombier else
5047dd7cddfSDavid du Colombier png_ptr->do_filter = PNG_ALL_FILTERS;
5057dd7cddfSDavid du Colombier }
5067dd7cddfSDavid du Colombier if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
5077dd7cddfSDavid du Colombier {
5087dd7cddfSDavid du Colombier if (png_ptr->do_filter != PNG_FILTER_NONE)
5097dd7cddfSDavid du Colombier png_ptr->zlib_strategy = Z_FILTERED;
5107dd7cddfSDavid du Colombier else
5117dd7cddfSDavid du Colombier png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
5127dd7cddfSDavid du Colombier }
5137dd7cddfSDavid du Colombier if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
5147dd7cddfSDavid du Colombier png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
5157dd7cddfSDavid du Colombier if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
5167dd7cddfSDavid du Colombier png_ptr->zlib_mem_level = 8;
5177dd7cddfSDavid du Colombier if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
5187dd7cddfSDavid du Colombier png_ptr->zlib_window_bits = 15;
5197dd7cddfSDavid du Colombier if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
5207dd7cddfSDavid du Colombier png_ptr->zlib_method = 8;
5217dd7cddfSDavid du Colombier deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
5227dd7cddfSDavid du Colombier png_ptr->zlib_method, png_ptr->zlib_window_bits,
5237dd7cddfSDavid du Colombier png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
5247dd7cddfSDavid du Colombier png_ptr->zstream.next_out = png_ptr->zbuf;
5257dd7cddfSDavid du Colombier png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
526*593dc095SDavid du Colombier /* libpng is not interested in zstream.data_type */
527*593dc095SDavid du Colombier /* set it to a predefined value, to avoid its evaluation inside zlib */
528*593dc095SDavid du Colombier png_ptr->zstream.data_type = Z_BINARY;
5297dd7cddfSDavid du Colombier
5307dd7cddfSDavid du Colombier png_ptr->mode = PNG_HAVE_IHDR;
5317dd7cddfSDavid du Colombier }
5327dd7cddfSDavid du Colombier
5337dd7cddfSDavid du Colombier /* write the palette. We are careful not to trust png_color to be in the
534*593dc095SDavid du Colombier * correct order for PNG, so people can redefine it to any convenient
5357dd7cddfSDavid du Colombier * structure.
5367dd7cddfSDavid du Colombier */
537*593dc095SDavid du Colombier void /* PRIVATE */
png_write_PLTE(png_structp png_ptr,png_colorp palette,png_uint_32 num_pal)5387dd7cddfSDavid du Colombier png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
5397dd7cddfSDavid du Colombier {
540*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
541*593dc095SDavid du Colombier PNG_PLTE;
542*593dc095SDavid du Colombier #endif
5437dd7cddfSDavid du Colombier png_uint_32 i;
5447dd7cddfSDavid du Colombier png_colorp pal_ptr;
5457dd7cddfSDavid du Colombier png_byte buf[3];
5467dd7cddfSDavid du Colombier
5477dd7cddfSDavid du Colombier png_debug(1, "in png_write_PLTE\n");
548*593dc095SDavid du Colombier if ((
549*593dc095SDavid du Colombier #if defined(PNG_MNG_FEATURES_SUPPORTED)
550*593dc095SDavid du Colombier !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
551*593dc095SDavid du Colombier #endif
552*593dc095SDavid du Colombier num_pal == 0) || num_pal > 256)
5537dd7cddfSDavid du Colombier {
5547dd7cddfSDavid du Colombier if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
5557dd7cddfSDavid du Colombier {
5567dd7cddfSDavid du Colombier png_error(png_ptr, "Invalid number of colors in palette");
5577dd7cddfSDavid du Colombier }
5587dd7cddfSDavid du Colombier else
5597dd7cddfSDavid du Colombier {
5607dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid number of colors in palette");
5617dd7cddfSDavid du Colombier return;
5627dd7cddfSDavid du Colombier }
5637dd7cddfSDavid du Colombier }
5647dd7cddfSDavid du Colombier
565*593dc095SDavid du Colombier if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
566*593dc095SDavid du Colombier {
567*593dc095SDavid du Colombier png_warning(png_ptr,
568*593dc095SDavid du Colombier "Ignoring request to write a PLTE chunk in grayscale PNG");
569*593dc095SDavid du Colombier return;
570*593dc095SDavid du Colombier }
571*593dc095SDavid du Colombier
5727dd7cddfSDavid du Colombier png_ptr->num_palette = (png_uint_16)num_pal;
5737dd7cddfSDavid du Colombier png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
5747dd7cddfSDavid du Colombier
575*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
576*593dc095SDavid du Colombier #ifndef PNG_NO_POINTER_INDEXING
5777dd7cddfSDavid du Colombier for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
5787dd7cddfSDavid du Colombier {
5797dd7cddfSDavid du Colombier buf[0] = pal_ptr->red;
5807dd7cddfSDavid du Colombier buf[1] = pal_ptr->green;
5817dd7cddfSDavid du Colombier buf[2] = pal_ptr->blue;
5827dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, buf, (png_size_t)3);
5837dd7cddfSDavid du Colombier }
584*593dc095SDavid du Colombier #else
585*593dc095SDavid du Colombier /* This is a little slower but some buggy compilers need to do this instead */
586*593dc095SDavid du Colombier pal_ptr=palette;
587*593dc095SDavid du Colombier for (i = 0; i < num_pal; i++)
588*593dc095SDavid du Colombier {
589*593dc095SDavid du Colombier buf[0] = pal_ptr[i].red;
590*593dc095SDavid du Colombier buf[1] = pal_ptr[i].green;
591*593dc095SDavid du Colombier buf[2] = pal_ptr[i].blue;
592*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, buf, (png_size_t)3);
593*593dc095SDavid du Colombier }
594*593dc095SDavid du Colombier #endif
5957dd7cddfSDavid du Colombier png_write_chunk_end(png_ptr);
5967dd7cddfSDavid du Colombier png_ptr->mode |= PNG_HAVE_PLTE;
5977dd7cddfSDavid du Colombier }
5987dd7cddfSDavid du Colombier
5997dd7cddfSDavid du Colombier /* write an IDAT chunk */
600*593dc095SDavid du Colombier void /* PRIVATE */
png_write_IDAT(png_structp png_ptr,png_bytep data,png_size_t length)6017dd7cddfSDavid du Colombier png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
6027dd7cddfSDavid du Colombier {
603*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
604*593dc095SDavid du Colombier PNG_IDAT;
605*593dc095SDavid du Colombier #endif
6067dd7cddfSDavid du Colombier png_debug(1, "in png_write_IDAT\n");
607*593dc095SDavid du Colombier
608*593dc095SDavid du Colombier /* Optimize the CMF field in the zlib stream. */
609*593dc095SDavid du Colombier /* This hack of the zlib stream is compliant to the stream specification. */
610*593dc095SDavid du Colombier if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
611*593dc095SDavid du Colombier png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
612*593dc095SDavid du Colombier {
613*593dc095SDavid du Colombier unsigned int z_cmf = data[0]; /* zlib compression method and flags */
614*593dc095SDavid du Colombier if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
615*593dc095SDavid du Colombier {
616*593dc095SDavid du Colombier /* Avoid memory underflows and multiplication overflows. */
617*593dc095SDavid du Colombier /* The conditions below are practically always satisfied;
618*593dc095SDavid du Colombier however, they still must be checked. */
619*593dc095SDavid du Colombier if (length >= 2 &&
620*593dc095SDavid du Colombier png_ptr->height < 16384 && png_ptr->width < 16384)
621*593dc095SDavid du Colombier {
622*593dc095SDavid du Colombier png_uint_32 uncompressed_idat_size = png_ptr->height *
623*593dc095SDavid du Colombier ((png_ptr->width *
624*593dc095SDavid du Colombier png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
625*593dc095SDavid du Colombier unsigned int z_cinfo = z_cmf >> 4;
626*593dc095SDavid du Colombier unsigned int half_z_window_size = 1 << (z_cinfo + 7);
627*593dc095SDavid du Colombier while (uncompressed_idat_size <= half_z_window_size &&
628*593dc095SDavid du Colombier half_z_window_size >= 256)
629*593dc095SDavid du Colombier {
630*593dc095SDavid du Colombier z_cinfo--;
631*593dc095SDavid du Colombier half_z_window_size >>= 1;
632*593dc095SDavid du Colombier }
633*593dc095SDavid du Colombier z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
634*593dc095SDavid du Colombier if (data[0] != (png_byte)z_cmf)
635*593dc095SDavid du Colombier {
636*593dc095SDavid du Colombier data[0] = (png_byte)z_cmf;
637*593dc095SDavid du Colombier data[1] &= 0xe0;
638*593dc095SDavid du Colombier data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
639*593dc095SDavid du Colombier }
640*593dc095SDavid du Colombier }
641*593dc095SDavid du Colombier }
642*593dc095SDavid du Colombier else
643*593dc095SDavid du Colombier png_error(png_ptr,
644*593dc095SDavid du Colombier "Invalid zlib compression method or flags in IDAT");
645*593dc095SDavid du Colombier }
646*593dc095SDavid du Colombier
647*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
6487dd7cddfSDavid du Colombier png_ptr->mode |= PNG_HAVE_IDAT;
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier
6517dd7cddfSDavid du Colombier /* write an IEND chunk */
652*593dc095SDavid du Colombier void /* PRIVATE */
png_write_IEND(png_structp png_ptr)6537dd7cddfSDavid du Colombier png_write_IEND(png_structp png_ptr)
6547dd7cddfSDavid du Colombier {
655*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
656*593dc095SDavid du Colombier PNG_IEND;
657*593dc095SDavid du Colombier #endif
6587dd7cddfSDavid du Colombier png_debug(1, "in png_write_IEND\n");
659*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL,
660*593dc095SDavid du Colombier (png_size_t)0);
6617dd7cddfSDavid du Colombier png_ptr->mode |= PNG_HAVE_IEND;
6627dd7cddfSDavid du Colombier }
6637dd7cddfSDavid du Colombier
6647dd7cddfSDavid du Colombier #if defined(PNG_WRITE_gAMA_SUPPORTED)
6657dd7cddfSDavid du Colombier /* write a gAMA chunk */
666*593dc095SDavid du Colombier #ifdef PNG_FLOATING_POINT_SUPPORTED
667*593dc095SDavid du Colombier void /* PRIVATE */
png_write_gAMA(png_structp png_ptr,double file_gamma)6687dd7cddfSDavid du Colombier png_write_gAMA(png_structp png_ptr, double file_gamma)
6697dd7cddfSDavid du Colombier {
670*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
671*593dc095SDavid du Colombier PNG_gAMA;
672*593dc095SDavid du Colombier #endif
6737dd7cddfSDavid du Colombier png_uint_32 igamma;
6747dd7cddfSDavid du Colombier png_byte buf[4];
6757dd7cddfSDavid du Colombier
6767dd7cddfSDavid du Colombier png_debug(1, "in png_write_gAMA\n");
6777dd7cddfSDavid du Colombier /* file_gamma is saved in 1/100,000ths */
6787dd7cddfSDavid du Colombier igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
6797dd7cddfSDavid du Colombier png_save_uint_32(buf, igamma);
680*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
6817dd7cddfSDavid du Colombier }
6827dd7cddfSDavid du Colombier #endif
683*593dc095SDavid du Colombier #ifdef PNG_FIXED_POINT_SUPPORTED
684*593dc095SDavid du Colombier void /* PRIVATE */
png_write_gAMA_fixed(png_structp png_ptr,png_fixed_point file_gamma)685*593dc095SDavid du Colombier png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
686*593dc095SDavid du Colombier {
687*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
688*593dc095SDavid du Colombier PNG_gAMA;
689*593dc095SDavid du Colombier #endif
690*593dc095SDavid du Colombier png_byte buf[4];
691*593dc095SDavid du Colombier
692*593dc095SDavid du Colombier png_debug(1, "in png_write_gAMA\n");
693*593dc095SDavid du Colombier /* file_gamma is saved in 1/100,000ths */
694*593dc095SDavid du Colombier png_save_uint_32(buf, (png_uint_32)file_gamma);
695*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
696*593dc095SDavid du Colombier }
697*593dc095SDavid du Colombier #endif
698*593dc095SDavid du Colombier #endif
6997dd7cddfSDavid du Colombier
7007dd7cddfSDavid du Colombier #if defined(PNG_WRITE_sRGB_SUPPORTED)
7017dd7cddfSDavid du Colombier /* write a sRGB chunk */
702*593dc095SDavid du Colombier void /* PRIVATE */
png_write_sRGB(png_structp png_ptr,int srgb_intent)7037dd7cddfSDavid du Colombier png_write_sRGB(png_structp png_ptr, int srgb_intent)
7047dd7cddfSDavid du Colombier {
705*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
706*593dc095SDavid du Colombier PNG_sRGB;
707*593dc095SDavid du Colombier #endif
7087dd7cddfSDavid du Colombier png_byte buf[1];
7097dd7cddfSDavid du Colombier
7107dd7cddfSDavid du Colombier png_debug(1, "in png_write_sRGB\n");
7117dd7cddfSDavid du Colombier if(srgb_intent >= PNG_sRGB_INTENT_LAST)
7127dd7cddfSDavid du Colombier png_warning(png_ptr,
7137dd7cddfSDavid du Colombier "Invalid sRGB rendering intent specified");
7147dd7cddfSDavid du Colombier buf[0]=(png_byte)srgb_intent;
715*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
716*593dc095SDavid du Colombier }
717*593dc095SDavid du Colombier #endif
718*593dc095SDavid du Colombier
719*593dc095SDavid du Colombier #if defined(PNG_WRITE_iCCP_SUPPORTED)
720*593dc095SDavid du Colombier /* write an iCCP chunk */
721*593dc095SDavid du Colombier void /* PRIVATE */
png_write_iCCP(png_structp png_ptr,png_charp name,int compression_type,png_charp profile,int profile_len)722*593dc095SDavid du Colombier png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
723*593dc095SDavid du Colombier png_charp profile, int profile_len)
724*593dc095SDavid du Colombier {
725*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
726*593dc095SDavid du Colombier PNG_iCCP;
727*593dc095SDavid du Colombier #endif
728*593dc095SDavid du Colombier png_size_t name_len;
729*593dc095SDavid du Colombier png_charp new_name;
730*593dc095SDavid du Colombier compression_state comp;
731*593dc095SDavid du Colombier
732*593dc095SDavid du Colombier png_debug(1, "in png_write_iCCP\n");
733*593dc095SDavid du Colombier if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
734*593dc095SDavid du Colombier &new_name)) == 0)
735*593dc095SDavid du Colombier {
736*593dc095SDavid du Colombier png_warning(png_ptr, "Empty keyword in iCCP chunk");
737*593dc095SDavid du Colombier return;
738*593dc095SDavid du Colombier }
739*593dc095SDavid du Colombier
740*593dc095SDavid du Colombier if (compression_type != PNG_COMPRESSION_TYPE_BASE)
741*593dc095SDavid du Colombier png_warning(png_ptr, "Unknown compression type in iCCP chunk");
742*593dc095SDavid du Colombier
743*593dc095SDavid du Colombier if (profile == NULL)
744*593dc095SDavid du Colombier profile_len = 0;
745*593dc095SDavid du Colombier
746*593dc095SDavid du Colombier if (profile_len)
747*593dc095SDavid du Colombier profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
748*593dc095SDavid du Colombier PNG_COMPRESSION_TYPE_BASE, &comp);
749*593dc095SDavid du Colombier
750*593dc095SDavid du Colombier /* make sure we include the NULL after the name and the compression type */
751*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
752*593dc095SDavid du Colombier (png_uint_32)name_len+profile_len+2);
753*593dc095SDavid du Colombier new_name[name_len+1]=0x00;
754*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2);
755*593dc095SDavid du Colombier
756*593dc095SDavid du Colombier if (profile_len)
757*593dc095SDavid du Colombier png_write_compressed_data_out(png_ptr, &comp);
758*593dc095SDavid du Colombier
759*593dc095SDavid du Colombier png_write_chunk_end(png_ptr);
760*593dc095SDavid du Colombier png_free(png_ptr, new_name);
761*593dc095SDavid du Colombier }
762*593dc095SDavid du Colombier #endif
763*593dc095SDavid du Colombier
764*593dc095SDavid du Colombier #if defined(PNG_WRITE_sPLT_SUPPORTED)
765*593dc095SDavid du Colombier /* write a sPLT chunk */
766*593dc095SDavid du Colombier void /* PRIVATE */
png_write_sPLT(png_structp png_ptr,png_sPLT_tp spalette)767*593dc095SDavid du Colombier png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
768*593dc095SDavid du Colombier {
769*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
770*593dc095SDavid du Colombier PNG_sPLT;
771*593dc095SDavid du Colombier #endif
772*593dc095SDavid du Colombier png_size_t name_len;
773*593dc095SDavid du Colombier png_charp new_name;
774*593dc095SDavid du Colombier png_byte entrybuf[10];
775*593dc095SDavid du Colombier int entry_size = (spalette->depth == 8 ? 6 : 10);
776*593dc095SDavid du Colombier int palette_size = entry_size * spalette->nentries;
777*593dc095SDavid du Colombier png_sPLT_entryp ep;
778*593dc095SDavid du Colombier #ifdef PNG_NO_POINTER_INDEXING
779*593dc095SDavid du Colombier int i;
780*593dc095SDavid du Colombier #endif
781*593dc095SDavid du Colombier
782*593dc095SDavid du Colombier png_debug(1, "in png_write_sPLT\n");
783*593dc095SDavid du Colombier if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
784*593dc095SDavid du Colombier spalette->name, &new_name))==0)
785*593dc095SDavid du Colombier {
786*593dc095SDavid du Colombier png_warning(png_ptr, "Empty keyword in sPLT chunk");
787*593dc095SDavid du Colombier return;
788*593dc095SDavid du Colombier }
789*593dc095SDavid du Colombier
790*593dc095SDavid du Colombier /* make sure we include the NULL after the name */
791*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
792*593dc095SDavid du Colombier (png_uint_32)(name_len + 2 + palette_size));
793*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
794*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
795*593dc095SDavid du Colombier
796*593dc095SDavid du Colombier /* loop through each palette entry, writing appropriately */
797*593dc095SDavid du Colombier #ifndef PNG_NO_POINTER_INDEXING
798*593dc095SDavid du Colombier for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
799*593dc095SDavid du Colombier {
800*593dc095SDavid du Colombier if (spalette->depth == 8)
801*593dc095SDavid du Colombier {
802*593dc095SDavid du Colombier entrybuf[0] = (png_byte)ep->red;
803*593dc095SDavid du Colombier entrybuf[1] = (png_byte)ep->green;
804*593dc095SDavid du Colombier entrybuf[2] = (png_byte)ep->blue;
805*593dc095SDavid du Colombier entrybuf[3] = (png_byte)ep->alpha;
806*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 4, ep->frequency);
807*593dc095SDavid du Colombier }
808*593dc095SDavid du Colombier else
809*593dc095SDavid du Colombier {
810*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 0, ep->red);
811*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 2, ep->green);
812*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 4, ep->blue);
813*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 6, ep->alpha);
814*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 8, ep->frequency);
815*593dc095SDavid du Colombier }
816*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
817*593dc095SDavid du Colombier }
818*593dc095SDavid du Colombier #else
819*593dc095SDavid du Colombier ep=spalette->entries;
820*593dc095SDavid du Colombier for (i=0; i>spalette->nentries; i++)
821*593dc095SDavid du Colombier {
822*593dc095SDavid du Colombier if (spalette->depth == 8)
823*593dc095SDavid du Colombier {
824*593dc095SDavid du Colombier entrybuf[0] = (png_byte)ep[i].red;
825*593dc095SDavid du Colombier entrybuf[1] = (png_byte)ep[i].green;
826*593dc095SDavid du Colombier entrybuf[2] = (png_byte)ep[i].blue;
827*593dc095SDavid du Colombier entrybuf[3] = (png_byte)ep[i].alpha;
828*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 4, ep[i].frequency);
829*593dc095SDavid du Colombier }
830*593dc095SDavid du Colombier else
831*593dc095SDavid du Colombier {
832*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 0, ep[i].red);
833*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 2, ep[i].green);
834*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 4, ep[i].blue);
835*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 6, ep[i].alpha);
836*593dc095SDavid du Colombier png_save_uint_16(entrybuf + 8, ep[i].frequency);
837*593dc095SDavid du Colombier }
838*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, entrybuf, entry_size);
839*593dc095SDavid du Colombier }
840*593dc095SDavid du Colombier #endif
841*593dc095SDavid du Colombier
842*593dc095SDavid du Colombier png_write_chunk_end(png_ptr);
843*593dc095SDavid du Colombier png_free(png_ptr, new_name);
8447dd7cddfSDavid du Colombier }
8457dd7cddfSDavid du Colombier #endif
8467dd7cddfSDavid du Colombier
8477dd7cddfSDavid du Colombier #if defined(PNG_WRITE_sBIT_SUPPORTED)
8487dd7cddfSDavid du Colombier /* write the sBIT chunk */
849*593dc095SDavid du Colombier void /* PRIVATE */
png_write_sBIT(png_structp png_ptr,png_color_8p sbit,int color_type)8507dd7cddfSDavid du Colombier png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
8517dd7cddfSDavid du Colombier {
852*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
853*593dc095SDavid du Colombier PNG_sBIT;
854*593dc095SDavid du Colombier #endif
8557dd7cddfSDavid du Colombier png_byte buf[4];
8567dd7cddfSDavid du Colombier png_size_t size;
8577dd7cddfSDavid du Colombier
8587dd7cddfSDavid du Colombier png_debug(1, "in png_write_sBIT\n");
8597dd7cddfSDavid du Colombier /* make sure we don't depend upon the order of PNG_COLOR_8 */
8607dd7cddfSDavid du Colombier if (color_type & PNG_COLOR_MASK_COLOR)
8617dd7cddfSDavid du Colombier {
8627dd7cddfSDavid du Colombier png_byte maxbits;
8637dd7cddfSDavid du Colombier
864*593dc095SDavid du Colombier maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
865*593dc095SDavid du Colombier png_ptr->usr_bit_depth);
8667dd7cddfSDavid du Colombier if (sbit->red == 0 || sbit->red > maxbits ||
8677dd7cddfSDavid du Colombier sbit->green == 0 || sbit->green > maxbits ||
8687dd7cddfSDavid du Colombier sbit->blue == 0 || sbit->blue > maxbits)
8697dd7cddfSDavid du Colombier {
8707dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid sBIT depth specified");
8717dd7cddfSDavid du Colombier return;
8727dd7cddfSDavid du Colombier }
8737dd7cddfSDavid du Colombier buf[0] = sbit->red;
8747dd7cddfSDavid du Colombier buf[1] = sbit->green;
8757dd7cddfSDavid du Colombier buf[2] = sbit->blue;
8767dd7cddfSDavid du Colombier size = 3;
8777dd7cddfSDavid du Colombier }
8787dd7cddfSDavid du Colombier else
8797dd7cddfSDavid du Colombier {
8807dd7cddfSDavid du Colombier if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
8817dd7cddfSDavid du Colombier {
8827dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid sBIT depth specified");
8837dd7cddfSDavid du Colombier return;
8847dd7cddfSDavid du Colombier }
8857dd7cddfSDavid du Colombier buf[0] = sbit->gray;
8867dd7cddfSDavid du Colombier size = 1;
8877dd7cddfSDavid du Colombier }
8887dd7cddfSDavid du Colombier
8897dd7cddfSDavid du Colombier if (color_type & PNG_COLOR_MASK_ALPHA)
8907dd7cddfSDavid du Colombier {
8917dd7cddfSDavid du Colombier if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
8927dd7cddfSDavid du Colombier {
8937dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid sBIT depth specified");
8947dd7cddfSDavid du Colombier return;
8957dd7cddfSDavid du Colombier }
8967dd7cddfSDavid du Colombier buf[size++] = sbit->alpha;
8977dd7cddfSDavid du Colombier }
8987dd7cddfSDavid du Colombier
899*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
9007dd7cddfSDavid du Colombier }
9017dd7cddfSDavid du Colombier #endif
9027dd7cddfSDavid du Colombier
9037dd7cddfSDavid du Colombier #if defined(PNG_WRITE_cHRM_SUPPORTED)
9047dd7cddfSDavid du Colombier /* write the cHRM chunk */
905*593dc095SDavid du Colombier #ifdef PNG_FLOATING_POINT_SUPPORTED
906*593dc095SDavid du Colombier void /* PRIVATE */
png_write_cHRM(png_structp png_ptr,double white_x,double white_y,double red_x,double red_y,double green_x,double green_y,double blue_x,double blue_y)9077dd7cddfSDavid du Colombier png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
9087dd7cddfSDavid du Colombier double red_x, double red_y, double green_x, double green_y,
9097dd7cddfSDavid du Colombier double blue_x, double blue_y)
9107dd7cddfSDavid du Colombier {
911*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
912*593dc095SDavid du Colombier PNG_cHRM;
913*593dc095SDavid du Colombier #endif
9147dd7cddfSDavid du Colombier png_byte buf[32];
915*593dc095SDavid du Colombier png_uint_32 itemp;
9167dd7cddfSDavid du Colombier
9177dd7cddfSDavid du Colombier png_debug(1, "in png_write_cHRM\n");
918*593dc095SDavid du Colombier /* each value is saved in 1/100,000ths */
9197dd7cddfSDavid du Colombier if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
9207dd7cddfSDavid du Colombier white_x + white_y > 1.0)
9217dd7cddfSDavid du Colombier {
9227dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid cHRM white point specified");
923*593dc095SDavid du Colombier #if !defined(PNG_NO_CONSOLE_IO)
924*593dc095SDavid du Colombier fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
925*593dc095SDavid du Colombier #endif
9267dd7cddfSDavid du Colombier return;
9277dd7cddfSDavid du Colombier }
9287dd7cddfSDavid du Colombier itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
9297dd7cddfSDavid du Colombier png_save_uint_32(buf, itemp);
9307dd7cddfSDavid du Colombier itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
9317dd7cddfSDavid du Colombier png_save_uint_32(buf + 4, itemp);
9327dd7cddfSDavid du Colombier
9337dd7cddfSDavid du Colombier if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
9347dd7cddfSDavid du Colombier red_x + red_y > 1.0)
9357dd7cddfSDavid du Colombier {
9367dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid cHRM red point specified");
9377dd7cddfSDavid du Colombier return;
9387dd7cddfSDavid du Colombier }
9397dd7cddfSDavid du Colombier itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
9407dd7cddfSDavid du Colombier png_save_uint_32(buf + 8, itemp);
9417dd7cddfSDavid du Colombier itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
9427dd7cddfSDavid du Colombier png_save_uint_32(buf + 12, itemp);
9437dd7cddfSDavid du Colombier
9447dd7cddfSDavid du Colombier if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
9457dd7cddfSDavid du Colombier green_x + green_y > 1.0)
9467dd7cddfSDavid du Colombier {
9477dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid cHRM green point specified");
9487dd7cddfSDavid du Colombier return;
9497dd7cddfSDavid du Colombier }
9507dd7cddfSDavid du Colombier itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
9517dd7cddfSDavid du Colombier png_save_uint_32(buf + 16, itemp);
9527dd7cddfSDavid du Colombier itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
9537dd7cddfSDavid du Colombier png_save_uint_32(buf + 20, itemp);
9547dd7cddfSDavid du Colombier
9557dd7cddfSDavid du Colombier if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
9567dd7cddfSDavid du Colombier blue_x + blue_y > 1.0)
9577dd7cddfSDavid du Colombier {
9587dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid cHRM blue point specified");
9597dd7cddfSDavid du Colombier return;
9607dd7cddfSDavid du Colombier }
9617dd7cddfSDavid du Colombier itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
9627dd7cddfSDavid du Colombier png_save_uint_32(buf + 24, itemp);
9637dd7cddfSDavid du Colombier itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
9647dd7cddfSDavid du Colombier png_save_uint_32(buf + 28, itemp);
9657dd7cddfSDavid du Colombier
966*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
9677dd7cddfSDavid du Colombier }
9687dd7cddfSDavid du Colombier #endif
969*593dc095SDavid du Colombier #ifdef PNG_FIXED_POINT_SUPPORTED
970*593dc095SDavid du Colombier void /* PRIVATE */
png_write_cHRM_fixed(png_structp png_ptr,png_fixed_point white_x,png_fixed_point white_y,png_fixed_point red_x,png_fixed_point red_y,png_fixed_point green_x,png_fixed_point green_y,png_fixed_point blue_x,png_fixed_point blue_y)971*593dc095SDavid du Colombier png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x,
972*593dc095SDavid du Colombier png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y,
973*593dc095SDavid du Colombier png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x,
974*593dc095SDavid du Colombier png_fixed_point blue_y)
975*593dc095SDavid du Colombier {
976*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
977*593dc095SDavid du Colombier PNG_cHRM;
978*593dc095SDavid du Colombier #endif
979*593dc095SDavid du Colombier png_byte buf[32];
980*593dc095SDavid du Colombier
981*593dc095SDavid du Colombier png_debug(1, "in png_write_cHRM\n");
982*593dc095SDavid du Colombier /* each value is saved in 1/100,000ths */
983*593dc095SDavid du Colombier if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
984*593dc095SDavid du Colombier {
985*593dc095SDavid du Colombier png_warning(png_ptr, "Invalid fixed cHRM white point specified");
986*593dc095SDavid du Colombier #if !defined(PNG_NO_CONSOLE_IO)
987*593dc095SDavid du Colombier fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
988*593dc095SDavid du Colombier #endif
989*593dc095SDavid du Colombier return;
990*593dc095SDavid du Colombier }
991*593dc095SDavid du Colombier png_save_uint_32(buf, (png_uint_32)white_x);
992*593dc095SDavid du Colombier png_save_uint_32(buf + 4, (png_uint_32)white_y);
993*593dc095SDavid du Colombier
994*593dc095SDavid du Colombier if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L)
995*593dc095SDavid du Colombier {
996*593dc095SDavid du Colombier png_warning(png_ptr, "Invalid cHRM fixed red point specified");
997*593dc095SDavid du Colombier return;
998*593dc095SDavid du Colombier }
999*593dc095SDavid du Colombier png_save_uint_32(buf + 8, (png_uint_32)red_x);
1000*593dc095SDavid du Colombier png_save_uint_32(buf + 12, (png_uint_32)red_y);
1001*593dc095SDavid du Colombier
1002*593dc095SDavid du Colombier if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L)
1003*593dc095SDavid du Colombier {
1004*593dc095SDavid du Colombier png_warning(png_ptr, "Invalid fixed cHRM green point specified");
1005*593dc095SDavid du Colombier return;
1006*593dc095SDavid du Colombier }
1007*593dc095SDavid du Colombier png_save_uint_32(buf + 16, (png_uint_32)green_x);
1008*593dc095SDavid du Colombier png_save_uint_32(buf + 20, (png_uint_32)green_y);
1009*593dc095SDavid du Colombier
1010*593dc095SDavid du Colombier if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L)
1011*593dc095SDavid du Colombier {
1012*593dc095SDavid du Colombier png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
1013*593dc095SDavid du Colombier return;
1014*593dc095SDavid du Colombier }
1015*593dc095SDavid du Colombier png_save_uint_32(buf + 24, (png_uint_32)blue_x);
1016*593dc095SDavid du Colombier png_save_uint_32(buf + 28, (png_uint_32)blue_y);
1017*593dc095SDavid du Colombier
1018*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
1019*593dc095SDavid du Colombier }
1020*593dc095SDavid du Colombier #endif
1021*593dc095SDavid du Colombier #endif
10227dd7cddfSDavid du Colombier
10237dd7cddfSDavid du Colombier #if defined(PNG_WRITE_tRNS_SUPPORTED)
10247dd7cddfSDavid du Colombier /* write the tRNS chunk */
1025*593dc095SDavid du Colombier void /* PRIVATE */
png_write_tRNS(png_structp png_ptr,png_bytep trans,png_color_16p tran,int num_trans,int color_type)10267dd7cddfSDavid du Colombier png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
10277dd7cddfSDavid du Colombier int num_trans, int color_type)
10287dd7cddfSDavid du Colombier {
1029*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1030*593dc095SDavid du Colombier PNG_tRNS;
1031*593dc095SDavid du Colombier #endif
10327dd7cddfSDavid du Colombier png_byte buf[6];
10337dd7cddfSDavid du Colombier
10347dd7cddfSDavid du Colombier png_debug(1, "in png_write_tRNS\n");
10357dd7cddfSDavid du Colombier if (color_type == PNG_COLOR_TYPE_PALETTE)
10367dd7cddfSDavid du Colombier {
1037*593dc095SDavid du Colombier if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
10387dd7cddfSDavid du Colombier {
10397dd7cddfSDavid du Colombier png_warning(png_ptr,"Invalid number of transparent colors specified");
10407dd7cddfSDavid du Colombier return;
10417dd7cddfSDavid du Colombier }
10427dd7cddfSDavid du Colombier /* write the chunk out as it is */
1043*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
10447dd7cddfSDavid du Colombier }
10457dd7cddfSDavid du Colombier else if (color_type == PNG_COLOR_TYPE_GRAY)
10467dd7cddfSDavid du Colombier {
10477dd7cddfSDavid du Colombier /* one 16 bit value */
1048*593dc095SDavid du Colombier if(tran->gray >= (1 << png_ptr->bit_depth))
1049*593dc095SDavid du Colombier {
1050*593dc095SDavid du Colombier png_warning(png_ptr,
1051*593dc095SDavid du Colombier "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
1052*593dc095SDavid du Colombier return;
1053*593dc095SDavid du Colombier }
10547dd7cddfSDavid du Colombier png_save_uint_16(buf, tran->gray);
1055*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
10567dd7cddfSDavid du Colombier }
10577dd7cddfSDavid du Colombier else if (color_type == PNG_COLOR_TYPE_RGB)
10587dd7cddfSDavid du Colombier {
10597dd7cddfSDavid du Colombier /* three 16 bit values */
10607dd7cddfSDavid du Colombier png_save_uint_16(buf, tran->red);
10617dd7cddfSDavid du Colombier png_save_uint_16(buf + 2, tran->green);
10627dd7cddfSDavid du Colombier png_save_uint_16(buf + 4, tran->blue);
1063*593dc095SDavid du Colombier if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1064*593dc095SDavid du Colombier {
1065*593dc095SDavid du Colombier png_warning(png_ptr,
1066*593dc095SDavid du Colombier "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
1067*593dc095SDavid du Colombier return;
1068*593dc095SDavid du Colombier }
1069*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
10707dd7cddfSDavid du Colombier }
10717dd7cddfSDavid du Colombier else
10727dd7cddfSDavid du Colombier {
10737dd7cddfSDavid du Colombier png_warning(png_ptr, "Can't write tRNS with an alpha channel");
10747dd7cddfSDavid du Colombier }
10757dd7cddfSDavid du Colombier }
10767dd7cddfSDavid du Colombier #endif
10777dd7cddfSDavid du Colombier
10787dd7cddfSDavid du Colombier #if defined(PNG_WRITE_bKGD_SUPPORTED)
10797dd7cddfSDavid du Colombier /* write the background chunk */
1080*593dc095SDavid du Colombier void /* PRIVATE */
png_write_bKGD(png_structp png_ptr,png_color_16p back,int color_type)10817dd7cddfSDavid du Colombier png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
10827dd7cddfSDavid du Colombier {
1083*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1084*593dc095SDavid du Colombier PNG_bKGD;
1085*593dc095SDavid du Colombier #endif
10867dd7cddfSDavid du Colombier png_byte buf[6];
10877dd7cddfSDavid du Colombier
10887dd7cddfSDavid du Colombier png_debug(1, "in png_write_bKGD\n");
10897dd7cddfSDavid du Colombier if (color_type == PNG_COLOR_TYPE_PALETTE)
10907dd7cddfSDavid du Colombier {
1091*593dc095SDavid du Colombier if (
1092*593dc095SDavid du Colombier #if defined(PNG_MNG_FEATURES_SUPPORTED)
1093*593dc095SDavid du Colombier (png_ptr->num_palette ||
1094*593dc095SDavid du Colombier (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
1095*593dc095SDavid du Colombier #endif
1096*593dc095SDavid du Colombier back->index > png_ptr->num_palette)
10977dd7cddfSDavid du Colombier {
10987dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid background palette index");
10997dd7cddfSDavid du Colombier return;
11007dd7cddfSDavid du Colombier }
11017dd7cddfSDavid du Colombier buf[0] = back->index;
1102*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
11037dd7cddfSDavid du Colombier }
11047dd7cddfSDavid du Colombier else if (color_type & PNG_COLOR_MASK_COLOR)
11057dd7cddfSDavid du Colombier {
11067dd7cddfSDavid du Colombier png_save_uint_16(buf, back->red);
11077dd7cddfSDavid du Colombier png_save_uint_16(buf + 2, back->green);
11087dd7cddfSDavid du Colombier png_save_uint_16(buf + 4, back->blue);
1109*593dc095SDavid du Colombier if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
1110*593dc095SDavid du Colombier {
1111*593dc095SDavid du Colombier png_warning(png_ptr,
1112*593dc095SDavid du Colombier "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
1113*593dc095SDavid du Colombier return;
1114*593dc095SDavid du Colombier }
1115*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
11167dd7cddfSDavid du Colombier }
11177dd7cddfSDavid du Colombier else
11187dd7cddfSDavid du Colombier {
1119*593dc095SDavid du Colombier if(back->gray >= (1 << png_ptr->bit_depth))
1120*593dc095SDavid du Colombier {
1121*593dc095SDavid du Colombier png_warning(png_ptr,
1122*593dc095SDavid du Colombier "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
1123*593dc095SDavid du Colombier return;
1124*593dc095SDavid du Colombier }
11257dd7cddfSDavid du Colombier png_save_uint_16(buf, back->gray);
1126*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
11277dd7cddfSDavid du Colombier }
11287dd7cddfSDavid du Colombier }
11297dd7cddfSDavid du Colombier #endif
11307dd7cddfSDavid du Colombier
11317dd7cddfSDavid du Colombier #if defined(PNG_WRITE_hIST_SUPPORTED)
11327dd7cddfSDavid du Colombier /* write the histogram */
1133*593dc095SDavid du Colombier void /* PRIVATE */
png_write_hIST(png_structp png_ptr,png_uint_16p hist,int num_hist)11347dd7cddfSDavid du Colombier png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
11357dd7cddfSDavid du Colombier {
1136*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1137*593dc095SDavid du Colombier PNG_hIST;
1138*593dc095SDavid du Colombier #endif
1139*593dc095SDavid du Colombier int i;
11407dd7cddfSDavid du Colombier png_byte buf[3];
11417dd7cddfSDavid du Colombier
11427dd7cddfSDavid du Colombier png_debug(1, "in png_write_hIST\n");
1143*593dc095SDavid du Colombier if (num_hist > (int)png_ptr->num_palette)
11447dd7cddfSDavid du Colombier {
11457dd7cddfSDavid du Colombier png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
11467dd7cddfSDavid du Colombier png_ptr->num_palette);
11477dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid number of histogram entries specified");
11487dd7cddfSDavid du Colombier return;
11497dd7cddfSDavid du Colombier }
11507dd7cddfSDavid du Colombier
1151*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
11527dd7cddfSDavid du Colombier for (i = 0; i < num_hist; i++)
11537dd7cddfSDavid du Colombier {
11547dd7cddfSDavid du Colombier png_save_uint_16(buf, hist[i]);
11557dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, buf, (png_size_t)2);
11567dd7cddfSDavid du Colombier }
11577dd7cddfSDavid du Colombier png_write_chunk_end(png_ptr);
11587dd7cddfSDavid du Colombier }
11597dd7cddfSDavid du Colombier #endif
11607dd7cddfSDavid du Colombier
1161*593dc095SDavid du Colombier #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
1162*593dc095SDavid du Colombier defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
11637dd7cddfSDavid du Colombier /* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
11647dd7cddfSDavid du Colombier * and if invalid, correct the keyword rather than discarding the entire
11657dd7cddfSDavid du Colombier * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
11667dd7cddfSDavid du Colombier * length, forbids leading or trailing whitespace, multiple internal spaces,
11677dd7cddfSDavid du Colombier * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
11687dd7cddfSDavid du Colombier *
11697dd7cddfSDavid du Colombier * The new_key is allocated to hold the corrected keyword and must be freed
11707dd7cddfSDavid du Colombier * by the calling routine. This avoids problems with trying to write to
11717dd7cddfSDavid du Colombier * static keywords without having to have duplicate copies of the strings.
11727dd7cddfSDavid du Colombier */
1173*593dc095SDavid du Colombier png_size_t /* PRIVATE */
png_check_keyword(png_structp png_ptr,png_charp key,png_charpp new_key)11747dd7cddfSDavid du Colombier png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
11757dd7cddfSDavid du Colombier {
11767dd7cddfSDavid du Colombier png_size_t key_len;
11777dd7cddfSDavid du Colombier png_charp kp, dp;
11787dd7cddfSDavid du Colombier int kflag;
1179*593dc095SDavid du Colombier int kwarn=0;
11807dd7cddfSDavid du Colombier
11817dd7cddfSDavid du Colombier png_debug(1, "in png_check_keyword\n");
11827dd7cddfSDavid du Colombier *new_key = NULL;
11837dd7cddfSDavid du Colombier
11847dd7cddfSDavid du Colombier if (key == NULL || (key_len = png_strlen(key)) == 0)
11857dd7cddfSDavid du Colombier {
1186*593dc095SDavid du Colombier png_warning(png_ptr, "zero length keyword");
11877dd7cddfSDavid du Colombier return ((png_size_t)0);
11887dd7cddfSDavid du Colombier }
11897dd7cddfSDavid du Colombier
11907dd7cddfSDavid du Colombier png_debug1(2, "Keyword to be checked is '%s'\n", key);
11917dd7cddfSDavid du Colombier
1192*593dc095SDavid du Colombier *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
1193*593dc095SDavid du Colombier if (*new_key == NULL)
1194*593dc095SDavid du Colombier {
1195*593dc095SDavid du Colombier png_warning(png_ptr, "Out of memory while procesing keyword");
1196*593dc095SDavid du Colombier return ((png_size_t)0);
1197*593dc095SDavid du Colombier }
11987dd7cddfSDavid du Colombier
11997dd7cddfSDavid du Colombier /* Replace non-printing characters with a blank and print a warning */
12007dd7cddfSDavid du Colombier for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
12017dd7cddfSDavid du Colombier {
12027dd7cddfSDavid du Colombier if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
12037dd7cddfSDavid du Colombier {
1204*593dc095SDavid du Colombier #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
12057dd7cddfSDavid du Colombier char msg[40];
12067dd7cddfSDavid du Colombier
12077dd7cddfSDavid du Colombier sprintf(msg, "invalid keyword character 0x%02X", *kp);
1208*593dc095SDavid du Colombier png_warning(png_ptr, msg);
12097dd7cddfSDavid du Colombier #else
1210*593dc095SDavid du Colombier png_warning(png_ptr, "invalid character in keyword");
12117dd7cddfSDavid du Colombier #endif
12127dd7cddfSDavid du Colombier *dp = ' ';
12137dd7cddfSDavid du Colombier }
12147dd7cddfSDavid du Colombier else
12157dd7cddfSDavid du Colombier {
12167dd7cddfSDavid du Colombier *dp = *kp;
12177dd7cddfSDavid du Colombier }
12187dd7cddfSDavid du Colombier }
12197dd7cddfSDavid du Colombier *dp = '\0';
12207dd7cddfSDavid du Colombier
12217dd7cddfSDavid du Colombier /* Remove any trailing white space. */
12227dd7cddfSDavid du Colombier kp = *new_key + key_len - 1;
12237dd7cddfSDavid du Colombier if (*kp == ' ')
12247dd7cddfSDavid du Colombier {
1225*593dc095SDavid du Colombier png_warning(png_ptr, "trailing spaces removed from keyword");
12267dd7cddfSDavid du Colombier
12277dd7cddfSDavid du Colombier while (*kp == ' ')
12287dd7cddfSDavid du Colombier {
12297dd7cddfSDavid du Colombier *(kp--) = '\0';
12307dd7cddfSDavid du Colombier key_len--;
12317dd7cddfSDavid du Colombier }
12327dd7cddfSDavid du Colombier }
12337dd7cddfSDavid du Colombier
12347dd7cddfSDavid du Colombier /* Remove any leading white space. */
12357dd7cddfSDavid du Colombier kp = *new_key;
12367dd7cddfSDavid du Colombier if (*kp == ' ')
12377dd7cddfSDavid du Colombier {
1238*593dc095SDavid du Colombier png_warning(png_ptr, "leading spaces removed from keyword");
12397dd7cddfSDavid du Colombier
12407dd7cddfSDavid du Colombier while (*kp == ' ')
12417dd7cddfSDavid du Colombier {
12427dd7cddfSDavid du Colombier kp++;
12437dd7cddfSDavid du Colombier key_len--;
12447dd7cddfSDavid du Colombier }
12457dd7cddfSDavid du Colombier }
12467dd7cddfSDavid du Colombier
12477dd7cddfSDavid du Colombier png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
12487dd7cddfSDavid du Colombier
12497dd7cddfSDavid du Colombier /* Remove multiple internal spaces. */
12507dd7cddfSDavid du Colombier for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
12517dd7cddfSDavid du Colombier {
12527dd7cddfSDavid du Colombier if (*kp == ' ' && kflag == 0)
12537dd7cddfSDavid du Colombier {
12547dd7cddfSDavid du Colombier *(dp++) = *kp;
12557dd7cddfSDavid du Colombier kflag = 1;
12567dd7cddfSDavid du Colombier }
12577dd7cddfSDavid du Colombier else if (*kp == ' ')
12587dd7cddfSDavid du Colombier {
12597dd7cddfSDavid du Colombier key_len--;
1260*593dc095SDavid du Colombier kwarn=1;
12617dd7cddfSDavid du Colombier }
12627dd7cddfSDavid du Colombier else
12637dd7cddfSDavid du Colombier {
12647dd7cddfSDavid du Colombier *(dp++) = *kp;
12657dd7cddfSDavid du Colombier kflag = 0;
12667dd7cddfSDavid du Colombier }
12677dd7cddfSDavid du Colombier }
12687dd7cddfSDavid du Colombier *dp = '\0';
1269*593dc095SDavid du Colombier if(kwarn)
1270*593dc095SDavid du Colombier png_warning(png_ptr, "extra interior spaces removed from keyword");
12717dd7cddfSDavid du Colombier
12727dd7cddfSDavid du Colombier if (key_len == 0)
12737dd7cddfSDavid du Colombier {
1274*593dc095SDavid du Colombier png_free(png_ptr, *new_key);
1275*593dc095SDavid du Colombier *new_key=NULL;
1276*593dc095SDavid du Colombier png_warning(png_ptr, "Zero length keyword");
12777dd7cddfSDavid du Colombier }
12787dd7cddfSDavid du Colombier
12797dd7cddfSDavid du Colombier if (key_len > 79)
12807dd7cddfSDavid du Colombier {
1281*593dc095SDavid du Colombier png_warning(png_ptr, "keyword length must be 1 - 79 characters");
12827dd7cddfSDavid du Colombier new_key[79] = '\0';
12837dd7cddfSDavid du Colombier key_len = 79;
12847dd7cddfSDavid du Colombier }
12857dd7cddfSDavid du Colombier
12867dd7cddfSDavid du Colombier return (key_len);
12877dd7cddfSDavid du Colombier }
12887dd7cddfSDavid du Colombier #endif
12897dd7cddfSDavid du Colombier
12907dd7cddfSDavid du Colombier #if defined(PNG_WRITE_tEXt_SUPPORTED)
12917dd7cddfSDavid du Colombier /* write a tEXt chunk */
1292*593dc095SDavid du Colombier void /* PRIVATE */
png_write_tEXt(png_structp png_ptr,png_charp key,png_charp text,png_size_t text_len)12937dd7cddfSDavid du Colombier png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
12947dd7cddfSDavid du Colombier png_size_t text_len)
12957dd7cddfSDavid du Colombier {
1296*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1297*593dc095SDavid du Colombier PNG_tEXt;
1298*593dc095SDavid du Colombier #endif
12997dd7cddfSDavid du Colombier png_size_t key_len;
13007dd7cddfSDavid du Colombier png_charp new_key;
13017dd7cddfSDavid du Colombier
13027dd7cddfSDavid du Colombier png_debug(1, "in png_write_tEXt\n");
13037dd7cddfSDavid du Colombier if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
13047dd7cddfSDavid du Colombier {
13057dd7cddfSDavid du Colombier png_warning(png_ptr, "Empty keyword in tEXt chunk");
13067dd7cddfSDavid du Colombier return;
13077dd7cddfSDavid du Colombier }
13087dd7cddfSDavid du Colombier
13097dd7cddfSDavid du Colombier if (text == NULL || *text == '\0')
13107dd7cddfSDavid du Colombier text_len = 0;
1311*593dc095SDavid du Colombier else
1312*593dc095SDavid du Colombier text_len = png_strlen(text);
13137dd7cddfSDavid du Colombier
13147dd7cddfSDavid du Colombier /* make sure we include the 0 after the key */
1315*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
1316*593dc095SDavid du Colombier /*
1317*593dc095SDavid du Colombier * We leave it to the application to meet PNG-1.0 requirements on the
1318*593dc095SDavid du Colombier * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
1319*593dc095SDavid du Colombier * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
1320*593dc095SDavid du Colombier * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1321*593dc095SDavid du Colombier */
13227dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
13237dd7cddfSDavid du Colombier if (text_len)
13247dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
13257dd7cddfSDavid du Colombier
13267dd7cddfSDavid du Colombier png_write_chunk_end(png_ptr);
13277dd7cddfSDavid du Colombier png_free(png_ptr, new_key);
13287dd7cddfSDavid du Colombier }
13297dd7cddfSDavid du Colombier #endif
13307dd7cddfSDavid du Colombier
13317dd7cddfSDavid du Colombier #if defined(PNG_WRITE_zTXt_SUPPORTED)
13327dd7cddfSDavid du Colombier /* write a compressed text chunk */
1333*593dc095SDavid du Colombier void /* PRIVATE */
png_write_zTXt(png_structp png_ptr,png_charp key,png_charp text,png_size_t text_len,int compression)13347dd7cddfSDavid du Colombier png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
13357dd7cddfSDavid du Colombier png_size_t text_len, int compression)
13367dd7cddfSDavid du Colombier {
1337*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1338*593dc095SDavid du Colombier PNG_zTXt;
1339*593dc095SDavid du Colombier #endif
13407dd7cddfSDavid du Colombier png_size_t key_len;
13417dd7cddfSDavid du Colombier char buf[1];
13427dd7cddfSDavid du Colombier png_charp new_key;
1343*593dc095SDavid du Colombier compression_state comp;
13447dd7cddfSDavid du Colombier
13457dd7cddfSDavid du Colombier png_debug(1, "in png_write_zTXt\n");
13467dd7cddfSDavid du Colombier
13477dd7cddfSDavid du Colombier if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
13487dd7cddfSDavid du Colombier {
13497dd7cddfSDavid du Colombier png_warning(png_ptr, "Empty keyword in zTXt chunk");
13507dd7cddfSDavid du Colombier return;
13517dd7cddfSDavid du Colombier }
13527dd7cddfSDavid du Colombier
13537dd7cddfSDavid du Colombier if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
13547dd7cddfSDavid du Colombier {
13557dd7cddfSDavid du Colombier png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
13567dd7cddfSDavid du Colombier png_free(png_ptr, new_key);
13577dd7cddfSDavid du Colombier return;
13587dd7cddfSDavid du Colombier }
13597dd7cddfSDavid du Colombier
1360*593dc095SDavid du Colombier text_len = png_strlen(text);
1361*593dc095SDavid du Colombier
13627dd7cddfSDavid du Colombier png_free(png_ptr, new_key);
13637dd7cddfSDavid du Colombier
1364*593dc095SDavid du Colombier /* compute the compressed data; do it now for the length */
1365*593dc095SDavid du Colombier text_len = png_text_compress(png_ptr, text, text_len, compression,
1366*593dc095SDavid du Colombier &comp);
13677dd7cddfSDavid du Colombier
13687dd7cddfSDavid du Colombier /* write start of chunk */
1369*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32)
1370*593dc095SDavid du Colombier (key_len+text_len+2));
13717dd7cddfSDavid du Colombier /* write key */
13727dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
13737dd7cddfSDavid du Colombier buf[0] = (png_byte)compression;
13747dd7cddfSDavid du Colombier /* write compression */
13757dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
1376*593dc095SDavid du Colombier /* write the compressed data */
1377*593dc095SDavid du Colombier png_write_compressed_data_out(png_ptr, &comp);
13787dd7cddfSDavid du Colombier
13797dd7cddfSDavid du Colombier /* close the chunk */
13807dd7cddfSDavid du Colombier png_write_chunk_end(png_ptr);
13817dd7cddfSDavid du Colombier }
13827dd7cddfSDavid du Colombier #endif
13837dd7cddfSDavid du Colombier
1384*593dc095SDavid du Colombier #if defined(PNG_WRITE_iTXt_SUPPORTED)
1385*593dc095SDavid du Colombier /* write an iTXt chunk */
1386*593dc095SDavid du Colombier void /* PRIVATE */
png_write_iTXt(png_structp png_ptr,int compression,png_charp key,png_charp lang,png_charp lang_key,png_charp text)1387*593dc095SDavid du Colombier png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
1388*593dc095SDavid du Colombier png_charp lang, png_charp lang_key, png_charp text)
1389*593dc095SDavid du Colombier {
1390*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1391*593dc095SDavid du Colombier PNG_iTXt;
1392*593dc095SDavid du Colombier #endif
1393*593dc095SDavid du Colombier png_size_t lang_len, key_len, lang_key_len, text_len;
1394*593dc095SDavid du Colombier png_charp new_lang, new_key;
1395*593dc095SDavid du Colombier png_byte cbuf[2];
1396*593dc095SDavid du Colombier compression_state comp;
1397*593dc095SDavid du Colombier
1398*593dc095SDavid du Colombier png_debug(1, "in png_write_iTXt\n");
1399*593dc095SDavid du Colombier
1400*593dc095SDavid du Colombier if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
1401*593dc095SDavid du Colombier {
1402*593dc095SDavid du Colombier png_warning(png_ptr, "Empty keyword in iTXt chunk");
1403*593dc095SDavid du Colombier return;
1404*593dc095SDavid du Colombier }
1405*593dc095SDavid du Colombier if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
1406*593dc095SDavid du Colombier {
1407*593dc095SDavid du Colombier png_warning(png_ptr, "Empty language field in iTXt chunk");
1408*593dc095SDavid du Colombier new_lang = NULL;
1409*593dc095SDavid du Colombier lang_len = 0;
1410*593dc095SDavid du Colombier }
1411*593dc095SDavid du Colombier
1412*593dc095SDavid du Colombier if (lang_key == NULL)
1413*593dc095SDavid du Colombier lang_key_len = 0;
1414*593dc095SDavid du Colombier else
1415*593dc095SDavid du Colombier lang_key_len = png_strlen(lang_key);
1416*593dc095SDavid du Colombier
1417*593dc095SDavid du Colombier if (text == NULL)
1418*593dc095SDavid du Colombier text_len = 0;
1419*593dc095SDavid du Colombier else
1420*593dc095SDavid du Colombier text_len = png_strlen(text);
1421*593dc095SDavid du Colombier
1422*593dc095SDavid du Colombier /* compute the compressed data; do it now for the length */
1423*593dc095SDavid du Colombier text_len = png_text_compress(png_ptr, text, text_len, compression-2,
1424*593dc095SDavid du Colombier &comp);
1425*593dc095SDavid du Colombier
1426*593dc095SDavid du Colombier
1427*593dc095SDavid du Colombier /* make sure we include the compression flag, the compression byte,
1428*593dc095SDavid du Colombier * and the NULs after the key, lang, and lang_key parts */
1429*593dc095SDavid du Colombier
1430*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_iTXt,
1431*593dc095SDavid du Colombier (png_uint_32)(
1432*593dc095SDavid du Colombier 5 /* comp byte, comp flag, terminators for key, lang and lang_key */
1433*593dc095SDavid du Colombier + key_len
1434*593dc095SDavid du Colombier + lang_len
1435*593dc095SDavid du Colombier + lang_key_len
1436*593dc095SDavid du Colombier + text_len));
1437*593dc095SDavid du Colombier
1438*593dc095SDavid du Colombier /*
1439*593dc095SDavid du Colombier * We leave it to the application to meet PNG-1.0 requirements on the
1440*593dc095SDavid du Colombier * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
1441*593dc095SDavid du Colombier * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
1442*593dc095SDavid du Colombier * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1443*593dc095SDavid du Colombier */
1444*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
1445*593dc095SDavid du Colombier
1446*593dc095SDavid du Colombier /* set the compression flag */
1447*593dc095SDavid du Colombier if (compression == PNG_ITXT_COMPRESSION_NONE || \
1448*593dc095SDavid du Colombier compression == PNG_TEXT_COMPRESSION_NONE)
1449*593dc095SDavid du Colombier cbuf[0] = 0;
1450*593dc095SDavid du Colombier else /* compression == PNG_ITXT_COMPRESSION_zTXt */
1451*593dc095SDavid du Colombier cbuf[0] = 1;
1452*593dc095SDavid du Colombier /* set the compression method */
1453*593dc095SDavid du Colombier cbuf[1] = 0;
1454*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, cbuf, 2);
1455*593dc095SDavid du Colombier
1456*593dc095SDavid du Colombier cbuf[0] = 0;
1457*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1);
1458*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1);
1459*593dc095SDavid du Colombier png_write_compressed_data_out(png_ptr, &comp);
1460*593dc095SDavid du Colombier
1461*593dc095SDavid du Colombier png_write_chunk_end(png_ptr);
1462*593dc095SDavid du Colombier png_free(png_ptr, new_key);
1463*593dc095SDavid du Colombier if (new_lang)
1464*593dc095SDavid du Colombier png_free(png_ptr, new_lang);
1465*593dc095SDavid du Colombier }
1466*593dc095SDavid du Colombier #endif
14677dd7cddfSDavid du Colombier
14687dd7cddfSDavid du Colombier #if defined(PNG_WRITE_oFFs_SUPPORTED)
14697dd7cddfSDavid du Colombier /* write the oFFs chunk */
1470*593dc095SDavid du Colombier void /* PRIVATE */
png_write_oFFs(png_structp png_ptr,png_int_32 x_offset,png_int_32 y_offset,int unit_type)1471*593dc095SDavid du Colombier png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
14727dd7cddfSDavid du Colombier int unit_type)
14737dd7cddfSDavid du Colombier {
1474*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1475*593dc095SDavid du Colombier PNG_oFFs;
1476*593dc095SDavid du Colombier #endif
14777dd7cddfSDavid du Colombier png_byte buf[9];
14787dd7cddfSDavid du Colombier
14797dd7cddfSDavid du Colombier png_debug(1, "in png_write_oFFs\n");
14807dd7cddfSDavid du Colombier if (unit_type >= PNG_OFFSET_LAST)
14817dd7cddfSDavid du Colombier png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
14827dd7cddfSDavid du Colombier
1483*593dc095SDavid du Colombier png_save_int_32(buf, x_offset);
1484*593dc095SDavid du Colombier png_save_int_32(buf + 4, y_offset);
14857dd7cddfSDavid du Colombier buf[8] = (png_byte)unit_type;
14867dd7cddfSDavid du Colombier
1487*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
14887dd7cddfSDavid du Colombier }
14897dd7cddfSDavid du Colombier #endif
14907dd7cddfSDavid du Colombier
14917dd7cddfSDavid du Colombier #if defined(PNG_WRITE_pCAL_SUPPORTED)
1492*593dc095SDavid du Colombier /* write the pCAL chunk (described in the PNG extensions document) */
1493*593dc095SDavid du Colombier void /* PRIVATE */
png_write_pCAL(png_structp png_ptr,png_charp purpose,png_int_32 X0,png_int_32 X1,int type,int nparams,png_charp units,png_charpp params)14947dd7cddfSDavid du Colombier png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
14957dd7cddfSDavid du Colombier png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
14967dd7cddfSDavid du Colombier {
1497*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1498*593dc095SDavid du Colombier PNG_pCAL;
1499*593dc095SDavid du Colombier #endif
15007dd7cddfSDavid du Colombier png_size_t purpose_len, units_len, total_len;
15017dd7cddfSDavid du Colombier png_uint_32p params_len;
15027dd7cddfSDavid du Colombier png_byte buf[10];
15037dd7cddfSDavid du Colombier png_charp new_purpose;
15047dd7cddfSDavid du Colombier int i;
15057dd7cddfSDavid du Colombier
15067dd7cddfSDavid du Colombier png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
15077dd7cddfSDavid du Colombier if (type >= PNG_EQUATION_LAST)
15087dd7cddfSDavid du Colombier png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
15097dd7cddfSDavid du Colombier
15107dd7cddfSDavid du Colombier purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
1511*593dc095SDavid du Colombier png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
15127dd7cddfSDavid du Colombier units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1513*593dc095SDavid du Colombier png_debug1(3, "pCAL units length = %d\n", (int)units_len);
15147dd7cddfSDavid du Colombier total_len = purpose_len + units_len + 10;
15157dd7cddfSDavid du Colombier
15167dd7cddfSDavid du Colombier params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
1517*593dc095SDavid du Colombier *png_sizeof(png_uint_32)));
15187dd7cddfSDavid du Colombier
15197dd7cddfSDavid du Colombier /* Find the length of each parameter, making sure we don't count the
15207dd7cddfSDavid du Colombier null terminator for the last parameter. */
15217dd7cddfSDavid du Colombier for (i = 0; i < nparams; i++)
15227dd7cddfSDavid du Colombier {
15237dd7cddfSDavid du Colombier params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
1524*593dc095SDavid du Colombier png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
15257dd7cddfSDavid du Colombier total_len += (png_size_t)params_len[i];
15267dd7cddfSDavid du Colombier }
15277dd7cddfSDavid du Colombier
1528*593dc095SDavid du Colombier png_debug1(3, "pCAL total length = %d\n", (int)total_len);
1529*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
15307dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
15317dd7cddfSDavid du Colombier png_save_int_32(buf, X0);
15327dd7cddfSDavid du Colombier png_save_int_32(buf + 4, X1);
15337dd7cddfSDavid du Colombier buf[8] = (png_byte)type;
15347dd7cddfSDavid du Colombier buf[9] = (png_byte)nparams;
15357dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, buf, (png_size_t)10);
15367dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
15377dd7cddfSDavid du Colombier
15387dd7cddfSDavid du Colombier png_free(png_ptr, new_purpose);
15397dd7cddfSDavid du Colombier
15407dd7cddfSDavid du Colombier for (i = 0; i < nparams; i++)
15417dd7cddfSDavid du Colombier {
15427dd7cddfSDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)params[i],
15437dd7cddfSDavid du Colombier (png_size_t)params_len[i]);
15447dd7cddfSDavid du Colombier }
15457dd7cddfSDavid du Colombier
15467dd7cddfSDavid du Colombier png_free(png_ptr, params_len);
15477dd7cddfSDavid du Colombier png_write_chunk_end(png_ptr);
15487dd7cddfSDavid du Colombier }
15497dd7cddfSDavid du Colombier #endif
15507dd7cddfSDavid du Colombier
1551*593dc095SDavid du Colombier #if defined(PNG_WRITE_sCAL_SUPPORTED)
1552*593dc095SDavid du Colombier /* write the sCAL chunk */
1553*593dc095SDavid du Colombier #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
1554*593dc095SDavid du Colombier void /* PRIVATE */
png_write_sCAL(png_structp png_ptr,int unit,double width,double height)1555*593dc095SDavid du Colombier png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
1556*593dc095SDavid du Colombier {
1557*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1558*593dc095SDavid du Colombier PNG_sCAL;
1559*593dc095SDavid du Colombier #endif
1560*593dc095SDavid du Colombier png_size_t total_len;
1561*593dc095SDavid du Colombier char wbuf[32], hbuf[32];
1562*593dc095SDavid du Colombier png_byte bunit = unit;
1563*593dc095SDavid du Colombier
1564*593dc095SDavid du Colombier png_debug(1, "in png_write_sCAL\n");
1565*593dc095SDavid du Colombier
1566*593dc095SDavid du Colombier #if defined(_WIN32_WCE)
1567*593dc095SDavid du Colombier /* sprintf() function is not supported on WindowsCE */
1568*593dc095SDavid du Colombier {
1569*593dc095SDavid du Colombier wchar_t wc_buf[32];
1570*593dc095SDavid du Colombier swprintf(wc_buf, TEXT("%12.12e"), width);
1571*593dc095SDavid du Colombier WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, wbuf, 32, NULL, NULL);
1572*593dc095SDavid du Colombier swprintf(wc_buf, TEXT("%12.12e"), height);
1573*593dc095SDavid du Colombier WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, hbuf, 32, NULL, NULL);
1574*593dc095SDavid du Colombier }
1575*593dc095SDavid du Colombier #else
1576*593dc095SDavid du Colombier sprintf(wbuf, "%12.12e", width);
1577*593dc095SDavid du Colombier sprintf(hbuf, "%12.12e", height);
1578*593dc095SDavid du Colombier #endif
1579*593dc095SDavid du Colombier total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1580*593dc095SDavid du Colombier
1581*593dc095SDavid du Colombier png_debug1(3, "sCAL total length = %d\n", (int)total_len);
1582*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1583*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1584*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
1585*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1586*593dc095SDavid du Colombier
1587*593dc095SDavid du Colombier png_write_chunk_end(png_ptr);
1588*593dc095SDavid du Colombier }
1589*593dc095SDavid du Colombier #else
1590*593dc095SDavid du Colombier #ifdef PNG_FIXED_POINT_SUPPORTED
1591*593dc095SDavid du Colombier void /* PRIVATE */
png_write_sCAL_s(png_structp png_ptr,int unit,png_charp width,png_charp height)1592*593dc095SDavid du Colombier png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
1593*593dc095SDavid du Colombier png_charp height)
1594*593dc095SDavid du Colombier {
1595*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1596*593dc095SDavid du Colombier PNG_sCAL;
1597*593dc095SDavid du Colombier #endif
1598*593dc095SDavid du Colombier png_size_t total_len;
1599*593dc095SDavid du Colombier char wbuf[32], hbuf[32];
1600*593dc095SDavid du Colombier png_byte bunit = unit;
1601*593dc095SDavid du Colombier
1602*593dc095SDavid du Colombier png_debug(1, "in png_write_sCAL_s\n");
1603*593dc095SDavid du Colombier
1604*593dc095SDavid du Colombier png_strcpy(wbuf,(const char *)width);
1605*593dc095SDavid du Colombier png_strcpy(hbuf,(const char *)height);
1606*593dc095SDavid du Colombier total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
1607*593dc095SDavid du Colombier
1608*593dc095SDavid du Colombier png_debug1(3, "sCAL total length = %d\n", total_len);
1609*593dc095SDavid du Colombier png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
1610*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
1611*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
1612*593dc095SDavid du Colombier png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
1613*593dc095SDavid du Colombier
1614*593dc095SDavid du Colombier png_write_chunk_end(png_ptr);
1615*593dc095SDavid du Colombier }
1616*593dc095SDavid du Colombier #endif
1617*593dc095SDavid du Colombier #endif
1618*593dc095SDavid du Colombier #endif
1619*593dc095SDavid du Colombier
16207dd7cddfSDavid du Colombier #if defined(PNG_WRITE_pHYs_SUPPORTED)
16217dd7cddfSDavid du Colombier /* write the pHYs chunk */
1622*593dc095SDavid du Colombier void /* PRIVATE */
png_write_pHYs(png_structp png_ptr,png_uint_32 x_pixels_per_unit,png_uint_32 y_pixels_per_unit,int unit_type)16237dd7cddfSDavid du Colombier png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
16247dd7cddfSDavid du Colombier png_uint_32 y_pixels_per_unit,
16257dd7cddfSDavid du Colombier int unit_type)
16267dd7cddfSDavid du Colombier {
1627*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1628*593dc095SDavid du Colombier PNG_pHYs;
1629*593dc095SDavid du Colombier #endif
16307dd7cddfSDavid du Colombier png_byte buf[9];
16317dd7cddfSDavid du Colombier
16327dd7cddfSDavid du Colombier png_debug(1, "in png_write_pHYs\n");
16337dd7cddfSDavid du Colombier if (unit_type >= PNG_RESOLUTION_LAST)
16347dd7cddfSDavid du Colombier png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
16357dd7cddfSDavid du Colombier
16367dd7cddfSDavid du Colombier png_save_uint_32(buf, x_pixels_per_unit);
16377dd7cddfSDavid du Colombier png_save_uint_32(buf + 4, y_pixels_per_unit);
16387dd7cddfSDavid du Colombier buf[8] = (png_byte)unit_type;
16397dd7cddfSDavid du Colombier
1640*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
16417dd7cddfSDavid du Colombier }
16427dd7cddfSDavid du Colombier #endif
16437dd7cddfSDavid du Colombier
16447dd7cddfSDavid du Colombier #if defined(PNG_WRITE_tIME_SUPPORTED)
16457dd7cddfSDavid du Colombier /* Write the tIME chunk. Use either png_convert_from_struct_tm()
16467dd7cddfSDavid du Colombier * or png_convert_from_time_t(), or fill in the structure yourself.
16477dd7cddfSDavid du Colombier */
1648*593dc095SDavid du Colombier void /* PRIVATE */
png_write_tIME(png_structp png_ptr,png_timep mod_time)16497dd7cddfSDavid du Colombier png_write_tIME(png_structp png_ptr, png_timep mod_time)
16507dd7cddfSDavid du Colombier {
1651*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1652*593dc095SDavid du Colombier PNG_tIME;
1653*593dc095SDavid du Colombier #endif
16547dd7cddfSDavid du Colombier png_byte buf[7];
16557dd7cddfSDavid du Colombier
16567dd7cddfSDavid du Colombier png_debug(1, "in png_write_tIME\n");
16577dd7cddfSDavid du Colombier if (mod_time->month > 12 || mod_time->month < 1 ||
16587dd7cddfSDavid du Colombier mod_time->day > 31 || mod_time->day < 1 ||
16597dd7cddfSDavid du Colombier mod_time->hour > 23 || mod_time->second > 60)
16607dd7cddfSDavid du Colombier {
16617dd7cddfSDavid du Colombier png_warning(png_ptr, "Invalid time specified for tIME chunk");
16627dd7cddfSDavid du Colombier return;
16637dd7cddfSDavid du Colombier }
16647dd7cddfSDavid du Colombier
16657dd7cddfSDavid du Colombier png_save_uint_16(buf, mod_time->year);
16667dd7cddfSDavid du Colombier buf[2] = mod_time->month;
16677dd7cddfSDavid du Colombier buf[3] = mod_time->day;
16687dd7cddfSDavid du Colombier buf[4] = mod_time->hour;
16697dd7cddfSDavid du Colombier buf[5] = mod_time->minute;
16707dd7cddfSDavid du Colombier buf[6] = mod_time->second;
16717dd7cddfSDavid du Colombier
1672*593dc095SDavid du Colombier png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
16737dd7cddfSDavid du Colombier }
16747dd7cddfSDavid du Colombier #endif
16757dd7cddfSDavid du Colombier
16767dd7cddfSDavid du Colombier /* initializes the row writing capability of libpng */
1677*593dc095SDavid du Colombier void /* PRIVATE */
png_write_start_row(png_structp png_ptr)16787dd7cddfSDavid du Colombier png_write_start_row(png_structp png_ptr)
16797dd7cddfSDavid du Colombier {
1680*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1681*593dc095SDavid du Colombier /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1682*593dc095SDavid du Colombier
1683*593dc095SDavid du Colombier /* start of interlace block */
1684*593dc095SDavid du Colombier int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1685*593dc095SDavid du Colombier
1686*593dc095SDavid du Colombier /* offset to next interlace block */
1687*593dc095SDavid du Colombier int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1688*593dc095SDavid du Colombier
1689*593dc095SDavid du Colombier /* start of interlace block in the y direction */
1690*593dc095SDavid du Colombier int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1691*593dc095SDavid du Colombier
1692*593dc095SDavid du Colombier /* offset to next interlace block in the y direction */
1693*593dc095SDavid du Colombier int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1694*593dc095SDavid du Colombier #endif
1695*593dc095SDavid du Colombier
16967dd7cddfSDavid du Colombier png_size_t buf_size;
16977dd7cddfSDavid du Colombier
16987dd7cddfSDavid du Colombier png_debug(1, "in png_write_start_row\n");
1699*593dc095SDavid du Colombier buf_size = (png_size_t)(PNG_ROWBYTES(
1700*593dc095SDavid du Colombier png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
17017dd7cddfSDavid du Colombier
17027dd7cddfSDavid du Colombier /* set up row buffer */
17037dd7cddfSDavid du Colombier png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
17047dd7cddfSDavid du Colombier png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
17057dd7cddfSDavid du Colombier
17067dd7cddfSDavid du Colombier /* set up filtering buffer, if using this filter */
17077dd7cddfSDavid du Colombier if (png_ptr->do_filter & PNG_FILTER_SUB)
17087dd7cddfSDavid du Colombier {
17097dd7cddfSDavid du Colombier png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
1710*593dc095SDavid du Colombier (png_ptr->rowbytes + 1));
17117dd7cddfSDavid du Colombier png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
17127dd7cddfSDavid du Colombier }
17137dd7cddfSDavid du Colombier
17147dd7cddfSDavid du Colombier /* We only need to keep the previous row if we are using one of these. */
17157dd7cddfSDavid du Colombier if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
17167dd7cddfSDavid du Colombier {
17177dd7cddfSDavid du Colombier /* set up previous row buffer */
17187dd7cddfSDavid du Colombier png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
17197dd7cddfSDavid du Colombier png_memset(png_ptr->prev_row, 0, buf_size);
17207dd7cddfSDavid du Colombier
17217dd7cddfSDavid du Colombier if (png_ptr->do_filter & PNG_FILTER_UP)
17227dd7cddfSDavid du Colombier {
17237dd7cddfSDavid du Colombier png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
1724*593dc095SDavid du Colombier (png_ptr->rowbytes + 1));
17257dd7cddfSDavid du Colombier png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
17267dd7cddfSDavid du Colombier }
17277dd7cddfSDavid du Colombier
17287dd7cddfSDavid du Colombier if (png_ptr->do_filter & PNG_FILTER_AVG)
17297dd7cddfSDavid du Colombier {
17307dd7cddfSDavid du Colombier png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1731*593dc095SDavid du Colombier (png_ptr->rowbytes + 1));
17327dd7cddfSDavid du Colombier png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
17337dd7cddfSDavid du Colombier }
17347dd7cddfSDavid du Colombier
17357dd7cddfSDavid du Colombier if (png_ptr->do_filter & PNG_FILTER_PAETH)
17367dd7cddfSDavid du Colombier {
17377dd7cddfSDavid du Colombier png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
1738*593dc095SDavid du Colombier (png_ptr->rowbytes + 1));
17397dd7cddfSDavid du Colombier png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
17407dd7cddfSDavid du Colombier }
17417dd7cddfSDavid du Colombier }
17427dd7cddfSDavid du Colombier
17437dd7cddfSDavid du Colombier #ifdef PNG_WRITE_INTERLACING_SUPPORTED
17447dd7cddfSDavid du Colombier /* if interlaced, we need to set up width and height of pass */
17457dd7cddfSDavid du Colombier if (png_ptr->interlaced)
17467dd7cddfSDavid du Colombier {
17477dd7cddfSDavid du Colombier if (!(png_ptr->transformations & PNG_INTERLACE))
17487dd7cddfSDavid du Colombier {
17497dd7cddfSDavid du Colombier png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
17507dd7cddfSDavid du Colombier png_pass_ystart[0]) / png_pass_yinc[0];
17517dd7cddfSDavid du Colombier png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
17527dd7cddfSDavid du Colombier png_pass_start[0]) / png_pass_inc[0];
17537dd7cddfSDavid du Colombier }
17547dd7cddfSDavid du Colombier else
17557dd7cddfSDavid du Colombier {
17567dd7cddfSDavid du Colombier png_ptr->num_rows = png_ptr->height;
17577dd7cddfSDavid du Colombier png_ptr->usr_width = png_ptr->width;
17587dd7cddfSDavid du Colombier }
17597dd7cddfSDavid du Colombier }
17607dd7cddfSDavid du Colombier else
17617dd7cddfSDavid du Colombier #endif
17627dd7cddfSDavid du Colombier {
17637dd7cddfSDavid du Colombier png_ptr->num_rows = png_ptr->height;
17647dd7cddfSDavid du Colombier png_ptr->usr_width = png_ptr->width;
17657dd7cddfSDavid du Colombier }
17667dd7cddfSDavid du Colombier png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
17677dd7cddfSDavid du Colombier png_ptr->zstream.next_out = png_ptr->zbuf;
17687dd7cddfSDavid du Colombier }
17697dd7cddfSDavid du Colombier
17707dd7cddfSDavid du Colombier /* Internal use only. Called when finished processing a row of data. */
1771*593dc095SDavid du Colombier void /* PRIVATE */
png_write_finish_row(png_structp png_ptr)17727dd7cddfSDavid du Colombier png_write_finish_row(png_structp png_ptr)
17737dd7cddfSDavid du Colombier {
1774*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1775*593dc095SDavid du Colombier /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1776*593dc095SDavid du Colombier
1777*593dc095SDavid du Colombier /* start of interlace block */
1778*593dc095SDavid du Colombier int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1779*593dc095SDavid du Colombier
1780*593dc095SDavid du Colombier /* offset to next interlace block */
1781*593dc095SDavid du Colombier int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1782*593dc095SDavid du Colombier
1783*593dc095SDavid du Colombier /* start of interlace block in the y direction */
1784*593dc095SDavid du Colombier int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1785*593dc095SDavid du Colombier
1786*593dc095SDavid du Colombier /* offset to next interlace block in the y direction */
1787*593dc095SDavid du Colombier int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1788*593dc095SDavid du Colombier #endif
1789*593dc095SDavid du Colombier
17907dd7cddfSDavid du Colombier int ret;
17917dd7cddfSDavid du Colombier
17927dd7cddfSDavid du Colombier png_debug(1, "in png_write_finish_row\n");
17937dd7cddfSDavid du Colombier /* next row */
17947dd7cddfSDavid du Colombier png_ptr->row_number++;
17957dd7cddfSDavid du Colombier
17967dd7cddfSDavid du Colombier /* see if we are done */
17977dd7cddfSDavid du Colombier if (png_ptr->row_number < png_ptr->num_rows)
17987dd7cddfSDavid du Colombier return;
17997dd7cddfSDavid du Colombier
18007dd7cddfSDavid du Colombier #ifdef PNG_WRITE_INTERLACING_SUPPORTED
18017dd7cddfSDavid du Colombier /* if interlaced, go to next pass */
18027dd7cddfSDavid du Colombier if (png_ptr->interlaced)
18037dd7cddfSDavid du Colombier {
18047dd7cddfSDavid du Colombier png_ptr->row_number = 0;
18057dd7cddfSDavid du Colombier if (png_ptr->transformations & PNG_INTERLACE)
18067dd7cddfSDavid du Colombier {
18077dd7cddfSDavid du Colombier png_ptr->pass++;
18087dd7cddfSDavid du Colombier }
18097dd7cddfSDavid du Colombier else
18107dd7cddfSDavid du Colombier {
18117dd7cddfSDavid du Colombier /* loop until we find a non-zero width or height pass */
18127dd7cddfSDavid du Colombier do
18137dd7cddfSDavid du Colombier {
18147dd7cddfSDavid du Colombier png_ptr->pass++;
18157dd7cddfSDavid du Colombier if (png_ptr->pass >= 7)
18167dd7cddfSDavid du Colombier break;
18177dd7cddfSDavid du Colombier png_ptr->usr_width = (png_ptr->width +
18187dd7cddfSDavid du Colombier png_pass_inc[png_ptr->pass] - 1 -
18197dd7cddfSDavid du Colombier png_pass_start[png_ptr->pass]) /
18207dd7cddfSDavid du Colombier png_pass_inc[png_ptr->pass];
18217dd7cddfSDavid du Colombier png_ptr->num_rows = (png_ptr->height +
18227dd7cddfSDavid du Colombier png_pass_yinc[png_ptr->pass] - 1 -
18237dd7cddfSDavid du Colombier png_pass_ystart[png_ptr->pass]) /
18247dd7cddfSDavid du Colombier png_pass_yinc[png_ptr->pass];
18257dd7cddfSDavid du Colombier if (png_ptr->transformations & PNG_INTERLACE)
18267dd7cddfSDavid du Colombier break;
18277dd7cddfSDavid du Colombier } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
18287dd7cddfSDavid du Colombier
18297dd7cddfSDavid du Colombier }
18307dd7cddfSDavid du Colombier
18317dd7cddfSDavid du Colombier /* reset the row above the image for the next pass */
18327dd7cddfSDavid du Colombier if (png_ptr->pass < 7)
18337dd7cddfSDavid du Colombier {
18347dd7cddfSDavid du Colombier if (png_ptr->prev_row != NULL)
18357dd7cddfSDavid du Colombier png_memset(png_ptr->prev_row, 0,
1836*593dc095SDavid du Colombier (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
1837*593dc095SDavid du Colombier png_ptr->usr_bit_depth,png_ptr->width))+1);
18387dd7cddfSDavid du Colombier return;
18397dd7cddfSDavid du Colombier }
18407dd7cddfSDavid du Colombier }
18417dd7cddfSDavid du Colombier #endif
18427dd7cddfSDavid du Colombier
18437dd7cddfSDavid du Colombier /* if we get here, we've just written the last row, so we need
18447dd7cddfSDavid du Colombier to flush the compressor */
18457dd7cddfSDavid du Colombier do
18467dd7cddfSDavid du Colombier {
18477dd7cddfSDavid du Colombier /* tell the compressor we are done */
18487dd7cddfSDavid du Colombier ret = deflate(&png_ptr->zstream, Z_FINISH);
18497dd7cddfSDavid du Colombier /* check for an error */
1850*593dc095SDavid du Colombier if (ret == Z_OK)
1851*593dc095SDavid du Colombier {
1852*593dc095SDavid du Colombier /* check to see if we need more room */
1853*593dc095SDavid du Colombier if (!(png_ptr->zstream.avail_out))
1854*593dc095SDavid du Colombier {
1855*593dc095SDavid du Colombier png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
1856*593dc095SDavid du Colombier png_ptr->zstream.next_out = png_ptr->zbuf;
1857*593dc095SDavid du Colombier png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
1858*593dc095SDavid du Colombier }
1859*593dc095SDavid du Colombier }
1860*593dc095SDavid du Colombier else if (ret != Z_STREAM_END)
18617dd7cddfSDavid du Colombier {
18627dd7cddfSDavid du Colombier if (png_ptr->zstream.msg != NULL)
18637dd7cddfSDavid du Colombier png_error(png_ptr, png_ptr->zstream.msg);
18647dd7cddfSDavid du Colombier else
18657dd7cddfSDavid du Colombier png_error(png_ptr, "zlib error");
18667dd7cddfSDavid du Colombier }
18677dd7cddfSDavid du Colombier } while (ret != Z_STREAM_END);
18687dd7cddfSDavid du Colombier
18697dd7cddfSDavid du Colombier /* write any extra space */
18707dd7cddfSDavid du Colombier if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
18717dd7cddfSDavid du Colombier {
18727dd7cddfSDavid du Colombier png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
18737dd7cddfSDavid du Colombier png_ptr->zstream.avail_out);
18747dd7cddfSDavid du Colombier }
18757dd7cddfSDavid du Colombier
18767dd7cddfSDavid du Colombier deflateReset(&png_ptr->zstream);
1877*593dc095SDavid du Colombier png_ptr->zstream.data_type = Z_BINARY;
18787dd7cddfSDavid du Colombier }
18797dd7cddfSDavid du Colombier
18807dd7cddfSDavid du Colombier #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
18817dd7cddfSDavid du Colombier /* Pick out the correct pixels for the interlace pass.
18827dd7cddfSDavid du Colombier * The basic idea here is to go through the row with a source
18837dd7cddfSDavid du Colombier * pointer and a destination pointer (sp and dp), and copy the
18847dd7cddfSDavid du Colombier * correct pixels for the pass. As the row gets compacted,
18857dd7cddfSDavid du Colombier * sp will always be >= dp, so we should never overwrite anything.
18867dd7cddfSDavid du Colombier * See the default: case for the easiest code to understand.
18877dd7cddfSDavid du Colombier */
1888*593dc095SDavid du Colombier void /* PRIVATE */
png_do_write_interlace(png_row_infop row_info,png_bytep row,int pass)18897dd7cddfSDavid du Colombier png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
18907dd7cddfSDavid du Colombier {
1891*593dc095SDavid du Colombier #ifdef PNG_USE_LOCAL_ARRAYS
1892*593dc095SDavid du Colombier /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1893*593dc095SDavid du Colombier
1894*593dc095SDavid du Colombier /* start of interlace block */
1895*593dc095SDavid du Colombier int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1896*593dc095SDavid du Colombier
1897*593dc095SDavid du Colombier /* offset to next interlace block */
1898*593dc095SDavid du Colombier int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1899*593dc095SDavid du Colombier #endif
1900*593dc095SDavid du Colombier
19017dd7cddfSDavid du Colombier png_debug(1, "in png_do_write_interlace\n");
19027dd7cddfSDavid du Colombier /* we don't have to do anything on the last pass (6) */
19037dd7cddfSDavid du Colombier #if defined(PNG_USELESS_TESTS_SUPPORTED)
19047dd7cddfSDavid du Colombier if (row != NULL && row_info != NULL && pass < 6)
19057dd7cddfSDavid du Colombier #else
19067dd7cddfSDavid du Colombier if (pass < 6)
19077dd7cddfSDavid du Colombier #endif
19087dd7cddfSDavid du Colombier {
1909*593dc095SDavid du Colombier /* each pixel depth is handled separately */
19107dd7cddfSDavid du Colombier switch (row_info->pixel_depth)
19117dd7cddfSDavid du Colombier {
19127dd7cddfSDavid du Colombier case 1:
19137dd7cddfSDavid du Colombier {
19147dd7cddfSDavid du Colombier png_bytep sp;
19157dd7cddfSDavid du Colombier png_bytep dp;
19167dd7cddfSDavid du Colombier int shift;
19177dd7cddfSDavid du Colombier int d;
19187dd7cddfSDavid du Colombier int value;
19197dd7cddfSDavid du Colombier png_uint_32 i;
1920*593dc095SDavid du Colombier png_uint_32 row_width = row_info->width;
19217dd7cddfSDavid du Colombier
19227dd7cddfSDavid du Colombier dp = row;
19237dd7cddfSDavid du Colombier d = 0;
19247dd7cddfSDavid du Colombier shift = 7;
1925*593dc095SDavid du Colombier for (i = png_pass_start[pass]; i < row_width;
19267dd7cddfSDavid du Colombier i += png_pass_inc[pass])
19277dd7cddfSDavid du Colombier {
19287dd7cddfSDavid du Colombier sp = row + (png_size_t)(i >> 3);
1929*593dc095SDavid du Colombier value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
19307dd7cddfSDavid du Colombier d |= (value << shift);
19317dd7cddfSDavid du Colombier
19327dd7cddfSDavid du Colombier if (shift == 0)
19337dd7cddfSDavid du Colombier {
19347dd7cddfSDavid du Colombier shift = 7;
19357dd7cddfSDavid du Colombier *dp++ = (png_byte)d;
19367dd7cddfSDavid du Colombier d = 0;
19377dd7cddfSDavid du Colombier }
19387dd7cddfSDavid du Colombier else
19397dd7cddfSDavid du Colombier shift--;
19407dd7cddfSDavid du Colombier
19417dd7cddfSDavid du Colombier }
19427dd7cddfSDavid du Colombier if (shift != 7)
19437dd7cddfSDavid du Colombier *dp = (png_byte)d;
19447dd7cddfSDavid du Colombier break;
19457dd7cddfSDavid du Colombier }
19467dd7cddfSDavid du Colombier case 2:
19477dd7cddfSDavid du Colombier {
19487dd7cddfSDavid du Colombier png_bytep sp;
19497dd7cddfSDavid du Colombier png_bytep dp;
19507dd7cddfSDavid du Colombier int shift;
19517dd7cddfSDavid du Colombier int d;
19527dd7cddfSDavid du Colombier int value;
19537dd7cddfSDavid du Colombier png_uint_32 i;
1954*593dc095SDavid du Colombier png_uint_32 row_width = row_info->width;
19557dd7cddfSDavid du Colombier
19567dd7cddfSDavid du Colombier dp = row;
19577dd7cddfSDavid du Colombier shift = 6;
19587dd7cddfSDavid du Colombier d = 0;
1959*593dc095SDavid du Colombier for (i = png_pass_start[pass]; i < row_width;
19607dd7cddfSDavid du Colombier i += png_pass_inc[pass])
19617dd7cddfSDavid du Colombier {
19627dd7cddfSDavid du Colombier sp = row + (png_size_t)(i >> 2);
1963*593dc095SDavid du Colombier value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
19647dd7cddfSDavid du Colombier d |= (value << shift);
19657dd7cddfSDavid du Colombier
19667dd7cddfSDavid du Colombier if (shift == 0)
19677dd7cddfSDavid du Colombier {
19687dd7cddfSDavid du Colombier shift = 6;
19697dd7cddfSDavid du Colombier *dp++ = (png_byte)d;
19707dd7cddfSDavid du Colombier d = 0;
19717dd7cddfSDavid du Colombier }
19727dd7cddfSDavid du Colombier else
19737dd7cddfSDavid du Colombier shift -= 2;
19747dd7cddfSDavid du Colombier }
19757dd7cddfSDavid du Colombier if (shift != 6)
19767dd7cddfSDavid du Colombier *dp = (png_byte)d;
19777dd7cddfSDavid du Colombier break;
19787dd7cddfSDavid du Colombier }
19797dd7cddfSDavid du Colombier case 4:
19807dd7cddfSDavid du Colombier {
19817dd7cddfSDavid du Colombier png_bytep sp;
19827dd7cddfSDavid du Colombier png_bytep dp;
19837dd7cddfSDavid du Colombier int shift;
19847dd7cddfSDavid du Colombier int d;
19857dd7cddfSDavid du Colombier int value;
19867dd7cddfSDavid du Colombier png_uint_32 i;
1987*593dc095SDavid du Colombier png_uint_32 row_width = row_info->width;
19887dd7cddfSDavid du Colombier
19897dd7cddfSDavid du Colombier dp = row;
19907dd7cddfSDavid du Colombier shift = 4;
19917dd7cddfSDavid du Colombier d = 0;
1992*593dc095SDavid du Colombier for (i = png_pass_start[pass]; i < row_width;
19937dd7cddfSDavid du Colombier i += png_pass_inc[pass])
19947dd7cddfSDavid du Colombier {
19957dd7cddfSDavid du Colombier sp = row + (png_size_t)(i >> 1);
1996*593dc095SDavid du Colombier value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
19977dd7cddfSDavid du Colombier d |= (value << shift);
19987dd7cddfSDavid du Colombier
19997dd7cddfSDavid du Colombier if (shift == 0)
20007dd7cddfSDavid du Colombier {
20017dd7cddfSDavid du Colombier shift = 4;
20027dd7cddfSDavid du Colombier *dp++ = (png_byte)d;
20037dd7cddfSDavid du Colombier d = 0;
20047dd7cddfSDavid du Colombier }
20057dd7cddfSDavid du Colombier else
20067dd7cddfSDavid du Colombier shift -= 4;
20077dd7cddfSDavid du Colombier }
20087dd7cddfSDavid du Colombier if (shift != 4)
20097dd7cddfSDavid du Colombier *dp = (png_byte)d;
20107dd7cddfSDavid du Colombier break;
20117dd7cddfSDavid du Colombier }
20127dd7cddfSDavid du Colombier default:
20137dd7cddfSDavid du Colombier {
20147dd7cddfSDavid du Colombier png_bytep sp;
20157dd7cddfSDavid du Colombier png_bytep dp;
20167dd7cddfSDavid du Colombier png_uint_32 i;
2017*593dc095SDavid du Colombier png_uint_32 row_width = row_info->width;
20187dd7cddfSDavid du Colombier png_size_t pixel_bytes;
20197dd7cddfSDavid du Colombier
20207dd7cddfSDavid du Colombier /* start at the beginning */
20217dd7cddfSDavid du Colombier dp = row;
20227dd7cddfSDavid du Colombier /* find out how many bytes each pixel takes up */
20237dd7cddfSDavid du Colombier pixel_bytes = (row_info->pixel_depth >> 3);
20247dd7cddfSDavid du Colombier /* loop through the row, only looking at the pixels that
20257dd7cddfSDavid du Colombier matter */
2026*593dc095SDavid du Colombier for (i = png_pass_start[pass]; i < row_width;
20277dd7cddfSDavid du Colombier i += png_pass_inc[pass])
20287dd7cddfSDavid du Colombier {
20297dd7cddfSDavid du Colombier /* find out where the original pixel is */
2030*593dc095SDavid du Colombier sp = row + (png_size_t)i * pixel_bytes;
20317dd7cddfSDavid du Colombier /* move the pixel */
20327dd7cddfSDavid du Colombier if (dp != sp)
20337dd7cddfSDavid du Colombier png_memcpy(dp, sp, pixel_bytes);
20347dd7cddfSDavid du Colombier /* next pixel */
20357dd7cddfSDavid du Colombier dp += pixel_bytes;
20367dd7cddfSDavid du Colombier }
20377dd7cddfSDavid du Colombier break;
20387dd7cddfSDavid du Colombier }
20397dd7cddfSDavid du Colombier }
20407dd7cddfSDavid du Colombier /* set new row width */
20417dd7cddfSDavid du Colombier row_info->width = (row_info->width +
20427dd7cddfSDavid du Colombier png_pass_inc[pass] - 1 -
20437dd7cddfSDavid du Colombier png_pass_start[pass]) /
20447dd7cddfSDavid du Colombier png_pass_inc[pass];
2045*593dc095SDavid du Colombier row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
2046*593dc095SDavid du Colombier row_info->width);
20477dd7cddfSDavid du Colombier }
20487dd7cddfSDavid du Colombier }
20497dd7cddfSDavid du Colombier #endif
20507dd7cddfSDavid du Colombier
20517dd7cddfSDavid du Colombier /* This filters the row, chooses which filter to use, if it has not already
20527dd7cddfSDavid du Colombier * been specified by the application, and then writes the row out with the
20537dd7cddfSDavid du Colombier * chosen filter.
20547dd7cddfSDavid du Colombier */
2055*593dc095SDavid du Colombier #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
20567dd7cddfSDavid du Colombier #define PNG_HISHIFT 10
2057*593dc095SDavid du Colombier #define PNG_LOMASK ((png_uint_32)0xffffL)
2058*593dc095SDavid du Colombier #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
2059*593dc095SDavid du Colombier void /* PRIVATE */
png_write_find_filter(png_structp png_ptr,png_row_infop row_info)20607dd7cddfSDavid du Colombier png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
20617dd7cddfSDavid du Colombier {
20627dd7cddfSDavid du Colombier png_bytep prev_row, best_row, row_buf;
20637dd7cddfSDavid du Colombier png_uint_32 mins, bpp;
2064*593dc095SDavid du Colombier png_byte filter_to_do = png_ptr->do_filter;
2065*593dc095SDavid du Colombier png_uint_32 row_bytes = row_info->rowbytes;
2066*593dc095SDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2067*593dc095SDavid du Colombier int num_p_filters = (int)png_ptr->num_prev_filters;
2068*593dc095SDavid du Colombier #endif
20697dd7cddfSDavid du Colombier
20707dd7cddfSDavid du Colombier png_debug(1, "in png_write_find_filter\n");
20717dd7cddfSDavid du Colombier /* find out how many bytes offset each pixel is */
2072*593dc095SDavid du Colombier bpp = (row_info->pixel_depth + 7) >> 3;
20737dd7cddfSDavid du Colombier
20747dd7cddfSDavid du Colombier prev_row = png_ptr->prev_row;
20757dd7cddfSDavid du Colombier best_row = row_buf = png_ptr->row_buf;
20767dd7cddfSDavid du Colombier mins = PNG_MAXSUM;
20777dd7cddfSDavid du Colombier
20787dd7cddfSDavid du Colombier /* The prediction method we use is to find which method provides the
20797dd7cddfSDavid du Colombier * smallest value when summing the absolute values of the distances
2080*593dc095SDavid du Colombier * from zero, using anything >= 128 as negative numbers. This is known
20817dd7cddfSDavid du Colombier * as the "minimum sum of absolute differences" heuristic. Other
2082*593dc095SDavid du Colombier * heuristics are the "weighted minimum sum of absolute differences"
20837dd7cddfSDavid du Colombier * (experimental and can in theory improve compression), and the "zlib
2084*593dc095SDavid du Colombier * predictive" method (not implemented yet), which does test compressions
2085*593dc095SDavid du Colombier * of lines using different filter methods, and then chooses the
2086*593dc095SDavid du Colombier * (series of) filter(s) that give minimum compressed data size (VERY
20877dd7cddfSDavid du Colombier * computationally expensive).
2088*593dc095SDavid du Colombier *
2089*593dc095SDavid du Colombier * GRR 980525: consider also
2090*593dc095SDavid du Colombier * (1) minimum sum of absolute differences from running average (i.e.,
2091*593dc095SDavid du Colombier * keep running sum of non-absolute differences & count of bytes)
2092*593dc095SDavid du Colombier * [track dispersion, too? restart average if dispersion too large?]
2093*593dc095SDavid du Colombier * (1b) minimum sum of absolute differences from sliding average, probably
2094*593dc095SDavid du Colombier * with window size <= deflate window (usually 32K)
2095*593dc095SDavid du Colombier * (2) minimum sum of squared differences from zero or running average
2096*593dc095SDavid du Colombier * (i.e., ~ root-mean-square approach)
20977dd7cddfSDavid du Colombier */
20987dd7cddfSDavid du Colombier
2099*593dc095SDavid du Colombier
21007dd7cddfSDavid du Colombier /* We don't need to test the 'no filter' case if this is the only filter
21017dd7cddfSDavid du Colombier * that has been chosen, as it doesn't actually do anything to the data.
21027dd7cddfSDavid du Colombier */
2103*593dc095SDavid du Colombier if ((filter_to_do & PNG_FILTER_NONE) &&
2104*593dc095SDavid du Colombier filter_to_do != PNG_FILTER_NONE)
21057dd7cddfSDavid du Colombier {
21067dd7cddfSDavid du Colombier png_bytep rp;
21077dd7cddfSDavid du Colombier png_uint_32 sum = 0;
2108*593dc095SDavid du Colombier png_uint_32 i;
21097dd7cddfSDavid du Colombier int v;
21107dd7cddfSDavid du Colombier
2111*593dc095SDavid du Colombier for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
21127dd7cddfSDavid du Colombier {
21137dd7cddfSDavid du Colombier v = *rp;
21147dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
21157dd7cddfSDavid du Colombier }
21167dd7cddfSDavid du Colombier
21177dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
21187dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
21197dd7cddfSDavid du Colombier {
21207dd7cddfSDavid du Colombier png_uint_32 sumhi, sumlo;
2121*593dc095SDavid du Colombier int j;
21227dd7cddfSDavid du Colombier sumlo = sum & PNG_LOMASK;
21237dd7cddfSDavid du Colombier sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
21247dd7cddfSDavid du Colombier
21257dd7cddfSDavid du Colombier /* Reduce the sum if we match any of the previous rows */
2126*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
21277dd7cddfSDavid du Colombier {
2128*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
21297dd7cddfSDavid du Colombier {
2130*593dc095SDavid du Colombier sumlo = (sumlo * png_ptr->filter_weights[j]) >>
21317dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2132*593dc095SDavid du Colombier sumhi = (sumhi * png_ptr->filter_weights[j]) >>
21337dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
21347dd7cddfSDavid du Colombier }
21357dd7cddfSDavid du Colombier }
21367dd7cddfSDavid du Colombier
21377dd7cddfSDavid du Colombier /* Factor in the cost of this filter (this is here for completeness,
21387dd7cddfSDavid du Colombier * but it makes no sense to have a "cost" for the NONE filter, as
21397dd7cddfSDavid du Colombier * it has the minimum possible computational cost - none).
21407dd7cddfSDavid du Colombier */
21417dd7cddfSDavid du Colombier sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
21427dd7cddfSDavid du Colombier PNG_COST_SHIFT;
21437dd7cddfSDavid du Colombier sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
21447dd7cddfSDavid du Colombier PNG_COST_SHIFT;
21457dd7cddfSDavid du Colombier
21467dd7cddfSDavid du Colombier if (sumhi > PNG_HIMASK)
21477dd7cddfSDavid du Colombier sum = PNG_MAXSUM;
21487dd7cddfSDavid du Colombier else
21497dd7cddfSDavid du Colombier sum = (sumhi << PNG_HISHIFT) + sumlo;
21507dd7cddfSDavid du Colombier }
21517dd7cddfSDavid du Colombier #endif
21527dd7cddfSDavid du Colombier mins = sum;
21537dd7cddfSDavid du Colombier }
21547dd7cddfSDavid du Colombier
21557dd7cddfSDavid du Colombier /* sub filter */
2156*593dc095SDavid du Colombier if (filter_to_do == PNG_FILTER_SUB)
2157*593dc095SDavid du Colombier /* it's the only filter so no testing is needed */
2158*593dc095SDavid du Colombier {
2159*593dc095SDavid du Colombier png_bytep rp, lp, dp;
2160*593dc095SDavid du Colombier png_uint_32 i;
2161*593dc095SDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
2162*593dc095SDavid du Colombier i++, rp++, dp++)
2163*593dc095SDavid du Colombier {
2164*593dc095SDavid du Colombier *dp = *rp;
2165*593dc095SDavid du Colombier }
2166*593dc095SDavid du Colombier for (lp = row_buf + 1; i < row_bytes;
2167*593dc095SDavid du Colombier i++, rp++, lp++, dp++)
2168*593dc095SDavid du Colombier {
2169*593dc095SDavid du Colombier *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
2170*593dc095SDavid du Colombier }
2171*593dc095SDavid du Colombier best_row = png_ptr->sub_row;
2172*593dc095SDavid du Colombier }
2173*593dc095SDavid du Colombier
2174*593dc095SDavid du Colombier else if (filter_to_do & PNG_FILTER_SUB)
21757dd7cddfSDavid du Colombier {
21767dd7cddfSDavid du Colombier png_bytep rp, dp, lp;
21777dd7cddfSDavid du Colombier png_uint_32 sum = 0, lmins = mins;
2178*593dc095SDavid du Colombier png_uint_32 i;
21797dd7cddfSDavid du Colombier int v;
21807dd7cddfSDavid du Colombier
21817dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2182*593dc095SDavid du Colombier /* We temporarily increase the "minimum sum" by the factor we
21837dd7cddfSDavid du Colombier * would reduce the sum of this filter, so that we can do the
21847dd7cddfSDavid du Colombier * early exit comparison without scaling the sum each time.
21857dd7cddfSDavid du Colombier */
21867dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
21877dd7cddfSDavid du Colombier {
2188*593dc095SDavid du Colombier int j;
21897dd7cddfSDavid du Colombier png_uint_32 lmhi, lmlo;
21907dd7cddfSDavid du Colombier lmlo = lmins & PNG_LOMASK;
21917dd7cddfSDavid du Colombier lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
21927dd7cddfSDavid du Colombier
2193*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
21947dd7cddfSDavid du Colombier {
2195*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
21967dd7cddfSDavid du Colombier {
2197*593dc095SDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
21987dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2199*593dc095SDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
22007dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
22017dd7cddfSDavid du Colombier }
22027dd7cddfSDavid du Colombier }
22037dd7cddfSDavid du Colombier
22047dd7cddfSDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
22057dd7cddfSDavid du Colombier PNG_COST_SHIFT;
22067dd7cddfSDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
22077dd7cddfSDavid du Colombier PNG_COST_SHIFT;
22087dd7cddfSDavid du Colombier
22097dd7cddfSDavid du Colombier if (lmhi > PNG_HIMASK)
22107dd7cddfSDavid du Colombier lmins = PNG_MAXSUM;
22117dd7cddfSDavid du Colombier else
22127dd7cddfSDavid du Colombier lmins = (lmhi << PNG_HISHIFT) + lmlo;
22137dd7cddfSDavid du Colombier }
22147dd7cddfSDavid du Colombier #endif
22157dd7cddfSDavid du Colombier
22167dd7cddfSDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
22177dd7cddfSDavid du Colombier i++, rp++, dp++)
22187dd7cddfSDavid du Colombier {
22197dd7cddfSDavid du Colombier v = *dp = *rp;
22207dd7cddfSDavid du Colombier
22217dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
22227dd7cddfSDavid du Colombier }
2223*593dc095SDavid du Colombier for (lp = row_buf + 1; i < row_bytes;
2224*593dc095SDavid du Colombier i++, rp++, lp++, dp++)
22257dd7cddfSDavid du Colombier {
22267dd7cddfSDavid du Colombier v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
22277dd7cddfSDavid du Colombier
22287dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
22297dd7cddfSDavid du Colombier
22307dd7cddfSDavid du Colombier if (sum > lmins) /* We are already worse, don't continue. */
22317dd7cddfSDavid du Colombier break;
22327dd7cddfSDavid du Colombier }
22337dd7cddfSDavid du Colombier
22347dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
22357dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
22367dd7cddfSDavid du Colombier {
2237*593dc095SDavid du Colombier int j;
22387dd7cddfSDavid du Colombier png_uint_32 sumhi, sumlo;
22397dd7cddfSDavid du Colombier sumlo = sum & PNG_LOMASK;
22407dd7cddfSDavid du Colombier sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
22417dd7cddfSDavid du Colombier
2242*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
22437dd7cddfSDavid du Colombier {
2244*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
22457dd7cddfSDavid du Colombier {
2246*593dc095SDavid du Colombier sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
22477dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2248*593dc095SDavid du Colombier sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
22497dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
22507dd7cddfSDavid du Colombier }
22517dd7cddfSDavid du Colombier }
22527dd7cddfSDavid du Colombier
22537dd7cddfSDavid du Colombier sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
22547dd7cddfSDavid du Colombier PNG_COST_SHIFT;
22557dd7cddfSDavid du Colombier sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
22567dd7cddfSDavid du Colombier PNG_COST_SHIFT;
22577dd7cddfSDavid du Colombier
22587dd7cddfSDavid du Colombier if (sumhi > PNG_HIMASK)
22597dd7cddfSDavid du Colombier sum = PNG_MAXSUM;
22607dd7cddfSDavid du Colombier else
22617dd7cddfSDavid du Colombier sum = (sumhi << PNG_HISHIFT) + sumlo;
22627dd7cddfSDavid du Colombier }
22637dd7cddfSDavid du Colombier #endif
22647dd7cddfSDavid du Colombier
22657dd7cddfSDavid du Colombier if (sum < mins)
22667dd7cddfSDavid du Colombier {
22677dd7cddfSDavid du Colombier mins = sum;
22687dd7cddfSDavid du Colombier best_row = png_ptr->sub_row;
22697dd7cddfSDavid du Colombier }
22707dd7cddfSDavid du Colombier }
22717dd7cddfSDavid du Colombier
22727dd7cddfSDavid du Colombier /* up filter */
2273*593dc095SDavid du Colombier if (filter_to_do == PNG_FILTER_UP)
2274*593dc095SDavid du Colombier {
2275*593dc095SDavid du Colombier png_bytep rp, dp, pp;
2276*593dc095SDavid du Colombier png_uint_32 i;
2277*593dc095SDavid du Colombier
2278*593dc095SDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2279*593dc095SDavid du Colombier pp = prev_row + 1; i < row_bytes;
2280*593dc095SDavid du Colombier i++, rp++, pp++, dp++)
2281*593dc095SDavid du Colombier {
2282*593dc095SDavid du Colombier *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
2283*593dc095SDavid du Colombier }
2284*593dc095SDavid du Colombier best_row = png_ptr->up_row;
2285*593dc095SDavid du Colombier }
2286*593dc095SDavid du Colombier
2287*593dc095SDavid du Colombier else if (filter_to_do & PNG_FILTER_UP)
22887dd7cddfSDavid du Colombier {
22897dd7cddfSDavid du Colombier png_bytep rp, dp, pp;
22907dd7cddfSDavid du Colombier png_uint_32 sum = 0, lmins = mins;
2291*593dc095SDavid du Colombier png_uint_32 i;
22927dd7cddfSDavid du Colombier int v;
22937dd7cddfSDavid du Colombier
2294*593dc095SDavid du Colombier
22957dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
22967dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
22977dd7cddfSDavid du Colombier {
2298*593dc095SDavid du Colombier int j;
22997dd7cddfSDavid du Colombier png_uint_32 lmhi, lmlo;
23007dd7cddfSDavid du Colombier lmlo = lmins & PNG_LOMASK;
23017dd7cddfSDavid du Colombier lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
23027dd7cddfSDavid du Colombier
2303*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
23047dd7cddfSDavid du Colombier {
2305*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
23067dd7cddfSDavid du Colombier {
2307*593dc095SDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
23087dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2309*593dc095SDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
23107dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
23117dd7cddfSDavid du Colombier }
23127dd7cddfSDavid du Colombier }
23137dd7cddfSDavid du Colombier
23147dd7cddfSDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
23157dd7cddfSDavid du Colombier PNG_COST_SHIFT;
23167dd7cddfSDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
23177dd7cddfSDavid du Colombier PNG_COST_SHIFT;
23187dd7cddfSDavid du Colombier
23197dd7cddfSDavid du Colombier if (lmhi > PNG_HIMASK)
23207dd7cddfSDavid du Colombier lmins = PNG_MAXSUM;
23217dd7cddfSDavid du Colombier else
23227dd7cddfSDavid du Colombier lmins = (lmhi << PNG_HISHIFT) + lmlo;
23237dd7cddfSDavid du Colombier }
23247dd7cddfSDavid du Colombier #endif
23257dd7cddfSDavid du Colombier
23267dd7cddfSDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
2327*593dc095SDavid du Colombier pp = prev_row + 1; i < row_bytes; i++)
23287dd7cddfSDavid du Colombier {
2329*593dc095SDavid du Colombier v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
23307dd7cddfSDavid du Colombier
23317dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
23327dd7cddfSDavid du Colombier
23337dd7cddfSDavid du Colombier if (sum > lmins) /* We are already worse, don't continue. */
23347dd7cddfSDavid du Colombier break;
23357dd7cddfSDavid du Colombier }
23367dd7cddfSDavid du Colombier
23377dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
23387dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
23397dd7cddfSDavid du Colombier {
2340*593dc095SDavid du Colombier int j;
23417dd7cddfSDavid du Colombier png_uint_32 sumhi, sumlo;
23427dd7cddfSDavid du Colombier sumlo = sum & PNG_LOMASK;
23437dd7cddfSDavid du Colombier sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
23447dd7cddfSDavid du Colombier
2345*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
23467dd7cddfSDavid du Colombier {
2347*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
23487dd7cddfSDavid du Colombier {
2349*593dc095SDavid du Colombier sumlo = (sumlo * png_ptr->filter_weights[j]) >>
23507dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2351*593dc095SDavid du Colombier sumhi = (sumhi * png_ptr->filter_weights[j]) >>
23527dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
23537dd7cddfSDavid du Colombier }
23547dd7cddfSDavid du Colombier }
23557dd7cddfSDavid du Colombier
23567dd7cddfSDavid du Colombier sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
23577dd7cddfSDavid du Colombier PNG_COST_SHIFT;
23587dd7cddfSDavid du Colombier sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
23597dd7cddfSDavid du Colombier PNG_COST_SHIFT;
23607dd7cddfSDavid du Colombier
23617dd7cddfSDavid du Colombier if (sumhi > PNG_HIMASK)
23627dd7cddfSDavid du Colombier sum = PNG_MAXSUM;
23637dd7cddfSDavid du Colombier else
23647dd7cddfSDavid du Colombier sum = (sumhi << PNG_HISHIFT) + sumlo;
23657dd7cddfSDavid du Colombier }
23667dd7cddfSDavid du Colombier #endif
23677dd7cddfSDavid du Colombier
23687dd7cddfSDavid du Colombier if (sum < mins)
23697dd7cddfSDavid du Colombier {
23707dd7cddfSDavid du Colombier mins = sum;
23717dd7cddfSDavid du Colombier best_row = png_ptr->up_row;
23727dd7cddfSDavid du Colombier }
23737dd7cddfSDavid du Colombier }
23747dd7cddfSDavid du Colombier
23757dd7cddfSDavid du Colombier /* avg filter */
2376*593dc095SDavid du Colombier if (filter_to_do == PNG_FILTER_AVG)
2377*593dc095SDavid du Colombier {
2378*593dc095SDavid du Colombier png_bytep rp, dp, pp, lp;
2379*593dc095SDavid du Colombier png_uint_32 i;
2380*593dc095SDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2381*593dc095SDavid du Colombier pp = prev_row + 1; i < bpp; i++)
2382*593dc095SDavid du Colombier {
2383*593dc095SDavid du Colombier *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2384*593dc095SDavid du Colombier }
2385*593dc095SDavid du Colombier for (lp = row_buf + 1; i < row_bytes; i++)
2386*593dc095SDavid du Colombier {
2387*593dc095SDavid du Colombier *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
2388*593dc095SDavid du Colombier & 0xff);
2389*593dc095SDavid du Colombier }
2390*593dc095SDavid du Colombier best_row = png_ptr->avg_row;
2391*593dc095SDavid du Colombier }
2392*593dc095SDavid du Colombier
2393*593dc095SDavid du Colombier else if (filter_to_do & PNG_FILTER_AVG)
23947dd7cddfSDavid du Colombier {
23957dd7cddfSDavid du Colombier png_bytep rp, dp, pp, lp;
23967dd7cddfSDavid du Colombier png_uint_32 sum = 0, lmins = mins;
2397*593dc095SDavid du Colombier png_uint_32 i;
23987dd7cddfSDavid du Colombier int v;
23997dd7cddfSDavid du Colombier
24007dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
24017dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
24027dd7cddfSDavid du Colombier {
2403*593dc095SDavid du Colombier int j;
24047dd7cddfSDavid du Colombier png_uint_32 lmhi, lmlo;
24057dd7cddfSDavid du Colombier lmlo = lmins & PNG_LOMASK;
24067dd7cddfSDavid du Colombier lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
24077dd7cddfSDavid du Colombier
2408*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
24097dd7cddfSDavid du Colombier {
2410*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
24117dd7cddfSDavid du Colombier {
2412*593dc095SDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
24137dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2414*593dc095SDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
24157dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
24167dd7cddfSDavid du Colombier }
24177dd7cddfSDavid du Colombier }
24187dd7cddfSDavid du Colombier
24197dd7cddfSDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
24207dd7cddfSDavid du Colombier PNG_COST_SHIFT;
24217dd7cddfSDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
24227dd7cddfSDavid du Colombier PNG_COST_SHIFT;
24237dd7cddfSDavid du Colombier
24247dd7cddfSDavid du Colombier if (lmhi > PNG_HIMASK)
24257dd7cddfSDavid du Colombier lmins = PNG_MAXSUM;
24267dd7cddfSDavid du Colombier else
24277dd7cddfSDavid du Colombier lmins = (lmhi << PNG_HISHIFT) + lmlo;
24287dd7cddfSDavid du Colombier }
24297dd7cddfSDavid du Colombier #endif
24307dd7cddfSDavid du Colombier
24317dd7cddfSDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
2432*593dc095SDavid du Colombier pp = prev_row + 1; i < bpp; i++)
24337dd7cddfSDavid du Colombier {
2434*593dc095SDavid du Colombier v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
24357dd7cddfSDavid du Colombier
24367dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
24377dd7cddfSDavid du Colombier }
2438*593dc095SDavid du Colombier for (lp = row_buf + 1; i < row_bytes; i++)
24397dd7cddfSDavid du Colombier {
2440*593dc095SDavid du Colombier v = *dp++ =
2441*593dc095SDavid du Colombier (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
24427dd7cddfSDavid du Colombier
24437dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
24447dd7cddfSDavid du Colombier
24457dd7cddfSDavid du Colombier if (sum > lmins) /* We are already worse, don't continue. */
24467dd7cddfSDavid du Colombier break;
24477dd7cddfSDavid du Colombier }
24487dd7cddfSDavid du Colombier
24497dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
24507dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
24517dd7cddfSDavid du Colombier {
2452*593dc095SDavid du Colombier int j;
24537dd7cddfSDavid du Colombier png_uint_32 sumhi, sumlo;
24547dd7cddfSDavid du Colombier sumlo = sum & PNG_LOMASK;
24557dd7cddfSDavid du Colombier sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
24567dd7cddfSDavid du Colombier
2457*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
24587dd7cddfSDavid du Colombier {
2459*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
24607dd7cddfSDavid du Colombier {
2461*593dc095SDavid du Colombier sumlo = (sumlo * png_ptr->filter_weights[j]) >>
24627dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2463*593dc095SDavid du Colombier sumhi = (sumhi * png_ptr->filter_weights[j]) >>
24647dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
24657dd7cddfSDavid du Colombier }
24667dd7cddfSDavid du Colombier }
24677dd7cddfSDavid du Colombier
24687dd7cddfSDavid du Colombier sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
24697dd7cddfSDavid du Colombier PNG_COST_SHIFT;
24707dd7cddfSDavid du Colombier sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
24717dd7cddfSDavid du Colombier PNG_COST_SHIFT;
24727dd7cddfSDavid du Colombier
24737dd7cddfSDavid du Colombier if (sumhi > PNG_HIMASK)
24747dd7cddfSDavid du Colombier sum = PNG_MAXSUM;
24757dd7cddfSDavid du Colombier else
24767dd7cddfSDavid du Colombier sum = (sumhi << PNG_HISHIFT) + sumlo;
24777dd7cddfSDavid du Colombier }
24787dd7cddfSDavid du Colombier #endif
24797dd7cddfSDavid du Colombier
24807dd7cddfSDavid du Colombier if (sum < mins)
24817dd7cddfSDavid du Colombier {
24827dd7cddfSDavid du Colombier mins = sum;
24837dd7cddfSDavid du Colombier best_row = png_ptr->avg_row;
24847dd7cddfSDavid du Colombier }
24857dd7cddfSDavid du Colombier }
24867dd7cddfSDavid du Colombier
24877dd7cddfSDavid du Colombier /* Paeth filter */
2488*593dc095SDavid du Colombier if (filter_to_do == PNG_FILTER_PAETH)
2489*593dc095SDavid du Colombier {
2490*593dc095SDavid du Colombier png_bytep rp, dp, pp, cp, lp;
2491*593dc095SDavid du Colombier png_uint_32 i;
2492*593dc095SDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2493*593dc095SDavid du Colombier pp = prev_row + 1; i < bpp; i++)
2494*593dc095SDavid du Colombier {
2495*593dc095SDavid du Colombier *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2496*593dc095SDavid du Colombier }
2497*593dc095SDavid du Colombier
2498*593dc095SDavid du Colombier for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
2499*593dc095SDavid du Colombier {
2500*593dc095SDavid du Colombier int a, b, c, pa, pb, pc, p;
2501*593dc095SDavid du Colombier
2502*593dc095SDavid du Colombier b = *pp++;
2503*593dc095SDavid du Colombier c = *cp++;
2504*593dc095SDavid du Colombier a = *lp++;
2505*593dc095SDavid du Colombier
2506*593dc095SDavid du Colombier p = b - c;
2507*593dc095SDavid du Colombier pc = a - c;
2508*593dc095SDavid du Colombier
2509*593dc095SDavid du Colombier #ifdef PNG_USE_ABS
2510*593dc095SDavid du Colombier pa = abs(p);
2511*593dc095SDavid du Colombier pb = abs(pc);
2512*593dc095SDavid du Colombier pc = abs(p + pc);
2513*593dc095SDavid du Colombier #else
2514*593dc095SDavid du Colombier pa = p < 0 ? -p : p;
2515*593dc095SDavid du Colombier pb = pc < 0 ? -pc : pc;
2516*593dc095SDavid du Colombier pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2517*593dc095SDavid du Colombier #endif
2518*593dc095SDavid du Colombier
2519*593dc095SDavid du Colombier p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2520*593dc095SDavid du Colombier
2521*593dc095SDavid du Colombier *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2522*593dc095SDavid du Colombier }
2523*593dc095SDavid du Colombier best_row = png_ptr->paeth_row;
2524*593dc095SDavid du Colombier }
2525*593dc095SDavid du Colombier
2526*593dc095SDavid du Colombier else if (filter_to_do & PNG_FILTER_PAETH)
25277dd7cddfSDavid du Colombier {
25287dd7cddfSDavid du Colombier png_bytep rp, dp, pp, cp, lp;
25297dd7cddfSDavid du Colombier png_uint_32 sum = 0, lmins = mins;
2530*593dc095SDavid du Colombier png_uint_32 i;
25317dd7cddfSDavid du Colombier int v;
25327dd7cddfSDavid du Colombier
25337dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
25347dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
25357dd7cddfSDavid du Colombier {
2536*593dc095SDavid du Colombier int j;
25377dd7cddfSDavid du Colombier png_uint_32 lmhi, lmlo;
25387dd7cddfSDavid du Colombier lmlo = lmins & PNG_LOMASK;
25397dd7cddfSDavid du Colombier lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
25407dd7cddfSDavid du Colombier
2541*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
25427dd7cddfSDavid du Colombier {
2543*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
25447dd7cddfSDavid du Colombier {
2545*593dc095SDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
25467dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2547*593dc095SDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
25487dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
25497dd7cddfSDavid du Colombier }
25507dd7cddfSDavid du Colombier }
25517dd7cddfSDavid du Colombier
25527dd7cddfSDavid du Colombier lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
25537dd7cddfSDavid du Colombier PNG_COST_SHIFT;
25547dd7cddfSDavid du Colombier lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
25557dd7cddfSDavid du Colombier PNG_COST_SHIFT;
25567dd7cddfSDavid du Colombier
25577dd7cddfSDavid du Colombier if (lmhi > PNG_HIMASK)
25587dd7cddfSDavid du Colombier lmins = PNG_MAXSUM;
25597dd7cddfSDavid du Colombier else
25607dd7cddfSDavid du Colombier lmins = (lmhi << PNG_HISHIFT) + lmlo;
25617dd7cddfSDavid du Colombier }
25627dd7cddfSDavid du Colombier #endif
25637dd7cddfSDavid du Colombier
25647dd7cddfSDavid du Colombier for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
2565*593dc095SDavid du Colombier pp = prev_row + 1; i < bpp; i++)
25667dd7cddfSDavid du Colombier {
2567*593dc095SDavid du Colombier v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
25687dd7cddfSDavid du Colombier
25697dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
25707dd7cddfSDavid du Colombier }
2571*593dc095SDavid du Colombier
2572*593dc095SDavid du Colombier for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
25737dd7cddfSDavid du Colombier {
25747dd7cddfSDavid du Colombier int a, b, c, pa, pb, pc, p;
25757dd7cddfSDavid du Colombier
2576*593dc095SDavid du Colombier b = *pp++;
2577*593dc095SDavid du Colombier c = *cp++;
2578*593dc095SDavid du Colombier a = *lp++;
25797dd7cddfSDavid du Colombier
2580*593dc095SDavid du Colombier #ifndef PNG_SLOW_PAETH
2581*593dc095SDavid du Colombier p = b - c;
2582*593dc095SDavid du Colombier pc = a - c;
2583*593dc095SDavid du Colombier #ifdef PNG_USE_ABS
2584*593dc095SDavid du Colombier pa = abs(p);
2585*593dc095SDavid du Colombier pb = abs(pc);
2586*593dc095SDavid du Colombier pc = abs(p + pc);
2587*593dc095SDavid du Colombier #else
2588*593dc095SDavid du Colombier pa = p < 0 ? -p : p;
2589*593dc095SDavid du Colombier pb = pc < 0 ? -pc : pc;
2590*593dc095SDavid du Colombier pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2591*593dc095SDavid du Colombier #endif
2592*593dc095SDavid du Colombier p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2593*593dc095SDavid du Colombier #else /* PNG_SLOW_PAETH */
25947dd7cddfSDavid du Colombier p = a + b - c;
25957dd7cddfSDavid du Colombier pa = abs(p - a);
25967dd7cddfSDavid du Colombier pb = abs(p - b);
25977dd7cddfSDavid du Colombier pc = abs(p - c);
25987dd7cddfSDavid du Colombier if (pa <= pb && pa <= pc)
25997dd7cddfSDavid du Colombier p = a;
26007dd7cddfSDavid du Colombier else if (pb <= pc)
26017dd7cddfSDavid du Colombier p = b;
26027dd7cddfSDavid du Colombier else
26037dd7cddfSDavid du Colombier p = c;
2604*593dc095SDavid du Colombier #endif /* PNG_SLOW_PAETH */
26057dd7cddfSDavid du Colombier
2606*593dc095SDavid du Colombier v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
26077dd7cddfSDavid du Colombier
26087dd7cddfSDavid du Colombier sum += (v < 128) ? v : 256 - v;
26097dd7cddfSDavid du Colombier
26107dd7cddfSDavid du Colombier if (sum > lmins) /* We are already worse, don't continue. */
26117dd7cddfSDavid du Colombier break;
26127dd7cddfSDavid du Colombier }
26137dd7cddfSDavid du Colombier
26147dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
26157dd7cddfSDavid du Colombier if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
26167dd7cddfSDavid du Colombier {
2617*593dc095SDavid du Colombier int j;
26187dd7cddfSDavid du Colombier png_uint_32 sumhi, sumlo;
26197dd7cddfSDavid du Colombier sumlo = sum & PNG_LOMASK;
26207dd7cddfSDavid du Colombier sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
26217dd7cddfSDavid du Colombier
2622*593dc095SDavid du Colombier for (j = 0; j < num_p_filters; j++)
26237dd7cddfSDavid du Colombier {
2624*593dc095SDavid du Colombier if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
26257dd7cddfSDavid du Colombier {
2626*593dc095SDavid du Colombier sumlo = (sumlo * png_ptr->filter_weights[j]) >>
26277dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
2628*593dc095SDavid du Colombier sumhi = (sumhi * png_ptr->filter_weights[j]) >>
26297dd7cddfSDavid du Colombier PNG_WEIGHT_SHIFT;
26307dd7cddfSDavid du Colombier }
26317dd7cddfSDavid du Colombier }
26327dd7cddfSDavid du Colombier
26337dd7cddfSDavid du Colombier sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
26347dd7cddfSDavid du Colombier PNG_COST_SHIFT;
26357dd7cddfSDavid du Colombier sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
26367dd7cddfSDavid du Colombier PNG_COST_SHIFT;
26377dd7cddfSDavid du Colombier
26387dd7cddfSDavid du Colombier if (sumhi > PNG_HIMASK)
26397dd7cddfSDavid du Colombier sum = PNG_MAXSUM;
26407dd7cddfSDavid du Colombier else
26417dd7cddfSDavid du Colombier sum = (sumhi << PNG_HISHIFT) + sumlo;
26427dd7cddfSDavid du Colombier }
26437dd7cddfSDavid du Colombier #endif
26447dd7cddfSDavid du Colombier
26457dd7cddfSDavid du Colombier if (sum < mins)
26467dd7cddfSDavid du Colombier {
26477dd7cddfSDavid du Colombier best_row = png_ptr->paeth_row;
26487dd7cddfSDavid du Colombier }
26497dd7cddfSDavid du Colombier }
26507dd7cddfSDavid du Colombier
26517dd7cddfSDavid du Colombier /* Do the actual writing of the filtered row data from the chosen filter. */
2652*593dc095SDavid du Colombier
26537dd7cddfSDavid du Colombier png_write_filtered_row(png_ptr, best_row);
26547dd7cddfSDavid du Colombier
26557dd7cddfSDavid du Colombier #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
26567dd7cddfSDavid du Colombier /* Save the type of filter we picked this time for future calculations */
26577dd7cddfSDavid du Colombier if (png_ptr->num_prev_filters > 0)
26587dd7cddfSDavid du Colombier {
2659*593dc095SDavid du Colombier int j;
2660*593dc095SDavid du Colombier for (j = 1; j < num_p_filters; j++)
26617dd7cddfSDavid du Colombier {
2662*593dc095SDavid du Colombier png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
26637dd7cddfSDavid du Colombier }
2664*593dc095SDavid du Colombier png_ptr->prev_filters[j] = best_row[0];
26657dd7cddfSDavid du Colombier }
26667dd7cddfSDavid du Colombier #endif
26677dd7cddfSDavid du Colombier }
26687dd7cddfSDavid du Colombier
26697dd7cddfSDavid du Colombier
26707dd7cddfSDavid du Colombier /* Do the actual writing of a previously filtered row. */
2671*593dc095SDavid du Colombier void /* PRIVATE */
png_write_filtered_row(png_structp png_ptr,png_bytep filtered_row)26727dd7cddfSDavid du Colombier png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
26737dd7cddfSDavid du Colombier {
26747dd7cddfSDavid du Colombier png_debug(1, "in png_write_filtered_row\n");
26757dd7cddfSDavid du Colombier png_debug1(2, "filter = %d\n", filtered_row[0]);
26767dd7cddfSDavid du Colombier /* set up the zlib input buffer */
2677*593dc095SDavid du Colombier
26787dd7cddfSDavid du Colombier png_ptr->zstream.next_in = filtered_row;
26797dd7cddfSDavid du Colombier png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
26807dd7cddfSDavid du Colombier /* repeat until we have compressed all the data */
26817dd7cddfSDavid du Colombier do
26827dd7cddfSDavid du Colombier {
26837dd7cddfSDavid du Colombier int ret; /* return of zlib */
26847dd7cddfSDavid du Colombier
26857dd7cddfSDavid du Colombier /* compress the data */
26867dd7cddfSDavid du Colombier ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
26877dd7cddfSDavid du Colombier /* check for compression errors */
26887dd7cddfSDavid du Colombier if (ret != Z_OK)
26897dd7cddfSDavid du Colombier {
26907dd7cddfSDavid du Colombier if (png_ptr->zstream.msg != NULL)
26917dd7cddfSDavid du Colombier png_error(png_ptr, png_ptr->zstream.msg);
26927dd7cddfSDavid du Colombier else
26937dd7cddfSDavid du Colombier png_error(png_ptr, "zlib error");
26947dd7cddfSDavid du Colombier }
26957dd7cddfSDavid du Colombier
26967dd7cddfSDavid du Colombier /* see if it is time to write another IDAT */
26977dd7cddfSDavid du Colombier if (!(png_ptr->zstream.avail_out))
26987dd7cddfSDavid du Colombier {
26997dd7cddfSDavid du Colombier /* write the IDAT and reset the zlib output buffer */
27007dd7cddfSDavid du Colombier png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
27017dd7cddfSDavid du Colombier png_ptr->zstream.next_out = png_ptr->zbuf;
27027dd7cddfSDavid du Colombier png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
27037dd7cddfSDavid du Colombier }
27047dd7cddfSDavid du Colombier /* repeat until all data has been compressed */
27057dd7cddfSDavid du Colombier } while (png_ptr->zstream.avail_in);
27067dd7cddfSDavid du Colombier
27077dd7cddfSDavid du Colombier /* swap the current and previous rows */
27087dd7cddfSDavid du Colombier if (png_ptr->prev_row != NULL)
27097dd7cddfSDavid du Colombier {
27107dd7cddfSDavid du Colombier png_bytep tptr;
27117dd7cddfSDavid du Colombier
27127dd7cddfSDavid du Colombier tptr = png_ptr->prev_row;
27137dd7cddfSDavid du Colombier png_ptr->prev_row = png_ptr->row_buf;
27147dd7cddfSDavid du Colombier png_ptr->row_buf = tptr;
27157dd7cddfSDavid du Colombier }
27167dd7cddfSDavid du Colombier
27177dd7cddfSDavid du Colombier /* finish row - updates counters and flushes zlib if last row */
27187dd7cddfSDavid du Colombier png_write_finish_row(png_ptr);
27197dd7cddfSDavid du Colombier
27207dd7cddfSDavid du Colombier #if defined(PNG_WRITE_FLUSH_SUPPORTED)
27217dd7cddfSDavid du Colombier png_ptr->flush_rows++;
27227dd7cddfSDavid du Colombier
27237dd7cddfSDavid du Colombier if (png_ptr->flush_dist > 0 &&
27247dd7cddfSDavid du Colombier png_ptr->flush_rows >= png_ptr->flush_dist)
27257dd7cddfSDavid du Colombier {
27267dd7cddfSDavid du Colombier png_write_flush(png_ptr);
27277dd7cddfSDavid du Colombier }
2728*593dc095SDavid du Colombier #endif
27297dd7cddfSDavid du Colombier }
2730*593dc095SDavid du Colombier #endif /* PNG_WRITE_SUPPORTED */
2731