blob: 4adc1c9b982585d204bac9e10cfa76f17e2870f5 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwutil.c - utilities to write a png file
3
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004 libpng 1.0 beta 4 - version 0.90
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06006 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06007 December 3, 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
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060065png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
Guy Schalnat6d764711995-12-19 03:22:19 -060066 png_bytep data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -050067{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060068 png_write_chunk_start(png_ptr, chunk_name, length);
69 png_write_chunk_data(png_ptr, data, length);
70 png_write_chunk_end(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -050071}
72
73/* Write the start of a png chunk. The type is the chunk type.
74 The total_length is the sum of the lengths of all the data you will be
75 passing in png_write_chunk_data() */
76void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060077png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
78 png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -050079{
80 /* write the length */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060081 png_write_uint_32(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -050082 /* write the chunk name */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060083 png_write_data(png_ptr, chunk_name, (png_uint_32)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050084 /* reset the crc and run it over the chunk name */
85 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060086 png_calculate_crc(png_ptr, chunk_name, (png_uint_32)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050087}
88
89/* write the data of a png chunk started with png_write_chunk_start().
90 Note that multiple calls to this function are allowed, and that the
91 sum of the lengths from these calls *must* add up to the total_length
92 given to png_write_chunk_start() */
93void
Guy Schalnat6d764711995-12-19 03:22:19 -060094png_write_chunk_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -050095{
96 /* write the data, and run the crc over it */
97 if (length)
98 {
99 png_calculate_crc(png_ptr, data, length);
Guy Schalnat6d764711995-12-19 03:22:19 -0600100 png_write_data(png_ptr, data, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500101 }
102}
103
104/* finish a chunk started with png_write_chunk_start() */
105void
Guy Schalnat6d764711995-12-19 03:22:19 -0600106png_write_chunk_end(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500107{
108 /* write the crc */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600109#ifdef PNG_USE_OWN_CRC
Guy Schalnat0d580581995-07-20 02:43:20 -0500110 png_write_uint_32(png_ptr, ~png_ptr->crc);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600111#else
112 png_write_uint_32(png_ptr, png_ptr->crc);
113#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500114}
115
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600116/* Simple function to write the signature. If we have already written
117 * the magic bytes of the signature, or more likely, the PNG stream is
118 * being embedded into another stream and doesn't need its own signature,
119 * we should call png_set_sig_bytes() to tell libpng how many of the
120 * bytes have already been written. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500121void
Guy Schalnat6d764711995-12-19 03:22:19 -0600122png_write_sig(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500123{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600124 /* write the rest of the 8 byte signature */
125 png_write_data(png_ptr, &png_sig[png_ptr->sig_bytes],
126 (png_uint_32)8 - png_ptr->sig_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500127}
128
129/* Write the IHDR chunk, and update the png_struct with the necessary
130 information. Note that the rest of this code depends upon this
131 information being correct. */
132void
Guy Schalnat6d764711995-12-19 03:22:19 -0600133png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
Guy Schalnat0d580581995-07-20 02:43:20 -0500134 int bit_depth, int color_type, int compression_type, int filter_type,
135 int interlace_type)
136{
137 png_byte buf[13]; /* buffer to store the IHDR info */
138
Guy Schalnate5a37791996-06-05 15:50:50 -0500139 /* Check that we have valid input data from the application info */
140 switch (color_type)
141 {
142 case 0:
143 switch (bit_depth)
144 {
145 case 1:
146 case 2:
147 case 4:
148 case 8:
149 case 16: png_ptr->channels = 1; break;
150 default: png_error(png_ptr, "Invalid bit depth for grayscale image");
151 }
152 break;
153 case 2:
154 if (bit_depth != 8 && bit_depth != 16)
155 png_error(png_ptr, "Invalid bit depth for RGB image");
156 png_ptr->channels = 3;
157 break;
158 case 3:
159 switch (bit_depth)
160 {
161 case 1:
162 case 2:
163 case 4:
164 case 8: png_ptr->channels = 1; break;
165 default: png_error(png_ptr, "Invalid bit depth for paletted image");
166 }
167 break;
168 case 4:
169 if (bit_depth != 8 && bit_depth != 16)
170 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
171 png_ptr->channels = 2;
172 break;
173 case 6:
174 if (bit_depth != 8 && bit_depth != 16)
175 png_error(png_ptr, "Invalid bit depth for RGBA image");
176 png_ptr->channels = 4;
177 break;
178 default:
179 png_error(png_ptr, "Invalid image color type specified");
180 }
181
182 if (compression_type != 0)
183 {
184 png_warning(png_ptr, "Invalid compression type specified");
185 compression_type = 0;
186 }
187
188 if (filter_type != 0)
189 {
190 png_warning(png_ptr, "Invalid filter type specified");
191 filter_type = 0;
192 }
193
194 if (interlace_type != 0 && interlace_type != 1)
195 {
196 png_warning(png_ptr, "Invalid interlace type specified");
197 interlace_type = 1;
198 }
199
200 /* save off the relevent information */
201 png_ptr->bit_depth = (png_byte)bit_depth;
202 png_ptr->color_type = (png_byte)color_type;
203 png_ptr->interlaced = (png_byte)interlace_type;
204 png_ptr->width = width;
205 png_ptr->height = height;
206
207 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
208 png_ptr->rowbytes = ((width * (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
209 /* set the usr info, so any transformations can modify it */
210 png_ptr->usr_width = png_ptr->width;
211 png_ptr->usr_bit_depth = png_ptr->bit_depth;
212 png_ptr->usr_channels = png_ptr->channels;
213
Guy Schalnat0d580581995-07-20 02:43:20 -0500214 /* pack the header information into the buffer */
215 png_save_uint_32(buf, width);
216 png_save_uint_32(buf + 4, height);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600217 buf[8] = (png_byte)bit_depth;
218 buf[9] = (png_byte)color_type;
219 buf[10] = (png_byte)compression_type;
220 buf[11] = (png_byte)filter_type;
221 buf[12] = (png_byte)interlace_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500222
223 /* write the chunk */
Guy Schalnate5a37791996-06-05 15:50:50 -0500224 png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500225
226 /* initialize zlib with png info */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600227 png_ptr->zstream.zalloc = png_zalloc;
228 png_ptr->zstream.zfree = png_zfree;
229 png_ptr->zstream.opaque = (voidpf)png_ptr;
Guy Schalnate5a37791996-06-05 15:50:50 -0500230 if (!(png_ptr->do_filter))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500231 {
232 if (png_ptr->color_type == 3 || png_ptr->bit_depth < 8)
Guy Schalnate5a37791996-06-05 15:50:50 -0500233 png_ptr->do_filter = PNG_FILTER_NONE;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500234 else
Guy Schalnate5a37791996-06-05 15:50:50 -0500235 png_ptr->do_filter = PNG_ALL_FILTERS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500236 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500237 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500238 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500239 if (png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500240 png_ptr->zlib_strategy = Z_FILTERED;
241 else
242 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
243 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500244 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500245 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
Guy Schalnate5a37791996-06-05 15:50:50 -0500246 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500247 png_ptr->zlib_mem_level = 8;
Guy Schalnate5a37791996-06-05 15:50:50 -0500248 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500249 png_ptr->zlib_window_bits = 15;
Guy Schalnate5a37791996-06-05 15:50:50 -0500250 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500251 png_ptr->zlib_method = 8;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600252 deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500253 png_ptr->zlib_method,
254 png_ptr->zlib_window_bits,
255 png_ptr->zlib_mem_level,
256 png_ptr->zlib_strategy);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600257 png_ptr->zstream.next_out = png_ptr->zbuf;
258 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500259
Guy Schalnate5a37791996-06-05 15:50:50 -0500260 png_ptr->mode = PNG_HAVE_IHDR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500261}
262
263/* write the palette. We are careful not to trust png_color to be in the
264 correct order for PNG, so people can redefine it to any convient
265 structure. */
266void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600267png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 number)
Guy Schalnat0d580581995-07-20 02:43:20 -0500268{
269 int i;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600270 png_colorp pal_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500271 png_byte buf[3];
272
Guy Schalnate5a37791996-06-05 15:50:50 -0500273 if (number == 0 || number > 256)
274 {
275 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
276 {
277 png_error(png_ptr, "Invalid number of colors in palette");
278 }
279 else
280 {
281 png_warning(png_ptr, "Invalid number of colors in palette");
282 return;
283 }
284 }
285
286 png_ptr->num_palette = number;
287
Guy Schalnat0d580581995-07-20 02:43:20 -0500288 png_write_chunk_start(png_ptr, png_PLTE, number * 3);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600289 for (i = 0, pal_ptr = palette; i < number; i++, pal_ptr++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500290 {
291 buf[0] = pal_ptr->red;
292 buf[1] = pal_ptr->green;
293 buf[2] = pal_ptr->blue;
294 png_write_chunk_data(png_ptr, buf, (png_uint_32)3);
295 }
296 png_write_chunk_end(png_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500297 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnat0d580581995-07-20 02:43:20 -0500298}
299
300/* write an IDAT chunk */
301void
Guy Schalnat6d764711995-12-19 03:22:19 -0600302png_write_IDAT(png_structp png_ptr, png_bytep data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500303{
Guy Schalnat0d580581995-07-20 02:43:20 -0500304 png_write_chunk(png_ptr, png_IDAT, data, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500305 png_ptr->mode |= PNG_HAVE_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500306}
307
308/* write an IEND chunk */
309void
Guy Schalnat6d764711995-12-19 03:22:19 -0600310png_write_IEND(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500311{
312 png_write_chunk(png_ptr, png_IEND, NULL, (png_uint_32)0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600313 png_ptr->mode |= PNG_HAVE_IEND;
Guy Schalnat0d580581995-07-20 02:43:20 -0500314}
315
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500316#if defined(PNG_WRITE_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500317/* write a gAMA chunk */
318void
Guy Schalnat6d764711995-12-19 03:22:19 -0600319png_write_gAMA(png_structp png_ptr, double gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500320{
321 png_uint_32 igamma;
322 png_byte buf[4];
323
324 /* gamma is saved in 1/100,000ths */
325 igamma = (png_uint_32)(gamma * 100000.0 + 0.5);
326 png_save_uint_32(buf, igamma);
327 png_write_chunk(png_ptr, png_gAMA, buf, (png_uint_32)4);
328}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500329#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500330
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500331#if defined(PNG_WRITE_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500332/* write the sBIT chunk */
333void
Guy Schalnat6d764711995-12-19 03:22:19 -0600334png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500335{
336 png_byte buf[4];
337 int size;
338
Guy Schalnat6d764711995-12-19 03:22:19 -0600339 /* make sure we don't depend upon the order of PNG_COLOR_8 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500340 if (color_type & PNG_COLOR_MASK_COLOR)
341 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500342 int maxbits;
343
344 maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8:png_ptr->usr_bit_depth;
345 if (sbit->red == 0 || sbit->red > maxbits ||
346 sbit->green == 0 || sbit->green > maxbits ||
347 sbit->blue == 0 || sbit->blue > maxbits)
348 {
349 png_warning(png_ptr, "Invalid sBIT depth specified");
350 return;
351 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500352 buf[0] = sbit->red;
353 buf[1] = sbit->green;
354 buf[2] = sbit->blue;
355 size = 3;
356 }
357 else
358 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500359 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
360 {
361 png_warning(png_ptr, "Invalid sBIT depth specified");
362 return;
363 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500364 buf[0] = sbit->gray;
365 size = 1;
366 }
367
368 if (color_type & PNG_COLOR_MASK_ALPHA)
369 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500370 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
371 {
372 png_warning(png_ptr, "Invalid sBIT depth specified");
373 return;
374 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500375 buf[size++] = sbit->alpha;
376 }
377
378 png_write_chunk(png_ptr, png_sBIT, buf, (png_uint_32)size);
379}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500380#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500381
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500382#if defined(PNG_WRITE_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500383/* write the cHRM chunk */
384void
Guy Schalnat6d764711995-12-19 03:22:19 -0600385png_write_cHRM ( png_structp png_ptr, double white_x, double white_y,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600386 double red_x, double red_y, double green_x, double green_y,
387 double blue_x, double blue_y)
Guy Schalnat0d580581995-07-20 02:43:20 -0500388{
389 png_uint_32 itemp;
390 png_byte buf[32];
391
392 /* each value is saved int 1/100,000ths */
Guy Schalnate5a37791996-06-05 15:50:50 -0500393 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
394 white_x + white_y > 1.0)
395 {
396 png_warning(png_ptr, "Invalid cHRM white point specified");
397 return;
398 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500399 itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
400 png_save_uint_32(buf, itemp);
401 itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
402 png_save_uint_32(buf + 4, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500403
404 if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
405 red_x + red_y > 1.0)
406 {
407 png_warning(png_ptr, "Invalid cHRM red point specified");
408 return;
409 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500410 itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
411 png_save_uint_32(buf + 8, itemp);
412 itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
413 png_save_uint_32(buf + 12, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500414
415 if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
416 green_x + green_y > 1.0)
417 {
418 png_warning(png_ptr, "Invalid cHRM green point specified");
419 return;
420 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500421 itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
422 png_save_uint_32(buf + 16, itemp);
423 itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
424 png_save_uint_32(buf + 20, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500425
426 if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
427 blue_x + blue_y > 1.0)
428 {
429 png_warning(png_ptr, "Invalid cHRM blue point specified");
430 return;
431 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500432 itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
433 png_save_uint_32(buf + 24, itemp);
434 itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
435 png_save_uint_32(buf + 28, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500436
Guy Schalnat0d580581995-07-20 02:43:20 -0500437 png_write_chunk(png_ptr, png_cHRM, buf, (png_uint_32)32);
438}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500439#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500440
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500441#if defined(PNG_WRITE_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500442/* write the tRNS chunk */
443void
Guy Schalnat6d764711995-12-19 03:22:19 -0600444png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
Guy Schalnat0d580581995-07-20 02:43:20 -0500445 int num_trans, int color_type)
446{
447 png_byte buf[6];
448
449 if (color_type == PNG_COLOR_TYPE_PALETTE)
450 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500451 if (num_trans <= 0 || num_trans > png_ptr->num_palette)
452 {
453 png_warning(png_ptr,"Invalid number of transparent colors specified");
454 return;
455 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500456 /* write the chunk out as it is */
457 png_write_chunk(png_ptr, png_tRNS, trans, (png_uint_32)num_trans);
458 }
459 else if (color_type == PNG_COLOR_TYPE_GRAY)
460 {
461 /* one 16 bit value */
462 png_save_uint_16(buf, tran->gray);
463 png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)2);
464 }
465 else if (color_type == PNG_COLOR_TYPE_RGB)
466 {
467 /* three 16 bit values */
468 png_save_uint_16(buf, tran->red);
469 png_save_uint_16(buf + 2, tran->green);
470 png_save_uint_16(buf + 4, tran->blue);
471 png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)6);
472 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500473 else
474 {
475 png_warning(png_ptr, "Can't write tRNS with and alpha channel");
476 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500477}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500478#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500479
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500480#if defined(PNG_WRITE_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500481/* write the background chunk */
482void
Guy Schalnat6d764711995-12-19 03:22:19 -0600483png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500484{
485 png_byte buf[6];
486
487 if (color_type == PNG_COLOR_TYPE_PALETTE)
488 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500489 if (back->index > png_ptr->num_palette)
490 {
491 png_warning(png_ptr, "Invalid background palette index");
492 return;
493 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500494 buf[0] = back->index;
495 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)1);
496 }
497 else if (color_type & PNG_COLOR_MASK_COLOR)
498 {
499 png_save_uint_16(buf, back->red);
500 png_save_uint_16(buf + 2, back->green);
501 png_save_uint_16(buf + 4, back->blue);
502 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)6);
503 }
504 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600505 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500506 png_save_uint_16(buf, back->gray);
507 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)2);
508 }
509}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500510#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500511
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500512#if defined(PNG_WRITE_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500513/* write the histogram */
514void
Guy Schalnat6d764711995-12-19 03:22:19 -0600515png_write_hIST(png_structp png_ptr, png_uint_16p hist, int number)
Guy Schalnat0d580581995-07-20 02:43:20 -0500516{
517 int i;
518 png_byte buf[3];
519
Guy Schalnate5a37791996-06-05 15:50:50 -0500520 if (number <= 0 || number > png_ptr->num_palette)
521 {
522 png_warning(png_ptr, "Invalid number of histogram entries specified");
523 return;
524 }
525
Guy Schalnat0d580581995-07-20 02:43:20 -0500526 png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(number * 2));
527 for (i = 0; i < number; i++)
528 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600529 png_save_uint_16(buf, hist[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500530 png_write_chunk_data(png_ptr, buf, (png_uint_32)2);
531 }
532 png_write_chunk_end(png_ptr);
533}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500534#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500535
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600536#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
537/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
538 * and if invalid, correct the keyword rather than discarding the entire
539 * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
540 * length, forbids leading or trailing whitespace, multiple internal spaces,
541 * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
542 */
543#undef BROKEN_CHECK
544int
545png_check_keyword(png_structp png_ptr, png_charpp key)
546{
547 png_charp kp;
548 int key_len;
549#ifdef BROKEN_CHECK
550 png_charp np;
551 int kflag;
552 char newkey[80];
553#endif
554
555 if (*key == NULL || (key_len = png_strlen(*key)) == 0)
556 {
557 char msg[40];
558
559 sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
560 png_warning(png_ptr, msg);
561 return 0;
562 }
563 else if (key_len > 79)
564 {
565 char msg[40];
566
567 sprintf(msg, "%s keyword length must be 1 - 79 characters",
568 png_ptr->chunk_name);
569 png_warning(png_ptr, msg);
570 (*key)[79] = '\0';
571 key_len = 79;
572 }
573
574 /* Replace non-printing characters with a blank and print a warning */
575 for (kp = *key; *kp != '\0'; kp++)
576 {
577 if (*kp < 0x20 || ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
578 {
579 char msg[40];
580
581 sprintf(msg, "Invalid %s keyword character 0x%02X",
582 png_ptr->chunk_name, *kp);
583 png_warning(png_ptr, msg);
584 *kp = ' ';
585 }
586 }
587
588 /* Remove any leading white space. */
589 while (**key == ' ')
590 {
591 (*key)++;
592 key_len--;
593 }
594
595 /* Remove any trailing white space. */
596 for (kp = *key + key_len - 1; *kp == ' '; key_len--)
597 *kp-- = '\0';
598
599#ifdef BROKEN_CHECK
600 /* Remove multiple internal spaces. This is currently broken for
601 * an unknown reason, and I didn't want to hold up the release of
602 * libpng-0.90 even longer to fix it. */
603 kflag = 0;
604 for (kp = *key, np = newkey; *kp; kp++)
605 {
606 if (*kp != ' ')
607 {
608 *np++ = *kp;
609 kflag = 0;
610 }
611 else if (kflag)
612 {
613 key_len--;
614 }
615 else
616 {
617 *np++ = *kp;
618 kflag = 1;
619 }
620 }
621 *np = *kp;
622 png_strcpy(kp, np);
623#endif
624
625 if (key_len == 0)
626 png_warning(png_ptr, "Zero length tEXt keyword");
627
628 return key_len;
629}
630#endif
631
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500632#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500633/* write a tEXt chunk */
634void
Guy Schalnat6d764711995-12-19 03:22:19 -0600635png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
Guy Schalnat0d580581995-07-20 02:43:20 -0500636 png_uint_32 text_len)
637{
638 int key_len;
639
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600640 if (key == NULL || (key_len = png_check_keyword(png_ptr, &key)) == 0)
Guy Schalnate5a37791996-06-05 15:50:50 -0500641 return;
Guy Schalnate5a37791996-06-05 15:50:50 -0500642
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600643 if (text == NULL)
644 text_len = 0;
645
646 /* make sure we include the 0 after the key */
Guy Schalnat0d580581995-07-20 02:43:20 -0500647 png_write_chunk_start(png_ptr, png_tEXt,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600648 (png_uint_32)(key_len + text_len + 1));
Guy Schalnat6d764711995-12-19 03:22:19 -0600649 png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600650 if (text_len)
Guy Schalnat6d764711995-12-19 03:22:19 -0600651 png_write_chunk_data(png_ptr, (png_bytep )text, (png_uint_32)text_len);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600652
Guy Schalnat0d580581995-07-20 02:43:20 -0500653 png_write_chunk_end(png_ptr);
654}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500655#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500656
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500657#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500658/* write a compressed chunk */
659void
Guy Schalnat6d764711995-12-19 03:22:19 -0600660png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
Guy Schalnat0d580581995-07-20 02:43:20 -0500661 png_uint_32 text_len, int compression)
662{
663 int key_len;
664 char buf[1];
665 int i, ret;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600666 png_charpp output_ptr = NULL; /* array of pointers to output */
Guy Schalnat0d580581995-07-20 02:43:20 -0500667 int num_output_ptr = 0; /* number of output pointers used */
668 int max_output_ptr = 0; /* size of output_ptr */
669
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600670 if (key == NULL || (key_len = png_check_keyword(png_ptr, &key)) == 0)
Guy Schalnate5a37791996-06-05 15:50:50 -0500671 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600672
673 if (text == NULL)
674 text_len = 0;
Guy Schalnate5a37791996-06-05 15:50:50 -0500675
676 if (compression != 0)
677 {
678 png_warning(png_ptr, "Only type 0 compression allowed for text\n");
679 compression = 0;
680 }
681
Guy Schalnat0d580581995-07-20 02:43:20 -0500682 /* we can't write the chunk until we find out how much data we have,
683 which means we need to run the compresser first, and save the
684 output. This shouldn't be a problem, as the vast majority of
685 comments should be reasonable, but we will set up an array of
686 malloced pointers to be sure. */
687
688 /* set up the compression buffers */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600689 png_ptr->zstream.avail_in = (uInt)text_len;
690 png_ptr->zstream.next_in = (Bytef *)text;
691 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
692 png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500693
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600694 /* this is the same compression loop as in png_write_row() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500695 do
696 {
697 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600698 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500699 if (ret != Z_OK)
700 {
701 /* error */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600702 if (png_ptr->zstream.msg)
703 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500704 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600705 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500706 }
707 /* check to see if we need more room */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600708 if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
Guy Schalnat0d580581995-07-20 02:43:20 -0500709 {
710 /* make sure the output array has room */
711 if (num_output_ptr >= max_output_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600712 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500713 png_uint_32 old_max;
714
715 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500716 max_output_ptr = num_output_ptr + 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600717 if (output_ptr)
718 {
719 png_charpp old_ptr;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600720
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600721 old_ptr = output_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600722 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600723 max_output_ptr * sizeof (png_charpp));
724 png_memcpy(output_ptr, old_ptr,
725 (png_size_t)(old_max * sizeof (png_charp)));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600726 png_free(png_ptr, old_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600727 }
728 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600729 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600730 max_output_ptr * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500731 }
732
733 /* save the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600734 output_ptr[num_output_ptr] = png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500735 png_ptr->zbuf_size);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500736 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500737 (png_size_t)png_ptr->zbuf_size);
738 num_output_ptr++;
739
740 /* and reset the buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600741 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
742 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500743 }
744 /* continue until we don't have anymore to compress */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600745 } while (png_ptr->zstream.avail_in);
Guy Schalnat0d580581995-07-20 02:43:20 -0500746
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600747 /* finish the compression */
Guy Schalnat0d580581995-07-20 02:43:20 -0500748 do
749 {
750 /* tell zlib we are finished */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600751 ret = deflate(&png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500752 if (ret != Z_OK && ret != Z_STREAM_END)
753 {
754 /* we got an error */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600755 if (png_ptr->zstream.msg)
756 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500757 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600758 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500759 }
760
761 /* check to see if we need more room */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600762 if (!png_ptr->zstream.avail_out && ret == Z_OK)
Guy Schalnat0d580581995-07-20 02:43:20 -0500763 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600764 /* check to make sure our output array has room */
765 if (num_output_ptr >= max_output_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500766 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500767 png_uint_32 old_max;
768
769 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500770 max_output_ptr = num_output_ptr + 4;
771 if (output_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600772 {
773 png_charpp old_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500774
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600775 old_ptr = output_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600776 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600777 max_output_ptr * sizeof (png_charpp));
778 png_memcpy(output_ptr, old_ptr,
779 (png_size_t)(old_max * sizeof (png_charp)));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600780 png_free(png_ptr, old_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600781 }
782 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600783 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600784 max_output_ptr * sizeof (png_charp));
785 }
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600786
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600787 /* save off the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600788 output_ptr[num_output_ptr] = png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600789 png_ptr->zbuf_size);
790 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500791 (png_size_t)png_ptr->zbuf_size);
792 num_output_ptr++;
793
794 /* and reset the buffer pointers */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600795 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
796 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500797 }
798 } while (ret != Z_STREAM_END);
799
800 /* text length is number of buffers plus last buffer */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600801 text_len = png_ptr->zbuf_size * num_output_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600802 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
Guy Schalnat0d580581995-07-20 02:43:20 -0500803 text_len += (png_uint_32)(png_ptr->zbuf_size -
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600804 png_ptr->zstream.avail_out);
Guy Schalnat0d580581995-07-20 02:43:20 -0500805
806 /* write start of chunk */
807 png_write_chunk_start(png_ptr, png_zTXt,
808 (png_uint_32)(key_len + text_len + 2));
809 /* write key */
Guy Schalnat6d764711995-12-19 03:22:19 -0600810 png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600811 buf[0] = (png_byte)compression;
Guy Schalnat0d580581995-07-20 02:43:20 -0500812 /* write compression */
Guy Schalnat6d764711995-12-19 03:22:19 -0600813 png_write_chunk_data(png_ptr, (png_bytep )buf, (png_uint_32)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500814
815 /* write saved output buffers, if any */
816 for (i = 0; i < num_output_ptr; i++)
817 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600818 png_write_chunk_data(png_ptr, (png_bytep )output_ptr[i], png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600819 png_free(png_ptr, output_ptr[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500820 }
821 if (max_output_ptr)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600822 png_free(png_ptr, output_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500823 /* write anything left in zbuf */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600824 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
Guy Schalnat0d580581995-07-20 02:43:20 -0500825 png_write_chunk_data(png_ptr, png_ptr->zbuf,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600826 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
Guy Schalnat0d580581995-07-20 02:43:20 -0500827 /* close the chunk */
828 png_write_chunk_end(png_ptr);
829
830 /* reset zlib for another zTXt or the image data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600831 deflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500832}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500833#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500834
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500835#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500836/* write the pHYs chunk */
837void
Guy Schalnat6d764711995-12-19 03:22:19 -0600838png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
Guy Schalnat0d580581995-07-20 02:43:20 -0500839 png_uint_32 y_pixels_per_unit,
840 int unit_type)
841{
842 png_byte buf[9];
843
Guy Schalnate5a37791996-06-05 15:50:50 -0500844 if (unit_type >= PNG_RESOLUTION_LAST)
845 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
846
Guy Schalnat0d580581995-07-20 02:43:20 -0500847 png_save_uint_32(buf, x_pixels_per_unit);
848 png_save_uint_32(buf + 4, y_pixels_per_unit);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600849 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500850
851 png_write_chunk(png_ptr, png_pHYs, buf, (png_uint_32)9);
852}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500853#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500854
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500855#if defined(PNG_WRITE_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500856/* write the oFFs chunk */
857void
Guy Schalnat6d764711995-12-19 03:22:19 -0600858png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
Guy Schalnat0d580581995-07-20 02:43:20 -0500859 png_uint_32 y_offset,
860 int unit_type)
861{
862 png_byte buf[9];
863
Guy Schalnate5a37791996-06-05 15:50:50 -0500864 if (unit_type >= PNG_OFFSET_LAST)
865 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
866
Guy Schalnat0d580581995-07-20 02:43:20 -0500867 png_save_uint_32(buf, x_offset);
868 png_save_uint_32(buf + 4, y_offset);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600869 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500870
871 png_write_chunk(png_ptr, png_oFFs, buf, (png_uint_32)9);
872}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500873#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500874
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500875#if defined(PNG_WRITE_tIME_SUPPORTED)
876/* write the tIME chunk. Use either png_convert_from_struct_tm()
877 or png_convert_from_time_t(), or fill in the structure yourself */
Guy Schalnat0d580581995-07-20 02:43:20 -0500878void
Guy Schalnat6d764711995-12-19 03:22:19 -0600879png_write_tIME(png_structp png_ptr, png_timep mod_time)
Guy Schalnat0d580581995-07-20 02:43:20 -0500880{
881 png_byte buf[7];
882
Guy Schalnate5a37791996-06-05 15:50:50 -0500883 if (mod_time->month > 12 || mod_time->month < 1 ||
884 mod_time->day > 31 || mod_time->day < 1 ||
885 mod_time->hour > 23 || mod_time->second > 60)
886 {
887 png_warning(png_ptr, "Invalid time specified for tIME chunk");
888 return;
889 }
890
Guy Schalnat0d580581995-07-20 02:43:20 -0500891 png_save_uint_16(buf, mod_time->year);
892 buf[2] = mod_time->month;
893 buf[3] = mod_time->day;
894 buf[4] = mod_time->hour;
895 buf[5] = mod_time->minute;
896 buf[6] = mod_time->second;
897
898 png_write_chunk(png_ptr, png_tIME, buf, (png_uint_32)7);
899}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500900#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500901
902/* initializes the row writing capability of libpng */
903void
Guy Schalnat6d764711995-12-19 03:22:19 -0600904png_write_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500905{
906 /* set up row buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600907 png_ptr->row_buf = (png_bytep )png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500908 (((png_uint_32)png_ptr->usr_channels *
909 (png_uint_32)png_ptr->usr_bit_depth *
Guy Schalnat6d764711995-12-19 03:22:19 -0600910 png_ptr->width + 7) >> 3) + 1);
Guy Schalnate5a37791996-06-05 15:50:50 -0500911 png_ptr->row_buf[0] = 0;
912
913 /* set up filtering buffer, if using this filter */
914 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -0500915 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600916 png_ptr->sub_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500917 png_ptr->rowbytes + 1);
918 png_ptr->sub_row[0] = 1; /* Set the row filter type */
919 }
920
921 /* We only need to keep the previous row if we are using one of these */
922 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
923 {
924 /* set up previous row buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600925 png_ptr->prev_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500926 (((png_uint_32)png_ptr->usr_channels *
927 (png_uint_32)png_ptr->usr_bit_depth *
928 png_ptr->width + 7) >> 3) + 1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600929 png_memset(png_ptr->prev_row, 0,
930 (png_size_t)(((png_uint_32)png_ptr->usr_channels *
931 (png_uint_32)png_ptr->usr_bit_depth *
932 png_ptr->width + 7) >> 3) + 1);
Guy Schalnate5a37791996-06-05 15:50:50 -0500933
934 if (png_ptr->do_filter & PNG_FILTER_UP)
935 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600936 png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500937 png_ptr->rowbytes + 1);
938 png_ptr->up_row[0] = 2; /* Set the row filter type */
939 }
940
941 if (png_ptr->do_filter & PNG_FILTER_AVG)
942 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600943 png_ptr->avg_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500944 png_ptr->rowbytes + 1);
945 png_ptr->avg_row[0] = 3; /* Set the row filter type */
946 }
947
948 if (png_ptr->do_filter & PNG_FILTER_PAETH)
949 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600950 png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500951 png_ptr->rowbytes + 1);
952 png_ptr->paeth_row[0] = 4; /* Set the row filter type */
953 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500954 }
955
956 /* if interlaced, we need to set up width and height of pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600957 if (png_ptr->interlaced)
Guy Schalnat0d580581995-07-20 02:43:20 -0500958 {
959 if (!(png_ptr->transformations & PNG_INTERLACE))
960 {
961 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
962 png_pass_ystart[0]) / png_pass_yinc[0];
963 png_ptr->usr_width = (png_ptr->width +
964 png_pass_inc[0] - 1 -
965 png_pass_start[0]) /
966 png_pass_inc[0];
967 }
968 else
969 {
970 png_ptr->num_rows = png_ptr->height;
971 png_ptr->usr_width = png_ptr->width;
972 }
973 }
974 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600975 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500976 png_ptr->num_rows = png_ptr->height;
977 png_ptr->usr_width = png_ptr->width;
978 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600979 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
980 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500981}
982
983/* Internal use only. Called when finished processing a row of data */
984void
Guy Schalnat6d764711995-12-19 03:22:19 -0600985png_write_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500986{
987 int ret;
988
989 /* next row */
990 png_ptr->row_number++;
Guy Schalnatc21f90c1996-06-17 16:24:45 -0500991
Guy Schalnat0d580581995-07-20 02:43:20 -0500992 /* see if we are done */
Guy Schalnat6d764711995-12-19 03:22:19 -0600993 if (png_ptr->row_number < png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600994 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500995
996 /* if interlaced, go to next pass */
997 if (png_ptr->interlaced)
998 {
999 png_ptr->row_number = 0;
1000 if (png_ptr->transformations & PNG_INTERLACE)
1001 {
1002 png_ptr->pass++;
1003 }
1004 else
1005 {
1006 /* loop until we find a non-zero width or height pass */
1007 do
1008 {
1009 png_ptr->pass++;
1010 if (png_ptr->pass >= 7)
1011 break;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001012 png_ptr->usr_width = (png_ptr->width +
Guy Schalnat0d580581995-07-20 02:43:20 -05001013 png_pass_inc[png_ptr->pass] - 1 -
1014 png_pass_start[png_ptr->pass]) /
1015 png_pass_inc[png_ptr->pass];
1016 png_ptr->num_rows = (png_ptr->height +
1017 png_pass_yinc[png_ptr->pass] - 1 -
1018 png_pass_ystart[png_ptr->pass]) /
1019 png_pass_yinc[png_ptr->pass];
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001020 if (png_ptr->transformations & PNG_INTERLACE)
1021 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001022 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
1023
1024 }
1025
Guy Schalnate5a37791996-06-05 15:50:50 -05001026 /* reset the row above the image for the next pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001027 if (png_ptr->pass < 7)
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001028 {
1029 if (png_ptr->prev_row)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001030 png_memset(png_ptr->prev_row, 0,
1031 (png_size_t) (((png_uint_32)png_ptr->usr_channels *
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001032 (png_uint_32)png_ptr->usr_bit_depth *
1033 png_ptr->width + 7) >> 3) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001034 return;
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001035 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001036 }
1037
1038 /* if we get here, we've just written the last row, so we need
1039 to flush the compressor */
1040 do
1041 {
1042 /* tell the compressor we are done */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001043 ret = deflate(&png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -05001044 /* check for an error */
1045 if (ret != Z_OK && ret != Z_STREAM_END)
1046 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001047 if (png_ptr->zstream.msg)
1048 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -05001049 else
Guy Schalnat6d764711995-12-19 03:22:19 -06001050 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -05001051 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001052 /* check to see if we need more room */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001053 if (!png_ptr->zstream.avail_out && ret == Z_OK)
Guy Schalnat0d580581995-07-20 02:43:20 -05001054 {
1055 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001056 png_ptr->zstream.next_out = png_ptr->zbuf;
1057 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -05001058 }
1059 } while (ret != Z_STREAM_END);
1060
1061 /* write any extra space */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001062 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
Guy Schalnat0d580581995-07-20 02:43:20 -05001063 {
1064 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001065 png_ptr->zstream.avail_out);
Guy Schalnat0d580581995-07-20 02:43:20 -05001066 }
1067
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001068 deflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05001069}
1070
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001071#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001072/* pick out the correct pixels for the interlace pass.
1073
1074 The basic idea here is to go through the row with a source
1075 pointer and a destination pointer (sp and dp), and copy the
1076 correct pixels for the pass. As the row gets compacted,
1077 sp will always be >= dp, so we should never overwrite anything.
1078 See the default: case for the easiest code to understand.
1079 */
1080void
Guy Schalnat6d764711995-12-19 03:22:19 -06001081png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -05001082{
1083 /* we don't have to do anything on the last pass (6) */
1084 if (row && row_info && pass < 6)
1085 {
1086 /* each pixel depth is handled seperately */
1087 switch (row_info->pixel_depth)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001088 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001089 case 1:
1090 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001091 png_bytep sp;
1092 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001093 int shift;
1094 int d;
1095 int value;
1096 png_uint_32 i;
1097
1098 dp = row;
1099 d = 0;
1100 shift = 7;
1101 for (i = png_pass_start[pass];
1102 i < row_info->width;
1103 i += png_pass_inc[pass])
1104 {
1105 sp = row + (png_size_t)(i >> 3);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001106 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
Guy Schalnat0d580581995-07-20 02:43:20 -05001107 d |= (value << shift);
1108
1109 if (shift == 0)
1110 {
1111 shift = 7;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001112 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001113 d = 0;
1114 }
1115 else
1116 shift--;
1117
1118 }
1119 if (shift != 7)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001120 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001121 break;
1122 }
1123 case 2:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001124 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001125 png_bytep sp;
1126 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001127 int shift;
1128 int d;
1129 int value;
1130 png_uint_32 i;
1131
1132 dp = row;
1133 shift = 6;
1134 d = 0;
1135 for (i = png_pass_start[pass];
1136 i < row_info->width;
1137 i += png_pass_inc[pass])
1138 {
1139 sp = row + (png_size_t)(i >> 2);
1140 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
1141 d |= (value << shift);
1142
1143 if (shift == 0)
1144 {
1145 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001146 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001147 d = 0;
1148 }
1149 else
1150 shift -= 2;
1151 }
1152 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001153 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001154 break;
1155 }
1156 case 4:
1157 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001158 png_bytep sp;
1159 png_bytep dp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001160 int shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05001161 int d;
1162 int value;
1163 png_uint_32 i;
1164
1165 dp = row;
1166 shift = 4;
1167 d = 0;
1168 for (i = png_pass_start[pass];
1169 i < row_info->width;
1170 i += png_pass_inc[pass])
1171 {
1172 sp = row + (png_size_t)(i >> 1);
1173 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
1174 d |= (value << shift);
1175
1176 if (shift == 0)
1177 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001178 shift = 4;
1179 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001180 d = 0;
1181 }
1182 else
1183 shift -= 4;
1184 }
1185 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001186 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001187 break;
1188 }
1189 default:
1190 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001191 png_bytep sp;
1192 png_bytep dp;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001193 png_uint_32 i, pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001194
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001195 /* start at the beginning */
Guy Schalnat0d580581995-07-20 02:43:20 -05001196 dp = row;
1197 /* find out how many bytes each pixel takes up */
1198 pixel_bytes = (row_info->pixel_depth >> 3);
1199 /* loop through the row, only looking at the pixels that
1200 matter */
1201 for (i = png_pass_start[pass];
1202 i < row_info->width;
1203 i += png_pass_inc[pass])
1204 {
1205 /* find out where the original pixel is */
1206 sp = row + (png_size_t)(i * pixel_bytes);
1207 /* move the pixel */
1208 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001209 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001210 /* next pixel */
1211 dp += pixel_bytes;
1212 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001213 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001214 }
1215 }
1216 /* set new row width */
1217 row_info->width = (row_info->width +
1218 png_pass_inc[pass] - 1 -
1219 png_pass_start[pass]) /
1220 png_pass_inc[pass];
1221 row_info->rowbytes = ((row_info->width *
1222 row_info->pixel_depth + 7) >> 3);
1223
1224 }
1225}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001226#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001227
Guy Schalnate5a37791996-06-05 15:50:50 -05001228/* this filters the row, chooses which filter to use, if it has not already
1229 * been given by the application, and then writes the row out with the
1230 * chosen filter */
Guy Schalnat0d580581995-07-20 02:43:20 -05001231void
Guy Schalnate5a37791996-06-05 15:50:50 -05001232png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
Guy Schalnat0d580581995-07-20 02:43:20 -05001233{
Guy Schalnate5a37791996-06-05 15:50:50 -05001234 png_bytep prev_row, best_row, row_buf;
1235 png_uint_32 mins;
1236 int bpp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001237
1238 /* find out how many bytes offset each pixel is */
1239 bpp = (row_info->pixel_depth + 7) / 8;
Guy Schalnate5a37791996-06-05 15:50:50 -05001240
1241 prev_row = png_ptr->prev_row;
1242 best_row = row_buf = png_ptr->row_buf;
1243 mins = 0xffffffff;
Guy Schalnat0d580581995-07-20 02:43:20 -05001244
1245 /* the prediction method we use is to find which method provides
1246 the smallest value when summing the abs of the distances from
1247 zero using anything >= 128 as negitive numbers. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001248
Guy Schalnate5a37791996-06-05 15:50:50 -05001249 /* We don't need to test the 'no filter' case if this is the only filter
1250 * that has been chosen, as it doesn't actually do anything to the data. */
1251 if (png_ptr->do_filter & PNG_FILTER_NONE &&
1252 png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001253 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001254 png_bytep rp;
1255 png_uint_32 sum = 0;
1256 int i, v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001257
Guy Schalnate5a37791996-06-05 15:50:50 -05001258 for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
1259 {
1260 v = *rp;
1261 sum += (v < 128) ? v : 256 - v;
1262 }
1263 mins = sum;
Guy Schalnat0d580581995-07-20 02:43:20 -05001264 }
1265
Guy Schalnate5a37791996-06-05 15:50:50 -05001266 /* sub filter */
1267 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -05001268 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001269 png_bytep rp, dp, lp;
1270 png_uint_32 sum = 0;
1271 int i, v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001272
Guy Schalnate5a37791996-06-05 15:50:50 -05001273 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
1274 i++, rp++, dp++)
1275 {
1276 v = *dp = *rp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001277
Guy Schalnate5a37791996-06-05 15:50:50 -05001278 sum += (v < 128) ? v : 256 - v;
1279 }
1280 for (lp = row_buf + 1; i < row_info->rowbytes; i++, rp++, lp++, dp++)
1281 {
1282 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001283
Guy Schalnate5a37791996-06-05 15:50:50 -05001284 sum += (v < 128) ? v : 256 - v;
1285 }
1286 if (sum < mins)
1287 {
1288 mins = sum;
1289 best_row = png_ptr->sub_row;
1290 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001291 }
1292
Guy Schalnate5a37791996-06-05 15:50:50 -05001293 /* up filter */
1294 if (png_ptr->do_filter & PNG_FILTER_UP)
Guy Schalnat0d580581995-07-20 02:43:20 -05001295 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001296 png_bytep rp, dp, pp;
1297 png_uint_32 sum = 0;
1298 int i, v;
1299
1300 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
1301 pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
1302 {
1303 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1304
1305 sum += (v < 128) ? v : 256 - v;
1306 }
1307 if (sum < mins)
1308 {
1309 mins = sum;
1310 best_row = png_ptr->up_row;
1311 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001312 }
1313
Guy Schalnate5a37791996-06-05 15:50:50 -05001314 /* avg filter */
1315 if (png_ptr->do_filter & PNG_FILTER_AVG)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001316 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001317 png_bytep rp, dp, pp, lp;
1318 png_uint_32 sum = 0;
1319 int i, v;
1320
1321 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
1322 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1323 {
1324 v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
1325
1326 sum += (v < 128) ? v : 256 - v;
1327 }
1328 for (lp = row_buf + 1; i < row_info->rowbytes;
1329 i++, rp++, pp++, lp++, dp++)
1330 {
1331 v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
1332
1333 sum += (v < 128) ? v : 256 - v;
1334 }
1335 if (sum < mins)
1336 {
1337 mins = sum;
1338 best_row = png_ptr->avg_row;
1339 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001340 }
1341
Guy Schalnate5a37791996-06-05 15:50:50 -05001342 /* paeth filter */
1343 if (png_ptr->do_filter & PNG_FILTER_PAETH)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001344 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001345 png_bytep rp, dp, pp, cp, lp;
1346 png_uint_32 sum = 0;
1347 int i, v;
1348
1349 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
1350 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1351 {
1352 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1353
1354 sum += (v < 128) ? v : 256 - v;
1355 }
1356 for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes;
1357 i++, rp++, pp++, lp++, dp++, cp++)
1358 {
1359 int a, b, c, pa, pb, pc, p;
1360
1361 b = *pp;
1362 c = *cp;
1363 a = *lp;
1364
1365 p = a + b - c;
1366 pa = abs(p - a);
1367 pb = abs(p - b);
1368 pc = abs(p - c);
1369
1370 if (pa <= pb && pa <= pc)
1371 p = a;
1372 else if (pb <= pc)
1373 p = b;
1374 else
1375 p = c;
1376
1377 v = *dp = (png_byte)(((int)*rp - p) & 0xff);
1378
1379 sum += (v < 128) ? v : 256 - v;
1380 }
1381 if (sum < mins)
1382 {
1383 best_row = png_ptr->paeth_row;
1384 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001385 }
1386
Guy Schalnate5a37791996-06-05 15:50:50 -05001387 /* Do the actual writing of the filtered row data from the chosen filter */
1388 png_write_filtered_row(png_ptr, best_row);
1389}
1390
1391
1392/* do the actual writing of a filtered row */
1393void
1394png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
1395{
1396 /* set up the zlib input buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001397 png_ptr->zstream.next_in = filtered_row;
1398 png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
Guy Schalnate5a37791996-06-05 15:50:50 -05001399 /* repeat until we have compressed all the data */
1400 do
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001401 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001402 int ret; /* return of zlib */
Guy Schalnat0d580581995-07-20 02:43:20 -05001403
Guy Schalnate5a37791996-06-05 15:50:50 -05001404 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001405 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnate5a37791996-06-05 15:50:50 -05001406 /* check for compression errors */
1407 if (ret != Z_OK)
1408 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001409 if (png_ptr->zstream.msg)
1410 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnate5a37791996-06-05 15:50:50 -05001411 else
1412 png_error(png_ptr, "zlib error");
1413 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001414
Guy Schalnate5a37791996-06-05 15:50:50 -05001415 /* see if it is time to write another IDAT */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001416 if (!png_ptr->zstream.avail_out)
Guy Schalnate5a37791996-06-05 15:50:50 -05001417 {
1418 /* write the IDAT and reset the zlib output buffer */
1419 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001420 png_ptr->zstream.next_out = png_ptr->zbuf;
1421 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001422 }
1423 /* repeat until all data has been compressed */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001424 } while (png_ptr->zstream.avail_in);
Guy Schalnate5a37791996-06-05 15:50:50 -05001425
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001426 /* swap the current and previous rows */
1427 if (png_ptr->prev_row)
1428 {
1429 png_bytep tptr;
1430
1431 tptr = png_ptr->prev_row;
1432 png_ptr->prev_row = png_ptr->row_buf;
1433 png_ptr->row_buf = tptr;
1434 }
1435
Guy Schalnate5a37791996-06-05 15:50:50 -05001436 /* finish row - updates counters and flushes zlib if last row */
1437 png_write_finish_row(png_ptr);
1438
1439#if defined(PNG_WRITE_FLUSH_SUPPORTED)
1440 png_ptr->flush_rows++;
1441
1442 if (png_ptr->flush_dist > 0 &&
1443 png_ptr->flush_rows >= png_ptr->flush_dist)
Guy Schalnat0d580581995-07-20 02:43:20 -05001444 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001445 png_write_flush(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001446 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001447#endif /* PNG_WRITE_FLUSH_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05001448}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001449