1*a67afe4dSAndroid Build Coastguard Worker
2*a67afe4dSAndroid Build Coastguard Worker /* pngwutil.c - utilities to write a PNG file
3*a67afe4dSAndroid Build Coastguard Worker *
4*a67afe4dSAndroid Build Coastguard Worker * Copyright (c) 2018-2024 Cosmin Truta
5*a67afe4dSAndroid Build Coastguard Worker * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
6*a67afe4dSAndroid Build Coastguard Worker * Copyright (c) 1996-1997 Andreas Dilger
7*a67afe4dSAndroid Build Coastguard Worker * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
8*a67afe4dSAndroid Build Coastguard Worker *
9*a67afe4dSAndroid Build Coastguard Worker * This code is released under the libpng license.
10*a67afe4dSAndroid Build Coastguard Worker * For conditions of distribution and use, see the disclaimer
11*a67afe4dSAndroid Build Coastguard Worker * and license in png.h
12*a67afe4dSAndroid Build Coastguard Worker */
13*a67afe4dSAndroid Build Coastguard Worker
14*a67afe4dSAndroid Build Coastguard Worker #include "pngpriv.h"
15*a67afe4dSAndroid Build Coastguard Worker
16*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_SUPPORTED
17*a67afe4dSAndroid Build Coastguard Worker
18*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
19*a67afe4dSAndroid Build Coastguard Worker /* Place a 32-bit number into a buffer in PNG byte order. We work
20*a67afe4dSAndroid Build Coastguard Worker * with unsigned numbers for convenience, although one supported
21*a67afe4dSAndroid Build Coastguard Worker * ancillary chunk uses signed (two's complement) numbers.
22*a67afe4dSAndroid Build Coastguard Worker */
23*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_save_uint_32(png_bytep buf,png_uint_32 i)24*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(png_bytep buf, png_uint_32 i)
25*a67afe4dSAndroid Build Coastguard Worker {
26*a67afe4dSAndroid Build Coastguard Worker buf[0] = (png_byte)((i >> 24) & 0xffU);
27*a67afe4dSAndroid Build Coastguard Worker buf[1] = (png_byte)((i >> 16) & 0xffU);
28*a67afe4dSAndroid Build Coastguard Worker buf[2] = (png_byte)((i >> 8) & 0xffU);
29*a67afe4dSAndroid Build Coastguard Worker buf[3] = (png_byte)( i & 0xffU);
30*a67afe4dSAndroid Build Coastguard Worker }
31*a67afe4dSAndroid Build Coastguard Worker
32*a67afe4dSAndroid Build Coastguard Worker /* Place a 16-bit number into a buffer in PNG byte order.
33*a67afe4dSAndroid Build Coastguard Worker * The parameter is declared unsigned int, not png_uint_16,
34*a67afe4dSAndroid Build Coastguard Worker * just to avoid potential problems on pre-ANSI C compilers.
35*a67afe4dSAndroid Build Coastguard Worker */
36*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_save_uint_16(png_bytep buf,unsigned int i)37*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(png_bytep buf, unsigned int i)
38*a67afe4dSAndroid Build Coastguard Worker {
39*a67afe4dSAndroid Build Coastguard Worker buf[0] = (png_byte)((i >> 8) & 0xffU);
40*a67afe4dSAndroid Build Coastguard Worker buf[1] = (png_byte)( i & 0xffU);
41*a67afe4dSAndroid Build Coastguard Worker }
42*a67afe4dSAndroid Build Coastguard Worker #endif
43*a67afe4dSAndroid Build Coastguard Worker
44*a67afe4dSAndroid Build Coastguard Worker /* Simple function to write the signature. If we have already written
45*a67afe4dSAndroid Build Coastguard Worker * the magic bytes of the signature, or more likely, the PNG stream is
46*a67afe4dSAndroid Build Coastguard Worker * being embedded into another stream and doesn't need its own signature,
47*a67afe4dSAndroid Build Coastguard Worker * we should call png_set_sig_bytes() to tell libpng how many of the
48*a67afe4dSAndroid Build Coastguard Worker * bytes have already been written.
49*a67afe4dSAndroid Build Coastguard Worker */
50*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_write_sig(png_structrp png_ptr)51*a67afe4dSAndroid Build Coastguard Worker png_write_sig(png_structrp png_ptr)
52*a67afe4dSAndroid Build Coastguard Worker {
53*a67afe4dSAndroid Build Coastguard Worker png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
54*a67afe4dSAndroid Build Coastguard Worker
55*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_IO_STATE_SUPPORTED
56*a67afe4dSAndroid Build Coastguard Worker /* Inform the I/O callback that the signature is being written */
57*a67afe4dSAndroid Build Coastguard Worker png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE;
58*a67afe4dSAndroid Build Coastguard Worker #endif
59*a67afe4dSAndroid Build Coastguard Worker
60*a67afe4dSAndroid Build Coastguard Worker /* Write the rest of the 8 byte signature */
61*a67afe4dSAndroid Build Coastguard Worker png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
62*a67afe4dSAndroid Build Coastguard Worker (size_t)(8 - png_ptr->sig_bytes));
63*a67afe4dSAndroid Build Coastguard Worker
64*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->sig_bytes < 3)
65*a67afe4dSAndroid Build Coastguard Worker png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
66*a67afe4dSAndroid Build Coastguard Worker }
67*a67afe4dSAndroid Build Coastguard Worker
68*a67afe4dSAndroid Build Coastguard Worker /* Write the start of a PNG chunk. The type is the chunk type.
69*a67afe4dSAndroid Build Coastguard Worker * The total_length is the sum of the lengths of all the data you will be
70*a67afe4dSAndroid Build Coastguard Worker * passing in png_write_chunk_data().
71*a67afe4dSAndroid Build Coastguard Worker */
72*a67afe4dSAndroid Build Coastguard Worker static void
png_write_chunk_header(png_structrp png_ptr,png_uint_32 chunk_name,png_uint_32 length)73*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name,
74*a67afe4dSAndroid Build Coastguard Worker png_uint_32 length)
75*a67afe4dSAndroid Build Coastguard Worker {
76*a67afe4dSAndroid Build Coastguard Worker png_byte buf[8];
77*a67afe4dSAndroid Build Coastguard Worker
78*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_DEBUG) && (PNG_DEBUG > 0)
79*a67afe4dSAndroid Build Coastguard Worker PNG_CSTRING_FROM_CHUNK(buf, chunk_name);
80*a67afe4dSAndroid Build Coastguard Worker png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length);
81*a67afe4dSAndroid Build Coastguard Worker #endif
82*a67afe4dSAndroid Build Coastguard Worker
83*a67afe4dSAndroid Build Coastguard Worker if (png_ptr == NULL)
84*a67afe4dSAndroid Build Coastguard Worker return;
85*a67afe4dSAndroid Build Coastguard Worker
86*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_IO_STATE_SUPPORTED
87*a67afe4dSAndroid Build Coastguard Worker /* Inform the I/O callback that the chunk header is being written.
88*a67afe4dSAndroid Build Coastguard Worker * PNG_IO_CHUNK_HDR requires a single I/O call.
89*a67afe4dSAndroid Build Coastguard Worker */
90*a67afe4dSAndroid Build Coastguard Worker png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR;
91*a67afe4dSAndroid Build Coastguard Worker #endif
92*a67afe4dSAndroid Build Coastguard Worker
93*a67afe4dSAndroid Build Coastguard Worker /* Write the length and the chunk name */
94*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf, length);
95*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf + 4, chunk_name);
96*a67afe4dSAndroid Build Coastguard Worker png_write_data(png_ptr, buf, 8);
97*a67afe4dSAndroid Build Coastguard Worker
98*a67afe4dSAndroid Build Coastguard Worker /* Put the chunk name into png_ptr->chunk_name */
99*a67afe4dSAndroid Build Coastguard Worker png_ptr->chunk_name = chunk_name;
100*a67afe4dSAndroid Build Coastguard Worker
101*a67afe4dSAndroid Build Coastguard Worker /* Reset the crc and run it over the chunk name */
102*a67afe4dSAndroid Build Coastguard Worker png_reset_crc(png_ptr);
103*a67afe4dSAndroid Build Coastguard Worker
104*a67afe4dSAndroid Build Coastguard Worker png_calculate_crc(png_ptr, buf + 4, 4);
105*a67afe4dSAndroid Build Coastguard Worker
106*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_IO_STATE_SUPPORTED
107*a67afe4dSAndroid Build Coastguard Worker /* Inform the I/O callback that chunk data will (possibly) be written.
108*a67afe4dSAndroid Build Coastguard Worker * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
109*a67afe4dSAndroid Build Coastguard Worker */
110*a67afe4dSAndroid Build Coastguard Worker png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA;
111*a67afe4dSAndroid Build Coastguard Worker #endif
112*a67afe4dSAndroid Build Coastguard Worker }
113*a67afe4dSAndroid Build Coastguard Worker
114*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_write_chunk_start(png_structrp png_ptr,png_const_bytep chunk_string,png_uint_32 length)115*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string,
116*a67afe4dSAndroid Build Coastguard Worker png_uint_32 length)
117*a67afe4dSAndroid Build Coastguard Worker {
118*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length);
119*a67afe4dSAndroid Build Coastguard Worker }
120*a67afe4dSAndroid Build Coastguard Worker
121*a67afe4dSAndroid Build Coastguard Worker /* Write the data of a PNG chunk started with png_write_chunk_header().
122*a67afe4dSAndroid Build Coastguard Worker * Note that multiple calls to this function are allowed, and that the
123*a67afe4dSAndroid Build Coastguard Worker * sum of the lengths from these calls *must* add up to the total_length
124*a67afe4dSAndroid Build Coastguard Worker * given to png_write_chunk_header().
125*a67afe4dSAndroid Build Coastguard Worker */
126*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_write_chunk_data(png_structrp png_ptr,png_const_bytep data,size_t length)127*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length)
128*a67afe4dSAndroid Build Coastguard Worker {
129*a67afe4dSAndroid Build Coastguard Worker /* Write the data, and run the CRC over it */
130*a67afe4dSAndroid Build Coastguard Worker if (png_ptr == NULL)
131*a67afe4dSAndroid Build Coastguard Worker return;
132*a67afe4dSAndroid Build Coastguard Worker
133*a67afe4dSAndroid Build Coastguard Worker if (data != NULL && length > 0)
134*a67afe4dSAndroid Build Coastguard Worker {
135*a67afe4dSAndroid Build Coastguard Worker png_write_data(png_ptr, data, length);
136*a67afe4dSAndroid Build Coastguard Worker
137*a67afe4dSAndroid Build Coastguard Worker /* Update the CRC after writing the data,
138*a67afe4dSAndroid Build Coastguard Worker * in case the user I/O routine alters it.
139*a67afe4dSAndroid Build Coastguard Worker */
140*a67afe4dSAndroid Build Coastguard Worker png_calculate_crc(png_ptr, data, length);
141*a67afe4dSAndroid Build Coastguard Worker }
142*a67afe4dSAndroid Build Coastguard Worker }
143*a67afe4dSAndroid Build Coastguard Worker
144*a67afe4dSAndroid Build Coastguard Worker /* Finish a chunk started with png_write_chunk_header(). */
145*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_write_chunk_end(png_structrp png_ptr)146*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_structrp png_ptr)
147*a67afe4dSAndroid Build Coastguard Worker {
148*a67afe4dSAndroid Build Coastguard Worker png_byte buf[4];
149*a67afe4dSAndroid Build Coastguard Worker
150*a67afe4dSAndroid Build Coastguard Worker if (png_ptr == NULL) return;
151*a67afe4dSAndroid Build Coastguard Worker
152*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_IO_STATE_SUPPORTED
153*a67afe4dSAndroid Build Coastguard Worker /* Inform the I/O callback that the chunk CRC is being written.
154*a67afe4dSAndroid Build Coastguard Worker * PNG_IO_CHUNK_CRC requires a single I/O function call.
155*a67afe4dSAndroid Build Coastguard Worker */
156*a67afe4dSAndroid Build Coastguard Worker png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC;
157*a67afe4dSAndroid Build Coastguard Worker #endif
158*a67afe4dSAndroid Build Coastguard Worker
159*a67afe4dSAndroid Build Coastguard Worker /* Write the crc in a single operation */
160*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf, png_ptr->crc);
161*a67afe4dSAndroid Build Coastguard Worker
162*a67afe4dSAndroid Build Coastguard Worker png_write_data(png_ptr, buf, 4);
163*a67afe4dSAndroid Build Coastguard Worker }
164*a67afe4dSAndroid Build Coastguard Worker
165*a67afe4dSAndroid Build Coastguard Worker /* Write a PNG chunk all at once. The type is an array of ASCII characters
166*a67afe4dSAndroid Build Coastguard Worker * representing the chunk name. The array must be at least 4 bytes in
167*a67afe4dSAndroid Build Coastguard Worker * length, and does not need to be null terminated. To be safe, pass the
168*a67afe4dSAndroid Build Coastguard Worker * pre-defined chunk names here, and if you need a new one, define it
169*a67afe4dSAndroid Build Coastguard Worker * where the others are defined. The length is the length of the data.
170*a67afe4dSAndroid Build Coastguard Worker * All the data must be present. If that is not possible, use the
171*a67afe4dSAndroid Build Coastguard Worker * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
172*a67afe4dSAndroid Build Coastguard Worker * functions instead.
173*a67afe4dSAndroid Build Coastguard Worker */
174*a67afe4dSAndroid Build Coastguard Worker static void
png_write_complete_chunk(png_structrp png_ptr,png_uint_32 chunk_name,png_const_bytep data,size_t length)175*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,
176*a67afe4dSAndroid Build Coastguard Worker png_const_bytep data, size_t length)
177*a67afe4dSAndroid Build Coastguard Worker {
178*a67afe4dSAndroid Build Coastguard Worker if (png_ptr == NULL)
179*a67afe4dSAndroid Build Coastguard Worker return;
180*a67afe4dSAndroid Build Coastguard Worker
181*a67afe4dSAndroid Build Coastguard Worker /* On 64-bit architectures 'length' may not fit in a png_uint_32. */
182*a67afe4dSAndroid Build Coastguard Worker if (length > PNG_UINT_31_MAX)
183*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "length exceeds PNG maximum");
184*a67afe4dSAndroid Build Coastguard Worker
185*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length);
186*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, data, length);
187*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
188*a67afe4dSAndroid Build Coastguard Worker }
189*a67afe4dSAndroid Build Coastguard Worker
190*a67afe4dSAndroid Build Coastguard Worker /* This is the API that calls the internal function above. */
191*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_write_chunk(png_structrp png_ptr,png_const_bytep chunk_string,png_const_bytep data,size_t length)192*a67afe4dSAndroid Build Coastguard Worker png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
193*a67afe4dSAndroid Build Coastguard Worker png_const_bytep data, size_t length)
194*a67afe4dSAndroid Build Coastguard Worker {
195*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,
196*a67afe4dSAndroid Build Coastguard Worker length);
197*a67afe4dSAndroid Build Coastguard Worker }
198*a67afe4dSAndroid Build Coastguard Worker
199*a67afe4dSAndroid Build Coastguard Worker /* This is used below to find the size of an image to pass to png_deflate_claim,
200*a67afe4dSAndroid Build Coastguard Worker * so it only needs to be accurate if the size is less than 16384 bytes (the
201*a67afe4dSAndroid Build Coastguard Worker * point at which a lower LZ window size can be used.)
202*a67afe4dSAndroid Build Coastguard Worker */
203*a67afe4dSAndroid Build Coastguard Worker static png_alloc_size_t
png_image_size(png_structrp png_ptr)204*a67afe4dSAndroid Build Coastguard Worker png_image_size(png_structrp png_ptr)
205*a67afe4dSAndroid Build Coastguard Worker {
206*a67afe4dSAndroid Build Coastguard Worker /* Only return sizes up to the maximum of a png_uint_32; do this by limiting
207*a67afe4dSAndroid Build Coastguard Worker * the width and height used to 15 bits.
208*a67afe4dSAndroid Build Coastguard Worker */
209*a67afe4dSAndroid Build Coastguard Worker png_uint_32 h = png_ptr->height;
210*a67afe4dSAndroid Build Coastguard Worker
211*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->rowbytes < 32768 && h < 32768)
212*a67afe4dSAndroid Build Coastguard Worker {
213*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->interlaced != 0)
214*a67afe4dSAndroid Build Coastguard Worker {
215*a67afe4dSAndroid Build Coastguard Worker /* Interlacing makes the image larger because of the replication of
216*a67afe4dSAndroid Build Coastguard Worker * both the filter byte and the padding to a byte boundary.
217*a67afe4dSAndroid Build Coastguard Worker */
218*a67afe4dSAndroid Build Coastguard Worker png_uint_32 w = png_ptr->width;
219*a67afe4dSAndroid Build Coastguard Worker unsigned int pd = png_ptr->pixel_depth;
220*a67afe4dSAndroid Build Coastguard Worker png_alloc_size_t cb_base;
221*a67afe4dSAndroid Build Coastguard Worker int pass;
222*a67afe4dSAndroid Build Coastguard Worker
223*a67afe4dSAndroid Build Coastguard Worker for (cb_base=0, pass=0; pass<=6; ++pass)
224*a67afe4dSAndroid Build Coastguard Worker {
225*a67afe4dSAndroid Build Coastguard Worker png_uint_32 pw = PNG_PASS_COLS(w, pass);
226*a67afe4dSAndroid Build Coastguard Worker
227*a67afe4dSAndroid Build Coastguard Worker if (pw > 0)
228*a67afe4dSAndroid Build Coastguard Worker cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass);
229*a67afe4dSAndroid Build Coastguard Worker }
230*a67afe4dSAndroid Build Coastguard Worker
231*a67afe4dSAndroid Build Coastguard Worker return cb_base;
232*a67afe4dSAndroid Build Coastguard Worker }
233*a67afe4dSAndroid Build Coastguard Worker
234*a67afe4dSAndroid Build Coastguard Worker else
235*a67afe4dSAndroid Build Coastguard Worker return (png_ptr->rowbytes+1) * h;
236*a67afe4dSAndroid Build Coastguard Worker }
237*a67afe4dSAndroid Build Coastguard Worker
238*a67afe4dSAndroid Build Coastguard Worker else
239*a67afe4dSAndroid Build Coastguard Worker return 0xffffffffU;
240*a67afe4dSAndroid Build Coastguard Worker }
241*a67afe4dSAndroid Build Coastguard Worker
242*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
243*a67afe4dSAndroid Build Coastguard Worker /* This is the code to hack the first two bytes of the deflate stream (the
244*a67afe4dSAndroid Build Coastguard Worker * deflate header) to correct the windowBits value to match the actual data
245*a67afe4dSAndroid Build Coastguard Worker * size. Note that the second argument is the *uncompressed* size but the
246*a67afe4dSAndroid Build Coastguard Worker * first argument is the *compressed* data (and it must be deflate
247*a67afe4dSAndroid Build Coastguard Worker * compressed.)
248*a67afe4dSAndroid Build Coastguard Worker */
249*a67afe4dSAndroid Build Coastguard Worker static void
optimize_cmf(png_bytep data,png_alloc_size_t data_size)250*a67afe4dSAndroid Build Coastguard Worker optimize_cmf(png_bytep data, png_alloc_size_t data_size)
251*a67afe4dSAndroid Build Coastguard Worker {
252*a67afe4dSAndroid Build Coastguard Worker /* Optimize the CMF field in the zlib stream. The resultant zlib stream is
253*a67afe4dSAndroid Build Coastguard Worker * still compliant to the stream specification.
254*a67afe4dSAndroid Build Coastguard Worker */
255*a67afe4dSAndroid Build Coastguard Worker if (data_size <= 16384) /* else windowBits must be 15 */
256*a67afe4dSAndroid Build Coastguard Worker {
257*a67afe4dSAndroid Build Coastguard Worker unsigned int z_cmf = data[0]; /* zlib compression method and flags */
258*a67afe4dSAndroid Build Coastguard Worker
259*a67afe4dSAndroid Build Coastguard Worker if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
260*a67afe4dSAndroid Build Coastguard Worker {
261*a67afe4dSAndroid Build Coastguard Worker unsigned int z_cinfo;
262*a67afe4dSAndroid Build Coastguard Worker unsigned int half_z_window_size;
263*a67afe4dSAndroid Build Coastguard Worker
264*a67afe4dSAndroid Build Coastguard Worker z_cinfo = z_cmf >> 4;
265*a67afe4dSAndroid Build Coastguard Worker half_z_window_size = 1U << (z_cinfo + 7);
266*a67afe4dSAndroid Build Coastguard Worker
267*a67afe4dSAndroid Build Coastguard Worker if (data_size <= half_z_window_size) /* else no change */
268*a67afe4dSAndroid Build Coastguard Worker {
269*a67afe4dSAndroid Build Coastguard Worker unsigned int tmp;
270*a67afe4dSAndroid Build Coastguard Worker
271*a67afe4dSAndroid Build Coastguard Worker do
272*a67afe4dSAndroid Build Coastguard Worker {
273*a67afe4dSAndroid Build Coastguard Worker half_z_window_size >>= 1;
274*a67afe4dSAndroid Build Coastguard Worker --z_cinfo;
275*a67afe4dSAndroid Build Coastguard Worker }
276*a67afe4dSAndroid Build Coastguard Worker while (z_cinfo > 0 && data_size <= half_z_window_size);
277*a67afe4dSAndroid Build Coastguard Worker
278*a67afe4dSAndroid Build Coastguard Worker z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
279*a67afe4dSAndroid Build Coastguard Worker
280*a67afe4dSAndroid Build Coastguard Worker data[0] = (png_byte)z_cmf;
281*a67afe4dSAndroid Build Coastguard Worker tmp = data[1] & 0xe0;
282*a67afe4dSAndroid Build Coastguard Worker tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f;
283*a67afe4dSAndroid Build Coastguard Worker data[1] = (png_byte)tmp;
284*a67afe4dSAndroid Build Coastguard Worker }
285*a67afe4dSAndroid Build Coastguard Worker }
286*a67afe4dSAndroid Build Coastguard Worker }
287*a67afe4dSAndroid Build Coastguard Worker }
288*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE_OPTIMIZE_CMF */
289*a67afe4dSAndroid Build Coastguard Worker
290*a67afe4dSAndroid Build Coastguard Worker /* Initialize the compressor for the appropriate type of compression. */
291*a67afe4dSAndroid Build Coastguard Worker static int
png_deflate_claim(png_structrp png_ptr,png_uint_32 owner,png_alloc_size_t data_size)292*a67afe4dSAndroid Build Coastguard Worker png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
293*a67afe4dSAndroid Build Coastguard Worker png_alloc_size_t data_size)
294*a67afe4dSAndroid Build Coastguard Worker {
295*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->zowner != 0)
296*a67afe4dSAndroid Build Coastguard Worker {
297*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED)
298*a67afe4dSAndroid Build Coastguard Worker char msg[64];
299*a67afe4dSAndroid Build Coastguard Worker
300*a67afe4dSAndroid Build Coastguard Worker PNG_STRING_FROM_CHUNK(msg, owner);
301*a67afe4dSAndroid Build Coastguard Worker msg[4] = ':';
302*a67afe4dSAndroid Build Coastguard Worker msg[5] = ' ';
303*a67afe4dSAndroid Build Coastguard Worker PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner);
304*a67afe4dSAndroid Build Coastguard Worker /* So the message that results is "<chunk> using zstream"; this is an
305*a67afe4dSAndroid Build Coastguard Worker * internal error, but is very useful for debugging. i18n requirements
306*a67afe4dSAndroid Build Coastguard Worker * are minimal.
307*a67afe4dSAndroid Build Coastguard Worker */
308*a67afe4dSAndroid Build Coastguard Worker (void)png_safecat(msg, (sizeof msg), 10, " using zstream");
309*a67afe4dSAndroid Build Coastguard Worker #endif
310*a67afe4dSAndroid Build Coastguard Worker #if PNG_RELEASE_BUILD
311*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, msg);
312*a67afe4dSAndroid Build Coastguard Worker
313*a67afe4dSAndroid Build Coastguard Worker /* Attempt sane error recovery */
314*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */
315*a67afe4dSAndroid Build Coastguard Worker {
316*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT");
317*a67afe4dSAndroid Build Coastguard Worker return Z_STREAM_ERROR;
318*a67afe4dSAndroid Build Coastguard Worker }
319*a67afe4dSAndroid Build Coastguard Worker
320*a67afe4dSAndroid Build Coastguard Worker png_ptr->zowner = 0;
321*a67afe4dSAndroid Build Coastguard Worker #else
322*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, msg);
323*a67afe4dSAndroid Build Coastguard Worker #endif
324*a67afe4dSAndroid Build Coastguard Worker }
325*a67afe4dSAndroid Build Coastguard Worker
326*a67afe4dSAndroid Build Coastguard Worker {
327*a67afe4dSAndroid Build Coastguard Worker int level = png_ptr->zlib_level;
328*a67afe4dSAndroid Build Coastguard Worker int method = png_ptr->zlib_method;
329*a67afe4dSAndroid Build Coastguard Worker int windowBits = png_ptr->zlib_window_bits;
330*a67afe4dSAndroid Build Coastguard Worker int memLevel = png_ptr->zlib_mem_level;
331*a67afe4dSAndroid Build Coastguard Worker int strategy; /* set below */
332*a67afe4dSAndroid Build Coastguard Worker int ret; /* zlib return code */
333*a67afe4dSAndroid Build Coastguard Worker
334*a67afe4dSAndroid Build Coastguard Worker if (owner == png_IDAT)
335*a67afe4dSAndroid Build Coastguard Worker {
336*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0)
337*a67afe4dSAndroid Build Coastguard Worker strategy = png_ptr->zlib_strategy;
338*a67afe4dSAndroid Build Coastguard Worker
339*a67afe4dSAndroid Build Coastguard Worker else if (png_ptr->do_filter != PNG_FILTER_NONE)
340*a67afe4dSAndroid Build Coastguard Worker strategy = PNG_Z_DEFAULT_STRATEGY;
341*a67afe4dSAndroid Build Coastguard Worker
342*a67afe4dSAndroid Build Coastguard Worker else
343*a67afe4dSAndroid Build Coastguard Worker strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY;
344*a67afe4dSAndroid Build Coastguard Worker }
345*a67afe4dSAndroid Build Coastguard Worker
346*a67afe4dSAndroid Build Coastguard Worker else
347*a67afe4dSAndroid Build Coastguard Worker {
348*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
349*a67afe4dSAndroid Build Coastguard Worker level = png_ptr->zlib_text_level;
350*a67afe4dSAndroid Build Coastguard Worker method = png_ptr->zlib_text_method;
351*a67afe4dSAndroid Build Coastguard Worker windowBits = png_ptr->zlib_text_window_bits;
352*a67afe4dSAndroid Build Coastguard Worker memLevel = png_ptr->zlib_text_mem_level;
353*a67afe4dSAndroid Build Coastguard Worker strategy = png_ptr->zlib_text_strategy;
354*a67afe4dSAndroid Build Coastguard Worker #else
355*a67afe4dSAndroid Build Coastguard Worker /* If customization is not supported the values all come from the
356*a67afe4dSAndroid Build Coastguard Worker * IDAT values except for the strategy, which is fixed to the
357*a67afe4dSAndroid Build Coastguard Worker * default. (This is the pre-1.6.0 behavior too, although it was
358*a67afe4dSAndroid Build Coastguard Worker * implemented in a very different way.)
359*a67afe4dSAndroid Build Coastguard Worker */
360*a67afe4dSAndroid Build Coastguard Worker strategy = Z_DEFAULT_STRATEGY;
361*a67afe4dSAndroid Build Coastguard Worker #endif
362*a67afe4dSAndroid Build Coastguard Worker }
363*a67afe4dSAndroid Build Coastguard Worker
364*a67afe4dSAndroid Build Coastguard Worker /* Adjust 'windowBits' down if larger than 'data_size'; to stop this
365*a67afe4dSAndroid Build Coastguard Worker * happening just pass 32768 as the data_size parameter. Notice that zlib
366*a67afe4dSAndroid Build Coastguard Worker * requires an extra 262 bytes in the window in addition to the data to be
367*a67afe4dSAndroid Build Coastguard Worker * able to see the whole of the data, so if data_size+262 takes us to the
368*a67afe4dSAndroid Build Coastguard Worker * next windowBits size we need to fix up the value later. (Because even
369*a67afe4dSAndroid Build Coastguard Worker * though deflate needs the extra window, inflate does not!)
370*a67afe4dSAndroid Build Coastguard Worker */
371*a67afe4dSAndroid Build Coastguard Worker if (data_size <= 16384)
372*a67afe4dSAndroid Build Coastguard Worker {
373*a67afe4dSAndroid Build Coastguard Worker /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to
374*a67afe4dSAndroid Build Coastguard Worker * work round a Microsoft Visual C misbehavior which, contrary to C-90,
375*a67afe4dSAndroid Build Coastguard Worker * widens the result of the following shift to 64-bits if (and,
376*a67afe4dSAndroid Build Coastguard Worker * apparently, only if) it is used in a test.
377*a67afe4dSAndroid Build Coastguard Worker */
378*a67afe4dSAndroid Build Coastguard Worker unsigned int half_window_size = 1U << (windowBits-1);
379*a67afe4dSAndroid Build Coastguard Worker
380*a67afe4dSAndroid Build Coastguard Worker while (data_size + 262 <= half_window_size)
381*a67afe4dSAndroid Build Coastguard Worker {
382*a67afe4dSAndroid Build Coastguard Worker half_window_size >>= 1;
383*a67afe4dSAndroid Build Coastguard Worker --windowBits;
384*a67afe4dSAndroid Build Coastguard Worker }
385*a67afe4dSAndroid Build Coastguard Worker }
386*a67afe4dSAndroid Build Coastguard Worker
387*a67afe4dSAndroid Build Coastguard Worker /* Check against the previous initialized values, if any. */
388*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 &&
389*a67afe4dSAndroid Build Coastguard Worker (png_ptr->zlib_set_level != level ||
390*a67afe4dSAndroid Build Coastguard Worker png_ptr->zlib_set_method != method ||
391*a67afe4dSAndroid Build Coastguard Worker png_ptr->zlib_set_window_bits != windowBits ||
392*a67afe4dSAndroid Build Coastguard Worker png_ptr->zlib_set_mem_level != memLevel ||
393*a67afe4dSAndroid Build Coastguard Worker png_ptr->zlib_set_strategy != strategy))
394*a67afe4dSAndroid Build Coastguard Worker {
395*a67afe4dSAndroid Build Coastguard Worker if (deflateEnd(&png_ptr->zstream) != Z_OK)
396*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "deflateEnd failed (ignored)");
397*a67afe4dSAndroid Build Coastguard Worker
398*a67afe4dSAndroid Build Coastguard Worker png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED;
399*a67afe4dSAndroid Build Coastguard Worker }
400*a67afe4dSAndroid Build Coastguard Worker
401*a67afe4dSAndroid Build Coastguard Worker /* For safety clear out the input and output pointers (currently zlib
402*a67afe4dSAndroid Build Coastguard Worker * doesn't use them on Init, but it might in the future).
403*a67afe4dSAndroid Build Coastguard Worker */
404*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_in = NULL;
405*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_in = 0;
406*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_out = NULL;
407*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_out = 0;
408*a67afe4dSAndroid Build Coastguard Worker
409*a67afe4dSAndroid Build Coastguard Worker /* Now initialize if required, setting the new parameters, otherwise just
410*a67afe4dSAndroid Build Coastguard Worker * do a simple reset to the previous parameters.
411*a67afe4dSAndroid Build Coastguard Worker */
412*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
413*a67afe4dSAndroid Build Coastguard Worker ret = deflateReset(&png_ptr->zstream);
414*a67afe4dSAndroid Build Coastguard Worker
415*a67afe4dSAndroid Build Coastguard Worker else
416*a67afe4dSAndroid Build Coastguard Worker {
417*a67afe4dSAndroid Build Coastguard Worker ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
418*a67afe4dSAndroid Build Coastguard Worker memLevel, strategy);
419*a67afe4dSAndroid Build Coastguard Worker
420*a67afe4dSAndroid Build Coastguard Worker if (ret == Z_OK)
421*a67afe4dSAndroid Build Coastguard Worker png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
422*a67afe4dSAndroid Build Coastguard Worker }
423*a67afe4dSAndroid Build Coastguard Worker
424*a67afe4dSAndroid Build Coastguard Worker /* The return code is from either deflateReset or deflateInit2; they have
425*a67afe4dSAndroid Build Coastguard Worker * pretty much the same set of error codes.
426*a67afe4dSAndroid Build Coastguard Worker */
427*a67afe4dSAndroid Build Coastguard Worker if (ret == Z_OK)
428*a67afe4dSAndroid Build Coastguard Worker png_ptr->zowner = owner;
429*a67afe4dSAndroid Build Coastguard Worker
430*a67afe4dSAndroid Build Coastguard Worker else
431*a67afe4dSAndroid Build Coastguard Worker png_zstream_error(png_ptr, ret);
432*a67afe4dSAndroid Build Coastguard Worker
433*a67afe4dSAndroid Build Coastguard Worker return ret;
434*a67afe4dSAndroid Build Coastguard Worker }
435*a67afe4dSAndroid Build Coastguard Worker }
436*a67afe4dSAndroid Build Coastguard Worker
437*a67afe4dSAndroid Build Coastguard Worker /* Clean up (or trim) a linked list of compression buffers. */
438*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_free_buffer_list(png_structrp png_ptr,png_compression_bufferp * listp)439*a67afe4dSAndroid Build Coastguard Worker png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)
440*a67afe4dSAndroid Build Coastguard Worker {
441*a67afe4dSAndroid Build Coastguard Worker png_compression_bufferp list = *listp;
442*a67afe4dSAndroid Build Coastguard Worker
443*a67afe4dSAndroid Build Coastguard Worker if (list != NULL)
444*a67afe4dSAndroid Build Coastguard Worker {
445*a67afe4dSAndroid Build Coastguard Worker *listp = NULL;
446*a67afe4dSAndroid Build Coastguard Worker
447*a67afe4dSAndroid Build Coastguard Worker do
448*a67afe4dSAndroid Build Coastguard Worker {
449*a67afe4dSAndroid Build Coastguard Worker png_compression_bufferp next = list->next;
450*a67afe4dSAndroid Build Coastguard Worker
451*a67afe4dSAndroid Build Coastguard Worker png_free(png_ptr, list);
452*a67afe4dSAndroid Build Coastguard Worker list = next;
453*a67afe4dSAndroid Build Coastguard Worker }
454*a67afe4dSAndroid Build Coastguard Worker while (list != NULL);
455*a67afe4dSAndroid Build Coastguard Worker }
456*a67afe4dSAndroid Build Coastguard Worker }
457*a67afe4dSAndroid Build Coastguard Worker
458*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
459*a67afe4dSAndroid Build Coastguard Worker /* This pair of functions encapsulates the operation of (a) compressing a
460*a67afe4dSAndroid Build Coastguard Worker * text string, and (b) issuing it later as a series of chunk data writes.
461*a67afe4dSAndroid Build Coastguard Worker * The compression_state structure is shared context for these functions
462*a67afe4dSAndroid Build Coastguard Worker * set up by the caller to allow access to the relevant local variables.
463*a67afe4dSAndroid Build Coastguard Worker *
464*a67afe4dSAndroid Build Coastguard Worker * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size
465*a67afe4dSAndroid Build Coastguard Worker * temporary buffers. From 1.6.0 it is retained in png_struct so that it will
466*a67afe4dSAndroid Build Coastguard Worker * be correctly freed in the event of a write error (previous implementations
467*a67afe4dSAndroid Build Coastguard Worker * just leaked memory.)
468*a67afe4dSAndroid Build Coastguard Worker */
469*a67afe4dSAndroid Build Coastguard Worker typedef struct
470*a67afe4dSAndroid Build Coastguard Worker {
471*a67afe4dSAndroid Build Coastguard Worker png_const_bytep input; /* The uncompressed input data */
472*a67afe4dSAndroid Build Coastguard Worker png_alloc_size_t input_len; /* Its length */
473*a67afe4dSAndroid Build Coastguard Worker png_uint_32 output_len; /* Final compressed length */
474*a67afe4dSAndroid Build Coastguard Worker png_byte output[1024]; /* First block of output */
475*a67afe4dSAndroid Build Coastguard Worker } compression_state;
476*a67afe4dSAndroid Build Coastguard Worker
477*a67afe4dSAndroid Build Coastguard Worker static void
png_text_compress_init(compression_state * comp,png_const_bytep input,png_alloc_size_t input_len)478*a67afe4dSAndroid Build Coastguard Worker png_text_compress_init(compression_state *comp, png_const_bytep input,
479*a67afe4dSAndroid Build Coastguard Worker png_alloc_size_t input_len)
480*a67afe4dSAndroid Build Coastguard Worker {
481*a67afe4dSAndroid Build Coastguard Worker comp->input = input;
482*a67afe4dSAndroid Build Coastguard Worker comp->input_len = input_len;
483*a67afe4dSAndroid Build Coastguard Worker comp->output_len = 0;
484*a67afe4dSAndroid Build Coastguard Worker }
485*a67afe4dSAndroid Build Coastguard Worker
486*a67afe4dSAndroid Build Coastguard Worker /* Compress the data in the compression state input */
487*a67afe4dSAndroid Build Coastguard Worker static int
png_text_compress(png_structrp png_ptr,png_uint_32 chunk_name,compression_state * comp,png_uint_32 prefix_len)488*a67afe4dSAndroid Build Coastguard Worker png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
489*a67afe4dSAndroid Build Coastguard Worker compression_state *comp, png_uint_32 prefix_len)
490*a67afe4dSAndroid Build Coastguard Worker {
491*a67afe4dSAndroid Build Coastguard Worker int ret;
492*a67afe4dSAndroid Build Coastguard Worker
493*a67afe4dSAndroid Build Coastguard Worker /* To find the length of the output it is necessary to first compress the
494*a67afe4dSAndroid Build Coastguard Worker * input. The result is buffered rather than using the two-pass algorithm
495*a67afe4dSAndroid Build Coastguard Worker * that is used on the inflate side; deflate is assumed to be slower and a
496*a67afe4dSAndroid Build Coastguard Worker * PNG writer is assumed to have more memory available than a PNG reader.
497*a67afe4dSAndroid Build Coastguard Worker *
498*a67afe4dSAndroid Build Coastguard Worker * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an
499*a67afe4dSAndroid Build Coastguard Worker * upper limit on the output size, but it is always bigger than the input
500*a67afe4dSAndroid Build Coastguard Worker * size so it is likely to be more efficient to use this linked-list
501*a67afe4dSAndroid Build Coastguard Worker * approach.
502*a67afe4dSAndroid Build Coastguard Worker */
503*a67afe4dSAndroid Build Coastguard Worker ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len);
504*a67afe4dSAndroid Build Coastguard Worker
505*a67afe4dSAndroid Build Coastguard Worker if (ret != Z_OK)
506*a67afe4dSAndroid Build Coastguard Worker return ret;
507*a67afe4dSAndroid Build Coastguard Worker
508*a67afe4dSAndroid Build Coastguard Worker /* Set up the compression buffers, we need a loop here to avoid overflowing a
509*a67afe4dSAndroid Build Coastguard Worker * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited
510*a67afe4dSAndroid Build Coastguard Worker * by the output buffer size, so there is no need to check that. Since this
511*a67afe4dSAndroid Build Coastguard Worker * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits
512*a67afe4dSAndroid Build Coastguard Worker * in size.
513*a67afe4dSAndroid Build Coastguard Worker */
514*a67afe4dSAndroid Build Coastguard Worker {
515*a67afe4dSAndroid Build Coastguard Worker png_compression_bufferp *end = &png_ptr->zbuffer_list;
516*a67afe4dSAndroid Build Coastguard Worker png_alloc_size_t input_len = comp->input_len; /* may be zero! */
517*a67afe4dSAndroid Build Coastguard Worker png_uint_32 output_len;
518*a67afe4dSAndroid Build Coastguard Worker
519*a67afe4dSAndroid Build Coastguard Worker /* zlib updates these for us: */
520*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input);
521*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_in = 0; /* Set below */
522*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_out = comp->output;
523*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_out = (sizeof comp->output);
524*a67afe4dSAndroid Build Coastguard Worker
525*a67afe4dSAndroid Build Coastguard Worker output_len = png_ptr->zstream.avail_out;
526*a67afe4dSAndroid Build Coastguard Worker
527*a67afe4dSAndroid Build Coastguard Worker do
528*a67afe4dSAndroid Build Coastguard Worker {
529*a67afe4dSAndroid Build Coastguard Worker uInt avail_in = ZLIB_IO_MAX;
530*a67afe4dSAndroid Build Coastguard Worker
531*a67afe4dSAndroid Build Coastguard Worker if (avail_in > input_len)
532*a67afe4dSAndroid Build Coastguard Worker avail_in = (uInt)input_len;
533*a67afe4dSAndroid Build Coastguard Worker
534*a67afe4dSAndroid Build Coastguard Worker input_len -= avail_in;
535*a67afe4dSAndroid Build Coastguard Worker
536*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_in = avail_in;
537*a67afe4dSAndroid Build Coastguard Worker
538*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->zstream.avail_out == 0)
539*a67afe4dSAndroid Build Coastguard Worker {
540*a67afe4dSAndroid Build Coastguard Worker png_compression_buffer *next;
541*a67afe4dSAndroid Build Coastguard Worker
542*a67afe4dSAndroid Build Coastguard Worker /* Chunk data is limited to 2^31 bytes in length, so the prefix
543*a67afe4dSAndroid Build Coastguard Worker * length must be counted here.
544*a67afe4dSAndroid Build Coastguard Worker */
545*a67afe4dSAndroid Build Coastguard Worker if (output_len + prefix_len > PNG_UINT_31_MAX)
546*a67afe4dSAndroid Build Coastguard Worker {
547*a67afe4dSAndroid Build Coastguard Worker ret = Z_MEM_ERROR;
548*a67afe4dSAndroid Build Coastguard Worker break;
549*a67afe4dSAndroid Build Coastguard Worker }
550*a67afe4dSAndroid Build Coastguard Worker
551*a67afe4dSAndroid Build Coastguard Worker /* Need a new (malloc'ed) buffer, but there may be one present
552*a67afe4dSAndroid Build Coastguard Worker * already.
553*a67afe4dSAndroid Build Coastguard Worker */
554*a67afe4dSAndroid Build Coastguard Worker next = *end;
555*a67afe4dSAndroid Build Coastguard Worker if (next == NULL)
556*a67afe4dSAndroid Build Coastguard Worker {
557*a67afe4dSAndroid Build Coastguard Worker next = png_voidcast(png_compression_bufferp, png_malloc_base
558*a67afe4dSAndroid Build Coastguard Worker (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
559*a67afe4dSAndroid Build Coastguard Worker
560*a67afe4dSAndroid Build Coastguard Worker if (next == NULL)
561*a67afe4dSAndroid Build Coastguard Worker {
562*a67afe4dSAndroid Build Coastguard Worker ret = Z_MEM_ERROR;
563*a67afe4dSAndroid Build Coastguard Worker break;
564*a67afe4dSAndroid Build Coastguard Worker }
565*a67afe4dSAndroid Build Coastguard Worker
566*a67afe4dSAndroid Build Coastguard Worker /* Link in this buffer (so that it will be freed later) */
567*a67afe4dSAndroid Build Coastguard Worker next->next = NULL;
568*a67afe4dSAndroid Build Coastguard Worker *end = next;
569*a67afe4dSAndroid Build Coastguard Worker }
570*a67afe4dSAndroid Build Coastguard Worker
571*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_out = next->output;
572*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_out = png_ptr->zbuffer_size;
573*a67afe4dSAndroid Build Coastguard Worker output_len += png_ptr->zstream.avail_out;
574*a67afe4dSAndroid Build Coastguard Worker
575*a67afe4dSAndroid Build Coastguard Worker /* Move 'end' to the next buffer pointer. */
576*a67afe4dSAndroid Build Coastguard Worker end = &next->next;
577*a67afe4dSAndroid Build Coastguard Worker }
578*a67afe4dSAndroid Build Coastguard Worker
579*a67afe4dSAndroid Build Coastguard Worker /* Compress the data */
580*a67afe4dSAndroid Build Coastguard Worker ret = deflate(&png_ptr->zstream,
581*a67afe4dSAndroid Build Coastguard Worker input_len > 0 ? Z_NO_FLUSH : Z_FINISH);
582*a67afe4dSAndroid Build Coastguard Worker
583*a67afe4dSAndroid Build Coastguard Worker /* Claw back input data that was not consumed (because avail_in is
584*a67afe4dSAndroid Build Coastguard Worker * reset above every time round the loop).
585*a67afe4dSAndroid Build Coastguard Worker */
586*a67afe4dSAndroid Build Coastguard Worker input_len += png_ptr->zstream.avail_in;
587*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_in = 0; /* safety */
588*a67afe4dSAndroid Build Coastguard Worker }
589*a67afe4dSAndroid Build Coastguard Worker while (ret == Z_OK);
590*a67afe4dSAndroid Build Coastguard Worker
591*a67afe4dSAndroid Build Coastguard Worker /* There may be some space left in the last output buffer. This needs to
592*a67afe4dSAndroid Build Coastguard Worker * be subtracted from output_len.
593*a67afe4dSAndroid Build Coastguard Worker */
594*a67afe4dSAndroid Build Coastguard Worker output_len -= png_ptr->zstream.avail_out;
595*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_out = 0; /* safety */
596*a67afe4dSAndroid Build Coastguard Worker comp->output_len = output_len;
597*a67afe4dSAndroid Build Coastguard Worker
598*a67afe4dSAndroid Build Coastguard Worker /* Now double check the output length, put in a custom message if it is
599*a67afe4dSAndroid Build Coastguard Worker * too long. Otherwise ensure the z_stream::msg pointer is set to
600*a67afe4dSAndroid Build Coastguard Worker * something.
601*a67afe4dSAndroid Build Coastguard Worker */
602*a67afe4dSAndroid Build Coastguard Worker if (output_len + prefix_len >= PNG_UINT_31_MAX)
603*a67afe4dSAndroid Build Coastguard Worker {
604*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long");
605*a67afe4dSAndroid Build Coastguard Worker ret = Z_MEM_ERROR;
606*a67afe4dSAndroid Build Coastguard Worker }
607*a67afe4dSAndroid Build Coastguard Worker
608*a67afe4dSAndroid Build Coastguard Worker else
609*a67afe4dSAndroid Build Coastguard Worker png_zstream_error(png_ptr, ret);
610*a67afe4dSAndroid Build Coastguard Worker
611*a67afe4dSAndroid Build Coastguard Worker /* Reset zlib for another zTXt/iTXt or image data */
612*a67afe4dSAndroid Build Coastguard Worker png_ptr->zowner = 0;
613*a67afe4dSAndroid Build Coastguard Worker
614*a67afe4dSAndroid Build Coastguard Worker /* The only success case is Z_STREAM_END, input_len must be 0; if not this
615*a67afe4dSAndroid Build Coastguard Worker * is an internal error.
616*a67afe4dSAndroid Build Coastguard Worker */
617*a67afe4dSAndroid Build Coastguard Worker if (ret == Z_STREAM_END && input_len == 0)
618*a67afe4dSAndroid Build Coastguard Worker {
619*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
620*a67afe4dSAndroid Build Coastguard Worker /* Fix up the deflate header, if required */
621*a67afe4dSAndroid Build Coastguard Worker optimize_cmf(comp->output, comp->input_len);
622*a67afe4dSAndroid Build Coastguard Worker #endif
623*a67afe4dSAndroid Build Coastguard Worker /* But Z_OK is returned, not Z_STREAM_END; this allows the claim
624*a67afe4dSAndroid Build Coastguard Worker * function above to return Z_STREAM_END on an error (though it never
625*a67afe4dSAndroid Build Coastguard Worker * does in the current versions of zlib.)
626*a67afe4dSAndroid Build Coastguard Worker */
627*a67afe4dSAndroid Build Coastguard Worker return Z_OK;
628*a67afe4dSAndroid Build Coastguard Worker }
629*a67afe4dSAndroid Build Coastguard Worker
630*a67afe4dSAndroid Build Coastguard Worker else
631*a67afe4dSAndroid Build Coastguard Worker return ret;
632*a67afe4dSAndroid Build Coastguard Worker }
633*a67afe4dSAndroid Build Coastguard Worker }
634*a67afe4dSAndroid Build Coastguard Worker
635*a67afe4dSAndroid Build Coastguard Worker /* Ship the compressed text out via chunk writes */
636*a67afe4dSAndroid Build Coastguard Worker static void
png_write_compressed_data_out(png_structrp png_ptr,compression_state * comp)637*a67afe4dSAndroid Build Coastguard Worker png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)
638*a67afe4dSAndroid Build Coastguard Worker {
639*a67afe4dSAndroid Build Coastguard Worker png_uint_32 output_len = comp->output_len;
640*a67afe4dSAndroid Build Coastguard Worker png_const_bytep output = comp->output;
641*a67afe4dSAndroid Build Coastguard Worker png_uint_32 avail = (sizeof comp->output);
642*a67afe4dSAndroid Build Coastguard Worker png_compression_buffer *next = png_ptr->zbuffer_list;
643*a67afe4dSAndroid Build Coastguard Worker
644*a67afe4dSAndroid Build Coastguard Worker for (;;)
645*a67afe4dSAndroid Build Coastguard Worker {
646*a67afe4dSAndroid Build Coastguard Worker if (avail > output_len)
647*a67afe4dSAndroid Build Coastguard Worker avail = output_len;
648*a67afe4dSAndroid Build Coastguard Worker
649*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, output, avail);
650*a67afe4dSAndroid Build Coastguard Worker
651*a67afe4dSAndroid Build Coastguard Worker output_len -= avail;
652*a67afe4dSAndroid Build Coastguard Worker
653*a67afe4dSAndroid Build Coastguard Worker if (output_len == 0 || next == NULL)
654*a67afe4dSAndroid Build Coastguard Worker break;
655*a67afe4dSAndroid Build Coastguard Worker
656*a67afe4dSAndroid Build Coastguard Worker avail = png_ptr->zbuffer_size;
657*a67afe4dSAndroid Build Coastguard Worker output = next->output;
658*a67afe4dSAndroid Build Coastguard Worker next = next->next;
659*a67afe4dSAndroid Build Coastguard Worker }
660*a67afe4dSAndroid Build Coastguard Worker
661*a67afe4dSAndroid Build Coastguard Worker /* This is an internal error; 'next' must have been NULL! */
662*a67afe4dSAndroid Build Coastguard Worker if (output_len > 0)
663*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "error writing ancillary chunked compressed data");
664*a67afe4dSAndroid Build Coastguard Worker }
665*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE_COMPRESSED_TEXT */
666*a67afe4dSAndroid Build Coastguard Worker
667*a67afe4dSAndroid Build Coastguard Worker /* Write the IHDR chunk, and update the png_struct with the necessary
668*a67afe4dSAndroid Build Coastguard Worker * information. Note that the rest of this code depends upon this
669*a67afe4dSAndroid Build Coastguard Worker * information being correct.
670*a67afe4dSAndroid Build Coastguard Worker */
671*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_IHDR(png_structrp png_ptr,png_uint_32 width,png_uint_32 height,int bit_depth,int color_type,int compression_type,int filter_type,int interlace_type)672*a67afe4dSAndroid Build Coastguard Worker png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
673*a67afe4dSAndroid Build Coastguard Worker int bit_depth, int color_type, int compression_type, int filter_type,
674*a67afe4dSAndroid Build Coastguard Worker int interlace_type)
675*a67afe4dSAndroid Build Coastguard Worker {
676*a67afe4dSAndroid Build Coastguard Worker png_byte buf[13]; /* Buffer to store the IHDR info */
677*a67afe4dSAndroid Build Coastguard Worker int is_invalid_depth;
678*a67afe4dSAndroid Build Coastguard Worker
679*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_IHDR");
680*a67afe4dSAndroid Build Coastguard Worker
681*a67afe4dSAndroid Build Coastguard Worker /* Check that we have valid input data from the application info */
682*a67afe4dSAndroid Build Coastguard Worker switch (color_type)
683*a67afe4dSAndroid Build Coastguard Worker {
684*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_GRAY:
685*a67afe4dSAndroid Build Coastguard Worker switch (bit_depth)
686*a67afe4dSAndroid Build Coastguard Worker {
687*a67afe4dSAndroid Build Coastguard Worker case 1:
688*a67afe4dSAndroid Build Coastguard Worker case 2:
689*a67afe4dSAndroid Build Coastguard Worker case 4:
690*a67afe4dSAndroid Build Coastguard Worker case 8:
691*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_16BIT_SUPPORTED
692*a67afe4dSAndroid Build Coastguard Worker case 16:
693*a67afe4dSAndroid Build Coastguard Worker #endif
694*a67afe4dSAndroid Build Coastguard Worker png_ptr->channels = 1; break;
695*a67afe4dSAndroid Build Coastguard Worker
696*a67afe4dSAndroid Build Coastguard Worker default:
697*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr,
698*a67afe4dSAndroid Build Coastguard Worker "Invalid bit depth for grayscale image");
699*a67afe4dSAndroid Build Coastguard Worker }
700*a67afe4dSAndroid Build Coastguard Worker break;
701*a67afe4dSAndroid Build Coastguard Worker
702*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_RGB:
703*a67afe4dSAndroid Build Coastguard Worker is_invalid_depth = (bit_depth != 8);
704*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_16BIT_SUPPORTED
705*a67afe4dSAndroid Build Coastguard Worker is_invalid_depth = (is_invalid_depth && bit_depth != 16);
706*a67afe4dSAndroid Build Coastguard Worker #endif
707*a67afe4dSAndroid Build Coastguard Worker if (is_invalid_depth)
708*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Invalid bit depth for RGB image");
709*a67afe4dSAndroid Build Coastguard Worker
710*a67afe4dSAndroid Build Coastguard Worker png_ptr->channels = 3;
711*a67afe4dSAndroid Build Coastguard Worker break;
712*a67afe4dSAndroid Build Coastguard Worker
713*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_PALETTE:
714*a67afe4dSAndroid Build Coastguard Worker switch (bit_depth)
715*a67afe4dSAndroid Build Coastguard Worker {
716*a67afe4dSAndroid Build Coastguard Worker case 1:
717*a67afe4dSAndroid Build Coastguard Worker case 2:
718*a67afe4dSAndroid Build Coastguard Worker case 4:
719*a67afe4dSAndroid Build Coastguard Worker case 8:
720*a67afe4dSAndroid Build Coastguard Worker png_ptr->channels = 1;
721*a67afe4dSAndroid Build Coastguard Worker break;
722*a67afe4dSAndroid Build Coastguard Worker
723*a67afe4dSAndroid Build Coastguard Worker default:
724*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Invalid bit depth for paletted image");
725*a67afe4dSAndroid Build Coastguard Worker }
726*a67afe4dSAndroid Build Coastguard Worker break;
727*a67afe4dSAndroid Build Coastguard Worker
728*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_GRAY_ALPHA:
729*a67afe4dSAndroid Build Coastguard Worker is_invalid_depth = (bit_depth != 8);
730*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_16BIT_SUPPORTED
731*a67afe4dSAndroid Build Coastguard Worker is_invalid_depth = (is_invalid_depth && bit_depth != 16);
732*a67afe4dSAndroid Build Coastguard Worker #endif
733*a67afe4dSAndroid Build Coastguard Worker if (is_invalid_depth)
734*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
735*a67afe4dSAndroid Build Coastguard Worker
736*a67afe4dSAndroid Build Coastguard Worker png_ptr->channels = 2;
737*a67afe4dSAndroid Build Coastguard Worker break;
738*a67afe4dSAndroid Build Coastguard Worker
739*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_RGB_ALPHA:
740*a67afe4dSAndroid Build Coastguard Worker is_invalid_depth = (bit_depth != 8);
741*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_16BIT_SUPPORTED
742*a67afe4dSAndroid Build Coastguard Worker is_invalid_depth = (is_invalid_depth && bit_depth != 16);
743*a67afe4dSAndroid Build Coastguard Worker #endif
744*a67afe4dSAndroid Build Coastguard Worker if (is_invalid_depth)
745*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Invalid bit depth for RGBA image");
746*a67afe4dSAndroid Build Coastguard Worker
747*a67afe4dSAndroid Build Coastguard Worker png_ptr->channels = 4;
748*a67afe4dSAndroid Build Coastguard Worker break;
749*a67afe4dSAndroid Build Coastguard Worker
750*a67afe4dSAndroid Build Coastguard Worker default:
751*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Invalid image color type specified");
752*a67afe4dSAndroid Build Coastguard Worker }
753*a67afe4dSAndroid Build Coastguard Worker
754*a67afe4dSAndroid Build Coastguard Worker if (compression_type != PNG_COMPRESSION_TYPE_BASE)
755*a67afe4dSAndroid Build Coastguard Worker {
756*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid compression type specified");
757*a67afe4dSAndroid Build Coastguard Worker compression_type = PNG_COMPRESSION_TYPE_BASE;
758*a67afe4dSAndroid Build Coastguard Worker }
759*a67afe4dSAndroid Build Coastguard Worker
760*a67afe4dSAndroid Build Coastguard Worker /* Write filter_method 64 (intrapixel differencing) only if
761*a67afe4dSAndroid Build Coastguard Worker * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
762*a67afe4dSAndroid Build Coastguard Worker * 2. Libpng did not write a PNG signature (this filter_method is only
763*a67afe4dSAndroid Build Coastguard Worker * used in PNG datastreams that are embedded in MNG datastreams) and
764*a67afe4dSAndroid Build Coastguard Worker * 3. The application called png_permit_mng_features with a mask that
765*a67afe4dSAndroid Build Coastguard Worker * included PNG_FLAG_MNG_FILTER_64 and
766*a67afe4dSAndroid Build Coastguard Worker * 4. The filter_method is 64 and
767*a67afe4dSAndroid Build Coastguard Worker * 5. The color_type is RGB or RGBA
768*a67afe4dSAndroid Build Coastguard Worker */
769*a67afe4dSAndroid Build Coastguard Worker if (
770*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_MNG_FEATURES_SUPPORTED
771*a67afe4dSAndroid Build Coastguard Worker !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
772*a67afe4dSAndroid Build Coastguard Worker ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
773*a67afe4dSAndroid Build Coastguard Worker (color_type == PNG_COLOR_TYPE_RGB ||
774*a67afe4dSAndroid Build Coastguard Worker color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
775*a67afe4dSAndroid Build Coastguard Worker (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
776*a67afe4dSAndroid Build Coastguard Worker #endif
777*a67afe4dSAndroid Build Coastguard Worker filter_type != PNG_FILTER_TYPE_BASE)
778*a67afe4dSAndroid Build Coastguard Worker {
779*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid filter type specified");
780*a67afe4dSAndroid Build Coastguard Worker filter_type = PNG_FILTER_TYPE_BASE;
781*a67afe4dSAndroid Build Coastguard Worker }
782*a67afe4dSAndroid Build Coastguard Worker
783*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_INTERLACING_SUPPORTED
784*a67afe4dSAndroid Build Coastguard Worker if (interlace_type != PNG_INTERLACE_NONE &&
785*a67afe4dSAndroid Build Coastguard Worker interlace_type != PNG_INTERLACE_ADAM7)
786*a67afe4dSAndroid Build Coastguard Worker {
787*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid interlace type specified");
788*a67afe4dSAndroid Build Coastguard Worker interlace_type = PNG_INTERLACE_ADAM7;
789*a67afe4dSAndroid Build Coastguard Worker }
790*a67afe4dSAndroid Build Coastguard Worker #else
791*a67afe4dSAndroid Build Coastguard Worker interlace_type=PNG_INTERLACE_NONE;
792*a67afe4dSAndroid Build Coastguard Worker #endif
793*a67afe4dSAndroid Build Coastguard Worker
794*a67afe4dSAndroid Build Coastguard Worker /* Save the relevant information */
795*a67afe4dSAndroid Build Coastguard Worker png_ptr->bit_depth = (png_byte)bit_depth;
796*a67afe4dSAndroid Build Coastguard Worker png_ptr->color_type = (png_byte)color_type;
797*a67afe4dSAndroid Build Coastguard Worker png_ptr->interlaced = (png_byte)interlace_type;
798*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_MNG_FEATURES_SUPPORTED
799*a67afe4dSAndroid Build Coastguard Worker png_ptr->filter_type = (png_byte)filter_type;
800*a67afe4dSAndroid Build Coastguard Worker #endif
801*a67afe4dSAndroid Build Coastguard Worker png_ptr->compression_type = (png_byte)compression_type;
802*a67afe4dSAndroid Build Coastguard Worker png_ptr->width = width;
803*a67afe4dSAndroid Build Coastguard Worker png_ptr->height = height;
804*a67afe4dSAndroid Build Coastguard Worker
805*a67afe4dSAndroid Build Coastguard Worker png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
806*a67afe4dSAndroid Build Coastguard Worker png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
807*a67afe4dSAndroid Build Coastguard Worker /* Set the usr info, so any transformations can modify it */
808*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_width = png_ptr->width;
809*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_bit_depth = png_ptr->bit_depth;
810*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_channels = png_ptr->channels;
811*a67afe4dSAndroid Build Coastguard Worker
812*a67afe4dSAndroid Build Coastguard Worker /* Pack the header information into the buffer */
813*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf, width);
814*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf + 4, height);
815*a67afe4dSAndroid Build Coastguard Worker buf[8] = (png_byte)bit_depth;
816*a67afe4dSAndroid Build Coastguard Worker buf[9] = (png_byte)color_type;
817*a67afe4dSAndroid Build Coastguard Worker buf[10] = (png_byte)compression_type;
818*a67afe4dSAndroid Build Coastguard Worker buf[11] = (png_byte)filter_type;
819*a67afe4dSAndroid Build Coastguard Worker buf[12] = (png_byte)interlace_type;
820*a67afe4dSAndroid Build Coastguard Worker
821*a67afe4dSAndroid Build Coastguard Worker /* Write the chunk */
822*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
823*a67afe4dSAndroid Build Coastguard Worker
824*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->do_filter) == PNG_NO_FILTERS)
825*a67afe4dSAndroid Build Coastguard Worker {
826*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
827*a67afe4dSAndroid Build Coastguard Worker png_ptr->bit_depth < 8)
828*a67afe4dSAndroid Build Coastguard Worker png_ptr->do_filter = PNG_FILTER_NONE;
829*a67afe4dSAndroid Build Coastguard Worker
830*a67afe4dSAndroid Build Coastguard Worker else
831*a67afe4dSAndroid Build Coastguard Worker png_ptr->do_filter = PNG_ALL_FILTERS;
832*a67afe4dSAndroid Build Coastguard Worker }
833*a67afe4dSAndroid Build Coastguard Worker
834*a67afe4dSAndroid Build Coastguard Worker png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */
835*a67afe4dSAndroid Build Coastguard Worker }
836*a67afe4dSAndroid Build Coastguard Worker
837*a67afe4dSAndroid Build Coastguard Worker /* Write the palette. We are careful not to trust png_color to be in the
838*a67afe4dSAndroid Build Coastguard Worker * correct order for PNG, so people can redefine it to any convenient
839*a67afe4dSAndroid Build Coastguard Worker * structure.
840*a67afe4dSAndroid Build Coastguard Worker */
841*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_PLTE(png_structrp png_ptr,png_const_colorp palette,png_uint_32 num_pal)842*a67afe4dSAndroid Build Coastguard Worker png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
843*a67afe4dSAndroid Build Coastguard Worker png_uint_32 num_pal)
844*a67afe4dSAndroid Build Coastguard Worker {
845*a67afe4dSAndroid Build Coastguard Worker png_uint_32 max_palette_length, i;
846*a67afe4dSAndroid Build Coastguard Worker png_const_colorp pal_ptr;
847*a67afe4dSAndroid Build Coastguard Worker png_byte buf[3];
848*a67afe4dSAndroid Build Coastguard Worker
849*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_PLTE");
850*a67afe4dSAndroid Build Coastguard Worker
851*a67afe4dSAndroid Build Coastguard Worker max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
852*a67afe4dSAndroid Build Coastguard Worker (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
853*a67afe4dSAndroid Build Coastguard Worker
854*a67afe4dSAndroid Build Coastguard Worker if ((
855*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_MNG_FEATURES_SUPPORTED
856*a67afe4dSAndroid Build Coastguard Worker (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 &&
857*a67afe4dSAndroid Build Coastguard Worker #endif
858*a67afe4dSAndroid Build Coastguard Worker num_pal == 0) || num_pal > max_palette_length)
859*a67afe4dSAndroid Build Coastguard Worker {
860*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
861*a67afe4dSAndroid Build Coastguard Worker {
862*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Invalid number of colors in palette");
863*a67afe4dSAndroid Build Coastguard Worker }
864*a67afe4dSAndroid Build Coastguard Worker
865*a67afe4dSAndroid Build Coastguard Worker else
866*a67afe4dSAndroid Build Coastguard Worker {
867*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid number of colors in palette");
868*a67afe4dSAndroid Build Coastguard Worker return;
869*a67afe4dSAndroid Build Coastguard Worker }
870*a67afe4dSAndroid Build Coastguard Worker }
871*a67afe4dSAndroid Build Coastguard Worker
872*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
873*a67afe4dSAndroid Build Coastguard Worker {
874*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr,
875*a67afe4dSAndroid Build Coastguard Worker "Ignoring request to write a PLTE chunk in grayscale PNG");
876*a67afe4dSAndroid Build Coastguard Worker
877*a67afe4dSAndroid Build Coastguard Worker return;
878*a67afe4dSAndroid Build Coastguard Worker }
879*a67afe4dSAndroid Build Coastguard Worker
880*a67afe4dSAndroid Build Coastguard Worker png_ptr->num_palette = (png_uint_16)num_pal;
881*a67afe4dSAndroid Build Coastguard Worker png_debug1(3, "num_palette = %d", png_ptr->num_palette);
882*a67afe4dSAndroid Build Coastguard Worker
883*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3));
884*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_POINTER_INDEXING_SUPPORTED
885*a67afe4dSAndroid Build Coastguard Worker
886*a67afe4dSAndroid Build Coastguard Worker for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
887*a67afe4dSAndroid Build Coastguard Worker {
888*a67afe4dSAndroid Build Coastguard Worker buf[0] = pal_ptr->red;
889*a67afe4dSAndroid Build Coastguard Worker buf[1] = pal_ptr->green;
890*a67afe4dSAndroid Build Coastguard Worker buf[2] = pal_ptr->blue;
891*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, buf, 3);
892*a67afe4dSAndroid Build Coastguard Worker }
893*a67afe4dSAndroid Build Coastguard Worker
894*a67afe4dSAndroid Build Coastguard Worker #else
895*a67afe4dSAndroid Build Coastguard Worker /* This is a little slower but some buggy compilers need to do this
896*a67afe4dSAndroid Build Coastguard Worker * instead
897*a67afe4dSAndroid Build Coastguard Worker */
898*a67afe4dSAndroid Build Coastguard Worker pal_ptr=palette;
899*a67afe4dSAndroid Build Coastguard Worker
900*a67afe4dSAndroid Build Coastguard Worker for (i = 0; i < num_pal; i++)
901*a67afe4dSAndroid Build Coastguard Worker {
902*a67afe4dSAndroid Build Coastguard Worker buf[0] = pal_ptr[i].red;
903*a67afe4dSAndroid Build Coastguard Worker buf[1] = pal_ptr[i].green;
904*a67afe4dSAndroid Build Coastguard Worker buf[2] = pal_ptr[i].blue;
905*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, buf, 3);
906*a67afe4dSAndroid Build Coastguard Worker }
907*a67afe4dSAndroid Build Coastguard Worker
908*a67afe4dSAndroid Build Coastguard Worker #endif
909*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
910*a67afe4dSAndroid Build Coastguard Worker png_ptr->mode |= PNG_HAVE_PLTE;
911*a67afe4dSAndroid Build Coastguard Worker }
912*a67afe4dSAndroid Build Coastguard Worker
913*a67afe4dSAndroid Build Coastguard Worker /* This is similar to png_text_compress, above, except that it does not require
914*a67afe4dSAndroid Build Coastguard Worker * all of the data at once and, instead of buffering the compressed result,
915*a67afe4dSAndroid Build Coastguard Worker * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out
916*a67afe4dSAndroid Build Coastguard Worker * because it calls the write interface. As a result it does its own error
917*a67afe4dSAndroid Build Coastguard Worker * reporting and does not return an error code. In the event of error it will
918*a67afe4dSAndroid Build Coastguard Worker * just call png_error. The input data length may exceed 32-bits. The 'flush'
919*a67afe4dSAndroid Build Coastguard Worker * parameter is exactly the same as that to deflate, with the following
920*a67afe4dSAndroid Build Coastguard Worker * meanings:
921*a67afe4dSAndroid Build Coastguard Worker *
922*a67afe4dSAndroid Build Coastguard Worker * Z_NO_FLUSH: normal incremental output of compressed data
923*a67afe4dSAndroid Build Coastguard Worker * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush
924*a67afe4dSAndroid Build Coastguard Worker * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up
925*a67afe4dSAndroid Build Coastguard Worker *
926*a67afe4dSAndroid Build Coastguard Worker * The routine manages the acquire and release of the png_ptr->zstream by
927*a67afe4dSAndroid Build Coastguard Worker * checking and (at the end) clearing png_ptr->zowner; it does some sanity
928*a67afe4dSAndroid Build Coastguard Worker * checks on the 'mode' flags while doing this.
929*a67afe4dSAndroid Build Coastguard Worker */
930*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_compress_IDAT(png_structrp png_ptr,png_const_bytep input,png_alloc_size_t input_len,int flush)931*a67afe4dSAndroid Build Coastguard Worker png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
932*a67afe4dSAndroid Build Coastguard Worker png_alloc_size_t input_len, int flush)
933*a67afe4dSAndroid Build Coastguard Worker {
934*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->zowner != png_IDAT)
935*a67afe4dSAndroid Build Coastguard Worker {
936*a67afe4dSAndroid Build Coastguard Worker /* First time. Ensure we have a temporary buffer for compression and
937*a67afe4dSAndroid Build Coastguard Worker * trim the buffer list if it has more than one entry to free memory.
938*a67afe4dSAndroid Build Coastguard Worker * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been
939*a67afe4dSAndroid Build Coastguard Worker * created at this point, but the check here is quick and safe.
940*a67afe4dSAndroid Build Coastguard Worker */
941*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->zbuffer_list == NULL)
942*a67afe4dSAndroid Build Coastguard Worker {
943*a67afe4dSAndroid Build Coastguard Worker png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,
944*a67afe4dSAndroid Build Coastguard Worker png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
945*a67afe4dSAndroid Build Coastguard Worker png_ptr->zbuffer_list->next = NULL;
946*a67afe4dSAndroid Build Coastguard Worker }
947*a67afe4dSAndroid Build Coastguard Worker
948*a67afe4dSAndroid Build Coastguard Worker else
949*a67afe4dSAndroid Build Coastguard Worker png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next);
950*a67afe4dSAndroid Build Coastguard Worker
951*a67afe4dSAndroid Build Coastguard Worker /* It is a terminal error if we can't claim the zstream. */
952*a67afe4dSAndroid Build Coastguard Worker if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK)
953*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, png_ptr->zstream.msg);
954*a67afe4dSAndroid Build Coastguard Worker
955*a67afe4dSAndroid Build Coastguard Worker /* The output state is maintained in png_ptr->zstream, so it must be
956*a67afe4dSAndroid Build Coastguard Worker * initialized here after the claim.
957*a67afe4dSAndroid Build Coastguard Worker */
958*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_out = png_ptr->zbuffer_list->output;
959*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_out = png_ptr->zbuffer_size;
960*a67afe4dSAndroid Build Coastguard Worker }
961*a67afe4dSAndroid Build Coastguard Worker
962*a67afe4dSAndroid Build Coastguard Worker /* Now loop reading and writing until all the input is consumed or an error
963*a67afe4dSAndroid Build Coastguard Worker * terminates the operation. The _out values are maintained across calls to
964*a67afe4dSAndroid Build Coastguard Worker * this function, but the input must be reset each time.
965*a67afe4dSAndroid Build Coastguard Worker */
966*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);
967*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_in = 0; /* set below */
968*a67afe4dSAndroid Build Coastguard Worker for (;;)
969*a67afe4dSAndroid Build Coastguard Worker {
970*a67afe4dSAndroid Build Coastguard Worker int ret;
971*a67afe4dSAndroid Build Coastguard Worker
972*a67afe4dSAndroid Build Coastguard Worker /* INPUT: from the row data */
973*a67afe4dSAndroid Build Coastguard Worker uInt avail = ZLIB_IO_MAX;
974*a67afe4dSAndroid Build Coastguard Worker
975*a67afe4dSAndroid Build Coastguard Worker if (avail > input_len)
976*a67afe4dSAndroid Build Coastguard Worker avail = (uInt)input_len; /* safe because of the check */
977*a67afe4dSAndroid Build Coastguard Worker
978*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_in = avail;
979*a67afe4dSAndroid Build Coastguard Worker input_len -= avail;
980*a67afe4dSAndroid Build Coastguard Worker
981*a67afe4dSAndroid Build Coastguard Worker ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush);
982*a67afe4dSAndroid Build Coastguard Worker
983*a67afe4dSAndroid Build Coastguard Worker /* Include as-yet unconsumed input */
984*a67afe4dSAndroid Build Coastguard Worker input_len += png_ptr->zstream.avail_in;
985*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_in = 0;
986*a67afe4dSAndroid Build Coastguard Worker
987*a67afe4dSAndroid Build Coastguard Worker /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note
988*a67afe4dSAndroid Build Coastguard Worker * that these two zstream fields are preserved across the calls, therefore
989*a67afe4dSAndroid Build Coastguard Worker * there is no need to set these up on entry to the loop.
990*a67afe4dSAndroid Build Coastguard Worker */
991*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->zstream.avail_out == 0)
992*a67afe4dSAndroid Build Coastguard Worker {
993*a67afe4dSAndroid Build Coastguard Worker png_bytep data = png_ptr->zbuffer_list->output;
994*a67afe4dSAndroid Build Coastguard Worker uInt size = png_ptr->zbuffer_size;
995*a67afe4dSAndroid Build Coastguard Worker
996*a67afe4dSAndroid Build Coastguard Worker /* Write an IDAT containing the data then reset the buffer. The
997*a67afe4dSAndroid Build Coastguard Worker * first IDAT may need deflate header optimization.
998*a67afe4dSAndroid Build Coastguard Worker */
999*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
1000*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&
1001*a67afe4dSAndroid Build Coastguard Worker png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
1002*a67afe4dSAndroid Build Coastguard Worker optimize_cmf(data, png_image_size(png_ptr));
1003*a67afe4dSAndroid Build Coastguard Worker #endif
1004*a67afe4dSAndroid Build Coastguard Worker
1005*a67afe4dSAndroid Build Coastguard Worker if (size > 0)
1006*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_IDAT, data, size);
1007*a67afe4dSAndroid Build Coastguard Worker png_ptr->mode |= PNG_HAVE_IDAT;
1008*a67afe4dSAndroid Build Coastguard Worker
1009*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_out = data;
1010*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_out = size;
1011*a67afe4dSAndroid Build Coastguard Worker
1012*a67afe4dSAndroid Build Coastguard Worker /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with
1013*a67afe4dSAndroid Build Coastguard Worker * the same flush parameter until it has finished output, for NO_FLUSH
1014*a67afe4dSAndroid Build Coastguard Worker * it doesn't matter.
1015*a67afe4dSAndroid Build Coastguard Worker */
1016*a67afe4dSAndroid Build Coastguard Worker if (ret == Z_OK && flush != Z_NO_FLUSH)
1017*a67afe4dSAndroid Build Coastguard Worker continue;
1018*a67afe4dSAndroid Build Coastguard Worker }
1019*a67afe4dSAndroid Build Coastguard Worker
1020*a67afe4dSAndroid Build Coastguard Worker /* The order of these checks doesn't matter much; it just affects which
1021*a67afe4dSAndroid Build Coastguard Worker * possible error might be detected if multiple things go wrong at once.
1022*a67afe4dSAndroid Build Coastguard Worker */
1023*a67afe4dSAndroid Build Coastguard Worker if (ret == Z_OK) /* most likely return code! */
1024*a67afe4dSAndroid Build Coastguard Worker {
1025*a67afe4dSAndroid Build Coastguard Worker /* If all the input has been consumed then just return. If Z_FINISH
1026*a67afe4dSAndroid Build Coastguard Worker * was used as the flush parameter something has gone wrong if we get
1027*a67afe4dSAndroid Build Coastguard Worker * here.
1028*a67afe4dSAndroid Build Coastguard Worker */
1029*a67afe4dSAndroid Build Coastguard Worker if (input_len == 0)
1030*a67afe4dSAndroid Build Coastguard Worker {
1031*a67afe4dSAndroid Build Coastguard Worker if (flush == Z_FINISH)
1032*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Z_OK on Z_FINISH with output space");
1033*a67afe4dSAndroid Build Coastguard Worker
1034*a67afe4dSAndroid Build Coastguard Worker return;
1035*a67afe4dSAndroid Build Coastguard Worker }
1036*a67afe4dSAndroid Build Coastguard Worker }
1037*a67afe4dSAndroid Build Coastguard Worker
1038*a67afe4dSAndroid Build Coastguard Worker else if (ret == Z_STREAM_END && flush == Z_FINISH)
1039*a67afe4dSAndroid Build Coastguard Worker {
1040*a67afe4dSAndroid Build Coastguard Worker /* This is the end of the IDAT data; any pending output must be
1041*a67afe4dSAndroid Build Coastguard Worker * flushed. For small PNG files we may still be at the beginning.
1042*a67afe4dSAndroid Build Coastguard Worker */
1043*a67afe4dSAndroid Build Coastguard Worker png_bytep data = png_ptr->zbuffer_list->output;
1044*a67afe4dSAndroid Build Coastguard Worker uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out;
1045*a67afe4dSAndroid Build Coastguard Worker
1046*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
1047*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&
1048*a67afe4dSAndroid Build Coastguard Worker png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
1049*a67afe4dSAndroid Build Coastguard Worker optimize_cmf(data, png_image_size(png_ptr));
1050*a67afe4dSAndroid Build Coastguard Worker #endif
1051*a67afe4dSAndroid Build Coastguard Worker
1052*a67afe4dSAndroid Build Coastguard Worker if (size > 0)
1053*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_IDAT, data, size);
1054*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.avail_out = 0;
1055*a67afe4dSAndroid Build Coastguard Worker png_ptr->zstream.next_out = NULL;
1056*a67afe4dSAndroid Build Coastguard Worker png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
1057*a67afe4dSAndroid Build Coastguard Worker
1058*a67afe4dSAndroid Build Coastguard Worker png_ptr->zowner = 0; /* Release the stream */
1059*a67afe4dSAndroid Build Coastguard Worker return;
1060*a67afe4dSAndroid Build Coastguard Worker }
1061*a67afe4dSAndroid Build Coastguard Worker
1062*a67afe4dSAndroid Build Coastguard Worker else
1063*a67afe4dSAndroid Build Coastguard Worker {
1064*a67afe4dSAndroid Build Coastguard Worker /* This is an error condition. */
1065*a67afe4dSAndroid Build Coastguard Worker png_zstream_error(png_ptr, ret);
1066*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, png_ptr->zstream.msg);
1067*a67afe4dSAndroid Build Coastguard Worker }
1068*a67afe4dSAndroid Build Coastguard Worker }
1069*a67afe4dSAndroid Build Coastguard Worker }
1070*a67afe4dSAndroid Build Coastguard Worker
1071*a67afe4dSAndroid Build Coastguard Worker /* Write an IEND chunk */
1072*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_IEND(png_structrp png_ptr)1073*a67afe4dSAndroid Build Coastguard Worker png_write_IEND(png_structrp png_ptr)
1074*a67afe4dSAndroid Build Coastguard Worker {
1075*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_IEND");
1076*a67afe4dSAndroid Build Coastguard Worker
1077*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_IEND, NULL, 0);
1078*a67afe4dSAndroid Build Coastguard Worker png_ptr->mode |= PNG_HAVE_IEND;
1079*a67afe4dSAndroid Build Coastguard Worker }
1080*a67afe4dSAndroid Build Coastguard Worker
1081*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_gAMA_SUPPORTED
1082*a67afe4dSAndroid Build Coastguard Worker /* Write a gAMA chunk */
1083*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_gAMA_fixed(png_structrp png_ptr,png_fixed_point file_gamma)1084*a67afe4dSAndroid Build Coastguard Worker png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma)
1085*a67afe4dSAndroid Build Coastguard Worker {
1086*a67afe4dSAndroid Build Coastguard Worker png_byte buf[4];
1087*a67afe4dSAndroid Build Coastguard Worker
1088*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_gAMA");
1089*a67afe4dSAndroid Build Coastguard Worker
1090*a67afe4dSAndroid Build Coastguard Worker /* file_gamma is saved in 1/100,000ths */
1091*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf, (png_uint_32)file_gamma);
1092*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_gAMA, buf, 4);
1093*a67afe4dSAndroid Build Coastguard Worker }
1094*a67afe4dSAndroid Build Coastguard Worker #endif
1095*a67afe4dSAndroid Build Coastguard Worker
1096*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_sRGB_SUPPORTED
1097*a67afe4dSAndroid Build Coastguard Worker /* Write a sRGB chunk */
1098*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_sRGB(png_structrp png_ptr,int srgb_intent)1099*a67afe4dSAndroid Build Coastguard Worker png_write_sRGB(png_structrp png_ptr, int srgb_intent)
1100*a67afe4dSAndroid Build Coastguard Worker {
1101*a67afe4dSAndroid Build Coastguard Worker png_byte buf[1];
1102*a67afe4dSAndroid Build Coastguard Worker
1103*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_sRGB");
1104*a67afe4dSAndroid Build Coastguard Worker
1105*a67afe4dSAndroid Build Coastguard Worker if (srgb_intent >= PNG_sRGB_INTENT_LAST)
1106*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr,
1107*a67afe4dSAndroid Build Coastguard Worker "Invalid sRGB rendering intent specified");
1108*a67afe4dSAndroid Build Coastguard Worker
1109*a67afe4dSAndroid Build Coastguard Worker buf[0]=(png_byte)srgb_intent;
1110*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_sRGB, buf, 1);
1111*a67afe4dSAndroid Build Coastguard Worker }
1112*a67afe4dSAndroid Build Coastguard Worker #endif
1113*a67afe4dSAndroid Build Coastguard Worker
1114*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_iCCP_SUPPORTED
1115*a67afe4dSAndroid Build Coastguard Worker /* Write an iCCP chunk */
1116*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_iCCP(png_structrp png_ptr,png_const_charp name,png_const_bytep profile)1117*a67afe4dSAndroid Build Coastguard Worker png_write_iCCP(png_structrp png_ptr, png_const_charp name,
1118*a67afe4dSAndroid Build Coastguard Worker png_const_bytep profile)
1119*a67afe4dSAndroid Build Coastguard Worker {
1120*a67afe4dSAndroid Build Coastguard Worker png_uint_32 name_len;
1121*a67afe4dSAndroid Build Coastguard Worker png_uint_32 profile_len;
1122*a67afe4dSAndroid Build Coastguard Worker png_byte new_name[81]; /* 1 byte for the compression byte */
1123*a67afe4dSAndroid Build Coastguard Worker compression_state comp;
1124*a67afe4dSAndroid Build Coastguard Worker png_uint_32 temp;
1125*a67afe4dSAndroid Build Coastguard Worker
1126*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_iCCP");
1127*a67afe4dSAndroid Build Coastguard Worker
1128*a67afe4dSAndroid Build Coastguard Worker /* These are all internal problems: the profile should have been checked
1129*a67afe4dSAndroid Build Coastguard Worker * before when it was stored.
1130*a67afe4dSAndroid Build Coastguard Worker */
1131*a67afe4dSAndroid Build Coastguard Worker if (profile == NULL)
1132*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */
1133*a67afe4dSAndroid Build Coastguard Worker
1134*a67afe4dSAndroid Build Coastguard Worker profile_len = png_get_uint_32(profile);
1135*a67afe4dSAndroid Build Coastguard Worker
1136*a67afe4dSAndroid Build Coastguard Worker if (profile_len < 132)
1137*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "ICC profile too short");
1138*a67afe4dSAndroid Build Coastguard Worker
1139*a67afe4dSAndroid Build Coastguard Worker temp = (png_uint_32) (*(profile+8));
1140*a67afe4dSAndroid Build Coastguard Worker if (temp > 3 && (profile_len & 0x03))
1141*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");
1142*a67afe4dSAndroid Build Coastguard Worker
1143*a67afe4dSAndroid Build Coastguard Worker {
1144*a67afe4dSAndroid Build Coastguard Worker png_uint_32 embedded_profile_len = png_get_uint_32(profile);
1145*a67afe4dSAndroid Build Coastguard Worker
1146*a67afe4dSAndroid Build Coastguard Worker if (profile_len != embedded_profile_len)
1147*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Profile length does not match profile");
1148*a67afe4dSAndroid Build Coastguard Worker }
1149*a67afe4dSAndroid Build Coastguard Worker
1150*a67afe4dSAndroid Build Coastguard Worker name_len = png_check_keyword(png_ptr, name, new_name);
1151*a67afe4dSAndroid Build Coastguard Worker
1152*a67afe4dSAndroid Build Coastguard Worker if (name_len == 0)
1153*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "iCCP: invalid keyword");
1154*a67afe4dSAndroid Build Coastguard Worker
1155*a67afe4dSAndroid Build Coastguard Worker new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE;
1156*a67afe4dSAndroid Build Coastguard Worker
1157*a67afe4dSAndroid Build Coastguard Worker /* Make sure we include the NULL after the name and the compression type */
1158*a67afe4dSAndroid Build Coastguard Worker ++name_len;
1159*a67afe4dSAndroid Build Coastguard Worker
1160*a67afe4dSAndroid Build Coastguard Worker png_text_compress_init(&comp, profile, profile_len);
1161*a67afe4dSAndroid Build Coastguard Worker
1162*a67afe4dSAndroid Build Coastguard Worker /* Allow for keyword terminator and compression byte */
1163*a67afe4dSAndroid Build Coastguard Worker if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK)
1164*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, png_ptr->zstream.msg);
1165*a67afe4dSAndroid Build Coastguard Worker
1166*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len);
1167*a67afe4dSAndroid Build Coastguard Worker
1168*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, new_name, name_len);
1169*a67afe4dSAndroid Build Coastguard Worker
1170*a67afe4dSAndroid Build Coastguard Worker png_write_compressed_data_out(png_ptr, &comp);
1171*a67afe4dSAndroid Build Coastguard Worker
1172*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1173*a67afe4dSAndroid Build Coastguard Worker }
1174*a67afe4dSAndroid Build Coastguard Worker #endif
1175*a67afe4dSAndroid Build Coastguard Worker
1176*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_sPLT_SUPPORTED
1177*a67afe4dSAndroid Build Coastguard Worker /* Write a sPLT chunk */
1178*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_sPLT(png_structrp png_ptr,png_const_sPLT_tp spalette)1179*a67afe4dSAndroid Build Coastguard Worker png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
1180*a67afe4dSAndroid Build Coastguard Worker {
1181*a67afe4dSAndroid Build Coastguard Worker png_uint_32 name_len;
1182*a67afe4dSAndroid Build Coastguard Worker png_byte new_name[80];
1183*a67afe4dSAndroid Build Coastguard Worker png_byte entrybuf[10];
1184*a67afe4dSAndroid Build Coastguard Worker size_t entry_size = (spalette->depth == 8 ? 6 : 10);
1185*a67afe4dSAndroid Build Coastguard Worker size_t palette_size = entry_size * (size_t)spalette->nentries;
1186*a67afe4dSAndroid Build Coastguard Worker png_sPLT_entryp ep;
1187*a67afe4dSAndroid Build Coastguard Worker #ifndef PNG_POINTER_INDEXING_SUPPORTED
1188*a67afe4dSAndroid Build Coastguard Worker int i;
1189*a67afe4dSAndroid Build Coastguard Worker #endif
1190*a67afe4dSAndroid Build Coastguard Worker
1191*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_sPLT");
1192*a67afe4dSAndroid Build Coastguard Worker
1193*a67afe4dSAndroid Build Coastguard Worker name_len = png_check_keyword(png_ptr, spalette->name, new_name);
1194*a67afe4dSAndroid Build Coastguard Worker
1195*a67afe4dSAndroid Build Coastguard Worker if (name_len == 0)
1196*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "sPLT: invalid keyword");
1197*a67afe4dSAndroid Build Coastguard Worker
1198*a67afe4dSAndroid Build Coastguard Worker /* Make sure we include the NULL after the name */
1199*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_sPLT,
1200*a67afe4dSAndroid Build Coastguard Worker (png_uint_32)(name_len + 2 + palette_size));
1201*a67afe4dSAndroid Build Coastguard Worker
1202*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, (png_bytep)new_name, (size_t)(name_len + 1));
1203*a67afe4dSAndroid Build Coastguard Worker
1204*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, &spalette->depth, 1);
1205*a67afe4dSAndroid Build Coastguard Worker
1206*a67afe4dSAndroid Build Coastguard Worker /* Loop through each palette entry, writing appropriately */
1207*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_POINTER_INDEXING_SUPPORTED
1208*a67afe4dSAndroid Build Coastguard Worker for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
1209*a67afe4dSAndroid Build Coastguard Worker {
1210*a67afe4dSAndroid Build Coastguard Worker if (spalette->depth == 8)
1211*a67afe4dSAndroid Build Coastguard Worker {
1212*a67afe4dSAndroid Build Coastguard Worker entrybuf[0] = (png_byte)ep->red;
1213*a67afe4dSAndroid Build Coastguard Worker entrybuf[1] = (png_byte)ep->green;
1214*a67afe4dSAndroid Build Coastguard Worker entrybuf[2] = (png_byte)ep->blue;
1215*a67afe4dSAndroid Build Coastguard Worker entrybuf[3] = (png_byte)ep->alpha;
1216*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 4, ep->frequency);
1217*a67afe4dSAndroid Build Coastguard Worker }
1218*a67afe4dSAndroid Build Coastguard Worker
1219*a67afe4dSAndroid Build Coastguard Worker else
1220*a67afe4dSAndroid Build Coastguard Worker {
1221*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 0, ep->red);
1222*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 2, ep->green);
1223*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 4, ep->blue);
1224*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 6, ep->alpha);
1225*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 8, ep->frequency);
1226*a67afe4dSAndroid Build Coastguard Worker }
1227*a67afe4dSAndroid Build Coastguard Worker
1228*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, entrybuf, entry_size);
1229*a67afe4dSAndroid Build Coastguard Worker }
1230*a67afe4dSAndroid Build Coastguard Worker #else
1231*a67afe4dSAndroid Build Coastguard Worker ep=spalette->entries;
1232*a67afe4dSAndroid Build Coastguard Worker for (i = 0; i>spalette->nentries; i++)
1233*a67afe4dSAndroid Build Coastguard Worker {
1234*a67afe4dSAndroid Build Coastguard Worker if (spalette->depth == 8)
1235*a67afe4dSAndroid Build Coastguard Worker {
1236*a67afe4dSAndroid Build Coastguard Worker entrybuf[0] = (png_byte)ep[i].red;
1237*a67afe4dSAndroid Build Coastguard Worker entrybuf[1] = (png_byte)ep[i].green;
1238*a67afe4dSAndroid Build Coastguard Worker entrybuf[2] = (png_byte)ep[i].blue;
1239*a67afe4dSAndroid Build Coastguard Worker entrybuf[3] = (png_byte)ep[i].alpha;
1240*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 4, ep[i].frequency);
1241*a67afe4dSAndroid Build Coastguard Worker }
1242*a67afe4dSAndroid Build Coastguard Worker
1243*a67afe4dSAndroid Build Coastguard Worker else
1244*a67afe4dSAndroid Build Coastguard Worker {
1245*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 0, ep[i].red);
1246*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 2, ep[i].green);
1247*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 4, ep[i].blue);
1248*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 6, ep[i].alpha);
1249*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(entrybuf + 8, ep[i].frequency);
1250*a67afe4dSAndroid Build Coastguard Worker }
1251*a67afe4dSAndroid Build Coastguard Worker
1252*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, entrybuf, entry_size);
1253*a67afe4dSAndroid Build Coastguard Worker }
1254*a67afe4dSAndroid Build Coastguard Worker #endif
1255*a67afe4dSAndroid Build Coastguard Worker
1256*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1257*a67afe4dSAndroid Build Coastguard Worker }
1258*a67afe4dSAndroid Build Coastguard Worker #endif
1259*a67afe4dSAndroid Build Coastguard Worker
1260*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_sBIT_SUPPORTED
1261*a67afe4dSAndroid Build Coastguard Worker /* Write the sBIT chunk */
1262*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_sBIT(png_structrp png_ptr,png_const_color_8p sbit,int color_type)1263*a67afe4dSAndroid Build Coastguard Worker png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type)
1264*a67afe4dSAndroid Build Coastguard Worker {
1265*a67afe4dSAndroid Build Coastguard Worker png_byte buf[4];
1266*a67afe4dSAndroid Build Coastguard Worker size_t size;
1267*a67afe4dSAndroid Build Coastguard Worker
1268*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_sBIT");
1269*a67afe4dSAndroid Build Coastguard Worker
1270*a67afe4dSAndroid Build Coastguard Worker /* Make sure we don't depend upon the order of PNG_COLOR_8 */
1271*a67afe4dSAndroid Build Coastguard Worker if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
1272*a67afe4dSAndroid Build Coastguard Worker {
1273*a67afe4dSAndroid Build Coastguard Worker png_byte maxbits;
1274*a67afe4dSAndroid Build Coastguard Worker
1275*a67afe4dSAndroid Build Coastguard Worker maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
1276*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_bit_depth);
1277*a67afe4dSAndroid Build Coastguard Worker
1278*a67afe4dSAndroid Build Coastguard Worker if (sbit->red == 0 || sbit->red > maxbits ||
1279*a67afe4dSAndroid Build Coastguard Worker sbit->green == 0 || sbit->green > maxbits ||
1280*a67afe4dSAndroid Build Coastguard Worker sbit->blue == 0 || sbit->blue > maxbits)
1281*a67afe4dSAndroid Build Coastguard Worker {
1282*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid sBIT depth specified");
1283*a67afe4dSAndroid Build Coastguard Worker return;
1284*a67afe4dSAndroid Build Coastguard Worker }
1285*a67afe4dSAndroid Build Coastguard Worker
1286*a67afe4dSAndroid Build Coastguard Worker buf[0] = sbit->red;
1287*a67afe4dSAndroid Build Coastguard Worker buf[1] = sbit->green;
1288*a67afe4dSAndroid Build Coastguard Worker buf[2] = sbit->blue;
1289*a67afe4dSAndroid Build Coastguard Worker size = 3;
1290*a67afe4dSAndroid Build Coastguard Worker }
1291*a67afe4dSAndroid Build Coastguard Worker
1292*a67afe4dSAndroid Build Coastguard Worker else
1293*a67afe4dSAndroid Build Coastguard Worker {
1294*a67afe4dSAndroid Build Coastguard Worker if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
1295*a67afe4dSAndroid Build Coastguard Worker {
1296*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid sBIT depth specified");
1297*a67afe4dSAndroid Build Coastguard Worker return;
1298*a67afe4dSAndroid Build Coastguard Worker }
1299*a67afe4dSAndroid Build Coastguard Worker
1300*a67afe4dSAndroid Build Coastguard Worker buf[0] = sbit->gray;
1301*a67afe4dSAndroid Build Coastguard Worker size = 1;
1302*a67afe4dSAndroid Build Coastguard Worker }
1303*a67afe4dSAndroid Build Coastguard Worker
1304*a67afe4dSAndroid Build Coastguard Worker if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)
1305*a67afe4dSAndroid Build Coastguard Worker {
1306*a67afe4dSAndroid Build Coastguard Worker if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
1307*a67afe4dSAndroid Build Coastguard Worker {
1308*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid sBIT depth specified");
1309*a67afe4dSAndroid Build Coastguard Worker return;
1310*a67afe4dSAndroid Build Coastguard Worker }
1311*a67afe4dSAndroid Build Coastguard Worker
1312*a67afe4dSAndroid Build Coastguard Worker buf[size++] = sbit->alpha;
1313*a67afe4dSAndroid Build Coastguard Worker }
1314*a67afe4dSAndroid Build Coastguard Worker
1315*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_sBIT, buf, size);
1316*a67afe4dSAndroid Build Coastguard Worker }
1317*a67afe4dSAndroid Build Coastguard Worker #endif
1318*a67afe4dSAndroid Build Coastguard Worker
1319*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_cHRM_SUPPORTED
1320*a67afe4dSAndroid Build Coastguard Worker /* Write the cHRM chunk */
1321*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_cHRM_fixed(png_structrp png_ptr,const png_xy * xy)1322*a67afe4dSAndroid Build Coastguard Worker png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy)
1323*a67afe4dSAndroid Build Coastguard Worker {
1324*a67afe4dSAndroid Build Coastguard Worker png_byte buf[32];
1325*a67afe4dSAndroid Build Coastguard Worker
1326*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_cHRM");
1327*a67afe4dSAndroid Build Coastguard Worker
1328*a67afe4dSAndroid Build Coastguard Worker /* Each value is saved in 1/100,000ths */
1329*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf, xy->whitex);
1330*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 4, xy->whitey);
1331*a67afe4dSAndroid Build Coastguard Worker
1332*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 8, xy->redx);
1333*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 12, xy->redy);
1334*a67afe4dSAndroid Build Coastguard Worker
1335*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 16, xy->greenx);
1336*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 20, xy->greeny);
1337*a67afe4dSAndroid Build Coastguard Worker
1338*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 24, xy->bluex);
1339*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 28, xy->bluey);
1340*a67afe4dSAndroid Build Coastguard Worker
1341*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_cHRM, buf, 32);
1342*a67afe4dSAndroid Build Coastguard Worker }
1343*a67afe4dSAndroid Build Coastguard Worker #endif
1344*a67afe4dSAndroid Build Coastguard Worker
1345*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_tRNS_SUPPORTED
1346*a67afe4dSAndroid Build Coastguard Worker /* Write the tRNS chunk */
1347*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_tRNS(png_structrp png_ptr,png_const_bytep trans_alpha,png_const_color_16p tran,int num_trans,int color_type)1348*a67afe4dSAndroid Build Coastguard Worker png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
1349*a67afe4dSAndroid Build Coastguard Worker png_const_color_16p tran, int num_trans, int color_type)
1350*a67afe4dSAndroid Build Coastguard Worker {
1351*a67afe4dSAndroid Build Coastguard Worker png_byte buf[6];
1352*a67afe4dSAndroid Build Coastguard Worker
1353*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_tRNS");
1354*a67afe4dSAndroid Build Coastguard Worker
1355*a67afe4dSAndroid Build Coastguard Worker if (color_type == PNG_COLOR_TYPE_PALETTE)
1356*a67afe4dSAndroid Build Coastguard Worker {
1357*a67afe4dSAndroid Build Coastguard Worker if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
1358*a67afe4dSAndroid Build Coastguard Worker {
1359*a67afe4dSAndroid Build Coastguard Worker png_app_warning(png_ptr,
1360*a67afe4dSAndroid Build Coastguard Worker "Invalid number of transparent colors specified");
1361*a67afe4dSAndroid Build Coastguard Worker return;
1362*a67afe4dSAndroid Build Coastguard Worker }
1363*a67afe4dSAndroid Build Coastguard Worker
1364*a67afe4dSAndroid Build Coastguard Worker /* Write the chunk out as it is */
1365*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,
1366*a67afe4dSAndroid Build Coastguard Worker (size_t)num_trans);
1367*a67afe4dSAndroid Build Coastguard Worker }
1368*a67afe4dSAndroid Build Coastguard Worker
1369*a67afe4dSAndroid Build Coastguard Worker else if (color_type == PNG_COLOR_TYPE_GRAY)
1370*a67afe4dSAndroid Build Coastguard Worker {
1371*a67afe4dSAndroid Build Coastguard Worker /* One 16-bit value */
1372*a67afe4dSAndroid Build Coastguard Worker if (tran->gray >= (1 << png_ptr->bit_depth))
1373*a67afe4dSAndroid Build Coastguard Worker {
1374*a67afe4dSAndroid Build Coastguard Worker png_app_warning(png_ptr,
1375*a67afe4dSAndroid Build Coastguard Worker "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
1376*a67afe4dSAndroid Build Coastguard Worker
1377*a67afe4dSAndroid Build Coastguard Worker return;
1378*a67afe4dSAndroid Build Coastguard Worker }
1379*a67afe4dSAndroid Build Coastguard Worker
1380*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf, tran->gray);
1381*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_tRNS, buf, 2);
1382*a67afe4dSAndroid Build Coastguard Worker }
1383*a67afe4dSAndroid Build Coastguard Worker
1384*a67afe4dSAndroid Build Coastguard Worker else if (color_type == PNG_COLOR_TYPE_RGB)
1385*a67afe4dSAndroid Build Coastguard Worker {
1386*a67afe4dSAndroid Build Coastguard Worker /* Three 16-bit values */
1387*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf, tran->red);
1388*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf + 2, tran->green);
1389*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf + 4, tran->blue);
1390*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_16BIT_SUPPORTED
1391*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
1392*a67afe4dSAndroid Build Coastguard Worker #else
1393*a67afe4dSAndroid Build Coastguard Worker if ((buf[0] | buf[2] | buf[4]) != 0)
1394*a67afe4dSAndroid Build Coastguard Worker #endif
1395*a67afe4dSAndroid Build Coastguard Worker {
1396*a67afe4dSAndroid Build Coastguard Worker png_app_warning(png_ptr,
1397*a67afe4dSAndroid Build Coastguard Worker "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
1398*a67afe4dSAndroid Build Coastguard Worker return;
1399*a67afe4dSAndroid Build Coastguard Worker }
1400*a67afe4dSAndroid Build Coastguard Worker
1401*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_tRNS, buf, 6);
1402*a67afe4dSAndroid Build Coastguard Worker }
1403*a67afe4dSAndroid Build Coastguard Worker
1404*a67afe4dSAndroid Build Coastguard Worker else
1405*a67afe4dSAndroid Build Coastguard Worker {
1406*a67afe4dSAndroid Build Coastguard Worker png_app_warning(png_ptr, "Can't write tRNS with an alpha channel");
1407*a67afe4dSAndroid Build Coastguard Worker }
1408*a67afe4dSAndroid Build Coastguard Worker }
1409*a67afe4dSAndroid Build Coastguard Worker #endif
1410*a67afe4dSAndroid Build Coastguard Worker
1411*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_bKGD_SUPPORTED
1412*a67afe4dSAndroid Build Coastguard Worker /* Write the background chunk */
1413*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_bKGD(png_structrp png_ptr,png_const_color_16p back,int color_type)1414*a67afe4dSAndroid Build Coastguard Worker png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
1415*a67afe4dSAndroid Build Coastguard Worker {
1416*a67afe4dSAndroid Build Coastguard Worker png_byte buf[6];
1417*a67afe4dSAndroid Build Coastguard Worker
1418*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_bKGD");
1419*a67afe4dSAndroid Build Coastguard Worker
1420*a67afe4dSAndroid Build Coastguard Worker if (color_type == PNG_COLOR_TYPE_PALETTE)
1421*a67afe4dSAndroid Build Coastguard Worker {
1422*a67afe4dSAndroid Build Coastguard Worker if (
1423*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_MNG_FEATURES_SUPPORTED
1424*a67afe4dSAndroid Build Coastguard Worker (png_ptr->num_palette != 0 ||
1425*a67afe4dSAndroid Build Coastguard Worker (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) &&
1426*a67afe4dSAndroid Build Coastguard Worker #endif
1427*a67afe4dSAndroid Build Coastguard Worker back->index >= png_ptr->num_palette)
1428*a67afe4dSAndroid Build Coastguard Worker {
1429*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid background palette index");
1430*a67afe4dSAndroid Build Coastguard Worker return;
1431*a67afe4dSAndroid Build Coastguard Worker }
1432*a67afe4dSAndroid Build Coastguard Worker
1433*a67afe4dSAndroid Build Coastguard Worker buf[0] = back->index;
1434*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_bKGD, buf, 1);
1435*a67afe4dSAndroid Build Coastguard Worker }
1436*a67afe4dSAndroid Build Coastguard Worker
1437*a67afe4dSAndroid Build Coastguard Worker else if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
1438*a67afe4dSAndroid Build Coastguard Worker {
1439*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf, back->red);
1440*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf + 2, back->green);
1441*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf + 4, back->blue);
1442*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_16BIT_SUPPORTED
1443*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
1444*a67afe4dSAndroid Build Coastguard Worker #else
1445*a67afe4dSAndroid Build Coastguard Worker if ((buf[0] | buf[2] | buf[4]) != 0)
1446*a67afe4dSAndroid Build Coastguard Worker #endif
1447*a67afe4dSAndroid Build Coastguard Worker {
1448*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr,
1449*a67afe4dSAndroid Build Coastguard Worker "Ignoring attempt to write 16-bit bKGD chunk "
1450*a67afe4dSAndroid Build Coastguard Worker "when bit_depth is 8");
1451*a67afe4dSAndroid Build Coastguard Worker
1452*a67afe4dSAndroid Build Coastguard Worker return;
1453*a67afe4dSAndroid Build Coastguard Worker }
1454*a67afe4dSAndroid Build Coastguard Worker
1455*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_bKGD, buf, 6);
1456*a67afe4dSAndroid Build Coastguard Worker }
1457*a67afe4dSAndroid Build Coastguard Worker
1458*a67afe4dSAndroid Build Coastguard Worker else
1459*a67afe4dSAndroid Build Coastguard Worker {
1460*a67afe4dSAndroid Build Coastguard Worker if (back->gray >= (1 << png_ptr->bit_depth))
1461*a67afe4dSAndroid Build Coastguard Worker {
1462*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr,
1463*a67afe4dSAndroid Build Coastguard Worker "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
1464*a67afe4dSAndroid Build Coastguard Worker
1465*a67afe4dSAndroid Build Coastguard Worker return;
1466*a67afe4dSAndroid Build Coastguard Worker }
1467*a67afe4dSAndroid Build Coastguard Worker
1468*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf, back->gray);
1469*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_bKGD, buf, 2);
1470*a67afe4dSAndroid Build Coastguard Worker }
1471*a67afe4dSAndroid Build Coastguard Worker }
1472*a67afe4dSAndroid Build Coastguard Worker #endif
1473*a67afe4dSAndroid Build Coastguard Worker
1474*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_eXIf_SUPPORTED
1475*a67afe4dSAndroid Build Coastguard Worker /* Write the Exif data */
1476*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_eXIf(png_structrp png_ptr,png_bytep exif,int num_exif)1477*a67afe4dSAndroid Build Coastguard Worker png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif)
1478*a67afe4dSAndroid Build Coastguard Worker {
1479*a67afe4dSAndroid Build Coastguard Worker int i;
1480*a67afe4dSAndroid Build Coastguard Worker png_byte buf[1];
1481*a67afe4dSAndroid Build Coastguard Worker
1482*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_eXIf");
1483*a67afe4dSAndroid Build Coastguard Worker
1484*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif));
1485*a67afe4dSAndroid Build Coastguard Worker
1486*a67afe4dSAndroid Build Coastguard Worker for (i = 0; i < num_exif; i++)
1487*a67afe4dSAndroid Build Coastguard Worker {
1488*a67afe4dSAndroid Build Coastguard Worker buf[0] = exif[i];
1489*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, buf, 1);
1490*a67afe4dSAndroid Build Coastguard Worker }
1491*a67afe4dSAndroid Build Coastguard Worker
1492*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1493*a67afe4dSAndroid Build Coastguard Worker }
1494*a67afe4dSAndroid Build Coastguard Worker #endif
1495*a67afe4dSAndroid Build Coastguard Worker
1496*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_hIST_SUPPORTED
1497*a67afe4dSAndroid Build Coastguard Worker /* Write the histogram */
1498*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_hIST(png_structrp png_ptr,png_const_uint_16p hist,int num_hist)1499*a67afe4dSAndroid Build Coastguard Worker png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist)
1500*a67afe4dSAndroid Build Coastguard Worker {
1501*a67afe4dSAndroid Build Coastguard Worker int i;
1502*a67afe4dSAndroid Build Coastguard Worker png_byte buf[3];
1503*a67afe4dSAndroid Build Coastguard Worker
1504*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_hIST");
1505*a67afe4dSAndroid Build Coastguard Worker
1506*a67afe4dSAndroid Build Coastguard Worker if (num_hist > (int)png_ptr->num_palette)
1507*a67afe4dSAndroid Build Coastguard Worker {
1508*a67afe4dSAndroid Build Coastguard Worker png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
1509*a67afe4dSAndroid Build Coastguard Worker png_ptr->num_palette);
1510*a67afe4dSAndroid Build Coastguard Worker
1511*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid number of histogram entries specified");
1512*a67afe4dSAndroid Build Coastguard Worker return;
1513*a67afe4dSAndroid Build Coastguard Worker }
1514*a67afe4dSAndroid Build Coastguard Worker
1515*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));
1516*a67afe4dSAndroid Build Coastguard Worker
1517*a67afe4dSAndroid Build Coastguard Worker for (i = 0; i < num_hist; i++)
1518*a67afe4dSAndroid Build Coastguard Worker {
1519*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf, hist[i]);
1520*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, buf, 2);
1521*a67afe4dSAndroid Build Coastguard Worker }
1522*a67afe4dSAndroid Build Coastguard Worker
1523*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1524*a67afe4dSAndroid Build Coastguard Worker }
1525*a67afe4dSAndroid Build Coastguard Worker #endif
1526*a67afe4dSAndroid Build Coastguard Worker
1527*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_tEXt_SUPPORTED
1528*a67afe4dSAndroid Build Coastguard Worker /* Write a tEXt chunk */
1529*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_tEXt(png_structrp png_ptr,png_const_charp key,png_const_charp text,size_t text_len)1530*a67afe4dSAndroid Build Coastguard Worker png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
1531*a67afe4dSAndroid Build Coastguard Worker size_t text_len)
1532*a67afe4dSAndroid Build Coastguard Worker {
1533*a67afe4dSAndroid Build Coastguard Worker png_uint_32 key_len;
1534*a67afe4dSAndroid Build Coastguard Worker png_byte new_key[80];
1535*a67afe4dSAndroid Build Coastguard Worker
1536*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_tEXt");
1537*a67afe4dSAndroid Build Coastguard Worker
1538*a67afe4dSAndroid Build Coastguard Worker key_len = png_check_keyword(png_ptr, key, new_key);
1539*a67afe4dSAndroid Build Coastguard Worker
1540*a67afe4dSAndroid Build Coastguard Worker if (key_len == 0)
1541*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "tEXt: invalid keyword");
1542*a67afe4dSAndroid Build Coastguard Worker
1543*a67afe4dSAndroid Build Coastguard Worker if (text == NULL || *text == '\0')
1544*a67afe4dSAndroid Build Coastguard Worker text_len = 0;
1545*a67afe4dSAndroid Build Coastguard Worker
1546*a67afe4dSAndroid Build Coastguard Worker else
1547*a67afe4dSAndroid Build Coastguard Worker text_len = strlen(text);
1548*a67afe4dSAndroid Build Coastguard Worker
1549*a67afe4dSAndroid Build Coastguard Worker if (text_len > PNG_UINT_31_MAX - (key_len+1))
1550*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "tEXt: text too long");
1551*a67afe4dSAndroid Build Coastguard Worker
1552*a67afe4dSAndroid Build Coastguard Worker /* Make sure we include the 0 after the key */
1553*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_tEXt,
1554*a67afe4dSAndroid Build Coastguard Worker (png_uint_32)/*checked above*/(key_len + text_len + 1));
1555*a67afe4dSAndroid Build Coastguard Worker /*
1556*a67afe4dSAndroid Build Coastguard Worker * We leave it to the application to meet PNG-1.0 requirements on the
1557*a67afe4dSAndroid Build Coastguard Worker * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
1558*a67afe4dSAndroid Build Coastguard Worker * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
1559*a67afe4dSAndroid Build Coastguard Worker * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1560*a67afe4dSAndroid Build Coastguard Worker */
1561*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, new_key, key_len + 1);
1562*a67afe4dSAndroid Build Coastguard Worker
1563*a67afe4dSAndroid Build Coastguard Worker if (text_len != 0)
1564*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len);
1565*a67afe4dSAndroid Build Coastguard Worker
1566*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1567*a67afe4dSAndroid Build Coastguard Worker }
1568*a67afe4dSAndroid Build Coastguard Worker #endif
1569*a67afe4dSAndroid Build Coastguard Worker
1570*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_zTXt_SUPPORTED
1571*a67afe4dSAndroid Build Coastguard Worker /* Write a compressed text chunk */
1572*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_zTXt(png_structrp png_ptr,png_const_charp key,png_const_charp text,int compression)1573*a67afe4dSAndroid Build Coastguard Worker png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
1574*a67afe4dSAndroid Build Coastguard Worker int compression)
1575*a67afe4dSAndroid Build Coastguard Worker {
1576*a67afe4dSAndroid Build Coastguard Worker png_uint_32 key_len;
1577*a67afe4dSAndroid Build Coastguard Worker png_byte new_key[81];
1578*a67afe4dSAndroid Build Coastguard Worker compression_state comp;
1579*a67afe4dSAndroid Build Coastguard Worker
1580*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_zTXt");
1581*a67afe4dSAndroid Build Coastguard Worker
1582*a67afe4dSAndroid Build Coastguard Worker if (compression == PNG_TEXT_COMPRESSION_NONE)
1583*a67afe4dSAndroid Build Coastguard Worker {
1584*a67afe4dSAndroid Build Coastguard Worker png_write_tEXt(png_ptr, key, text, 0);
1585*a67afe4dSAndroid Build Coastguard Worker return;
1586*a67afe4dSAndroid Build Coastguard Worker }
1587*a67afe4dSAndroid Build Coastguard Worker
1588*a67afe4dSAndroid Build Coastguard Worker if (compression != PNG_TEXT_COMPRESSION_zTXt)
1589*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "zTXt: invalid compression type");
1590*a67afe4dSAndroid Build Coastguard Worker
1591*a67afe4dSAndroid Build Coastguard Worker key_len = png_check_keyword(png_ptr, key, new_key);
1592*a67afe4dSAndroid Build Coastguard Worker
1593*a67afe4dSAndroid Build Coastguard Worker if (key_len == 0)
1594*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "zTXt: invalid keyword");
1595*a67afe4dSAndroid Build Coastguard Worker
1596*a67afe4dSAndroid Build Coastguard Worker /* Add the compression method and 1 for the keyword separator. */
1597*a67afe4dSAndroid Build Coastguard Worker new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
1598*a67afe4dSAndroid Build Coastguard Worker ++key_len;
1599*a67afe4dSAndroid Build Coastguard Worker
1600*a67afe4dSAndroid Build Coastguard Worker /* Compute the compressed data; do it now for the length */
1601*a67afe4dSAndroid Build Coastguard Worker png_text_compress_init(&comp, (png_const_bytep)text,
1602*a67afe4dSAndroid Build Coastguard Worker text == NULL ? 0 : strlen(text));
1603*a67afe4dSAndroid Build Coastguard Worker
1604*a67afe4dSAndroid Build Coastguard Worker if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)
1605*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, png_ptr->zstream.msg);
1606*a67afe4dSAndroid Build Coastguard Worker
1607*a67afe4dSAndroid Build Coastguard Worker /* Write start of chunk */
1608*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len);
1609*a67afe4dSAndroid Build Coastguard Worker
1610*a67afe4dSAndroid Build Coastguard Worker /* Write key */
1611*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, new_key, key_len);
1612*a67afe4dSAndroid Build Coastguard Worker
1613*a67afe4dSAndroid Build Coastguard Worker /* Write the compressed data */
1614*a67afe4dSAndroid Build Coastguard Worker png_write_compressed_data_out(png_ptr, &comp);
1615*a67afe4dSAndroid Build Coastguard Worker
1616*a67afe4dSAndroid Build Coastguard Worker /* Close the chunk */
1617*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1618*a67afe4dSAndroid Build Coastguard Worker }
1619*a67afe4dSAndroid Build Coastguard Worker #endif
1620*a67afe4dSAndroid Build Coastguard Worker
1621*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_iTXt_SUPPORTED
1622*a67afe4dSAndroid Build Coastguard Worker /* Write an iTXt chunk */
1623*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_iTXt(png_structrp png_ptr,int compression,png_const_charp key,png_const_charp lang,png_const_charp lang_key,png_const_charp text)1624*a67afe4dSAndroid Build Coastguard Worker png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,
1625*a67afe4dSAndroid Build Coastguard Worker png_const_charp lang, png_const_charp lang_key, png_const_charp text)
1626*a67afe4dSAndroid Build Coastguard Worker {
1627*a67afe4dSAndroid Build Coastguard Worker png_uint_32 key_len, prefix_len;
1628*a67afe4dSAndroid Build Coastguard Worker size_t lang_len, lang_key_len;
1629*a67afe4dSAndroid Build Coastguard Worker png_byte new_key[82];
1630*a67afe4dSAndroid Build Coastguard Worker compression_state comp;
1631*a67afe4dSAndroid Build Coastguard Worker
1632*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_iTXt");
1633*a67afe4dSAndroid Build Coastguard Worker
1634*a67afe4dSAndroid Build Coastguard Worker key_len = png_check_keyword(png_ptr, key, new_key);
1635*a67afe4dSAndroid Build Coastguard Worker
1636*a67afe4dSAndroid Build Coastguard Worker if (key_len == 0)
1637*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "iTXt: invalid keyword");
1638*a67afe4dSAndroid Build Coastguard Worker
1639*a67afe4dSAndroid Build Coastguard Worker /* Set the compression flag */
1640*a67afe4dSAndroid Build Coastguard Worker switch (compression)
1641*a67afe4dSAndroid Build Coastguard Worker {
1642*a67afe4dSAndroid Build Coastguard Worker case PNG_ITXT_COMPRESSION_NONE:
1643*a67afe4dSAndroid Build Coastguard Worker case PNG_TEXT_COMPRESSION_NONE:
1644*a67afe4dSAndroid Build Coastguard Worker compression = new_key[++key_len] = 0; /* no compression */
1645*a67afe4dSAndroid Build Coastguard Worker break;
1646*a67afe4dSAndroid Build Coastguard Worker
1647*a67afe4dSAndroid Build Coastguard Worker case PNG_TEXT_COMPRESSION_zTXt:
1648*a67afe4dSAndroid Build Coastguard Worker case PNG_ITXT_COMPRESSION_zTXt:
1649*a67afe4dSAndroid Build Coastguard Worker compression = new_key[++key_len] = 1; /* compressed */
1650*a67afe4dSAndroid Build Coastguard Worker break;
1651*a67afe4dSAndroid Build Coastguard Worker
1652*a67afe4dSAndroid Build Coastguard Worker default:
1653*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "iTXt: invalid compression");
1654*a67afe4dSAndroid Build Coastguard Worker }
1655*a67afe4dSAndroid Build Coastguard Worker
1656*a67afe4dSAndroid Build Coastguard Worker new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
1657*a67afe4dSAndroid Build Coastguard Worker ++key_len; /* for the keywod separator */
1658*a67afe4dSAndroid Build Coastguard Worker
1659*a67afe4dSAndroid Build Coastguard Worker /* We leave it to the application to meet PNG-1.0 requirements on the
1660*a67afe4dSAndroid Build Coastguard Worker * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
1661*a67afe4dSAndroid Build Coastguard Worker * any non-Latin-1 characters except for NEWLINE. ISO PNG, however,
1662*a67afe4dSAndroid Build Coastguard Worker * specifies that the text is UTF-8 and this really doesn't require any
1663*a67afe4dSAndroid Build Coastguard Worker * checking.
1664*a67afe4dSAndroid Build Coastguard Worker *
1665*a67afe4dSAndroid Build Coastguard Worker * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1666*a67afe4dSAndroid Build Coastguard Worker *
1667*a67afe4dSAndroid Build Coastguard Worker * TODO: validate the language tag correctly (see the spec.)
1668*a67afe4dSAndroid Build Coastguard Worker */
1669*a67afe4dSAndroid Build Coastguard Worker if (lang == NULL) lang = ""; /* empty language is valid */
1670*a67afe4dSAndroid Build Coastguard Worker lang_len = strlen(lang)+1;
1671*a67afe4dSAndroid Build Coastguard Worker if (lang_key == NULL) lang_key = ""; /* may be empty */
1672*a67afe4dSAndroid Build Coastguard Worker lang_key_len = strlen(lang_key)+1;
1673*a67afe4dSAndroid Build Coastguard Worker if (text == NULL) text = ""; /* may be empty */
1674*a67afe4dSAndroid Build Coastguard Worker
1675*a67afe4dSAndroid Build Coastguard Worker prefix_len = key_len;
1676*a67afe4dSAndroid Build Coastguard Worker if (lang_len > PNG_UINT_31_MAX-prefix_len)
1677*a67afe4dSAndroid Build Coastguard Worker prefix_len = PNG_UINT_31_MAX;
1678*a67afe4dSAndroid Build Coastguard Worker else
1679*a67afe4dSAndroid Build Coastguard Worker prefix_len = (png_uint_32)(prefix_len + lang_len);
1680*a67afe4dSAndroid Build Coastguard Worker
1681*a67afe4dSAndroid Build Coastguard Worker if (lang_key_len > PNG_UINT_31_MAX-prefix_len)
1682*a67afe4dSAndroid Build Coastguard Worker prefix_len = PNG_UINT_31_MAX;
1683*a67afe4dSAndroid Build Coastguard Worker else
1684*a67afe4dSAndroid Build Coastguard Worker prefix_len = (png_uint_32)(prefix_len + lang_key_len);
1685*a67afe4dSAndroid Build Coastguard Worker
1686*a67afe4dSAndroid Build Coastguard Worker png_text_compress_init(&comp, (png_const_bytep)text, strlen(text));
1687*a67afe4dSAndroid Build Coastguard Worker
1688*a67afe4dSAndroid Build Coastguard Worker if (compression != 0)
1689*a67afe4dSAndroid Build Coastguard Worker {
1690*a67afe4dSAndroid Build Coastguard Worker if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)
1691*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, png_ptr->zstream.msg);
1692*a67afe4dSAndroid Build Coastguard Worker }
1693*a67afe4dSAndroid Build Coastguard Worker
1694*a67afe4dSAndroid Build Coastguard Worker else
1695*a67afe4dSAndroid Build Coastguard Worker {
1696*a67afe4dSAndroid Build Coastguard Worker if (comp.input_len > PNG_UINT_31_MAX-prefix_len)
1697*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "iTXt: uncompressed text too long");
1698*a67afe4dSAndroid Build Coastguard Worker
1699*a67afe4dSAndroid Build Coastguard Worker /* So the string will fit in a chunk: */
1700*a67afe4dSAndroid Build Coastguard Worker comp.output_len = (png_uint_32)/*SAFE*/comp.input_len;
1701*a67afe4dSAndroid Build Coastguard Worker }
1702*a67afe4dSAndroid Build Coastguard Worker
1703*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len);
1704*a67afe4dSAndroid Build Coastguard Worker
1705*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, new_key, key_len);
1706*a67afe4dSAndroid Build Coastguard Worker
1707*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len);
1708*a67afe4dSAndroid Build Coastguard Worker
1709*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len);
1710*a67afe4dSAndroid Build Coastguard Worker
1711*a67afe4dSAndroid Build Coastguard Worker if (compression != 0)
1712*a67afe4dSAndroid Build Coastguard Worker png_write_compressed_data_out(png_ptr, &comp);
1713*a67afe4dSAndroid Build Coastguard Worker
1714*a67afe4dSAndroid Build Coastguard Worker else
1715*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len);
1716*a67afe4dSAndroid Build Coastguard Worker
1717*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1718*a67afe4dSAndroid Build Coastguard Worker }
1719*a67afe4dSAndroid Build Coastguard Worker #endif
1720*a67afe4dSAndroid Build Coastguard Worker
1721*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_oFFs_SUPPORTED
1722*a67afe4dSAndroid Build Coastguard Worker /* Write the oFFs chunk */
1723*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_oFFs(png_structrp png_ptr,png_int_32 x_offset,png_int_32 y_offset,int unit_type)1724*a67afe4dSAndroid Build Coastguard Worker png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
1725*a67afe4dSAndroid Build Coastguard Worker int unit_type)
1726*a67afe4dSAndroid Build Coastguard Worker {
1727*a67afe4dSAndroid Build Coastguard Worker png_byte buf[9];
1728*a67afe4dSAndroid Build Coastguard Worker
1729*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_oFFs");
1730*a67afe4dSAndroid Build Coastguard Worker
1731*a67afe4dSAndroid Build Coastguard Worker if (unit_type >= PNG_OFFSET_LAST)
1732*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
1733*a67afe4dSAndroid Build Coastguard Worker
1734*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf, x_offset);
1735*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 4, y_offset);
1736*a67afe4dSAndroid Build Coastguard Worker buf[8] = (png_byte)unit_type;
1737*a67afe4dSAndroid Build Coastguard Worker
1738*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_oFFs, buf, 9);
1739*a67afe4dSAndroid Build Coastguard Worker }
1740*a67afe4dSAndroid Build Coastguard Worker #endif
1741*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_pCAL_SUPPORTED
1742*a67afe4dSAndroid Build Coastguard Worker /* Write the pCAL chunk (described in the PNG extensions document) */
1743*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_pCAL(png_structrp png_ptr,png_charp purpose,png_int_32 X0,png_int_32 X1,int type,int nparams,png_const_charp units,png_charpp params)1744*a67afe4dSAndroid Build Coastguard Worker png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
1745*a67afe4dSAndroid Build Coastguard Worker png_int_32 X1, int type, int nparams, png_const_charp units,
1746*a67afe4dSAndroid Build Coastguard Worker png_charpp params)
1747*a67afe4dSAndroid Build Coastguard Worker {
1748*a67afe4dSAndroid Build Coastguard Worker png_uint_32 purpose_len;
1749*a67afe4dSAndroid Build Coastguard Worker size_t units_len, total_len;
1750*a67afe4dSAndroid Build Coastguard Worker size_t *params_len;
1751*a67afe4dSAndroid Build Coastguard Worker png_byte buf[10];
1752*a67afe4dSAndroid Build Coastguard Worker png_byte new_purpose[80];
1753*a67afe4dSAndroid Build Coastguard Worker int i;
1754*a67afe4dSAndroid Build Coastguard Worker
1755*a67afe4dSAndroid Build Coastguard Worker png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
1756*a67afe4dSAndroid Build Coastguard Worker
1757*a67afe4dSAndroid Build Coastguard Worker if (type >= PNG_EQUATION_LAST)
1758*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "Unrecognized equation type for pCAL chunk");
1759*a67afe4dSAndroid Build Coastguard Worker
1760*a67afe4dSAndroid Build Coastguard Worker purpose_len = png_check_keyword(png_ptr, purpose, new_purpose);
1761*a67afe4dSAndroid Build Coastguard Worker
1762*a67afe4dSAndroid Build Coastguard Worker if (purpose_len == 0)
1763*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "pCAL: invalid keyword");
1764*a67afe4dSAndroid Build Coastguard Worker
1765*a67afe4dSAndroid Build Coastguard Worker ++purpose_len; /* terminator */
1766*a67afe4dSAndroid Build Coastguard Worker
1767*a67afe4dSAndroid Build Coastguard Worker png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
1768*a67afe4dSAndroid Build Coastguard Worker units_len = strlen(units) + (nparams == 0 ? 0 : 1);
1769*a67afe4dSAndroid Build Coastguard Worker png_debug1(3, "pCAL units length = %d", (int)units_len);
1770*a67afe4dSAndroid Build Coastguard Worker total_len = purpose_len + units_len + 10;
1771*a67afe4dSAndroid Build Coastguard Worker
1772*a67afe4dSAndroid Build Coastguard Worker params_len = (size_t *)png_malloc(png_ptr,
1773*a67afe4dSAndroid Build Coastguard Worker (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t))));
1774*a67afe4dSAndroid Build Coastguard Worker
1775*a67afe4dSAndroid Build Coastguard Worker /* Find the length of each parameter, making sure we don't count the
1776*a67afe4dSAndroid Build Coastguard Worker * null terminator for the last parameter.
1777*a67afe4dSAndroid Build Coastguard Worker */
1778*a67afe4dSAndroid Build Coastguard Worker for (i = 0; i < nparams; i++)
1779*a67afe4dSAndroid Build Coastguard Worker {
1780*a67afe4dSAndroid Build Coastguard Worker params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
1781*a67afe4dSAndroid Build Coastguard Worker png_debug2(3, "pCAL parameter %d length = %lu", i,
1782*a67afe4dSAndroid Build Coastguard Worker (unsigned long)params_len[i]);
1783*a67afe4dSAndroid Build Coastguard Worker total_len += params_len[i];
1784*a67afe4dSAndroid Build Coastguard Worker }
1785*a67afe4dSAndroid Build Coastguard Worker
1786*a67afe4dSAndroid Build Coastguard Worker png_debug1(3, "pCAL total length = %d", (int)total_len);
1787*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len);
1788*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, new_purpose, purpose_len);
1789*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf, X0);
1790*a67afe4dSAndroid Build Coastguard Worker png_save_int_32(buf + 4, X1);
1791*a67afe4dSAndroid Build Coastguard Worker buf[8] = (png_byte)type;
1792*a67afe4dSAndroid Build Coastguard Worker buf[9] = (png_byte)nparams;
1793*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, buf, 10);
1794*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, (png_const_bytep)units, (size_t)units_len);
1795*a67afe4dSAndroid Build Coastguard Worker
1796*a67afe4dSAndroid Build Coastguard Worker for (i = 0; i < nparams; i++)
1797*a67afe4dSAndroid Build Coastguard Worker {
1798*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);
1799*a67afe4dSAndroid Build Coastguard Worker }
1800*a67afe4dSAndroid Build Coastguard Worker
1801*a67afe4dSAndroid Build Coastguard Worker png_free(png_ptr, params_len);
1802*a67afe4dSAndroid Build Coastguard Worker png_write_chunk_end(png_ptr);
1803*a67afe4dSAndroid Build Coastguard Worker }
1804*a67afe4dSAndroid Build Coastguard Worker #endif
1805*a67afe4dSAndroid Build Coastguard Worker
1806*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_sCAL_SUPPORTED
1807*a67afe4dSAndroid Build Coastguard Worker /* Write the sCAL chunk */
1808*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_sCAL_s(png_structrp png_ptr,int unit,png_const_charp width,png_const_charp height)1809*a67afe4dSAndroid Build Coastguard Worker png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width,
1810*a67afe4dSAndroid Build Coastguard Worker png_const_charp height)
1811*a67afe4dSAndroid Build Coastguard Worker {
1812*a67afe4dSAndroid Build Coastguard Worker png_byte buf[64];
1813*a67afe4dSAndroid Build Coastguard Worker size_t wlen, hlen, total_len;
1814*a67afe4dSAndroid Build Coastguard Worker
1815*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_sCAL_s");
1816*a67afe4dSAndroid Build Coastguard Worker
1817*a67afe4dSAndroid Build Coastguard Worker wlen = strlen(width);
1818*a67afe4dSAndroid Build Coastguard Worker hlen = strlen(height);
1819*a67afe4dSAndroid Build Coastguard Worker total_len = wlen + hlen + 2;
1820*a67afe4dSAndroid Build Coastguard Worker
1821*a67afe4dSAndroid Build Coastguard Worker if (total_len > 64)
1822*a67afe4dSAndroid Build Coastguard Worker {
1823*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Can't write sCAL (buffer too small)");
1824*a67afe4dSAndroid Build Coastguard Worker return;
1825*a67afe4dSAndroid Build Coastguard Worker }
1826*a67afe4dSAndroid Build Coastguard Worker
1827*a67afe4dSAndroid Build Coastguard Worker buf[0] = (png_byte)unit;
1828*a67afe4dSAndroid Build Coastguard Worker memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */
1829*a67afe4dSAndroid Build Coastguard Worker memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */
1830*a67afe4dSAndroid Build Coastguard Worker
1831*a67afe4dSAndroid Build Coastguard Worker png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
1832*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len);
1833*a67afe4dSAndroid Build Coastguard Worker }
1834*a67afe4dSAndroid Build Coastguard Worker #endif
1835*a67afe4dSAndroid Build Coastguard Worker
1836*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_pHYs_SUPPORTED
1837*a67afe4dSAndroid Build Coastguard Worker /* Write the pHYs chunk */
1838*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_pHYs(png_structrp png_ptr,png_uint_32 x_pixels_per_unit,png_uint_32 y_pixels_per_unit,int unit_type)1839*a67afe4dSAndroid Build Coastguard Worker png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit,
1840*a67afe4dSAndroid Build Coastguard Worker png_uint_32 y_pixels_per_unit,
1841*a67afe4dSAndroid Build Coastguard Worker int unit_type)
1842*a67afe4dSAndroid Build Coastguard Worker {
1843*a67afe4dSAndroid Build Coastguard Worker png_byte buf[9];
1844*a67afe4dSAndroid Build Coastguard Worker
1845*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_pHYs");
1846*a67afe4dSAndroid Build Coastguard Worker
1847*a67afe4dSAndroid Build Coastguard Worker if (unit_type >= PNG_RESOLUTION_LAST)
1848*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
1849*a67afe4dSAndroid Build Coastguard Worker
1850*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf, x_pixels_per_unit);
1851*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(buf + 4, y_pixels_per_unit);
1852*a67afe4dSAndroid Build Coastguard Worker buf[8] = (png_byte)unit_type;
1853*a67afe4dSAndroid Build Coastguard Worker
1854*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_pHYs, buf, 9);
1855*a67afe4dSAndroid Build Coastguard Worker }
1856*a67afe4dSAndroid Build Coastguard Worker #endif
1857*a67afe4dSAndroid Build Coastguard Worker
1858*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_tIME_SUPPORTED
1859*a67afe4dSAndroid Build Coastguard Worker /* Write the tIME chunk. Use either png_convert_from_struct_tm()
1860*a67afe4dSAndroid Build Coastguard Worker * or png_convert_from_time_t(), or fill in the structure yourself.
1861*a67afe4dSAndroid Build Coastguard Worker */
1862*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_tIME(png_structrp png_ptr,png_const_timep mod_time)1863*a67afe4dSAndroid Build Coastguard Worker png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
1864*a67afe4dSAndroid Build Coastguard Worker {
1865*a67afe4dSAndroid Build Coastguard Worker png_byte buf[7];
1866*a67afe4dSAndroid Build Coastguard Worker
1867*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_tIME");
1868*a67afe4dSAndroid Build Coastguard Worker
1869*a67afe4dSAndroid Build Coastguard Worker if (mod_time->month > 12 || mod_time->month < 1 ||
1870*a67afe4dSAndroid Build Coastguard Worker mod_time->day > 31 || mod_time->day < 1 ||
1871*a67afe4dSAndroid Build Coastguard Worker mod_time->hour > 23 || mod_time->second > 60)
1872*a67afe4dSAndroid Build Coastguard Worker {
1873*a67afe4dSAndroid Build Coastguard Worker png_warning(png_ptr, "Invalid time specified for tIME chunk");
1874*a67afe4dSAndroid Build Coastguard Worker return;
1875*a67afe4dSAndroid Build Coastguard Worker }
1876*a67afe4dSAndroid Build Coastguard Worker
1877*a67afe4dSAndroid Build Coastguard Worker png_save_uint_16(buf, mod_time->year);
1878*a67afe4dSAndroid Build Coastguard Worker buf[2] = mod_time->month;
1879*a67afe4dSAndroid Build Coastguard Worker buf[3] = mod_time->day;
1880*a67afe4dSAndroid Build Coastguard Worker buf[4] = mod_time->hour;
1881*a67afe4dSAndroid Build Coastguard Worker buf[5] = mod_time->minute;
1882*a67afe4dSAndroid Build Coastguard Worker buf[6] = mod_time->second;
1883*a67afe4dSAndroid Build Coastguard Worker
1884*a67afe4dSAndroid Build Coastguard Worker png_write_complete_chunk(png_ptr, png_tIME, buf, 7);
1885*a67afe4dSAndroid Build Coastguard Worker }
1886*a67afe4dSAndroid Build Coastguard Worker #endif
1887*a67afe4dSAndroid Build Coastguard Worker
1888*a67afe4dSAndroid Build Coastguard Worker /* Initializes the row writing capability of libpng */
1889*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_start_row(png_structrp png_ptr)1890*a67afe4dSAndroid Build Coastguard Worker png_write_start_row(png_structrp png_ptr)
1891*a67afe4dSAndroid Build Coastguard Worker {
1892*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_INTERLACING_SUPPORTED
1893*a67afe4dSAndroid Build Coastguard Worker /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1894*a67afe4dSAndroid Build Coastguard Worker
1895*a67afe4dSAndroid Build Coastguard Worker /* Start of interlace block */
1896*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1897*a67afe4dSAndroid Build Coastguard Worker
1898*a67afe4dSAndroid Build Coastguard Worker /* Offset to next interlace block */
1899*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1900*a67afe4dSAndroid Build Coastguard Worker
1901*a67afe4dSAndroid Build Coastguard Worker /* Start of interlace block in the y direction */
1902*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1903*a67afe4dSAndroid Build Coastguard Worker
1904*a67afe4dSAndroid Build Coastguard Worker /* Offset to next interlace block in the y direction */
1905*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
1906*a67afe4dSAndroid Build Coastguard Worker #endif
1907*a67afe4dSAndroid Build Coastguard Worker
1908*a67afe4dSAndroid Build Coastguard Worker png_alloc_size_t buf_size;
1909*a67afe4dSAndroid Build Coastguard Worker int usr_pixel_depth;
1910*a67afe4dSAndroid Build Coastguard Worker
1911*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_FILTER_SUPPORTED
1912*a67afe4dSAndroid Build Coastguard Worker png_byte filters;
1913*a67afe4dSAndroid Build Coastguard Worker #endif
1914*a67afe4dSAndroid Build Coastguard Worker
1915*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_start_row");
1916*a67afe4dSAndroid Build Coastguard Worker
1917*a67afe4dSAndroid Build Coastguard Worker usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;
1918*a67afe4dSAndroid Build Coastguard Worker buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1;
1919*a67afe4dSAndroid Build Coastguard Worker
1920*a67afe4dSAndroid Build Coastguard Worker /* 1.5.6: added to allow checking in the row write code. */
1921*a67afe4dSAndroid Build Coastguard Worker png_ptr->transformed_pixel_depth = png_ptr->pixel_depth;
1922*a67afe4dSAndroid Build Coastguard Worker png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;
1923*a67afe4dSAndroid Build Coastguard Worker
1924*a67afe4dSAndroid Build Coastguard Worker /* Set up row buffer */
1925*a67afe4dSAndroid Build Coastguard Worker png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
1926*a67afe4dSAndroid Build Coastguard Worker
1927*a67afe4dSAndroid Build Coastguard Worker png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
1928*a67afe4dSAndroid Build Coastguard Worker
1929*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_FILTER_SUPPORTED
1930*a67afe4dSAndroid Build Coastguard Worker filters = png_ptr->do_filter;
1931*a67afe4dSAndroid Build Coastguard Worker
1932*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->height == 1)
1933*a67afe4dSAndroid Build Coastguard Worker filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
1934*a67afe4dSAndroid Build Coastguard Worker
1935*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->width == 1)
1936*a67afe4dSAndroid Build Coastguard Worker filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
1937*a67afe4dSAndroid Build Coastguard Worker
1938*a67afe4dSAndroid Build Coastguard Worker if (filters == 0)
1939*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_NONE;
1940*a67afe4dSAndroid Build Coastguard Worker
1941*a67afe4dSAndroid Build Coastguard Worker png_ptr->do_filter = filters;
1942*a67afe4dSAndroid Build Coastguard Worker
1943*a67afe4dSAndroid Build Coastguard Worker if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG |
1944*a67afe4dSAndroid Build Coastguard Worker PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL)
1945*a67afe4dSAndroid Build Coastguard Worker {
1946*a67afe4dSAndroid Build Coastguard Worker int num_filters = 0;
1947*a67afe4dSAndroid Build Coastguard Worker
1948*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
1949*a67afe4dSAndroid Build Coastguard Worker
1950*a67afe4dSAndroid Build Coastguard Worker if (filters & PNG_FILTER_SUB)
1951*a67afe4dSAndroid Build Coastguard Worker num_filters++;
1952*a67afe4dSAndroid Build Coastguard Worker
1953*a67afe4dSAndroid Build Coastguard Worker if (filters & PNG_FILTER_UP)
1954*a67afe4dSAndroid Build Coastguard Worker num_filters++;
1955*a67afe4dSAndroid Build Coastguard Worker
1956*a67afe4dSAndroid Build Coastguard Worker if (filters & PNG_FILTER_AVG)
1957*a67afe4dSAndroid Build Coastguard Worker num_filters++;
1958*a67afe4dSAndroid Build Coastguard Worker
1959*a67afe4dSAndroid Build Coastguard Worker if (filters & PNG_FILTER_PAETH)
1960*a67afe4dSAndroid Build Coastguard Worker num_filters++;
1961*a67afe4dSAndroid Build Coastguard Worker
1962*a67afe4dSAndroid Build Coastguard Worker if (num_filters > 1)
1963*a67afe4dSAndroid Build Coastguard Worker png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr,
1964*a67afe4dSAndroid Build Coastguard Worker buf_size));
1965*a67afe4dSAndroid Build Coastguard Worker }
1966*a67afe4dSAndroid Build Coastguard Worker
1967*a67afe4dSAndroid Build Coastguard Worker /* We only need to keep the previous row if we are using one of the following
1968*a67afe4dSAndroid Build Coastguard Worker * filters.
1969*a67afe4dSAndroid Build Coastguard Worker */
1970*a67afe4dSAndroid Build Coastguard Worker if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0)
1971*a67afe4dSAndroid Build Coastguard Worker png_ptr->prev_row = png_voidcast(png_bytep,
1972*a67afe4dSAndroid Build Coastguard Worker png_calloc(png_ptr, buf_size));
1973*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE_FILTER */
1974*a67afe4dSAndroid Build Coastguard Worker
1975*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_INTERLACING_SUPPORTED
1976*a67afe4dSAndroid Build Coastguard Worker /* If interlaced, we need to set up width and height of pass */
1977*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->interlaced != 0)
1978*a67afe4dSAndroid Build Coastguard Worker {
1979*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->transformations & PNG_INTERLACE) == 0)
1980*a67afe4dSAndroid Build Coastguard Worker {
1981*a67afe4dSAndroid Build Coastguard Worker png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
1982*a67afe4dSAndroid Build Coastguard Worker png_pass_ystart[0]) / png_pass_yinc[0];
1983*a67afe4dSAndroid Build Coastguard Worker
1984*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
1985*a67afe4dSAndroid Build Coastguard Worker png_pass_start[0]) / png_pass_inc[0];
1986*a67afe4dSAndroid Build Coastguard Worker }
1987*a67afe4dSAndroid Build Coastguard Worker
1988*a67afe4dSAndroid Build Coastguard Worker else
1989*a67afe4dSAndroid Build Coastguard Worker {
1990*a67afe4dSAndroid Build Coastguard Worker png_ptr->num_rows = png_ptr->height;
1991*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_width = png_ptr->width;
1992*a67afe4dSAndroid Build Coastguard Worker }
1993*a67afe4dSAndroid Build Coastguard Worker }
1994*a67afe4dSAndroid Build Coastguard Worker
1995*a67afe4dSAndroid Build Coastguard Worker else
1996*a67afe4dSAndroid Build Coastguard Worker #endif
1997*a67afe4dSAndroid Build Coastguard Worker {
1998*a67afe4dSAndroid Build Coastguard Worker png_ptr->num_rows = png_ptr->height;
1999*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_width = png_ptr->width;
2000*a67afe4dSAndroid Build Coastguard Worker }
2001*a67afe4dSAndroid Build Coastguard Worker }
2002*a67afe4dSAndroid Build Coastguard Worker
2003*a67afe4dSAndroid Build Coastguard Worker /* Internal use only. Called when finished processing a row of data. */
2004*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_finish_row(png_structrp png_ptr)2005*a67afe4dSAndroid Build Coastguard Worker png_write_finish_row(png_structrp png_ptr)
2006*a67afe4dSAndroid Build Coastguard Worker {
2007*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_INTERLACING_SUPPORTED
2008*a67afe4dSAndroid Build Coastguard Worker /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2009*a67afe4dSAndroid Build Coastguard Worker
2010*a67afe4dSAndroid Build Coastguard Worker /* Start of interlace block */
2011*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
2012*a67afe4dSAndroid Build Coastguard Worker
2013*a67afe4dSAndroid Build Coastguard Worker /* Offset to next interlace block */
2014*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
2015*a67afe4dSAndroid Build Coastguard Worker
2016*a67afe4dSAndroid Build Coastguard Worker /* Start of interlace block in the y direction */
2017*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
2018*a67afe4dSAndroid Build Coastguard Worker
2019*a67afe4dSAndroid Build Coastguard Worker /* Offset to next interlace block in the y direction */
2020*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
2021*a67afe4dSAndroid Build Coastguard Worker #endif
2022*a67afe4dSAndroid Build Coastguard Worker
2023*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_finish_row");
2024*a67afe4dSAndroid Build Coastguard Worker
2025*a67afe4dSAndroid Build Coastguard Worker /* Next row */
2026*a67afe4dSAndroid Build Coastguard Worker png_ptr->row_number++;
2027*a67afe4dSAndroid Build Coastguard Worker
2028*a67afe4dSAndroid Build Coastguard Worker /* See if we are done */
2029*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->row_number < png_ptr->num_rows)
2030*a67afe4dSAndroid Build Coastguard Worker return;
2031*a67afe4dSAndroid Build Coastguard Worker
2032*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_INTERLACING_SUPPORTED
2033*a67afe4dSAndroid Build Coastguard Worker /* If interlaced, go to next pass */
2034*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->interlaced != 0)
2035*a67afe4dSAndroid Build Coastguard Worker {
2036*a67afe4dSAndroid Build Coastguard Worker png_ptr->row_number = 0;
2037*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->transformations & PNG_INTERLACE) != 0)
2038*a67afe4dSAndroid Build Coastguard Worker {
2039*a67afe4dSAndroid Build Coastguard Worker png_ptr->pass++;
2040*a67afe4dSAndroid Build Coastguard Worker }
2041*a67afe4dSAndroid Build Coastguard Worker
2042*a67afe4dSAndroid Build Coastguard Worker else
2043*a67afe4dSAndroid Build Coastguard Worker {
2044*a67afe4dSAndroid Build Coastguard Worker /* Loop until we find a non-zero width or height pass */
2045*a67afe4dSAndroid Build Coastguard Worker do
2046*a67afe4dSAndroid Build Coastguard Worker {
2047*a67afe4dSAndroid Build Coastguard Worker png_ptr->pass++;
2048*a67afe4dSAndroid Build Coastguard Worker
2049*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->pass >= 7)
2050*a67afe4dSAndroid Build Coastguard Worker break;
2051*a67afe4dSAndroid Build Coastguard Worker
2052*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_width = (png_ptr->width +
2053*a67afe4dSAndroid Build Coastguard Worker png_pass_inc[png_ptr->pass] - 1 -
2054*a67afe4dSAndroid Build Coastguard Worker png_pass_start[png_ptr->pass]) /
2055*a67afe4dSAndroid Build Coastguard Worker png_pass_inc[png_ptr->pass];
2056*a67afe4dSAndroid Build Coastguard Worker
2057*a67afe4dSAndroid Build Coastguard Worker png_ptr->num_rows = (png_ptr->height +
2058*a67afe4dSAndroid Build Coastguard Worker png_pass_yinc[png_ptr->pass] - 1 -
2059*a67afe4dSAndroid Build Coastguard Worker png_pass_ystart[png_ptr->pass]) /
2060*a67afe4dSAndroid Build Coastguard Worker png_pass_yinc[png_ptr->pass];
2061*a67afe4dSAndroid Build Coastguard Worker
2062*a67afe4dSAndroid Build Coastguard Worker if ((png_ptr->transformations & PNG_INTERLACE) != 0)
2063*a67afe4dSAndroid Build Coastguard Worker break;
2064*a67afe4dSAndroid Build Coastguard Worker
2065*a67afe4dSAndroid Build Coastguard Worker } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
2066*a67afe4dSAndroid Build Coastguard Worker
2067*a67afe4dSAndroid Build Coastguard Worker }
2068*a67afe4dSAndroid Build Coastguard Worker
2069*a67afe4dSAndroid Build Coastguard Worker /* Reset the row above the image for the next pass */
2070*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->pass < 7)
2071*a67afe4dSAndroid Build Coastguard Worker {
2072*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->prev_row != NULL)
2073*a67afe4dSAndroid Build Coastguard Worker memset(png_ptr->prev_row, 0,
2074*a67afe4dSAndroid Build Coastguard Worker PNG_ROWBYTES(png_ptr->usr_channels *
2075*a67afe4dSAndroid Build Coastguard Worker png_ptr->usr_bit_depth, png_ptr->width) + 1);
2076*a67afe4dSAndroid Build Coastguard Worker
2077*a67afe4dSAndroid Build Coastguard Worker return;
2078*a67afe4dSAndroid Build Coastguard Worker }
2079*a67afe4dSAndroid Build Coastguard Worker }
2080*a67afe4dSAndroid Build Coastguard Worker #endif
2081*a67afe4dSAndroid Build Coastguard Worker
2082*a67afe4dSAndroid Build Coastguard Worker /* If we get here, we've just written the last row, so we need
2083*a67afe4dSAndroid Build Coastguard Worker to flush the compressor */
2084*a67afe4dSAndroid Build Coastguard Worker png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH);
2085*a67afe4dSAndroid Build Coastguard Worker }
2086*a67afe4dSAndroid Build Coastguard Worker
2087*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_INTERLACING_SUPPORTED
2088*a67afe4dSAndroid Build Coastguard Worker /* Pick out the correct pixels for the interlace pass.
2089*a67afe4dSAndroid Build Coastguard Worker * The basic idea here is to go through the row with a source
2090*a67afe4dSAndroid Build Coastguard Worker * pointer and a destination pointer (sp and dp), and copy the
2091*a67afe4dSAndroid Build Coastguard Worker * correct pixels for the pass. As the row gets compacted,
2092*a67afe4dSAndroid Build Coastguard Worker * sp will always be >= dp, so we should never overwrite anything.
2093*a67afe4dSAndroid Build Coastguard Worker * See the default: case for the easiest code to understand.
2094*a67afe4dSAndroid Build Coastguard Worker */
2095*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_do_write_interlace(png_row_infop row_info,png_bytep row,int pass)2096*a67afe4dSAndroid Build Coastguard Worker png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
2097*a67afe4dSAndroid Build Coastguard Worker {
2098*a67afe4dSAndroid Build Coastguard Worker /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2099*a67afe4dSAndroid Build Coastguard Worker
2100*a67afe4dSAndroid Build Coastguard Worker /* Start of interlace block */
2101*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
2102*a67afe4dSAndroid Build Coastguard Worker
2103*a67afe4dSAndroid Build Coastguard Worker /* Offset to next interlace block */
2104*a67afe4dSAndroid Build Coastguard Worker static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
2105*a67afe4dSAndroid Build Coastguard Worker
2106*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_do_write_interlace");
2107*a67afe4dSAndroid Build Coastguard Worker
2108*a67afe4dSAndroid Build Coastguard Worker /* We don't have to do anything on the last pass (6) */
2109*a67afe4dSAndroid Build Coastguard Worker if (pass < 6)
2110*a67afe4dSAndroid Build Coastguard Worker {
2111*a67afe4dSAndroid Build Coastguard Worker /* Each pixel depth is handled separately */
2112*a67afe4dSAndroid Build Coastguard Worker switch (row_info->pixel_depth)
2113*a67afe4dSAndroid Build Coastguard Worker {
2114*a67afe4dSAndroid Build Coastguard Worker case 1:
2115*a67afe4dSAndroid Build Coastguard Worker {
2116*a67afe4dSAndroid Build Coastguard Worker png_bytep sp;
2117*a67afe4dSAndroid Build Coastguard Worker png_bytep dp;
2118*a67afe4dSAndroid Build Coastguard Worker unsigned int shift;
2119*a67afe4dSAndroid Build Coastguard Worker int d;
2120*a67afe4dSAndroid Build Coastguard Worker int value;
2121*a67afe4dSAndroid Build Coastguard Worker png_uint_32 i;
2122*a67afe4dSAndroid Build Coastguard Worker png_uint_32 row_width = row_info->width;
2123*a67afe4dSAndroid Build Coastguard Worker
2124*a67afe4dSAndroid Build Coastguard Worker dp = row;
2125*a67afe4dSAndroid Build Coastguard Worker d = 0;
2126*a67afe4dSAndroid Build Coastguard Worker shift = 7;
2127*a67afe4dSAndroid Build Coastguard Worker
2128*a67afe4dSAndroid Build Coastguard Worker for (i = png_pass_start[pass]; i < row_width;
2129*a67afe4dSAndroid Build Coastguard Worker i += png_pass_inc[pass])
2130*a67afe4dSAndroid Build Coastguard Worker {
2131*a67afe4dSAndroid Build Coastguard Worker sp = row + (size_t)(i >> 3);
2132*a67afe4dSAndroid Build Coastguard Worker value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
2133*a67afe4dSAndroid Build Coastguard Worker d |= (value << shift);
2134*a67afe4dSAndroid Build Coastguard Worker
2135*a67afe4dSAndroid Build Coastguard Worker if (shift == 0)
2136*a67afe4dSAndroid Build Coastguard Worker {
2137*a67afe4dSAndroid Build Coastguard Worker shift = 7;
2138*a67afe4dSAndroid Build Coastguard Worker *dp++ = (png_byte)d;
2139*a67afe4dSAndroid Build Coastguard Worker d = 0;
2140*a67afe4dSAndroid Build Coastguard Worker }
2141*a67afe4dSAndroid Build Coastguard Worker
2142*a67afe4dSAndroid Build Coastguard Worker else
2143*a67afe4dSAndroid Build Coastguard Worker shift--;
2144*a67afe4dSAndroid Build Coastguard Worker
2145*a67afe4dSAndroid Build Coastguard Worker }
2146*a67afe4dSAndroid Build Coastguard Worker if (shift != 7)
2147*a67afe4dSAndroid Build Coastguard Worker *dp = (png_byte)d;
2148*a67afe4dSAndroid Build Coastguard Worker
2149*a67afe4dSAndroid Build Coastguard Worker break;
2150*a67afe4dSAndroid Build Coastguard Worker }
2151*a67afe4dSAndroid Build Coastguard Worker
2152*a67afe4dSAndroid Build Coastguard Worker case 2:
2153*a67afe4dSAndroid Build Coastguard Worker {
2154*a67afe4dSAndroid Build Coastguard Worker png_bytep sp;
2155*a67afe4dSAndroid Build Coastguard Worker png_bytep dp;
2156*a67afe4dSAndroid Build Coastguard Worker unsigned int shift;
2157*a67afe4dSAndroid Build Coastguard Worker int d;
2158*a67afe4dSAndroid Build Coastguard Worker int value;
2159*a67afe4dSAndroid Build Coastguard Worker png_uint_32 i;
2160*a67afe4dSAndroid Build Coastguard Worker png_uint_32 row_width = row_info->width;
2161*a67afe4dSAndroid Build Coastguard Worker
2162*a67afe4dSAndroid Build Coastguard Worker dp = row;
2163*a67afe4dSAndroid Build Coastguard Worker shift = 6;
2164*a67afe4dSAndroid Build Coastguard Worker d = 0;
2165*a67afe4dSAndroid Build Coastguard Worker
2166*a67afe4dSAndroid Build Coastguard Worker for (i = png_pass_start[pass]; i < row_width;
2167*a67afe4dSAndroid Build Coastguard Worker i += png_pass_inc[pass])
2168*a67afe4dSAndroid Build Coastguard Worker {
2169*a67afe4dSAndroid Build Coastguard Worker sp = row + (size_t)(i >> 2);
2170*a67afe4dSAndroid Build Coastguard Worker value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
2171*a67afe4dSAndroid Build Coastguard Worker d |= (value << shift);
2172*a67afe4dSAndroid Build Coastguard Worker
2173*a67afe4dSAndroid Build Coastguard Worker if (shift == 0)
2174*a67afe4dSAndroid Build Coastguard Worker {
2175*a67afe4dSAndroid Build Coastguard Worker shift = 6;
2176*a67afe4dSAndroid Build Coastguard Worker *dp++ = (png_byte)d;
2177*a67afe4dSAndroid Build Coastguard Worker d = 0;
2178*a67afe4dSAndroid Build Coastguard Worker }
2179*a67afe4dSAndroid Build Coastguard Worker
2180*a67afe4dSAndroid Build Coastguard Worker else
2181*a67afe4dSAndroid Build Coastguard Worker shift -= 2;
2182*a67afe4dSAndroid Build Coastguard Worker }
2183*a67afe4dSAndroid Build Coastguard Worker if (shift != 6)
2184*a67afe4dSAndroid Build Coastguard Worker *dp = (png_byte)d;
2185*a67afe4dSAndroid Build Coastguard Worker
2186*a67afe4dSAndroid Build Coastguard Worker break;
2187*a67afe4dSAndroid Build Coastguard Worker }
2188*a67afe4dSAndroid Build Coastguard Worker
2189*a67afe4dSAndroid Build Coastguard Worker case 4:
2190*a67afe4dSAndroid Build Coastguard Worker {
2191*a67afe4dSAndroid Build Coastguard Worker png_bytep sp;
2192*a67afe4dSAndroid Build Coastguard Worker png_bytep dp;
2193*a67afe4dSAndroid Build Coastguard Worker unsigned int shift;
2194*a67afe4dSAndroid Build Coastguard Worker int d;
2195*a67afe4dSAndroid Build Coastguard Worker int value;
2196*a67afe4dSAndroid Build Coastguard Worker png_uint_32 i;
2197*a67afe4dSAndroid Build Coastguard Worker png_uint_32 row_width = row_info->width;
2198*a67afe4dSAndroid Build Coastguard Worker
2199*a67afe4dSAndroid Build Coastguard Worker dp = row;
2200*a67afe4dSAndroid Build Coastguard Worker shift = 4;
2201*a67afe4dSAndroid Build Coastguard Worker d = 0;
2202*a67afe4dSAndroid Build Coastguard Worker for (i = png_pass_start[pass]; i < row_width;
2203*a67afe4dSAndroid Build Coastguard Worker i += png_pass_inc[pass])
2204*a67afe4dSAndroid Build Coastguard Worker {
2205*a67afe4dSAndroid Build Coastguard Worker sp = row + (size_t)(i >> 1);
2206*a67afe4dSAndroid Build Coastguard Worker value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
2207*a67afe4dSAndroid Build Coastguard Worker d |= (value << shift);
2208*a67afe4dSAndroid Build Coastguard Worker
2209*a67afe4dSAndroid Build Coastguard Worker if (shift == 0)
2210*a67afe4dSAndroid Build Coastguard Worker {
2211*a67afe4dSAndroid Build Coastguard Worker shift = 4;
2212*a67afe4dSAndroid Build Coastguard Worker *dp++ = (png_byte)d;
2213*a67afe4dSAndroid Build Coastguard Worker d = 0;
2214*a67afe4dSAndroid Build Coastguard Worker }
2215*a67afe4dSAndroid Build Coastguard Worker
2216*a67afe4dSAndroid Build Coastguard Worker else
2217*a67afe4dSAndroid Build Coastguard Worker shift -= 4;
2218*a67afe4dSAndroid Build Coastguard Worker }
2219*a67afe4dSAndroid Build Coastguard Worker if (shift != 4)
2220*a67afe4dSAndroid Build Coastguard Worker *dp = (png_byte)d;
2221*a67afe4dSAndroid Build Coastguard Worker
2222*a67afe4dSAndroid Build Coastguard Worker break;
2223*a67afe4dSAndroid Build Coastguard Worker }
2224*a67afe4dSAndroid Build Coastguard Worker
2225*a67afe4dSAndroid Build Coastguard Worker default:
2226*a67afe4dSAndroid Build Coastguard Worker {
2227*a67afe4dSAndroid Build Coastguard Worker png_bytep sp;
2228*a67afe4dSAndroid Build Coastguard Worker png_bytep dp;
2229*a67afe4dSAndroid Build Coastguard Worker png_uint_32 i;
2230*a67afe4dSAndroid Build Coastguard Worker png_uint_32 row_width = row_info->width;
2231*a67afe4dSAndroid Build Coastguard Worker size_t pixel_bytes;
2232*a67afe4dSAndroid Build Coastguard Worker
2233*a67afe4dSAndroid Build Coastguard Worker /* Start at the beginning */
2234*a67afe4dSAndroid Build Coastguard Worker dp = row;
2235*a67afe4dSAndroid Build Coastguard Worker
2236*a67afe4dSAndroid Build Coastguard Worker /* Find out how many bytes each pixel takes up */
2237*a67afe4dSAndroid Build Coastguard Worker pixel_bytes = (row_info->pixel_depth >> 3);
2238*a67afe4dSAndroid Build Coastguard Worker
2239*a67afe4dSAndroid Build Coastguard Worker /* Loop through the row, only looking at the pixels that matter */
2240*a67afe4dSAndroid Build Coastguard Worker for (i = png_pass_start[pass]; i < row_width;
2241*a67afe4dSAndroid Build Coastguard Worker i += png_pass_inc[pass])
2242*a67afe4dSAndroid Build Coastguard Worker {
2243*a67afe4dSAndroid Build Coastguard Worker /* Find out where the original pixel is */
2244*a67afe4dSAndroid Build Coastguard Worker sp = row + (size_t)i * pixel_bytes;
2245*a67afe4dSAndroid Build Coastguard Worker
2246*a67afe4dSAndroid Build Coastguard Worker /* Move the pixel */
2247*a67afe4dSAndroid Build Coastguard Worker if (dp != sp)
2248*a67afe4dSAndroid Build Coastguard Worker memcpy(dp, sp, pixel_bytes);
2249*a67afe4dSAndroid Build Coastguard Worker
2250*a67afe4dSAndroid Build Coastguard Worker /* Next pixel */
2251*a67afe4dSAndroid Build Coastguard Worker dp += pixel_bytes;
2252*a67afe4dSAndroid Build Coastguard Worker }
2253*a67afe4dSAndroid Build Coastguard Worker break;
2254*a67afe4dSAndroid Build Coastguard Worker }
2255*a67afe4dSAndroid Build Coastguard Worker }
2256*a67afe4dSAndroid Build Coastguard Worker /* Set new row width */
2257*a67afe4dSAndroid Build Coastguard Worker row_info->width = (row_info->width +
2258*a67afe4dSAndroid Build Coastguard Worker png_pass_inc[pass] - 1 -
2259*a67afe4dSAndroid Build Coastguard Worker png_pass_start[pass]) /
2260*a67afe4dSAndroid Build Coastguard Worker png_pass_inc[pass];
2261*a67afe4dSAndroid Build Coastguard Worker
2262*a67afe4dSAndroid Build Coastguard Worker row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
2263*a67afe4dSAndroid Build Coastguard Worker row_info->width);
2264*a67afe4dSAndroid Build Coastguard Worker }
2265*a67afe4dSAndroid Build Coastguard Worker }
2266*a67afe4dSAndroid Build Coastguard Worker #endif
2267*a67afe4dSAndroid Build Coastguard Worker
2268*a67afe4dSAndroid Build Coastguard Worker
2269*a67afe4dSAndroid Build Coastguard Worker /* This filters the row, chooses which filter to use, if it has not already
2270*a67afe4dSAndroid Build Coastguard Worker * been specified by the application, and then writes the row out with the
2271*a67afe4dSAndroid Build Coastguard Worker * chosen filter.
2272*a67afe4dSAndroid Build Coastguard Worker */
2273*a67afe4dSAndroid Build Coastguard Worker static void /* PRIVATE */
2274*a67afe4dSAndroid Build Coastguard Worker png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
2275*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes);
2276*a67afe4dSAndroid Build Coastguard Worker
2277*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_FILTER_SUPPORTED
2278*a67afe4dSAndroid Build Coastguard Worker static size_t /* PRIVATE */
png_setup_sub_row(png_structrp png_ptr,png_uint_32 bpp,size_t row_bytes,size_t lmins)2279*a67afe4dSAndroid Build Coastguard Worker png_setup_sub_row(png_structrp png_ptr, png_uint_32 bpp,
2280*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes, size_t lmins)
2281*a67afe4dSAndroid Build Coastguard Worker {
2282*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, lp;
2283*a67afe4dSAndroid Build Coastguard Worker size_t i;
2284*a67afe4dSAndroid Build Coastguard Worker size_t sum = 0;
2285*a67afe4dSAndroid Build Coastguard Worker unsigned int v;
2286*a67afe4dSAndroid Build Coastguard Worker
2287*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
2288*a67afe4dSAndroid Build Coastguard Worker
2289*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
2290*a67afe4dSAndroid Build Coastguard Worker i++, rp++, dp++)
2291*a67afe4dSAndroid Build Coastguard Worker {
2292*a67afe4dSAndroid Build Coastguard Worker v = *dp = *rp;
2293*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2294*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2295*a67afe4dSAndroid Build Coastguard Worker #else
2296*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2297*a67afe4dSAndroid Build Coastguard Worker #endif
2298*a67afe4dSAndroid Build Coastguard Worker }
2299*a67afe4dSAndroid Build Coastguard Worker
2300*a67afe4dSAndroid Build Coastguard Worker for (lp = png_ptr->row_buf + 1; i < row_bytes;
2301*a67afe4dSAndroid Build Coastguard Worker i++, rp++, lp++, dp++)
2302*a67afe4dSAndroid Build Coastguard Worker {
2303*a67afe4dSAndroid Build Coastguard Worker v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
2304*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2305*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2306*a67afe4dSAndroid Build Coastguard Worker #else
2307*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2308*a67afe4dSAndroid Build Coastguard Worker #endif
2309*a67afe4dSAndroid Build Coastguard Worker
2310*a67afe4dSAndroid Build Coastguard Worker if (sum > lmins) /* We are already worse, don't continue. */
2311*a67afe4dSAndroid Build Coastguard Worker break;
2312*a67afe4dSAndroid Build Coastguard Worker }
2313*a67afe4dSAndroid Build Coastguard Worker
2314*a67afe4dSAndroid Build Coastguard Worker return sum;
2315*a67afe4dSAndroid Build Coastguard Worker }
2316*a67afe4dSAndroid Build Coastguard Worker
2317*a67afe4dSAndroid Build Coastguard Worker static void /* PRIVATE */
png_setup_sub_row_only(png_structrp png_ptr,png_uint_32 bpp,size_t row_bytes)2318*a67afe4dSAndroid Build Coastguard Worker png_setup_sub_row_only(png_structrp png_ptr, png_uint_32 bpp,
2319*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes)
2320*a67afe4dSAndroid Build Coastguard Worker {
2321*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, lp;
2322*a67afe4dSAndroid Build Coastguard Worker size_t i;
2323*a67afe4dSAndroid Build Coastguard Worker
2324*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
2325*a67afe4dSAndroid Build Coastguard Worker
2326*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
2327*a67afe4dSAndroid Build Coastguard Worker i++, rp++, dp++)
2328*a67afe4dSAndroid Build Coastguard Worker {
2329*a67afe4dSAndroid Build Coastguard Worker *dp = *rp;
2330*a67afe4dSAndroid Build Coastguard Worker }
2331*a67afe4dSAndroid Build Coastguard Worker
2332*a67afe4dSAndroid Build Coastguard Worker for (lp = png_ptr->row_buf + 1; i < row_bytes;
2333*a67afe4dSAndroid Build Coastguard Worker i++, rp++, lp++, dp++)
2334*a67afe4dSAndroid Build Coastguard Worker {
2335*a67afe4dSAndroid Build Coastguard Worker *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
2336*a67afe4dSAndroid Build Coastguard Worker }
2337*a67afe4dSAndroid Build Coastguard Worker }
2338*a67afe4dSAndroid Build Coastguard Worker
2339*a67afe4dSAndroid Build Coastguard Worker static size_t /* PRIVATE */
png_setup_up_row(png_structrp png_ptr,size_t row_bytes,size_t lmins)2340*a67afe4dSAndroid Build Coastguard Worker png_setup_up_row(png_structrp png_ptr, size_t row_bytes, size_t lmins)
2341*a67afe4dSAndroid Build Coastguard Worker {
2342*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, pp;
2343*a67afe4dSAndroid Build Coastguard Worker size_t i;
2344*a67afe4dSAndroid Build Coastguard Worker size_t sum = 0;
2345*a67afe4dSAndroid Build Coastguard Worker unsigned int v;
2346*a67afe4dSAndroid Build Coastguard Worker
2347*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
2348*a67afe4dSAndroid Build Coastguard Worker
2349*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
2350*a67afe4dSAndroid Build Coastguard Worker pp = png_ptr->prev_row + 1; i < row_bytes;
2351*a67afe4dSAndroid Build Coastguard Worker i++, rp++, pp++, dp++)
2352*a67afe4dSAndroid Build Coastguard Worker {
2353*a67afe4dSAndroid Build Coastguard Worker v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
2354*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2355*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2356*a67afe4dSAndroid Build Coastguard Worker #else
2357*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2358*a67afe4dSAndroid Build Coastguard Worker #endif
2359*a67afe4dSAndroid Build Coastguard Worker
2360*a67afe4dSAndroid Build Coastguard Worker if (sum > lmins) /* We are already worse, don't continue. */
2361*a67afe4dSAndroid Build Coastguard Worker break;
2362*a67afe4dSAndroid Build Coastguard Worker }
2363*a67afe4dSAndroid Build Coastguard Worker
2364*a67afe4dSAndroid Build Coastguard Worker return sum;
2365*a67afe4dSAndroid Build Coastguard Worker }
2366*a67afe4dSAndroid Build Coastguard Worker static void /* PRIVATE */
png_setup_up_row_only(png_structrp png_ptr,size_t row_bytes)2367*a67afe4dSAndroid Build Coastguard Worker png_setup_up_row_only(png_structrp png_ptr, size_t row_bytes)
2368*a67afe4dSAndroid Build Coastguard Worker {
2369*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, pp;
2370*a67afe4dSAndroid Build Coastguard Worker size_t i;
2371*a67afe4dSAndroid Build Coastguard Worker
2372*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
2373*a67afe4dSAndroid Build Coastguard Worker
2374*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
2375*a67afe4dSAndroid Build Coastguard Worker pp = png_ptr->prev_row + 1; i < row_bytes;
2376*a67afe4dSAndroid Build Coastguard Worker i++, rp++, pp++, dp++)
2377*a67afe4dSAndroid Build Coastguard Worker {
2378*a67afe4dSAndroid Build Coastguard Worker *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
2379*a67afe4dSAndroid Build Coastguard Worker }
2380*a67afe4dSAndroid Build Coastguard Worker }
2381*a67afe4dSAndroid Build Coastguard Worker
2382*a67afe4dSAndroid Build Coastguard Worker static size_t /* PRIVATE */
png_setup_avg_row(png_structrp png_ptr,png_uint_32 bpp,size_t row_bytes,size_t lmins)2383*a67afe4dSAndroid Build Coastguard Worker png_setup_avg_row(png_structrp png_ptr, png_uint_32 bpp,
2384*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes, size_t lmins)
2385*a67afe4dSAndroid Build Coastguard Worker {
2386*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, pp, lp;
2387*a67afe4dSAndroid Build Coastguard Worker png_uint_32 i;
2388*a67afe4dSAndroid Build Coastguard Worker size_t sum = 0;
2389*a67afe4dSAndroid Build Coastguard Worker unsigned int v;
2390*a67afe4dSAndroid Build Coastguard Worker
2391*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
2392*a67afe4dSAndroid Build Coastguard Worker
2393*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
2394*a67afe4dSAndroid Build Coastguard Worker pp = png_ptr->prev_row + 1; i < bpp; i++)
2395*a67afe4dSAndroid Build Coastguard Worker {
2396*a67afe4dSAndroid Build Coastguard Worker v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2397*a67afe4dSAndroid Build Coastguard Worker
2398*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2399*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2400*a67afe4dSAndroid Build Coastguard Worker #else
2401*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2402*a67afe4dSAndroid Build Coastguard Worker #endif
2403*a67afe4dSAndroid Build Coastguard Worker }
2404*a67afe4dSAndroid Build Coastguard Worker
2405*a67afe4dSAndroid Build Coastguard Worker for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
2406*a67afe4dSAndroid Build Coastguard Worker {
2407*a67afe4dSAndroid Build Coastguard Worker v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
2408*a67afe4dSAndroid Build Coastguard Worker & 0xff);
2409*a67afe4dSAndroid Build Coastguard Worker
2410*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2411*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2412*a67afe4dSAndroid Build Coastguard Worker #else
2413*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2414*a67afe4dSAndroid Build Coastguard Worker #endif
2415*a67afe4dSAndroid Build Coastguard Worker
2416*a67afe4dSAndroid Build Coastguard Worker if (sum > lmins) /* We are already worse, don't continue. */
2417*a67afe4dSAndroid Build Coastguard Worker break;
2418*a67afe4dSAndroid Build Coastguard Worker }
2419*a67afe4dSAndroid Build Coastguard Worker
2420*a67afe4dSAndroid Build Coastguard Worker return sum;
2421*a67afe4dSAndroid Build Coastguard Worker }
2422*a67afe4dSAndroid Build Coastguard Worker static void /* PRIVATE */
png_setup_avg_row_only(png_structrp png_ptr,png_uint_32 bpp,size_t row_bytes)2423*a67afe4dSAndroid Build Coastguard Worker png_setup_avg_row_only(png_structrp png_ptr, png_uint_32 bpp,
2424*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes)
2425*a67afe4dSAndroid Build Coastguard Worker {
2426*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, pp, lp;
2427*a67afe4dSAndroid Build Coastguard Worker png_uint_32 i;
2428*a67afe4dSAndroid Build Coastguard Worker
2429*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
2430*a67afe4dSAndroid Build Coastguard Worker
2431*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
2432*a67afe4dSAndroid Build Coastguard Worker pp = png_ptr->prev_row + 1; i < bpp; i++)
2433*a67afe4dSAndroid Build Coastguard Worker {
2434*a67afe4dSAndroid Build Coastguard Worker *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
2435*a67afe4dSAndroid Build Coastguard Worker }
2436*a67afe4dSAndroid Build Coastguard Worker
2437*a67afe4dSAndroid Build Coastguard Worker for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
2438*a67afe4dSAndroid Build Coastguard Worker {
2439*a67afe4dSAndroid Build Coastguard Worker *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
2440*a67afe4dSAndroid Build Coastguard Worker & 0xff);
2441*a67afe4dSAndroid Build Coastguard Worker }
2442*a67afe4dSAndroid Build Coastguard Worker }
2443*a67afe4dSAndroid Build Coastguard Worker
2444*a67afe4dSAndroid Build Coastguard Worker static size_t /* PRIVATE */
png_setup_paeth_row(png_structrp png_ptr,png_uint_32 bpp,size_t row_bytes,size_t lmins)2445*a67afe4dSAndroid Build Coastguard Worker png_setup_paeth_row(png_structrp png_ptr, png_uint_32 bpp,
2446*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes, size_t lmins)
2447*a67afe4dSAndroid Build Coastguard Worker {
2448*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, pp, cp, lp;
2449*a67afe4dSAndroid Build Coastguard Worker size_t i;
2450*a67afe4dSAndroid Build Coastguard Worker size_t sum = 0;
2451*a67afe4dSAndroid Build Coastguard Worker unsigned int v;
2452*a67afe4dSAndroid Build Coastguard Worker
2453*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
2454*a67afe4dSAndroid Build Coastguard Worker
2455*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
2456*a67afe4dSAndroid Build Coastguard Worker pp = png_ptr->prev_row + 1; i < bpp; i++)
2457*a67afe4dSAndroid Build Coastguard Worker {
2458*a67afe4dSAndroid Build Coastguard Worker v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2459*a67afe4dSAndroid Build Coastguard Worker
2460*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2461*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2462*a67afe4dSAndroid Build Coastguard Worker #else
2463*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2464*a67afe4dSAndroid Build Coastguard Worker #endif
2465*a67afe4dSAndroid Build Coastguard Worker }
2466*a67afe4dSAndroid Build Coastguard Worker
2467*a67afe4dSAndroid Build Coastguard Worker for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
2468*a67afe4dSAndroid Build Coastguard Worker i++)
2469*a67afe4dSAndroid Build Coastguard Worker {
2470*a67afe4dSAndroid Build Coastguard Worker int a, b, c, pa, pb, pc, p;
2471*a67afe4dSAndroid Build Coastguard Worker
2472*a67afe4dSAndroid Build Coastguard Worker b = *pp++;
2473*a67afe4dSAndroid Build Coastguard Worker c = *cp++;
2474*a67afe4dSAndroid Build Coastguard Worker a = *lp++;
2475*a67afe4dSAndroid Build Coastguard Worker
2476*a67afe4dSAndroid Build Coastguard Worker p = b - c;
2477*a67afe4dSAndroid Build Coastguard Worker pc = a - c;
2478*a67afe4dSAndroid Build Coastguard Worker
2479*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2480*a67afe4dSAndroid Build Coastguard Worker pa = abs(p);
2481*a67afe4dSAndroid Build Coastguard Worker pb = abs(pc);
2482*a67afe4dSAndroid Build Coastguard Worker pc = abs(p + pc);
2483*a67afe4dSAndroid Build Coastguard Worker #else
2484*a67afe4dSAndroid Build Coastguard Worker pa = p < 0 ? -p : p;
2485*a67afe4dSAndroid Build Coastguard Worker pb = pc < 0 ? -pc : pc;
2486*a67afe4dSAndroid Build Coastguard Worker pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2487*a67afe4dSAndroid Build Coastguard Worker #endif
2488*a67afe4dSAndroid Build Coastguard Worker
2489*a67afe4dSAndroid Build Coastguard Worker p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2490*a67afe4dSAndroid Build Coastguard Worker
2491*a67afe4dSAndroid Build Coastguard Worker v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2492*a67afe4dSAndroid Build Coastguard Worker
2493*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2494*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2495*a67afe4dSAndroid Build Coastguard Worker #else
2496*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2497*a67afe4dSAndroid Build Coastguard Worker #endif
2498*a67afe4dSAndroid Build Coastguard Worker
2499*a67afe4dSAndroid Build Coastguard Worker if (sum > lmins) /* We are already worse, don't continue. */
2500*a67afe4dSAndroid Build Coastguard Worker break;
2501*a67afe4dSAndroid Build Coastguard Worker }
2502*a67afe4dSAndroid Build Coastguard Worker
2503*a67afe4dSAndroid Build Coastguard Worker return sum;
2504*a67afe4dSAndroid Build Coastguard Worker }
2505*a67afe4dSAndroid Build Coastguard Worker static void /* PRIVATE */
png_setup_paeth_row_only(png_structrp png_ptr,png_uint_32 bpp,size_t row_bytes)2506*a67afe4dSAndroid Build Coastguard Worker png_setup_paeth_row_only(png_structrp png_ptr, png_uint_32 bpp,
2507*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes)
2508*a67afe4dSAndroid Build Coastguard Worker {
2509*a67afe4dSAndroid Build Coastguard Worker png_bytep rp, dp, pp, cp, lp;
2510*a67afe4dSAndroid Build Coastguard Worker size_t i;
2511*a67afe4dSAndroid Build Coastguard Worker
2512*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
2513*a67afe4dSAndroid Build Coastguard Worker
2514*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
2515*a67afe4dSAndroid Build Coastguard Worker pp = png_ptr->prev_row + 1; i < bpp; i++)
2516*a67afe4dSAndroid Build Coastguard Worker {
2517*a67afe4dSAndroid Build Coastguard Worker *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
2518*a67afe4dSAndroid Build Coastguard Worker }
2519*a67afe4dSAndroid Build Coastguard Worker
2520*a67afe4dSAndroid Build Coastguard Worker for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
2521*a67afe4dSAndroid Build Coastguard Worker i++)
2522*a67afe4dSAndroid Build Coastguard Worker {
2523*a67afe4dSAndroid Build Coastguard Worker int a, b, c, pa, pb, pc, p;
2524*a67afe4dSAndroid Build Coastguard Worker
2525*a67afe4dSAndroid Build Coastguard Worker b = *pp++;
2526*a67afe4dSAndroid Build Coastguard Worker c = *cp++;
2527*a67afe4dSAndroid Build Coastguard Worker a = *lp++;
2528*a67afe4dSAndroid Build Coastguard Worker
2529*a67afe4dSAndroid Build Coastguard Worker p = b - c;
2530*a67afe4dSAndroid Build Coastguard Worker pc = a - c;
2531*a67afe4dSAndroid Build Coastguard Worker
2532*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2533*a67afe4dSAndroid Build Coastguard Worker pa = abs(p);
2534*a67afe4dSAndroid Build Coastguard Worker pb = abs(pc);
2535*a67afe4dSAndroid Build Coastguard Worker pc = abs(p + pc);
2536*a67afe4dSAndroid Build Coastguard Worker #else
2537*a67afe4dSAndroid Build Coastguard Worker pa = p < 0 ? -p : p;
2538*a67afe4dSAndroid Build Coastguard Worker pb = pc < 0 ? -pc : pc;
2539*a67afe4dSAndroid Build Coastguard Worker pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2540*a67afe4dSAndroid Build Coastguard Worker #endif
2541*a67afe4dSAndroid Build Coastguard Worker
2542*a67afe4dSAndroid Build Coastguard Worker p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2543*a67afe4dSAndroid Build Coastguard Worker
2544*a67afe4dSAndroid Build Coastguard Worker *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
2545*a67afe4dSAndroid Build Coastguard Worker }
2546*a67afe4dSAndroid Build Coastguard Worker }
2547*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE_FILTER */
2548*a67afe4dSAndroid Build Coastguard Worker
2549*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_write_find_filter(png_structrp png_ptr,png_row_infop row_info)2550*a67afe4dSAndroid Build Coastguard Worker png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
2551*a67afe4dSAndroid Build Coastguard Worker {
2552*a67afe4dSAndroid Build Coastguard Worker #ifndef PNG_WRITE_FILTER_SUPPORTED
2553*a67afe4dSAndroid Build Coastguard Worker png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1);
2554*a67afe4dSAndroid Build Coastguard Worker #else
2555*a67afe4dSAndroid Build Coastguard Worker unsigned int filter_to_do = png_ptr->do_filter;
2556*a67afe4dSAndroid Build Coastguard Worker png_bytep row_buf;
2557*a67afe4dSAndroid Build Coastguard Worker png_bytep best_row;
2558*a67afe4dSAndroid Build Coastguard Worker png_uint_32 bpp;
2559*a67afe4dSAndroid Build Coastguard Worker size_t mins;
2560*a67afe4dSAndroid Build Coastguard Worker size_t row_bytes = row_info->rowbytes;
2561*a67afe4dSAndroid Build Coastguard Worker
2562*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_find_filter");
2563*a67afe4dSAndroid Build Coastguard Worker
2564*a67afe4dSAndroid Build Coastguard Worker /* Find out how many bytes offset each pixel is */
2565*a67afe4dSAndroid Build Coastguard Worker bpp = (row_info->pixel_depth + 7) >> 3;
2566*a67afe4dSAndroid Build Coastguard Worker
2567*a67afe4dSAndroid Build Coastguard Worker row_buf = png_ptr->row_buf;
2568*a67afe4dSAndroid Build Coastguard Worker mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the
2569*a67afe4dSAndroid Build Coastguard Worker running sum */;
2570*a67afe4dSAndroid Build Coastguard Worker
2571*a67afe4dSAndroid Build Coastguard Worker /* The prediction method we use is to find which method provides the
2572*a67afe4dSAndroid Build Coastguard Worker * smallest value when summing the absolute values of the distances
2573*a67afe4dSAndroid Build Coastguard Worker * from zero, using anything >= 128 as negative numbers. This is known
2574*a67afe4dSAndroid Build Coastguard Worker * as the "minimum sum of absolute differences" heuristic. Other
2575*a67afe4dSAndroid Build Coastguard Worker * heuristics are the "weighted minimum sum of absolute differences"
2576*a67afe4dSAndroid Build Coastguard Worker * (experimental and can in theory improve compression), and the "zlib
2577*a67afe4dSAndroid Build Coastguard Worker * predictive" method (not implemented yet), which does test compressions
2578*a67afe4dSAndroid Build Coastguard Worker * of lines using different filter methods, and then chooses the
2579*a67afe4dSAndroid Build Coastguard Worker * (series of) filter(s) that give minimum compressed data size (VERY
2580*a67afe4dSAndroid Build Coastguard Worker * computationally expensive).
2581*a67afe4dSAndroid Build Coastguard Worker *
2582*a67afe4dSAndroid Build Coastguard Worker * GRR 980525: consider also
2583*a67afe4dSAndroid Build Coastguard Worker *
2584*a67afe4dSAndroid Build Coastguard Worker * (1) minimum sum of absolute differences from running average (i.e.,
2585*a67afe4dSAndroid Build Coastguard Worker * keep running sum of non-absolute differences & count of bytes)
2586*a67afe4dSAndroid Build Coastguard Worker * [track dispersion, too? restart average if dispersion too large?]
2587*a67afe4dSAndroid Build Coastguard Worker *
2588*a67afe4dSAndroid Build Coastguard Worker * (1b) minimum sum of absolute differences from sliding average, probably
2589*a67afe4dSAndroid Build Coastguard Worker * with window size <= deflate window (usually 32K)
2590*a67afe4dSAndroid Build Coastguard Worker *
2591*a67afe4dSAndroid Build Coastguard Worker * (2) minimum sum of squared differences from zero or running average
2592*a67afe4dSAndroid Build Coastguard Worker * (i.e., ~ root-mean-square approach)
2593*a67afe4dSAndroid Build Coastguard Worker */
2594*a67afe4dSAndroid Build Coastguard Worker
2595*a67afe4dSAndroid Build Coastguard Worker
2596*a67afe4dSAndroid Build Coastguard Worker /* We don't need to test the 'no filter' case if this is the only filter
2597*a67afe4dSAndroid Build Coastguard Worker * that has been chosen, as it doesn't actually do anything to the data.
2598*a67afe4dSAndroid Build Coastguard Worker */
2599*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->row_buf;
2600*a67afe4dSAndroid Build Coastguard Worker
2601*a67afe4dSAndroid Build Coastguard Worker if (PNG_SIZE_MAX/128 <= row_bytes)
2602*a67afe4dSAndroid Build Coastguard Worker {
2603*a67afe4dSAndroid Build Coastguard Worker /* Overflow can occur in the calculation, just select the lowest set
2604*a67afe4dSAndroid Build Coastguard Worker * filter.
2605*a67afe4dSAndroid Build Coastguard Worker */
2606*a67afe4dSAndroid Build Coastguard Worker filter_to_do &= 0U-filter_to_do;
2607*a67afe4dSAndroid Build Coastguard Worker }
2608*a67afe4dSAndroid Build Coastguard Worker else if ((filter_to_do & PNG_FILTER_NONE) != 0 &&
2609*a67afe4dSAndroid Build Coastguard Worker filter_to_do != PNG_FILTER_NONE)
2610*a67afe4dSAndroid Build Coastguard Worker {
2611*a67afe4dSAndroid Build Coastguard Worker /* Overflow not possible and multiple filters in the list, including the
2612*a67afe4dSAndroid Build Coastguard Worker * 'none' filter.
2613*a67afe4dSAndroid Build Coastguard Worker */
2614*a67afe4dSAndroid Build Coastguard Worker png_bytep rp;
2615*a67afe4dSAndroid Build Coastguard Worker size_t sum = 0;
2616*a67afe4dSAndroid Build Coastguard Worker size_t i;
2617*a67afe4dSAndroid Build Coastguard Worker unsigned int v;
2618*a67afe4dSAndroid Build Coastguard Worker
2619*a67afe4dSAndroid Build Coastguard Worker {
2620*a67afe4dSAndroid Build Coastguard Worker for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
2621*a67afe4dSAndroid Build Coastguard Worker {
2622*a67afe4dSAndroid Build Coastguard Worker v = *rp;
2623*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USE_ABS
2624*a67afe4dSAndroid Build Coastguard Worker sum += 128 - abs((int)v - 128);
2625*a67afe4dSAndroid Build Coastguard Worker #else
2626*a67afe4dSAndroid Build Coastguard Worker sum += (v < 128) ? v : 256 - v;
2627*a67afe4dSAndroid Build Coastguard Worker #endif
2628*a67afe4dSAndroid Build Coastguard Worker }
2629*a67afe4dSAndroid Build Coastguard Worker }
2630*a67afe4dSAndroid Build Coastguard Worker
2631*a67afe4dSAndroid Build Coastguard Worker mins = sum;
2632*a67afe4dSAndroid Build Coastguard Worker }
2633*a67afe4dSAndroid Build Coastguard Worker
2634*a67afe4dSAndroid Build Coastguard Worker /* Sub filter */
2635*a67afe4dSAndroid Build Coastguard Worker if (filter_to_do == PNG_FILTER_SUB)
2636*a67afe4dSAndroid Build Coastguard Worker /* It's the only filter so no testing is needed */
2637*a67afe4dSAndroid Build Coastguard Worker {
2638*a67afe4dSAndroid Build Coastguard Worker png_setup_sub_row_only(png_ptr, bpp, row_bytes);
2639*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2640*a67afe4dSAndroid Build Coastguard Worker }
2641*a67afe4dSAndroid Build Coastguard Worker
2642*a67afe4dSAndroid Build Coastguard Worker else if ((filter_to_do & PNG_FILTER_SUB) != 0)
2643*a67afe4dSAndroid Build Coastguard Worker {
2644*a67afe4dSAndroid Build Coastguard Worker size_t sum;
2645*a67afe4dSAndroid Build Coastguard Worker size_t lmins = mins;
2646*a67afe4dSAndroid Build Coastguard Worker
2647*a67afe4dSAndroid Build Coastguard Worker sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins);
2648*a67afe4dSAndroid Build Coastguard Worker
2649*a67afe4dSAndroid Build Coastguard Worker if (sum < mins)
2650*a67afe4dSAndroid Build Coastguard Worker {
2651*a67afe4dSAndroid Build Coastguard Worker mins = sum;
2652*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2653*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->tst_row != NULL)
2654*a67afe4dSAndroid Build Coastguard Worker {
2655*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row = png_ptr->tst_row;
2656*a67afe4dSAndroid Build Coastguard Worker png_ptr->tst_row = best_row;
2657*a67afe4dSAndroid Build Coastguard Worker }
2658*a67afe4dSAndroid Build Coastguard Worker }
2659*a67afe4dSAndroid Build Coastguard Worker }
2660*a67afe4dSAndroid Build Coastguard Worker
2661*a67afe4dSAndroid Build Coastguard Worker /* Up filter */
2662*a67afe4dSAndroid Build Coastguard Worker if (filter_to_do == PNG_FILTER_UP)
2663*a67afe4dSAndroid Build Coastguard Worker {
2664*a67afe4dSAndroid Build Coastguard Worker png_setup_up_row_only(png_ptr, row_bytes);
2665*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2666*a67afe4dSAndroid Build Coastguard Worker }
2667*a67afe4dSAndroid Build Coastguard Worker
2668*a67afe4dSAndroid Build Coastguard Worker else if ((filter_to_do & PNG_FILTER_UP) != 0)
2669*a67afe4dSAndroid Build Coastguard Worker {
2670*a67afe4dSAndroid Build Coastguard Worker size_t sum;
2671*a67afe4dSAndroid Build Coastguard Worker size_t lmins = mins;
2672*a67afe4dSAndroid Build Coastguard Worker
2673*a67afe4dSAndroid Build Coastguard Worker sum = png_setup_up_row(png_ptr, row_bytes, lmins);
2674*a67afe4dSAndroid Build Coastguard Worker
2675*a67afe4dSAndroid Build Coastguard Worker if (sum < mins)
2676*a67afe4dSAndroid Build Coastguard Worker {
2677*a67afe4dSAndroid Build Coastguard Worker mins = sum;
2678*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2679*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->tst_row != NULL)
2680*a67afe4dSAndroid Build Coastguard Worker {
2681*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row = png_ptr->tst_row;
2682*a67afe4dSAndroid Build Coastguard Worker png_ptr->tst_row = best_row;
2683*a67afe4dSAndroid Build Coastguard Worker }
2684*a67afe4dSAndroid Build Coastguard Worker }
2685*a67afe4dSAndroid Build Coastguard Worker }
2686*a67afe4dSAndroid Build Coastguard Worker
2687*a67afe4dSAndroid Build Coastguard Worker /* Avg filter */
2688*a67afe4dSAndroid Build Coastguard Worker if (filter_to_do == PNG_FILTER_AVG)
2689*a67afe4dSAndroid Build Coastguard Worker {
2690*a67afe4dSAndroid Build Coastguard Worker png_setup_avg_row_only(png_ptr, bpp, row_bytes);
2691*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2692*a67afe4dSAndroid Build Coastguard Worker }
2693*a67afe4dSAndroid Build Coastguard Worker
2694*a67afe4dSAndroid Build Coastguard Worker else if ((filter_to_do & PNG_FILTER_AVG) != 0)
2695*a67afe4dSAndroid Build Coastguard Worker {
2696*a67afe4dSAndroid Build Coastguard Worker size_t sum;
2697*a67afe4dSAndroid Build Coastguard Worker size_t lmins = mins;
2698*a67afe4dSAndroid Build Coastguard Worker
2699*a67afe4dSAndroid Build Coastguard Worker sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins);
2700*a67afe4dSAndroid Build Coastguard Worker
2701*a67afe4dSAndroid Build Coastguard Worker if (sum < mins)
2702*a67afe4dSAndroid Build Coastguard Worker {
2703*a67afe4dSAndroid Build Coastguard Worker mins = sum;
2704*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2705*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->tst_row != NULL)
2706*a67afe4dSAndroid Build Coastguard Worker {
2707*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row = png_ptr->tst_row;
2708*a67afe4dSAndroid Build Coastguard Worker png_ptr->tst_row = best_row;
2709*a67afe4dSAndroid Build Coastguard Worker }
2710*a67afe4dSAndroid Build Coastguard Worker }
2711*a67afe4dSAndroid Build Coastguard Worker }
2712*a67afe4dSAndroid Build Coastguard Worker
2713*a67afe4dSAndroid Build Coastguard Worker /* Paeth filter */
2714*a67afe4dSAndroid Build Coastguard Worker if (filter_to_do == PNG_FILTER_PAETH)
2715*a67afe4dSAndroid Build Coastguard Worker {
2716*a67afe4dSAndroid Build Coastguard Worker png_setup_paeth_row_only(png_ptr, bpp, row_bytes);
2717*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2718*a67afe4dSAndroid Build Coastguard Worker }
2719*a67afe4dSAndroid Build Coastguard Worker
2720*a67afe4dSAndroid Build Coastguard Worker else if ((filter_to_do & PNG_FILTER_PAETH) != 0)
2721*a67afe4dSAndroid Build Coastguard Worker {
2722*a67afe4dSAndroid Build Coastguard Worker size_t sum;
2723*a67afe4dSAndroid Build Coastguard Worker size_t lmins = mins;
2724*a67afe4dSAndroid Build Coastguard Worker
2725*a67afe4dSAndroid Build Coastguard Worker sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins);
2726*a67afe4dSAndroid Build Coastguard Worker
2727*a67afe4dSAndroid Build Coastguard Worker if (sum < mins)
2728*a67afe4dSAndroid Build Coastguard Worker {
2729*a67afe4dSAndroid Build Coastguard Worker best_row = png_ptr->try_row;
2730*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->tst_row != NULL)
2731*a67afe4dSAndroid Build Coastguard Worker {
2732*a67afe4dSAndroid Build Coastguard Worker png_ptr->try_row = png_ptr->tst_row;
2733*a67afe4dSAndroid Build Coastguard Worker png_ptr->tst_row = best_row;
2734*a67afe4dSAndroid Build Coastguard Worker }
2735*a67afe4dSAndroid Build Coastguard Worker }
2736*a67afe4dSAndroid Build Coastguard Worker }
2737*a67afe4dSAndroid Build Coastguard Worker
2738*a67afe4dSAndroid Build Coastguard Worker /* Do the actual writing of the filtered row data from the chosen filter. */
2739*a67afe4dSAndroid Build Coastguard Worker png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);
2740*a67afe4dSAndroid Build Coastguard Worker
2741*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE_FILTER */
2742*a67afe4dSAndroid Build Coastguard Worker }
2743*a67afe4dSAndroid Build Coastguard Worker
2744*a67afe4dSAndroid Build Coastguard Worker
2745*a67afe4dSAndroid Build Coastguard Worker /* Do the actual writing of a previously filtered row. */
2746*a67afe4dSAndroid Build Coastguard Worker static void
png_write_filtered_row(png_structrp png_ptr,png_bytep filtered_row,size_t full_row_length)2747*a67afe4dSAndroid Build Coastguard Worker png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
2748*a67afe4dSAndroid Build Coastguard Worker size_t full_row_length/*includes filter byte*/)
2749*a67afe4dSAndroid Build Coastguard Worker {
2750*a67afe4dSAndroid Build Coastguard Worker png_debug(1, "in png_write_filtered_row");
2751*a67afe4dSAndroid Build Coastguard Worker
2752*a67afe4dSAndroid Build Coastguard Worker png_debug1(2, "filter = %d", filtered_row[0]);
2753*a67afe4dSAndroid Build Coastguard Worker
2754*a67afe4dSAndroid Build Coastguard Worker png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH);
2755*a67afe4dSAndroid Build Coastguard Worker
2756*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_FILTER_SUPPORTED
2757*a67afe4dSAndroid Build Coastguard Worker /* Swap the current and previous rows */
2758*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->prev_row != NULL)
2759*a67afe4dSAndroid Build Coastguard Worker {
2760*a67afe4dSAndroid Build Coastguard Worker png_bytep tptr;
2761*a67afe4dSAndroid Build Coastguard Worker
2762*a67afe4dSAndroid Build Coastguard Worker tptr = png_ptr->prev_row;
2763*a67afe4dSAndroid Build Coastguard Worker png_ptr->prev_row = png_ptr->row_buf;
2764*a67afe4dSAndroid Build Coastguard Worker png_ptr->row_buf = tptr;
2765*a67afe4dSAndroid Build Coastguard Worker }
2766*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE_FILTER */
2767*a67afe4dSAndroid Build Coastguard Worker
2768*a67afe4dSAndroid Build Coastguard Worker /* Finish row - updates counters and flushes zlib if last row */
2769*a67afe4dSAndroid Build Coastguard Worker png_write_finish_row(png_ptr);
2770*a67afe4dSAndroid Build Coastguard Worker
2771*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WRITE_FLUSH_SUPPORTED
2772*a67afe4dSAndroid Build Coastguard Worker png_ptr->flush_rows++;
2773*a67afe4dSAndroid Build Coastguard Worker
2774*a67afe4dSAndroid Build Coastguard Worker if (png_ptr->flush_dist > 0 &&
2775*a67afe4dSAndroid Build Coastguard Worker png_ptr->flush_rows >= png_ptr->flush_dist)
2776*a67afe4dSAndroid Build Coastguard Worker {
2777*a67afe4dSAndroid Build Coastguard Worker png_write_flush(png_ptr);
2778*a67afe4dSAndroid Build Coastguard Worker }
2779*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE_FLUSH */
2780*a67afe4dSAndroid Build Coastguard Worker }
2781*a67afe4dSAndroid Build Coastguard Worker #endif /* WRITE */
2782