blob: d1f834f7b6f2d35bdf9a2b137378b22c00146d71 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwutil.c - utilities to write a png file
3
Guy Schalnat6d764711995-12-19 03:22:19 -06004 libpng 1.0 beta 2 - version 0.85
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 Schalnat6d764711995-12-19 03:22:19 -06007 December 19, 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
Guy Schalnat6d764711995-12-19 03:22:19 -060016png_save_uint_32(png_bytep buf, png_uint_32 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050017{
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
Guy Schalnat6d764711995-12-19 03:22:19 -060026png_save_uint_16(png_bytep buf, png_uint_16 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050027{
28 buf[0] = (png_byte)((i >> 8) & 0xff);
29 buf[1] = (png_byte)(i & 0xff);
30}
31
32/* write a 32 bit number */
33void
Guy Schalnat6d764711995-12-19 03:22:19 -060034png_write_uint_32(png_structp png_ptr, png_uint_32 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050035{
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 Schalnat6d764711995-12-19 03:22:19 -060042 png_write_data(png_ptr, buf, 4);
Guy Schalnat0d580581995-07-20 02:43:20 -050043}
44
45/* write a 16 bit number */
46void
Guy Schalnat6d764711995-12-19 03:22:19 -060047png_write_uint_16(png_structp png_ptr, png_uint_16 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050048{
49 png_byte buf[2];
50
51 buf[0] = (png_byte)((i >> 8) & 0xff);
52 buf[1] = (png_byte)(i & 0xff);
Guy Schalnat6d764711995-12-19 03:22:19 -060053 png_write_data(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
Guy Schalnat6d764711995-12-19 03:22:19 -060065png_write_chunk(png_structp png_ptr, png_bytep type,
66 png_bytep 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 Schalnat6d764711995-12-19 03:22:19 -060071 png_write_data(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 Schalnat6d764711995-12-19 03:22:19 -060079 png_write_data(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
Guy Schalnat6d764711995-12-19 03:22:19 -060089png_write_chunk_start(png_structp png_ptr, png_bytep type,
Guy Schalnat0d580581995-07-20 02:43:20 -050090 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 Schalnat6d764711995-12-19 03:22:19 -060095 png_write_data(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 Schalnat6d764711995-12-19 03:22:19 -0600106png_write_chunk_data(png_structp png_ptr, png_bytep 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 Schalnat6d764711995-12-19 03:22:19 -0600112 png_write_data(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
Guy Schalnat6d764711995-12-19 03:22:19 -0600118png_write_chunk_end(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500119{
120 /* write the crc */
121 png_write_uint_32(png_ptr, ~png_ptr->crc);
122}
123
124/* simple function to write the signature */
125void
Guy Schalnat6d764711995-12-19 03:22:19 -0600126png_write_sig(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500127{
128 /* write the 8 byte signature */
Guy Schalnat6d764711995-12-19 03:22:19 -0600129 png_write_data(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
Guy Schalnat6d764711995-12-19 03:22:19 -0600136png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
Guy Schalnat0d580581995-07-20 02:43:20 -0500137 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 Schalnat6d764711995-12-19 03:22:19 -0600178 png_ptr->usr_channels = png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500179
180 /* write the chunk */
Guy Schalnat6d764711995-12-19 03:22:19 -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 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600184 png_ptr->zstream = (z_stream *)png_malloc(png_ptr, sizeof (z_stream));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500185 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600224png_write_PLTE(png_structp png_ptr, png_colorp palette, int number)
Guy Schalnat0d580581995-07-20 02:43:20 -0500225{
226 int i;
Guy Schalnat6d764711995-12-19 03:22:19 -0600227 png_colorp pal_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500228 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 Schalnat6d764711995-12-19 03:22:19 -0600245png_write_IDAT(png_structp png_ptr, png_bytep 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600252png_write_IEND(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500253{
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
Guy Schalnat6d764711995-12-19 03:22:19 -0600260png_write_gAMA(png_structp png_ptr, double gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500261{
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
Guy Schalnat6d764711995-12-19 03:22:19 -0600275png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500276{
277 png_byte buf[4];
278 int size;
279
Guy Schalnat6d764711995-12-19 03:22:19 -0600280 /* make sure we don't depend upon the order of PNG_COLOR_8 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500281 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600306png_write_cHRM ( png_structp png_ptr, double white_x, double white_y,
307 double red_x, double red_y, double green_x, double green_y,
308 double blue_x, double blue_y)
Guy Schalnat0d580581995-07-20 02:43:20 -0500309{
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
Guy Schalnat6d764711995-12-19 03:22:19 -0600337png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
Guy Schalnat0d580581995-07-20 02:43:20 -0500338 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600367png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500368{
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
Guy Schalnat6d764711995-12-19 03:22:19 -0600384 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500385 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600394png_write_hIST(png_structp png_ptr, png_uint_16p hist, int number)
Guy Schalnat0d580581995-07-20 02:43:20 -0500395{
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 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600402 png_save_uint_16(buf, hist[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500403 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 Schalnat6d764711995-12-19 03:22:19 -0600412png_write_tEXt(png_structp png_ptr, png_charp key, png_charp 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,
Guy Schalnat6d764711995-12-19 03:22:19 -0600420 (png_uint_32)(key_len + text_len + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -0500421 /* key has an 0 at the end. How nice */
Guy Schalnat6d764711995-12-19 03:22:19 -0600422 png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -0500423 if (text && text_len)
Guy Schalnat6d764711995-12-19 03:22:19 -0600424 png_write_chunk_data(png_ptr, (png_bytep )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 Schalnat6d764711995-12-19 03:22:19 -0600432png_write_zTXt(png_structp png_ptr, png_charp key, png_charp 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 Schalnat6d764711995-12-19 03:22:19 -0600438 png_charpp 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600456 /* this is the same compression loop as in png_write_row() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500457 do
458 {
459 /* compress the data */
Guy Schalnat6d764711995-12-19 03:22:19 -0600460 ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500461 if (ret != Z_OK)
462 {
463 /* error */
464 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600465 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500466 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600467 png_error(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)
Guy Schalnat6d764711995-12-19 03:22:19 -0600474 {
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)
Guy Schalnat6d764711995-12-19 03:22:19 -0600480 output_ptr = (png_charpp)png_realloc(png_ptr, output_ptr,
481 max_output_ptr * sizeof (png_charpp),
482 old_max * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500483 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600484 output_ptr = (png_charpp)png_malloc(png_ptr,
485 max_output_ptr * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500486 }
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
Guy Schalnat6d764711995-12-19 03:22:19 -0600502 /* finish the compression */
Guy Schalnat0d580581995-07-20 02:43:20 -0500503 do
504 {
505 /* tell zlib we are finished */
Guy Schalnat6d764711995-12-19 03:22:19 -0600506 ret = deflate(png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500507 if (ret != Z_OK && ret != Z_STREAM_END)
508 {
509 /* we got an error */
510 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600511 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500512 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600513 png_error(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 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600520 if (num_output_ptr >= max_output_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500521 {
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)
Guy Schalnat6d764711995-12-19 03:22:19 -0600527 output_ptr = (png_charpp)png_realloc(png_ptr, output_ptr,
528 max_output_ptr * sizeof (png_charp),
529 old_max * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500530 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600531 output_ptr = (png_charpp)png_malloc(png_ptr,
532 max_output_ptr * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500533 }
534
535 /* save off the data */
536 output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
537 png_ptr->zbuf_size);
Guy Schalnat6d764711995-12-19 03:22:19 -0600538 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 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600549 text_len = png_ptr->zbuf_size * num_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500550 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 Schalnat6d764711995-12-19 03:22:19 -0600558 png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -0500559 buf[0] = compression;
560 /* write compression */
Guy Schalnat6d764711995-12-19 03:22:19 -0600561 png_write_chunk_data(png_ptr, (png_bytep )buf, (png_uint_32)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500562
563 /* write saved output buffers, if any */
564 for (i = 0; i < num_output_ptr; i++)
565 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600566 png_write_chunk_data(png_ptr, (png_bytep )output_ptr[i], png_ptr->zbuf_size);
567 png_large_free(png_ptr, output_ptr[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500568 }
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 Schalnat6d764711995-12-19 03:22:19 -0600579 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600586png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
Guy Schalnat0d580581995-07-20 02:43:20 -0500587 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600603png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
Guy Schalnat0d580581995-07-20 02:43:20 -0500604 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600621png_write_tIME(png_structp png_ptr, png_timep mod_time)
Guy Schalnat0d580581995-07-20 02:43:20 -0500622{
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
Guy Schalnat6d764711995-12-19 03:22:19 -0600638png_write_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500639{
640 /* set up row buffer */
Guy Schalnat6d764711995-12-19 03:22:19 -0600641 png_ptr->row_buf = (png_bytep )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 *
Guy Schalnat6d764711995-12-19 03:22:19 -0600644 png_ptr->width + 7) >> 3) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500645 /* 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 Schalnat6d764711995-12-19 03:22:19 -0600648 png_ptr->prev_row = (png_bytep )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);
Guy Schalnat6d764711995-12-19 03:22:19 -0600651 png_ptr->save_row = (png_bytep )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 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600657 if (png_ptr->interlaced)
Guy Schalnat0d580581995-07-20 02:43:20 -0500658 {
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
Guy Schalnat6d764711995-12-19 03:22:19 -0600675 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500676 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
Guy Schalnat6d764711995-12-19 03:22:19 -0600685png_write_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500686{
687 int ret;
688
689 /* next row */
690 png_ptr->row_number++;
691 /* see if we are done */
Guy Schalnat6d764711995-12-19 03:22:19 -0600692 if (png_ptr->row_number < png_ptr->num_rows)
693 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500694
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;
Guy Schalnat6d764711995-12-19 03:22:19 -0600711 png_ptr->usr_width = (png_ptr->width +
Guy Schalnat0d580581995-07-20 02:43:20 -0500712 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 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600729 if (png_ptr->pass < 7)
Guy Schalnat0d580581995-07-20 02:43:20 -0500730 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 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600738 ret = deflate(png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500739 /* check for an error */
740 if (ret != Z_OK && ret != Z_STREAM_END)
741 {
742 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600743 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500744 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600745 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500746 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600747 /* check to see if we need more room */
Guy Schalnat0d580581995-07-20 02:43:20 -0500748 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 Schalnat0d580581995-07-20 02:43:20 -0500764}
765
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500766#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500767/* pick out the correct pixels for the interlace pass.
768
769 The basic idea here is to go through the row with a source
770 pointer and a destination pointer (sp and dp), and copy the
771 correct pixels for the pass. As the row gets compacted,
772 sp will always be >= dp, so we should never overwrite anything.
773 See the default: case for the easiest code to understand.
774 */
775void
Guy Schalnat6d764711995-12-19 03:22:19 -0600776png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -0500777{
778 /* we don't have to do anything on the last pass (6) */
779 if (row && row_info && pass < 6)
780 {
781 /* each pixel depth is handled seperately */
782 switch (row_info->pixel_depth)
Guy Schalnat6d764711995-12-19 03:22:19 -0600783 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500784 case 1:
785 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600786 png_bytep sp;
787 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500788 int shift;
789 int d;
790 int value;
791 png_uint_32 i;
792
793 dp = row;
794 d = 0;
795 shift = 7;
796 for (i = png_pass_start[pass];
797 i < row_info->width;
798 i += png_pass_inc[pass])
799 {
800 sp = row + (png_size_t)(i >> 3);
Guy Schalnat6d764711995-12-19 03:22:19 -0600801 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
Guy Schalnat0d580581995-07-20 02:43:20 -0500802 d |= (value << shift);
803
804 if (shift == 0)
805 {
806 shift = 7;
807 *dp++ = d;
808 d = 0;
809 }
810 else
811 shift--;
812
813 }
814 if (shift != 7)
815 *dp = d;
816 break;
817 }
818 case 2:
Guy Schalnat6d764711995-12-19 03:22:19 -0600819 {
820 png_bytep sp;
821 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500822 int shift;
823 int d;
824 int value;
825 png_uint_32 i;
826
827 dp = row;
828 shift = 6;
829 d = 0;
830 for (i = png_pass_start[pass];
831 i < row_info->width;
832 i += png_pass_inc[pass])
833 {
834 sp = row + (png_size_t)(i >> 2);
835 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
836 d |= (value << shift);
837
838 if (shift == 0)
839 {
840 shift = 6;
841 *dp++ = d;
842 d = 0;
843 }
844 else
845 shift -= 2;
846 }
847 if (shift != 6)
848 *dp = d;
849 break;
850 }
851 case 4:
852 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600853 png_bytep sp;
854 png_bytep dp;
855 int shift;
Guy Schalnat0d580581995-07-20 02:43:20 -0500856 int d;
857 int value;
858 png_uint_32 i;
859
860 dp = row;
861 shift = 4;
862 d = 0;
863 for (i = png_pass_start[pass];
864 i < row_info->width;
865 i += png_pass_inc[pass])
866 {
867 sp = row + (png_size_t)(i >> 1);
868 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
869 d |= (value << shift);
870
871 if (shift == 0)
872 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600873 shift = 4;
Guy Schalnat0d580581995-07-20 02:43:20 -0500874 *dp++ = d;
875 d = 0;
876 }
877 else
878 shift -= 4;
879 }
880 if (shift != 4)
881 *dp = d;
882 break;
883 }
884 default:
885 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600886 png_bytep sp;
887 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500888 png_uint_32 i;
889 int pixel_bytes;
890
Guy Schalnat6d764711995-12-19 03:22:19 -0600891 /* start at the beginning */
Guy Schalnat0d580581995-07-20 02:43:20 -0500892 dp = row;
893 /* find out how many bytes each pixel takes up */
894 pixel_bytes = (row_info->pixel_depth >> 3);
895 /* loop through the row, only looking at the pixels that
896 matter */
897 for (i = png_pass_start[pass];
898 i < row_info->width;
899 i += png_pass_inc[pass])
900 {
901 /* find out where the original pixel is */
902 sp = row + (png_size_t)(i * pixel_bytes);
903 /* move the pixel */
904 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500905 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500906 /* next pixel */
907 dp += pixel_bytes;
908 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600909 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500910 }
911 }
912 /* set new row width */
913 row_info->width = (row_info->width +
914 png_pass_inc[pass] - 1 -
915 png_pass_start[pass]) /
916 png_pass_inc[pass];
917 row_info->rowbytes = ((row_info->width *
918 row_info->pixel_depth + 7) >> 3);
919
920 }
921}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500922#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500923
924/* this filters the row. Both row and prev_row have space at the
925 first byte for the filter byte. */
926void
Guy Schalnat6d764711995-12-19 03:22:19 -0600927png_write_filter_row(png_row_infop row_info, png_bytep row,
928 png_bytep prev_row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500929{
930 int minf, bpp;
931 png_uint_32 i, v;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500932 png_uint_32 s0, s1, s2, s3, s4, mins;
Guy Schalnat6d764711995-12-19 03:22:19 -0600933 png_bytep rp, pp, cp, lp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500934
935 /* find out how many bytes offset each pixel is */
936 bpp = (row_info->pixel_depth + 7) / 8;
937 if (bpp < 1)
938 bpp = 1;
939
940 /* the prediction method we use is to find which method provides
941 the smallest value when summing the abs of the distances from
942 zero using anything >= 128 as negitive numbers. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500943 s0 = s1 = s2 = s3 = s4 = 0;
944
Guy Schalnat6d764711995-12-19 03:22:19 -0600945 for (i = 0, rp = row + 1, pp = prev_row + 1, lp = row + 1 - bpp,
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500946 cp = prev_row + 1 - bpp;
947 i < bpp; i++, rp++, pp++, lp++, cp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500948 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500949 /* check none filter */
Guy Schalnat0d580581995-07-20 02:43:20 -0500950 v = *rp;
951 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500952 s0 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500953 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500954 s0 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500955
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500956 /* check up filter */
Guy Schalnat0d580581995-07-20 02:43:20 -0500957 v = (png_byte)(((int)*rp - (int)*pp) & 0xff);
958
959 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500960 s2 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500961 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500962 s2 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500963
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500964 /* check avg filter */
965 v = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500966
967 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500968 s3 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500969 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500970 s3 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500971 }
972
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500973 /* some filters are same until we get past bpp */
974 s1 = s0;
975 s4 = s2;
Guy Schalnat0d580581995-07-20 02:43:20 -0500976
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500977 for (; i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500978 {
979 int a, b, c, pa, pb, pc, p;
980
Guy Schalnat6d764711995-12-19 03:22:19 -0600981 /* check none filter */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500982 v = *rp;
983 if (v < 128)
984 s0 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500985 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500986 s0 += 256 - v;
987
988 /* check sub filter */
989 v = (png_byte)(((int)*rp - (int)*lp) & 0xff);
990
991 if (v < 128)
992 s1 += v;
993 else
994 s1 += 256 - v;
995
996 /* check up filter */
997 v = (png_byte)(((int)*rp - (int)*pp) & 0xff);
998
Guy Schalnat6d764711995-12-19 03:22:19 -0600999 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001000 s2 += v;
1001 else
1002 s2 += 256 - v;
1003
1004 /* check avg filter */
1005 v = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
1006
1007 if (v < 128)
1008 s3 += v;
1009 else
1010 s3 += 256 - v;
1011
1012 /* check paeth filter */
1013 b = *pp;
1014 c = *cp;
1015 a = *lp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001016 p = a + b - c;
Guy Schalnat6d764711995-12-19 03:22:19 -06001017 pa = abs(p - a);
Guy Schalnat0d580581995-07-20 02:43:20 -05001018 pb = abs(p - b);
1019 pc = abs(p - c);
1020
1021 if (pa <= pb && pa <= pc)
1022 p = a;
1023 else if (pb <= pc)
1024 p = b;
1025 else
1026 p = c;
1027
1028 v = (png_byte)(((int)*rp - p) & 0xff);
1029
1030 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001031 s4 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001032 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001033 s4 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001034 }
1035
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001036 mins = s0;
1037 minf = 0;
1038
1039 if (s1 < mins)
Guy Schalnat0d580581995-07-20 02:43:20 -05001040 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001041 mins = s1;
1042 minf = 1;
1043 }
1044
1045 if (s2 < mins)
1046 {
1047 mins = s2;
1048 minf = 2;
1049 }
1050
1051 if (s3 < mins)
1052 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001053 mins = s3;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001054 minf = 3;
1055 }
1056
1057 if (s4 < mins)
1058 {
1059 mins = s4;
Guy Schalnat0d580581995-07-20 02:43:20 -05001060 minf = 4;
1061 }
1062
1063 /* set filter byte */
1064 row[0] = minf;
1065
1066 /* do filter */
1067 switch (minf)
1068 {
1069 /* sub filter */
1070 case 1:
Guy Schalnat6d764711995-12-19 03:22:19 -06001071 for (i = bpp, rp = row + (png_size_t)row_info->rowbytes,
Guy Schalnat0d580581995-07-20 02:43:20 -05001072 lp = row + (png_size_t)row_info->rowbytes - bpp;
1073 i < row_info->rowbytes; i++, rp--, lp--)
1074 {
1075 *rp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
1076 }
1077 break;
1078 /* up filter */
1079 case 2:
1080 for (i = 0, rp = row + (png_size_t)row_info->rowbytes,
1081 pp = prev_row + (png_size_t)row_info->rowbytes;
1082 i < row_info->rowbytes; i++, rp--, pp--)
1083 {
1084 *rp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1085 }
1086 break;
1087 /* avg filter */
1088 case 3:
Guy Schalnat6d764711995-12-19 03:22:19 -06001089 for (i = row_info->rowbytes,
Guy Schalnat0d580581995-07-20 02:43:20 -05001090 rp = row + (png_size_t)row_info->rowbytes,
1091 pp = prev_row + (png_size_t)row_info->rowbytes,
1092 lp = row + (png_size_t)row_info->rowbytes - bpp;
1093 i > bpp; i--, rp--, lp--, pp--)
1094 {
1095 *rp = (png_byte)(((int)*rp - (((int)*lp + (int)*pp) /
1096 2)) & 0xff);
1097 }
1098 for (; i > 0; i--, rp--, pp--)
1099 {
1100 *rp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
1101 }
1102 break;
1103 /* paeth filter */
1104 case 4:
1105 for (i = row_info->rowbytes,
1106 rp = row + (png_size_t)row_info->rowbytes,
Guy Schalnat6d764711995-12-19 03:22:19 -06001107 pp = prev_row + (png_size_t)row_info->rowbytes,
Guy Schalnat0d580581995-07-20 02:43:20 -05001108 lp = row + (png_size_t)row_info->rowbytes - bpp,
1109 cp = prev_row + (png_size_t)row_info->rowbytes - bpp;
1110 i > 0; i--, rp--, lp--, pp--, cp--)
1111 {
1112 int a, b, c, pa, pb, pc, p;
1113
1114 b = *pp;
1115 if (i > bpp)
1116 {
1117 c = *cp;
1118 a = *lp;
1119 }
1120 else
1121 {
1122 a = c = 0;
1123 }
1124 p = a + b - c;
Guy Schalnat6d764711995-12-19 03:22:19 -06001125 pa = abs(p - a);
Guy Schalnat0d580581995-07-20 02:43:20 -05001126 pb = abs(p - b);
1127 pc = abs(p - c);
1128
1129 if (pa <= pb && pa <= pc)
1130 p = a;
1131 else if (pb <= pc)
1132 p = b;
1133 else
1134 p = c;
1135
1136 *rp = (png_byte)(((int)*rp - p) & 0xff);
1137 }
1138 break;
1139 }
1140}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001141