blob: c34d94ac87ca0d3add4d78665cb6adecbe92f918 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwutil.c - utilities to write a png file
3
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004 libpng 1.0 beta 2 - version 0.81
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
6 Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
Guy Schalnat51f0eb41995-09-26 05:22:39 -05007 August 24, 1995
Guy Schalnat0d580581995-07-20 02:43:20 -05008 */
9#define PNG_INTERNAL
10#include "png.h"
11
12/* place a 32 bit number into a buffer in png byte order. We work
13 with unsigned numbers for convenience, you may have to cast
14 signed numbers (if you use any, most png data is unsigned). */
15void
16png_save_uint_32(png_byte *buf, png_uint_32 i)
17{
18 buf[0] = (png_byte)((i >> 24) & 0xff);
19 buf[1] = (png_byte)((i >> 16) & 0xff);
20 buf[2] = (png_byte)((i >> 8) & 0xff);
21 buf[3] = (png_byte)(i & 0xff);
22}
23
24/* place a 16 bit number into a buffer in png byte order */
25void
26png_save_uint_16(png_byte *buf, png_uint_16 i)
27{
28 buf[0] = (png_byte)((i >> 8) & 0xff);
29 buf[1] = (png_byte)(i & 0xff);
30}
31
32/* write a 32 bit number */
33void
34png_write_uint_32(png_struct *png_ptr, png_uint_32 i)
35{
36 png_byte buf[4];
37
38 buf[0] = (png_byte)((i >> 24) & 0xff);
39 buf[1] = (png_byte)((i >> 16) & 0xff);
40 buf[2] = (png_byte)((i >> 8) & 0xff);
41 buf[3] = (png_byte)(i & 0xff);
Guy Schalnat0f716451995-11-28 11:22:13 -060042 (*(png_ptr->write_data_fn))(png_ptr, buf, 4);
Guy Schalnat0d580581995-07-20 02:43:20 -050043}
44
45/* write a 16 bit number */
46void
47png_write_uint_16(png_struct *png_ptr, png_uint_16 i)
48{
49 png_byte buf[2];
50
51 buf[0] = (png_byte)((i >> 8) & 0xff);
52 buf[1] = (png_byte)(i & 0xff);
Guy Schalnat0f716451995-11-28 11:22:13 -060053 (*(png_ptr->write_data_fn))(png_ptr, buf, 2);
Guy Schalnat0d580581995-07-20 02:43:20 -050054}
55
56/* Write a png chunk all at once. The type is an array of ASCII characters
57 representing the chunk name. The array must be at least 4 bytes in
58 length, and does not need to be null terminated. To be safe, pass the
59 pre-defined chunk names here, and if you need a new one, define it
60 where the others are defined. The length is the length of the data.
61 All the data must be present. If that is not possible, use the
62 png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
63 functions instead. */
64void
65png_write_chunk(png_struct *png_ptr, png_byte *type,
Guy Schalnat51f0eb41995-09-26 05:22:39 -050066 png_bytef *data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -050067{
68 /* write length */
69 png_write_uint_32(png_ptr, length);
70 /* write chunk name */
Guy Schalnat0f716451995-11-28 11:22:13 -060071 (*(png_ptr->write_data_fn))(png_ptr, type, (png_uint_32)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050072 /* reset the crc and run the chunk name over it */
73 png_reset_crc(png_ptr);
74 png_calculate_crc(png_ptr, type, (png_uint_32)4);
75 /* write the data and update the crc */
76 if (length)
77 {
78 png_calculate_crc(png_ptr, data, length);
Guy Schalnat0f716451995-11-28 11:22:13 -060079 (*(png_ptr->write_data_fn))(png_ptr, data, length);
Guy Schalnat0d580581995-07-20 02:43:20 -050080 }
81 /* write the crc */
82 png_write_uint_32(png_ptr, ~png_ptr->crc);
83}
84
85/* Write the start of a png chunk. The type is the chunk type.
86 The total_length is the sum of the lengths of all the data you will be
87 passing in png_write_chunk_data() */
88void
89png_write_chunk_start(png_struct *png_ptr, png_byte *type,
90 png_uint_32 total_length)
91{
92 /* write the length */
93 png_write_uint_32(png_ptr, total_length);
94 /* write the chunk name */
Guy Schalnat0f716451995-11-28 11:22:13 -060095 (*(png_ptr->write_data_fn))(png_ptr, type, (png_uint_32)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050096 /* reset the crc and run it over the chunk name */
97 png_reset_crc(png_ptr);
98 png_calculate_crc(png_ptr, type, (png_uint_32)4);
99}
100
101/* write the data of a png chunk started with png_write_chunk_start().
102 Note that multiple calls to this function are allowed, and that the
103 sum of the lengths from these calls *must* add up to the total_length
104 given to png_write_chunk_start() */
105void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500106png_write_chunk_data(png_struct *png_ptr, png_bytef *data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500107{
108 /* write the data, and run the crc over it */
109 if (length)
110 {
111 png_calculate_crc(png_ptr, data, length);
Guy Schalnat0f716451995-11-28 11:22:13 -0600112 (*(png_ptr->write_data_fn))(png_ptr, data, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500113 }
114}
115
116/* finish a chunk started with png_write_chunk_start() */
117void
118png_write_chunk_end(png_struct *png_ptr)
119{
120 /* write the crc */
121 png_write_uint_32(png_ptr, ~png_ptr->crc);
122}
123
124/* simple function to write the signature */
125void
126png_write_sig(png_struct *png_ptr)
127{
128 /* write the 8 byte signature */
Guy Schalnat0f716451995-11-28 11:22:13 -0600129 (*(png_ptr->write_data_fn))(png_ptr, png_sig, (png_uint_32)8);
Guy Schalnat0d580581995-07-20 02:43:20 -0500130}
131
132/* Write the IHDR chunk, and update the png_struct with the necessary
133 information. Note that the rest of this code depends upon this
134 information being correct. */
135void
136png_write_IHDR(png_struct *png_ptr, png_uint_32 width, png_uint_32 height,
137 int bit_depth, int color_type, int compression_type, int filter_type,
138 int interlace_type)
139{
140 png_byte buf[13]; /* buffer to store the IHDR info */
141
142 /* pack the header information into the buffer */
143 png_save_uint_32(buf, width);
144 png_save_uint_32(buf + 4, height);
145 buf[8] = bit_depth;
146 buf[9] = color_type;
147 buf[10] = compression_type;
148 buf[11] = filter_type;
149 buf[12] = interlace_type;
150 /* save off the relevent information */
151 png_ptr->bit_depth = bit_depth;
152 png_ptr->color_type = color_type;
153 png_ptr->interlaced = interlace_type;
154 png_ptr->width = width;
155 png_ptr->height = height;
156
157 switch (color_type)
158 {
159 case 0:
160 case 3:
161 png_ptr->channels = 1;
162 break;
163 case 2:
164 png_ptr->channels = 3;
165 break;
166 case 4:
167 png_ptr->channels = 2;
168 break;
169 case 6:
170 png_ptr->channels = 4;
171 break;
172 }
173 png_ptr->pixel_depth = bit_depth * png_ptr->channels;
174 png_ptr->rowbytes = ((width * (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
175 /* set the usr info, so any transformations can modify it */
176 png_ptr->usr_width = png_ptr->width;
177 png_ptr->usr_bit_depth = png_ptr->bit_depth;
Guy Schalnat0f716451995-11-28 11:22:13 -0600178 png_ptr->usr_channels = png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500179
180 /* write the chunk */
Guy Schalnat0f716451995-11-28 11:22:13 -0600181 png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500182
183 /* initialize zlib with png info */
184 png_ptr->zstream = &(png_ptr->zstream_struct);
185 png_ptr->zstream->zalloc = png_zalloc;
186 png_ptr->zstream->zfree = png_zfree;
187 png_ptr->zstream->opaque = (voidp)png_ptr;
188 if (!png_ptr->do_custom_filter)
189 {
190 if (png_ptr->color_type == 3 || png_ptr->bit_depth < 8)
191 png_ptr->do_filter = 0;
192 else
193 png_ptr->do_filter = 1;
194 }
195 if (!png_ptr->zlib_custom_strategy)
196 {
197 if (png_ptr->do_filter)
198 png_ptr->zlib_strategy = Z_FILTERED;
199 else
200 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
201 }
202 if (!png_ptr->zlib_custom_level)
203 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
204 if (!png_ptr->zlib_custom_mem_level)
205 png_ptr->zlib_mem_level = 8;
206 if (!png_ptr->zlib_custom_window_bits)
207 png_ptr->zlib_window_bits = 15;
208 if (!png_ptr->zlib_custom_method)
209 png_ptr->zlib_method = 8;
210 deflateInit2(png_ptr->zstream, png_ptr->zlib_level,
211 png_ptr->zlib_method,
212 png_ptr->zlib_window_bits,
213 png_ptr->zlib_mem_level,
214 png_ptr->zlib_strategy);
215 png_ptr->zstream->next_out = png_ptr->zbuf;
216 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
217
Guy Schalnat0d580581995-07-20 02:43:20 -0500218}
219
220/* write the palette. We are careful not to trust png_color to be in the
221 correct order for PNG, so people can redefine it to any convient
222 structure. */
223void
224png_write_PLTE(png_struct *png_ptr, png_color *palette, int number)
225{
226 int i;
227 png_color *pal_ptr;
228 png_byte buf[3];
229
230 png_write_chunk_start(png_ptr, png_PLTE, number * 3);
231 for (i = 0, pal_ptr = palette;
232 i < number;
233 i++, pal_ptr++)
234 {
235 buf[0] = pal_ptr->red;
236 buf[1] = pal_ptr->green;
237 buf[2] = pal_ptr->blue;
238 png_write_chunk_data(png_ptr, buf, (png_uint_32)3);
239 }
240 png_write_chunk_end(png_ptr);
241}
242
243/* write an IDAT chunk */
244void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500245png_write_IDAT(png_struct *png_ptr, png_bytef *data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500246{
Guy Schalnat0d580581995-07-20 02:43:20 -0500247 png_write_chunk(png_ptr, png_IDAT, data, length);
248}
249
250/* write an IEND chunk */
251void
252png_write_IEND(png_struct *png_ptr)
253{
254 png_write_chunk(png_ptr, png_IEND, NULL, (png_uint_32)0);
255}
256
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500257#if defined(PNG_WRITE_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500258/* write a gAMA chunk */
259void
260png_write_gAMA(png_struct *png_ptr, float gamma)
261{
262 png_uint_32 igamma;
263 png_byte buf[4];
264
265 /* gamma is saved in 1/100,000ths */
266 igamma = (png_uint_32)(gamma * 100000.0 + 0.5);
267 png_save_uint_32(buf, igamma);
268 png_write_chunk(png_ptr, png_gAMA, buf, (png_uint_32)4);
269}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500270#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500271
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500272#if defined(PNG_WRITE_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500273/* write the sBIT chunk */
274void
275png_write_sBIT(png_struct *png_ptr, png_color_8 *sbit, int color_type)
276{
277 png_byte buf[4];
278 int size;
279
280 /* make sure we don't depend upon the order of png_color_8 */
281 if (color_type & PNG_COLOR_MASK_COLOR)
282 {
283 buf[0] = sbit->red;
284 buf[1] = sbit->green;
285 buf[2] = sbit->blue;
286 size = 3;
287 }
288 else
289 {
290 buf[0] = sbit->gray;
291 size = 1;
292 }
293
294 if (color_type & PNG_COLOR_MASK_ALPHA)
295 {
296 buf[size++] = sbit->alpha;
297 }
298
299 png_write_chunk(png_ptr, png_sBIT, buf, (png_uint_32)size);
300}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500301#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500302
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500303#if defined(PNG_WRITE_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500304/* write the cHRM chunk */
305void
306png_write_cHRM(png_struct *png_ptr, float white_x, float white_y,
307 float red_x, float red_y, float green_x, float green_y,
308 float blue_x, float blue_y)
309{
310 png_uint_32 itemp;
311 png_byte buf[32];
312
313 /* each value is saved int 1/100,000ths */
314 itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
315 png_save_uint_32(buf, itemp);
316 itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
317 png_save_uint_32(buf + 4, itemp);
318 itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
319 png_save_uint_32(buf + 8, itemp);
320 itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
321 png_save_uint_32(buf + 12, itemp);
322 itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
323 png_save_uint_32(buf + 16, itemp);
324 itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
325 png_save_uint_32(buf + 20, itemp);
326 itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
327 png_save_uint_32(buf + 24, itemp);
328 itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
329 png_save_uint_32(buf + 28, itemp);
330 png_write_chunk(png_ptr, png_cHRM, buf, (png_uint_32)32);
331}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500332#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500333
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500334#if defined(PNG_WRITE_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500335/* write the tRNS chunk */
336void
337png_write_tRNS(png_struct *png_ptr, png_byte *trans, png_color_16 *tran,
338 int num_trans, int color_type)
339{
340 png_byte buf[6];
341
342 if (color_type == PNG_COLOR_TYPE_PALETTE)
343 {
344 /* write the chunk out as it is */
345 png_write_chunk(png_ptr, png_tRNS, trans, (png_uint_32)num_trans);
346 }
347 else if (color_type == PNG_COLOR_TYPE_GRAY)
348 {
349 /* one 16 bit value */
350 png_save_uint_16(buf, tran->gray);
351 png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)2);
352 }
353 else if (color_type == PNG_COLOR_TYPE_RGB)
354 {
355 /* three 16 bit values */
356 png_save_uint_16(buf, tran->red);
357 png_save_uint_16(buf + 2, tran->green);
358 png_save_uint_16(buf + 4, tran->blue);
359 png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)6);
360 }
361}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500362#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500363
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500364#if defined(PNG_WRITE_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500365/* write the background chunk */
366void
367png_write_bKGD(png_struct *png_ptr, png_color_16 *back, int color_type)
368{
369 png_byte buf[6];
370
371 if (color_type == PNG_COLOR_TYPE_PALETTE)
372 {
373 buf[0] = back->index;
374 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)1);
375 }
376 else if (color_type & PNG_COLOR_MASK_COLOR)
377 {
378 png_save_uint_16(buf, back->red);
379 png_save_uint_16(buf + 2, back->green);
380 png_save_uint_16(buf + 4, back->blue);
381 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)6);
382 }
383 else
384 {
385 png_save_uint_16(buf, back->gray);
386 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)2);
387 }
388}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500389#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500390
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500391#if defined(PNG_WRITE_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500392/* write the histogram */
393void
394png_write_hIST(png_struct *png_ptr, png_uint_16 *hist, int number)
395{
396 int i;
397 png_byte buf[3];
398
399 png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(number * 2));
400 for (i = 0; i < number; i++)
401 {
402 png_save_uint_16(buf, hist[i]);
403 png_write_chunk_data(png_ptr, buf, (png_uint_32)2);
404 }
405 png_write_chunk_end(png_ptr);
406}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500407#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500408
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500409#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500410/* write a tEXt chunk */
411void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500412png_write_tEXt(png_struct *png_ptr, charf *key, charf *text,
Guy Schalnat0d580581995-07-20 02:43:20 -0500413 png_uint_32 text_len)
414{
415 int key_len;
416
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500417 key_len = png_strlen(key);
Guy Schalnat0d580581995-07-20 02:43:20 -0500418 /* make sure we count the 0 after the key */
419 png_write_chunk_start(png_ptr, png_tEXt,
420 (png_uint_32)(key_len + text_len + 1));
421 /* key has an 0 at the end. How nice */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500422 png_write_chunk_data(png_ptr, (png_bytef *)key, (png_uint_32)(key_len + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -0500423 if (text && text_len)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500424 png_write_chunk_data(png_ptr, (png_bytef *)text, (png_uint_32)text_len);
Guy Schalnat0d580581995-07-20 02:43:20 -0500425 png_write_chunk_end(png_ptr);
426}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500427#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500428
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500429#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500430/* write a compressed chunk */
431void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500432png_write_zTXt(png_struct *png_ptr, charf *key, charf *text,
Guy Schalnat0d580581995-07-20 02:43:20 -0500433 png_uint_32 text_len, int compression)
434{
435 int key_len;
436 char buf[1];
437 int i, ret;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500438 charf **output_ptr = NULL; /* array of pointers to output */
Guy Schalnat0d580581995-07-20 02:43:20 -0500439 int num_output_ptr = 0; /* number of output pointers used */
440 int max_output_ptr = 0; /* size of output_ptr */
441
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500442 key_len = png_strlen(key);
Guy Schalnat0d580581995-07-20 02:43:20 -0500443
444 /* we can't write the chunk until we find out how much data we have,
445 which means we need to run the compresser first, and save the
446 output. This shouldn't be a problem, as the vast majority of
447 comments should be reasonable, but we will set up an array of
448 malloced pointers to be sure. */
449
450 /* set up the compression buffers */
451 png_ptr->zstream->avail_in = (uInt)text_len;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500452 png_ptr->zstream->next_in = (Bytef *)text;
Guy Schalnat0d580581995-07-20 02:43:20 -0500453 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500454 png_ptr->zstream->next_out = (Bytef *)png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500455
456 /* this is the same compression loop as in png_write_row() */
457 do
458 {
459 /* compress the data */
460 ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
461 if (ret != Z_OK)
462 {
463 /* error */
464 if (png_ptr->zstream->msg)
Guy Schalnat0f716451995-11-28 11:22:13 -0600465 (*(png_ptr->error_fn))(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500466 else
Guy Schalnat0f716451995-11-28 11:22:13 -0600467 (*(png_ptr->error_fn))(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500468 }
469 /* check to see if we need more room */
470 if (!png_ptr->zstream->avail_out && png_ptr->zstream->avail_in)
471 {
472 /* make sure the output array has room */
473 if (num_output_ptr >= max_output_ptr)
474 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500475 png_uint_32 old_max;
476
477 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500478 max_output_ptr = num_output_ptr + 4;
479 if (output_ptr)
480 output_ptr = png_realloc(png_ptr, output_ptr,
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500481 max_output_ptr * sizeof (char *),
482 old_max * sizeof (char *));
Guy Schalnat0d580581995-07-20 02:43:20 -0500483 else
484 output_ptr = png_malloc(png_ptr,
485 max_output_ptr * sizeof (char *));
486 }
487
488 /* save the data */
489 output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
490 png_ptr->zbuf_size);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500491 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500492 (png_size_t)png_ptr->zbuf_size);
493 num_output_ptr++;
494
495 /* and reset the buffer */
496 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
497 png_ptr->zstream->next_out = png_ptr->zbuf;
498 }
499 /* continue until we don't have anymore to compress */
500 } while (png_ptr->zstream->avail_in);
501
502 /* finish the compression */
503 do
504 {
505 /* tell zlib we are finished */
506 ret = deflate(png_ptr->zstream, Z_FINISH);
507 if (ret != Z_OK && ret != Z_STREAM_END)
508 {
509 /* we got an error */
510 if (png_ptr->zstream->msg)
Guy Schalnat0f716451995-11-28 11:22:13 -0600511 (*(png_ptr->error_fn))(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500512 else
Guy Schalnat0f716451995-11-28 11:22:13 -0600513 (*(png_ptr->error_fn))(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500514 }
515
516 /* check to see if we need more room */
517 if (!png_ptr->zstream->avail_out && ret == Z_OK)
518 {
519 /* check to make sure our output array has room */
520 if (num_output_ptr >= max_output_ptr)
521 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500522 png_uint_32 old_max;
523
524 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500525 max_output_ptr = num_output_ptr + 4;
526 if (output_ptr)
527 output_ptr = png_realloc(png_ptr, output_ptr,
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500528 max_output_ptr * sizeof (char *),
529 old_max * sizeof (char *));
Guy Schalnat0d580581995-07-20 02:43:20 -0500530 else
531 output_ptr = png_malloc(png_ptr,
532 max_output_ptr * sizeof (char *));
533 }
534
535 /* save off the data */
536 output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
537 png_ptr->zbuf_size);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500538 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500539 (png_size_t)png_ptr->zbuf_size);
540 num_output_ptr++;
541
542 /* and reset the buffer pointers */
543 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
544 png_ptr->zstream->next_out = png_ptr->zbuf;
545 }
546 } while (ret != Z_STREAM_END);
547
548 /* text length is number of buffers plus last buffer */
549 text_len = png_ptr->zbuf_size * num_output_ptr;
550 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
551 text_len += (png_uint_32)(png_ptr->zbuf_size -
552 png_ptr->zstream->avail_out);
553
554 /* write start of chunk */
555 png_write_chunk_start(png_ptr, png_zTXt,
556 (png_uint_32)(key_len + text_len + 2));
557 /* write key */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500558 png_write_chunk_data(png_ptr, (png_bytef *)key, (png_uint_32)(key_len + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -0500559 buf[0] = compression;
560 /* write compression */
561 png_write_chunk_data(png_ptr, (png_byte *)buf, (png_uint_32)1);
562
563 /* write saved output buffers, if any */
564 for (i = 0; i < num_output_ptr; i++)
565 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500566 png_write_chunk_data(png_ptr, (png_bytef *)output_ptr[i], png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500567 png_large_free(png_ptr, output_ptr[i]);
568 }
569 if (max_output_ptr)
570 png_free(png_ptr, output_ptr);
571 /* write anything left in zbuf */
572 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
573 png_write_chunk_data(png_ptr, png_ptr->zbuf,
574 png_ptr->zbuf_size - png_ptr->zstream->avail_out);
575 /* close the chunk */
576 png_write_chunk_end(png_ptr);
577
578 /* reset zlib for another zTXt or the image data */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500579 deflateReset(png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500580}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500581#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500582
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500583#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500584/* write the pHYs chunk */
585void
586png_write_pHYs(png_struct *png_ptr, png_uint_32 x_pixels_per_unit,
587 png_uint_32 y_pixels_per_unit,
588 int unit_type)
589{
590 png_byte buf[9];
591
592 png_save_uint_32(buf, x_pixels_per_unit);
593 png_save_uint_32(buf + 4, y_pixels_per_unit);
594 buf[8] = unit_type;
595
596 png_write_chunk(png_ptr, png_pHYs, buf, (png_uint_32)9);
597}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500598#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500599
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500600#if defined(PNG_WRITE_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500601/* write the oFFs chunk */
602void
603png_write_oFFs(png_struct *png_ptr, png_uint_32 x_offset,
604 png_uint_32 y_offset,
605 int unit_type)
606{
607 png_byte buf[9];
608
609 png_save_uint_32(buf, x_offset);
610 png_save_uint_32(buf + 4, y_offset);
611 buf[8] = unit_type;
612
613 png_write_chunk(png_ptr, png_oFFs, buf, (png_uint_32)9);
614}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500615#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500616
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500617#if defined(PNG_WRITE_tIME_SUPPORTED)
618/* write the tIME chunk. Use either png_convert_from_struct_tm()
619 or png_convert_from_time_t(), or fill in the structure yourself */
Guy Schalnat0d580581995-07-20 02:43:20 -0500620void
621png_write_tIME(png_struct *png_ptr, png_time *mod_time)
622{
623 png_byte buf[7];
624
625 png_save_uint_16(buf, mod_time->year);
626 buf[2] = mod_time->month;
627 buf[3] = mod_time->day;
628 buf[4] = mod_time->hour;
629 buf[5] = mod_time->minute;
630 buf[6] = mod_time->second;
631
632 png_write_chunk(png_ptr, png_tIME, buf, (png_uint_32)7);
633}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500634#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500635
636/* initializes the row writing capability of libpng */
637void
638png_write_start_row(png_struct *png_ptr)
639{
640 /* set up row buffer */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500641 png_ptr->row_buf = (png_bytef *)png_large_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500642 (((png_uint_32)png_ptr->usr_channels *
643 (png_uint_32)png_ptr->usr_bit_depth *
644 png_ptr->width) >> 3) + 1);
645 /* set up filtering buffers, if filtering */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500646 if (png_ptr->do_filter)
Guy Schalnat0d580581995-07-20 02:43:20 -0500647 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500648 png_ptr->prev_row = (png_bytef *)png_large_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500649 png_ptr->rowbytes + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500650 png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
651 png_ptr->save_row = (png_bytef *)png_large_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500652 png_ptr->rowbytes + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500653 png_memset(png_ptr->save_row, 0, (png_size_t)png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500654 }
655
656 /* if interlaced, we need to set up width and height of pass */
657 if (png_ptr->interlaced)
658 {
659 if (!(png_ptr->transformations & PNG_INTERLACE))
660 {
661 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
662 png_pass_ystart[0]) / png_pass_yinc[0];
663 png_ptr->usr_width = (png_ptr->width +
664 png_pass_inc[0] - 1 -
665 png_pass_start[0]) /
666 png_pass_inc[0];
667 }
668 else
669 {
670 png_ptr->num_rows = png_ptr->height;
671 png_ptr->usr_width = png_ptr->width;
672 }
673 }
674 else
675 {
676 png_ptr->num_rows = png_ptr->height;
677 png_ptr->usr_width = png_ptr->width;
678 }
679 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
680 png_ptr->zstream->next_out = png_ptr->zbuf;
681}
682
683/* Internal use only. Called when finished processing a row of data */
684void
685png_write_finish_row(png_struct *png_ptr)
686{
687 int ret;
688
689 /* next row */
690 png_ptr->row_number++;
691 /* see if we are done */
Guy Schalnat0f716451995-11-28 11:22:13 -0600692 if (png_ptr->row_number < png_ptr->num_rows || png_ptr->mode > PNG_HAVE_IDAT)
Guy Schalnat0d580581995-07-20 02:43:20 -0500693 return;
694
695 /* if interlaced, go to next pass */
696 if (png_ptr->interlaced)
697 {
698 png_ptr->row_number = 0;
699 if (png_ptr->transformations & PNG_INTERLACE)
700 {
701 png_ptr->pass++;
702 }
703 else
704 {
705 /* loop until we find a non-zero width or height pass */
706 do
707 {
708 png_ptr->pass++;
709 if (png_ptr->pass >= 7)
710 break;
711 png_ptr->usr_width = (png_ptr->width +
712 png_pass_inc[png_ptr->pass] - 1 -
713 png_pass_start[png_ptr->pass]) /
714 png_pass_inc[png_ptr->pass];
715 png_ptr->num_rows = (png_ptr->height +
716 png_pass_yinc[png_ptr->pass] - 1 -
717 png_pass_ystart[png_ptr->pass]) /
718 png_pass_yinc[png_ptr->pass];
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500719 if (png_ptr->transformations & PNG_INTERLACE)
720 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500721 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
722
723 }
724
725 /* reset filter row */
726 if (png_ptr->prev_row)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500727 png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500728 /* if we have more data to get, go get it */
729 if (png_ptr->pass < 7)
730 return;
731 }
732
733 /* if we get here, we've just written the last row, so we need
734 to flush the compressor */
735 do
736 {
737 /* tell the compressor we are done */
738 ret = deflate(png_ptr->zstream, Z_FINISH);
739 /* check for an error */
740 if (ret != Z_OK && ret != Z_STREAM_END)
741 {
742 if (png_ptr->zstream->msg)
Guy Schalnat0f716451995-11-28 11:22:13 -0600743 (*(png_ptr->error_fn))(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500744 else
Guy Schalnat0f716451995-11-28 11:22:13 -0600745 (*(png_ptr->error_fn))(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500746 }
747 /* check to see if we need more room */
748 if (!png_ptr->zstream->avail_out && ret == Z_OK)
749 {
750 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
751 png_ptr->zstream->next_out = png_ptr->zbuf;
752 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
753 }
754 } while (ret != Z_STREAM_END);
755
756 /* write any extra space */
757 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
758 {
759 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
760 png_ptr->zstream->avail_out);
761 }
762
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500763 deflateReset(png_ptr->zstream);
Guy Schalnat0f716451995-11-28 11:22:13 -0600764 png_ptr->mode = PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500765}
766
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500767#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500768/* pick out the correct pixels for the interlace pass.
769
770 The basic idea here is to go through the row with a source
771 pointer and a destination pointer (sp and dp), and copy the
772 correct pixels for the pass. As the row gets compacted,
773 sp will always be >= dp, so we should never overwrite anything.
774 See the default: case for the easiest code to understand.
775 */
776void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500777png_do_write_interlace(png_row_info *row_info, png_bytef *row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -0500778{
779 /* we don't have to do anything on the last pass (6) */
780 if (row && row_info && pass < 6)
781 {
782 /* each pixel depth is handled seperately */
783 switch (row_info->pixel_depth)
784 {
785 case 1:
786 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500787 png_bytef *sp;
788 png_bytef *dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500789 int shift;
790 int d;
791 int value;
792 png_uint_32 i;
793
794 dp = row;
795 d = 0;
796 shift = 7;
797 for (i = png_pass_start[pass];
798 i < row_info->width;
799 i += png_pass_inc[pass])
800 {
801 sp = row + (png_size_t)(i >> 3);
802 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
803 d |= (value << shift);
804
805 if (shift == 0)
806 {
807 shift = 7;
808 *dp++ = d;
809 d = 0;
810 }
811 else
812 shift--;
813
814 }
815 if (shift != 7)
816 *dp = d;
817 break;
818 }
819 case 2:
820 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500821 png_bytef *sp;
822 png_bytef *dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500823 int shift;
824 int d;
825 int value;
826 png_uint_32 i;
827
828 dp = row;
829 shift = 6;
830 d = 0;
831 for (i = png_pass_start[pass];
832 i < row_info->width;
833 i += png_pass_inc[pass])
834 {
835 sp = row + (png_size_t)(i >> 2);
836 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
837 d |= (value << shift);
838
839 if (shift == 0)
840 {
841 shift = 6;
842 *dp++ = d;
843 d = 0;
844 }
845 else
846 shift -= 2;
847 }
848 if (shift != 6)
849 *dp = d;
850 break;
851 }
852 case 4:
853 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500854 png_bytef *sp;
855 png_bytef *dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500856 int shift;
857 int d;
858 int value;
859 png_uint_32 i;
860
861 dp = row;
862 shift = 4;
863 d = 0;
864 for (i = png_pass_start[pass];
865 i < row_info->width;
866 i += png_pass_inc[pass])
867 {
868 sp = row + (png_size_t)(i >> 1);
869 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
870 d |= (value << shift);
871
872 if (shift == 0)
873 {
874 shift = 4;
875 *dp++ = d;
876 d = 0;
877 }
878 else
879 shift -= 4;
880 }
881 if (shift != 4)
882 *dp = d;
883 break;
884 }
885 default:
886 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500887 png_bytef *sp;
888 png_bytef *dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500889 png_uint_32 i;
890 int pixel_bytes;
891
892 /* start at the beginning */
893 dp = row;
894 /* find out how many bytes each pixel takes up */
895 pixel_bytes = (row_info->pixel_depth >> 3);
896 /* loop through the row, only looking at the pixels that
897 matter */
898 for (i = png_pass_start[pass];
899 i < row_info->width;
900 i += png_pass_inc[pass])
901 {
902 /* find out where the original pixel is */
903 sp = row + (png_size_t)(i * pixel_bytes);
904 /* move the pixel */
905 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500906 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500907 /* next pixel */
908 dp += pixel_bytes;
909 }
910 break;
911 }
912 }
913 /* set new row width */
914 row_info->width = (row_info->width +
915 png_pass_inc[pass] - 1 -
916 png_pass_start[pass]) /
917 png_pass_inc[pass];
918 row_info->rowbytes = ((row_info->width *
919 row_info->pixel_depth + 7) >> 3);
920
921 }
922}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500923#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500924
925/* this filters the row. Both row and prev_row have space at the
926 first byte for the filter byte. */
927void
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500928png_write_filter_row(png_row_info *row_info, png_bytef *row,
929 png_bytef *prev_row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500930{
931 int minf, bpp;
932 png_uint_32 i, v;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500933 png_uint_32 s0, s1, s2, s3, s4, mins;
934 png_bytef *rp, *pp, *cp, *lp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500935
936 /* find out how many bytes offset each pixel is */
937 bpp = (row_info->pixel_depth + 7) / 8;
938 if (bpp < 1)
939 bpp = 1;
940
941 /* the prediction method we use is to find which method provides
942 the smallest value when summing the abs of the distances from
943 zero using anything >= 128 as negitive numbers. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500944 s0 = s1 = s2 = s3 = s4 = 0;
945
946 for (i = 0, rp = row + 1, pp = prev_row + 1, lp = row + 1 - bpp,
947 cp = prev_row + 1 - bpp;
948 i < bpp; i++, rp++, pp++, lp++, cp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500949 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500950 /* check none filter */
Guy Schalnat0d580581995-07-20 02:43:20 -0500951 v = *rp;
952 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500953 s0 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500954 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500955 s0 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500956
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500957 /* check up filter */
Guy Schalnat0d580581995-07-20 02:43:20 -0500958 v = (png_byte)(((int)*rp - (int)*pp) & 0xff);
959
960 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500961 s2 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500962 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500963 s2 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500964
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500965 /* check avg filter */
966 v = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500967
968 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500969 s3 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500970 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500971 s3 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500972 }
973
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500974 /* some filters are same until we get past bpp */
975 s1 = s0;
976 s4 = s2;
Guy Schalnat0d580581995-07-20 02:43:20 -0500977
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500978 for (; i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500979 {
980 int a, b, c, pa, pb, pc, p;
981
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500982 /* check none filter */
983 v = *rp;
984 if (v < 128)
985 s0 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500986 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500987 s0 += 256 - v;
988
989 /* check sub filter */
990 v = (png_byte)(((int)*rp - (int)*lp) & 0xff);
991
992 if (v < 128)
993 s1 += v;
994 else
995 s1 += 256 - v;
996
997 /* check up filter */
998 v = (png_byte)(((int)*rp - (int)*pp) & 0xff);
999
1000 if (v < 128)
1001 s2 += v;
1002 else
1003 s2 += 256 - v;
1004
1005 /* check avg filter */
1006 v = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
1007
1008 if (v < 128)
1009 s3 += v;
1010 else
1011 s3 += 256 - v;
1012
1013 /* check paeth filter */
1014 b = *pp;
1015 c = *cp;
1016 a = *lp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001017 p = a + b - c;
1018 pa = abs(p - a);
1019 pb = abs(p - b);
1020 pc = abs(p - c);
1021
1022 if (pa <= pb && pa <= pc)
1023 p = a;
1024 else if (pb <= pc)
1025 p = b;
1026 else
1027 p = c;
1028
1029 v = (png_byte)(((int)*rp - p) & 0xff);
1030
1031 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001032 s4 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001033 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001034 s4 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001035 }
1036
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001037 mins = s0;
1038 minf = 0;
1039
1040 if (s1 < mins)
Guy Schalnat0d580581995-07-20 02:43:20 -05001041 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001042 mins = s1;
1043 minf = 1;
1044 }
1045
1046 if (s2 < mins)
1047 {
1048 mins = s2;
1049 minf = 2;
1050 }
1051
1052 if (s3 < mins)
1053 {
1054 mins = s3;
1055 minf = 3;
1056 }
1057
1058 if (s4 < mins)
1059 {
1060 mins = s4;
Guy Schalnat0d580581995-07-20 02:43:20 -05001061 minf = 4;
1062 }
1063
1064 /* set filter byte */
1065 row[0] = minf;
1066
1067 /* do filter */
1068 switch (minf)
1069 {
1070 /* sub filter */
1071 case 1:
1072 for (i = bpp, rp = row + (png_size_t)row_info->rowbytes,
1073 lp = row + (png_size_t)row_info->rowbytes - bpp;
1074 i < row_info->rowbytes; i++, rp--, lp--)
1075 {
1076 *rp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
1077 }
1078 break;
1079 /* up filter */
1080 case 2:
1081 for (i = 0, rp = row + (png_size_t)row_info->rowbytes,
1082 pp = prev_row + (png_size_t)row_info->rowbytes;
1083 i < row_info->rowbytes; i++, rp--, pp--)
1084 {
1085 *rp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1086 }
1087 break;
1088 /* avg filter */
1089 case 3:
1090 for (i = row_info->rowbytes,
1091 rp = row + (png_size_t)row_info->rowbytes,
1092 pp = prev_row + (png_size_t)row_info->rowbytes,
1093 lp = row + (png_size_t)row_info->rowbytes - bpp;
1094 i > bpp; i--, rp--, lp--, pp--)
1095 {
1096 *rp = (png_byte)(((int)*rp - (((int)*lp + (int)*pp) /
1097 2)) & 0xff);
1098 }
1099 for (; i > 0; i--, rp--, pp--)
1100 {
1101 *rp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
1102 }
1103 break;
1104 /* paeth filter */
1105 case 4:
1106 for (i = row_info->rowbytes,
1107 rp = row + (png_size_t)row_info->rowbytes,
1108 pp = prev_row + (png_size_t)row_info->rowbytes,
1109 lp = row + (png_size_t)row_info->rowbytes - bpp,
1110 cp = prev_row + (png_size_t)row_info->rowbytes - bpp;
1111 i > 0; i--, rp--, lp--, pp--, cp--)
1112 {
1113 int a, b, c, pa, pb, pc, p;
1114
1115 b = *pp;
1116 if (i > bpp)
1117 {
1118 c = *cp;
1119 a = *lp;
1120 }
1121 else
1122 {
1123 a = c = 0;
1124 }
1125 p = a + b - c;
1126 pa = abs(p - a);
1127 pb = abs(p - b);
1128 pc = abs(p - c);
1129
1130 if (pa <= pb && pa <= pc)
1131 p = a;
1132 else if (pb <= pc)
1133 p = b;
1134 else
1135 p = c;
1136
1137 *rp = (png_byte)(((int)*rp - p) & 0xff);
1138 }
1139 break;
1140 }
1141}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001142