blob: cde6ab51beebcc00ba46e867e1783e81c98d29fb [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwutil.c - utilities to write a png file
3
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004 libpng 1.0 beta 2 - version 0.88
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06006 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
7 January 25, 1996
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);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600145 buf[8] = (png_byte)bit_depth;
146 buf[9] = (png_byte)color_type;
147 buf[10] = (png_byte)compression_type;
148 buf[11] = (png_byte)filter_type;
149 buf[12] = (png_byte)interlace_type;
150 /* save off the relevent information */
151 png_ptr->bit_depth = (png_byte)bit_depth;
152 png_ptr->color_type = (png_byte)color_type;
153 png_ptr->interlaced = (png_byte)interlace_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500154 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 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600173 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500174 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;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600187 png_ptr->zstream->opaque = (voidpf)png_ptr;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500188 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 Schalnatb2e01bd1996-01-26 01:38:47 -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,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600307 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 Schalnatb2e01bd1996-01-26 01:38:47 -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 Schalnatb2e01bd1996-01-26 01:38:47 -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 Schalnatb2e01bd1996-01-26 01:38:47 -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 Schalnatb2e01bd1996-01-26 01:38:47 -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 Schalnatb2e01bd1996-01-26 01:38:47 -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 Schalnatb2e01bd1996-01-26 01:38:47 -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 Schalnatb2e01bd1996-01-26 01:38:47 -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;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600479 if (output_ptr)
480 {
481 png_charpp old_ptr;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600482
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600483 old_ptr = output_ptr;
484 output_ptr = (png_charpp)png_large_malloc(png_ptr,
485 max_output_ptr * sizeof (png_charpp));
486 png_memcpy(output_ptr, old_ptr,
487 (png_size_t)(old_max * sizeof (png_charp)));
488 png_large_free(png_ptr, old_ptr);
489 }
490 else
491 output_ptr = (png_charpp)png_large_malloc(png_ptr,
492 max_output_ptr * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500493 }
494
495 /* save the data */
496 output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
497 png_ptr->zbuf_size);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500498 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500499 (png_size_t)png_ptr->zbuf_size);
500 num_output_ptr++;
501
502 /* and reset the buffer */
503 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
504 png_ptr->zstream->next_out = png_ptr->zbuf;
505 }
506 /* continue until we don't have anymore to compress */
507 } while (png_ptr->zstream->avail_in);
508
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600509 /* finish the compression */
Guy Schalnat0d580581995-07-20 02:43:20 -0500510 do
511 {
512 /* tell zlib we are finished */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600513 ret = deflate(png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500514 if (ret != Z_OK && ret != Z_STREAM_END)
515 {
516 /* we got an error */
517 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600518 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500519 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600520 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500521 }
522
523 /* check to see if we need more room */
524 if (!png_ptr->zstream->avail_out && ret == Z_OK)
525 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600526 /* check to make sure our output array has room */
527 if (num_output_ptr >= max_output_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500528 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500529 png_uint_32 old_max;
530
531 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500532 max_output_ptr = num_output_ptr + 4;
533 if (output_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600534 {
535 png_charpp old_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500536
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600537 old_ptr = output_ptr;
538 output_ptr = (png_charpp)png_large_malloc(png_ptr,
539 max_output_ptr * sizeof (png_charpp));
540 png_memcpy(output_ptr, old_ptr,
541 (png_size_t)(old_max * sizeof (png_charp)));
542 png_large_free(png_ptr, old_ptr);
543 }
544 else
545 output_ptr = (png_charpp)png_large_malloc(png_ptr,
546 max_output_ptr * sizeof (png_charp));
547 }
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600548
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600549 /* save off the data */
550 output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
551 png_ptr->zbuf_size);
552 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500553 (png_size_t)png_ptr->zbuf_size);
554 num_output_ptr++;
555
556 /* and reset the buffer pointers */
557 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
558 png_ptr->zstream->next_out = png_ptr->zbuf;
559 }
560 } while (ret != Z_STREAM_END);
561
562 /* text length is number of buffers plus last buffer */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600563 text_len = png_ptr->zbuf_size * num_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500564 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
565 text_len += (png_uint_32)(png_ptr->zbuf_size -
566 png_ptr->zstream->avail_out);
567
568 /* write start of chunk */
569 png_write_chunk_start(png_ptr, png_zTXt,
570 (png_uint_32)(key_len + text_len + 2));
571 /* write key */
Guy Schalnat6d764711995-12-19 03:22:19 -0600572 png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600573 buf[0] = (png_byte)compression;
Guy Schalnat0d580581995-07-20 02:43:20 -0500574 /* write compression */
Guy Schalnat6d764711995-12-19 03:22:19 -0600575 png_write_chunk_data(png_ptr, (png_bytep )buf, (png_uint_32)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500576
577 /* write saved output buffers, if any */
578 for (i = 0; i < num_output_ptr; i++)
579 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600580 png_write_chunk_data(png_ptr, (png_bytep )output_ptr[i], png_ptr->zbuf_size);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600581 png_large_free(png_ptr, output_ptr[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500582 }
583 if (max_output_ptr)
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600584 png_large_free(png_ptr, output_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500585 /* write anything left in zbuf */
586 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
587 png_write_chunk_data(png_ptr, png_ptr->zbuf,
588 png_ptr->zbuf_size - png_ptr->zstream->avail_out);
589 /* close the chunk */
590 png_write_chunk_end(png_ptr);
591
592 /* reset zlib for another zTXt or the image data */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600593 deflateReset(png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500594}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500595#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500596
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500597#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500598/* write the pHYs chunk */
599void
Guy Schalnat6d764711995-12-19 03:22:19 -0600600png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
Guy Schalnat0d580581995-07-20 02:43:20 -0500601 png_uint_32 y_pixels_per_unit,
602 int unit_type)
603{
604 png_byte buf[9];
605
606 png_save_uint_32(buf, x_pixels_per_unit);
607 png_save_uint_32(buf + 4, y_pixels_per_unit);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600608 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500609
610 png_write_chunk(png_ptr, png_pHYs, buf, (png_uint_32)9);
611}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500612#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500613
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500614#if defined(PNG_WRITE_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500615/* write the oFFs chunk */
616void
Guy Schalnat6d764711995-12-19 03:22:19 -0600617png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
Guy Schalnat0d580581995-07-20 02:43:20 -0500618 png_uint_32 y_offset,
619 int unit_type)
620{
621 png_byte buf[9];
622
623 png_save_uint_32(buf, x_offset);
624 png_save_uint_32(buf + 4, y_offset);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600625 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500626
627 png_write_chunk(png_ptr, png_oFFs, buf, (png_uint_32)9);
628}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500629#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500630
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500631#if defined(PNG_WRITE_tIME_SUPPORTED)
632/* write the tIME chunk. Use either png_convert_from_struct_tm()
633 or png_convert_from_time_t(), or fill in the structure yourself */
Guy Schalnat0d580581995-07-20 02:43:20 -0500634void
Guy Schalnat6d764711995-12-19 03:22:19 -0600635png_write_tIME(png_structp png_ptr, png_timep mod_time)
Guy Schalnat0d580581995-07-20 02:43:20 -0500636{
637 png_byte buf[7];
638
639 png_save_uint_16(buf, mod_time->year);
640 buf[2] = mod_time->month;
641 buf[3] = mod_time->day;
642 buf[4] = mod_time->hour;
643 buf[5] = mod_time->minute;
644 buf[6] = mod_time->second;
645
646 png_write_chunk(png_ptr, png_tIME, buf, (png_uint_32)7);
647}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500648#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500649
650/* initializes the row writing capability of libpng */
651void
Guy Schalnat6d764711995-12-19 03:22:19 -0600652png_write_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500653{
654 /* set up row buffer */
Guy Schalnat6d764711995-12-19 03:22:19 -0600655 png_ptr->row_buf = (png_bytep )png_large_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500656 (((png_uint_32)png_ptr->usr_channels *
657 (png_uint_32)png_ptr->usr_bit_depth *
Guy Schalnat6d764711995-12-19 03:22:19 -0600658 png_ptr->width + 7) >> 3) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500659 /* set up filtering buffers, if filtering */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500660 if (png_ptr->do_filter)
Guy Schalnat0d580581995-07-20 02:43:20 -0500661 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600662 png_ptr->prev_row = (png_bytep )png_large_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500663 png_ptr->rowbytes + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500664 png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
Guy Schalnat6d764711995-12-19 03:22:19 -0600665 png_ptr->save_row = (png_bytep )png_large_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500666 png_ptr->rowbytes + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500667 png_memset(png_ptr->save_row, 0, (png_size_t)png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500668 }
669
670 /* if interlaced, we need to set up width and height of pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600671 if (png_ptr->interlaced)
Guy Schalnat0d580581995-07-20 02:43:20 -0500672 {
673 if (!(png_ptr->transformations & PNG_INTERLACE))
674 {
675 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
676 png_pass_ystart[0]) / png_pass_yinc[0];
677 png_ptr->usr_width = (png_ptr->width +
678 png_pass_inc[0] - 1 -
679 png_pass_start[0]) /
680 png_pass_inc[0];
681 }
682 else
683 {
684 png_ptr->num_rows = png_ptr->height;
685 png_ptr->usr_width = png_ptr->width;
686 }
687 }
688 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600689 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500690 png_ptr->num_rows = png_ptr->height;
691 png_ptr->usr_width = png_ptr->width;
692 }
693 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
694 png_ptr->zstream->next_out = png_ptr->zbuf;
695}
696
697/* Internal use only. Called when finished processing a row of data */
698void
Guy Schalnat6d764711995-12-19 03:22:19 -0600699png_write_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500700{
701 int ret;
702
703 /* next row */
704 png_ptr->row_number++;
705 /* see if we are done */
Guy Schalnat6d764711995-12-19 03:22:19 -0600706 if (png_ptr->row_number < png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600707 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500708
709 /* if interlaced, go to next pass */
710 if (png_ptr->interlaced)
711 {
712 png_ptr->row_number = 0;
713 if (png_ptr->transformations & PNG_INTERLACE)
714 {
715 png_ptr->pass++;
716 }
717 else
718 {
719 /* loop until we find a non-zero width or height pass */
720 do
721 {
722 png_ptr->pass++;
723 if (png_ptr->pass >= 7)
724 break;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600725 png_ptr->usr_width = (png_ptr->width +
Guy Schalnat0d580581995-07-20 02:43:20 -0500726 png_pass_inc[png_ptr->pass] - 1 -
727 png_pass_start[png_ptr->pass]) /
728 png_pass_inc[png_ptr->pass];
729 png_ptr->num_rows = (png_ptr->height +
730 png_pass_yinc[png_ptr->pass] - 1 -
731 png_pass_ystart[png_ptr->pass]) /
732 png_pass_yinc[png_ptr->pass];
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500733 if (png_ptr->transformations & PNG_INTERLACE)
734 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500735 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
736
737 }
738
739 /* reset filter row */
740 if (png_ptr->prev_row)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500741 png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500742 /* if we have more data to get, go get it */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600743 if (png_ptr->pass < 7)
Guy Schalnat0d580581995-07-20 02:43:20 -0500744 return;
745 }
746
747 /* if we get here, we've just written the last row, so we need
748 to flush the compressor */
749 do
750 {
751 /* tell the compressor we are done */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600752 ret = deflate(png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500753 /* check for an error */
754 if (ret != Z_OK && ret != Z_STREAM_END)
755 {
756 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600757 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500758 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600759 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500760 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600761 /* check to see if we need more room */
Guy Schalnat0d580581995-07-20 02:43:20 -0500762 if (!png_ptr->zstream->avail_out && ret == Z_OK)
763 {
764 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
765 png_ptr->zstream->next_out = png_ptr->zbuf;
766 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
767 }
768 } while (ret != Z_STREAM_END);
769
770 /* write any extra space */
771 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
772 {
773 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
774 png_ptr->zstream->avail_out);
775 }
776
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500777 deflateReset(png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500778}
779
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500780#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500781/* pick out the correct pixels for the interlace pass.
782
783 The basic idea here is to go through the row with a source
784 pointer and a destination pointer (sp and dp), and copy the
785 correct pixels for the pass. As the row gets compacted,
786 sp will always be >= dp, so we should never overwrite anything.
787 See the default: case for the easiest code to understand.
788 */
789void
Guy Schalnat6d764711995-12-19 03:22:19 -0600790png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -0500791{
792 /* we don't have to do anything on the last pass (6) */
793 if (row && row_info && pass < 6)
794 {
795 /* each pixel depth is handled seperately */
796 switch (row_info->pixel_depth)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600797 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500798 case 1:
799 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600800 png_bytep sp;
801 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500802 int shift;
803 int d;
804 int value;
805 png_uint_32 i;
806
807 dp = row;
808 d = 0;
809 shift = 7;
810 for (i = png_pass_start[pass];
811 i < row_info->width;
812 i += png_pass_inc[pass])
813 {
814 sp = row + (png_size_t)(i >> 3);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600815 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
Guy Schalnat0d580581995-07-20 02:43:20 -0500816 d |= (value << shift);
817
818 if (shift == 0)
819 {
820 shift = 7;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600821 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -0500822 d = 0;
823 }
824 else
825 shift--;
826
827 }
828 if (shift != 7)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600829 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -0500830 break;
831 }
832 case 2:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600833 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600834 png_bytep sp;
835 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500836 int shift;
837 int d;
838 int value;
839 png_uint_32 i;
840
841 dp = row;
842 shift = 6;
843 d = 0;
844 for (i = png_pass_start[pass];
845 i < row_info->width;
846 i += png_pass_inc[pass])
847 {
848 sp = row + (png_size_t)(i >> 2);
849 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
850 d |= (value << shift);
851
852 if (shift == 0)
853 {
854 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600855 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -0500856 d = 0;
857 }
858 else
859 shift -= 2;
860 }
861 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600862 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -0500863 break;
864 }
865 case 4:
866 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600867 png_bytep sp;
868 png_bytep dp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600869 int shift;
Guy Schalnat0d580581995-07-20 02:43:20 -0500870 int d;
871 int value;
872 png_uint_32 i;
873
874 dp = row;
875 shift = 4;
876 d = 0;
877 for (i = png_pass_start[pass];
878 i < row_info->width;
879 i += png_pass_inc[pass])
880 {
881 sp = row + (png_size_t)(i >> 1);
882 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
883 d |= (value << shift);
884
885 if (shift == 0)
886 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600887 shift = 4;
888 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -0500889 d = 0;
890 }
891 else
892 shift -= 4;
893 }
894 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600895 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -0500896 break;
897 }
898 default:
899 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600900 png_bytep sp;
901 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500902 png_uint_32 i;
903 int pixel_bytes;
904
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600905 /* start at the beginning */
Guy Schalnat0d580581995-07-20 02:43:20 -0500906 dp = row;
907 /* find out how many bytes each pixel takes up */
908 pixel_bytes = (row_info->pixel_depth >> 3);
909 /* loop through the row, only looking at the pixels that
910 matter */
911 for (i = png_pass_start[pass];
912 i < row_info->width;
913 i += png_pass_inc[pass])
914 {
915 /* find out where the original pixel is */
916 sp = row + (png_size_t)(i * pixel_bytes);
917 /* move the pixel */
918 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500919 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500920 /* next pixel */
921 dp += pixel_bytes;
922 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600923 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500924 }
925 }
926 /* set new row width */
927 row_info->width = (row_info->width +
928 png_pass_inc[pass] - 1 -
929 png_pass_start[pass]) /
930 png_pass_inc[pass];
931 row_info->rowbytes = ((row_info->width *
932 row_info->pixel_depth + 7) >> 3);
933
934 }
935}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500936#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500937
938/* this filters the row. Both row and prev_row have space at the
939 first byte for the filter byte. */
940void
Guy Schalnat6d764711995-12-19 03:22:19 -0600941png_write_filter_row(png_row_infop row_info, png_bytep row,
942 png_bytep prev_row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500943{
944 int minf, bpp;
945 png_uint_32 i, v;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500946 png_uint_32 s0, s1, s2, s3, s4, mins;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600947 png_bytep rp, pp, cp, lp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500948
949 /* find out how many bytes offset each pixel is */
950 bpp = (row_info->pixel_depth + 7) / 8;
951 if (bpp < 1)
952 bpp = 1;
953
954 /* the prediction method we use is to find which method provides
955 the smallest value when summing the abs of the distances from
956 zero using anything >= 128 as negitive numbers. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500957 s0 = s1 = s2 = s3 = s4 = 0;
958
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600959 for (i = 0, rp = row + 1, pp = prev_row + 1, lp = row + 1 - bpp,
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500960 cp = prev_row + 1 - bpp;
961 i < bpp; i++, rp++, pp++, lp++, cp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500962 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500963 /* check none filter */
Guy Schalnat0d580581995-07-20 02:43:20 -0500964 v = *rp;
965 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500966 s0 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500967 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500968 s0 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500969
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500970 /* check up filter */
Guy Schalnat0d580581995-07-20 02:43:20 -0500971 v = (png_byte)(((int)*rp - (int)*pp) & 0xff);
972
973 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500974 s2 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500975 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500976 s2 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500977
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500978 /* check avg filter */
979 v = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -0500980
981 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500982 s3 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500983 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500984 s3 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500985 }
986
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500987 /* some filters are same until we get past bpp */
988 s1 = s0;
989 s4 = s2;
Guy Schalnat0d580581995-07-20 02:43:20 -0500990
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500991 for (; i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500992 {
993 int a, b, c, pa, pb, pc, p;
994
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600995 /* check none filter */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500996 v = *rp;
997 if (v < 128)
998 s0 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -0500999 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001000 s0 += 256 - v;
1001
1002 /* check sub filter */
1003 v = (png_byte)(((int)*rp - (int)*lp) & 0xff);
1004
1005 if (v < 128)
1006 s1 += v;
1007 else
1008 s1 += 256 - v;
1009
1010 /* check up filter */
1011 v = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1012
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001013 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001014 s2 += v;
1015 else
1016 s2 += 256 - v;
1017
1018 /* check avg filter */
1019 v = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
1020
1021 if (v < 128)
1022 s3 += v;
1023 else
1024 s3 += 256 - v;
1025
1026 /* check paeth filter */
1027 b = *pp;
1028 c = *cp;
1029 a = *lp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001030 p = a + b - c;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001031 pa = abs(p - a);
Guy Schalnat0d580581995-07-20 02:43:20 -05001032 pb = abs(p - b);
1033 pc = abs(p - c);
1034
1035 if (pa <= pb && pa <= pc)
1036 p = a;
1037 else if (pb <= pc)
1038 p = b;
1039 else
1040 p = c;
1041
1042 v = (png_byte)(((int)*rp - p) & 0xff);
1043
1044 if (v < 128)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001045 s4 += v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001046 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001047 s4 += 256 - v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001048 }
1049
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001050 mins = s0;
1051 minf = 0;
1052
1053 if (s1 < mins)
Guy Schalnat0d580581995-07-20 02:43:20 -05001054 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001055 mins = s1;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001056 minf = 1;
1057 }
1058
1059 if (s2 < mins)
1060 {
1061 mins = s2;
1062 minf = 2;
1063 }
1064
1065 if (s3 < mins)
1066 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001067 mins = s3;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001068 minf = 3;
1069 }
1070
1071 if (s4 < mins)
1072 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001073 minf = 4;
1074 }
1075
1076 /* set filter byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001077 row[0] = (png_byte)minf;
Guy Schalnat0d580581995-07-20 02:43:20 -05001078
1079 /* do filter */
1080 switch (minf)
1081 {
1082 /* sub filter */
1083 case 1:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001084 for (i = bpp, rp = row + (png_size_t)row_info->rowbytes,
Guy Schalnat0d580581995-07-20 02:43:20 -05001085 lp = row + (png_size_t)row_info->rowbytes - bpp;
1086 i < row_info->rowbytes; i++, rp--, lp--)
1087 {
1088 *rp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
1089 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001090 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001091 /* up filter */
1092 case 2:
1093 for (i = 0, rp = row + (png_size_t)row_info->rowbytes,
1094 pp = prev_row + (png_size_t)row_info->rowbytes;
1095 i < row_info->rowbytes; i++, rp--, pp--)
1096 {
1097 *rp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1098 }
1099 break;
1100 /* avg filter */
1101 case 3:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001102 for (i = row_info->rowbytes,
Guy Schalnat0d580581995-07-20 02:43:20 -05001103 rp = row + (png_size_t)row_info->rowbytes,
1104 pp = prev_row + (png_size_t)row_info->rowbytes,
1105 lp = row + (png_size_t)row_info->rowbytes - bpp;
1106 i > bpp; i--, rp--, lp--, pp--)
1107 {
1108 *rp = (png_byte)(((int)*rp - (((int)*lp + (int)*pp) /
1109 2)) & 0xff);
1110 }
1111 for (; i > 0; i--, rp--, pp--)
1112 {
1113 *rp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
1114 }
1115 break;
1116 /* paeth filter */
1117 case 4:
1118 for (i = row_info->rowbytes,
1119 rp = row + (png_size_t)row_info->rowbytes,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001120 pp = prev_row + (png_size_t)row_info->rowbytes,
Guy Schalnat0d580581995-07-20 02:43:20 -05001121 lp = row + (png_size_t)row_info->rowbytes - bpp,
1122 cp = prev_row + (png_size_t)row_info->rowbytes - bpp;
1123 i > 0; i--, rp--, lp--, pp--, cp--)
1124 {
1125 int a, b, c, pa, pb, pc, p;
1126
1127 b = *pp;
1128 if (i > bpp)
1129 {
1130 c = *cp;
1131 a = *lp;
1132 }
1133 else
1134 {
1135 a = c = 0;
1136 }
1137 p = a + b - c;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001138 pa = abs(p - a);
Guy Schalnat0d580581995-07-20 02:43:20 -05001139 pb = abs(p - b);
1140 pc = abs(p - c);
1141
1142 if (pa <= pb && pa <= pc)
1143 p = a;
1144 else if (pb <= pc)
1145 p = b;
1146 else
1147 p = c;
1148
1149 *rp = (png_byte)(((int)*rp - p) & 0xff);
1150 }
1151 break;
1152 }
1153}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001154