]> git.cworth.org Git - apitrace/blob - thirdparty/libpng/pngtrans.c
Update to libpng 1.5.9.
[apitrace] / thirdparty / libpng / pngtrans.c
1
2 /* pngtrans.c - transforms the data in a row (used by both readers and writers)
3  *
4  * Last changed in libpng 1.5.4 [July 7, 2011]
5  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
6  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8  *
9  * This code is released under the libpng license.
10  * For conditions of distribution and use, see the disclaimer
11  * and license in png.h
12  */
13
14 #include "pngpriv.h"
15
16 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
17
18 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
19 /* Turn on BGR-to-RGB mapping */
20 void PNGAPI
21 png_set_bgr(png_structp png_ptr)
22 {
23    png_debug(1, "in png_set_bgr");
24
25    if (png_ptr == NULL)
26       return;
27
28    png_ptr->transformations |= PNG_BGR;
29 }
30 #endif
31
32 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
33 /* Turn on 16 bit byte swapping */
34 void PNGAPI
35 png_set_swap(png_structp png_ptr)
36 {
37    png_debug(1, "in png_set_swap");
38
39    if (png_ptr == NULL)
40       return;
41
42    if (png_ptr->bit_depth == 16)
43       png_ptr->transformations |= PNG_SWAP_BYTES;
44 }
45 #endif
46
47 #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
48 /* Turn on pixel packing */
49 void PNGAPI
50 png_set_packing(png_structp png_ptr)
51 {
52    png_debug(1, "in png_set_packing");
53
54    if (png_ptr == NULL)
55       return;
56
57    if (png_ptr->bit_depth < 8)
58    {
59       png_ptr->transformations |= PNG_PACK;
60       png_ptr->usr_bit_depth = 8;
61    }
62 }
63 #endif
64
65 #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
66 /* Turn on packed pixel swapping */
67 void PNGAPI
68 png_set_packswap(png_structp png_ptr)
69 {
70    png_debug(1, "in png_set_packswap");
71
72    if (png_ptr == NULL)
73       return;
74
75    if (png_ptr->bit_depth < 8)
76       png_ptr->transformations |= PNG_PACKSWAP;
77 }
78 #endif
79
80 #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
81 void PNGAPI
82 png_set_shift(png_structp png_ptr, png_const_color_8p true_bits)
83 {
84    png_debug(1, "in png_set_shift");
85
86    if (png_ptr == NULL)
87       return;
88
89    png_ptr->transformations |= PNG_SHIFT;
90    png_ptr->shift = *true_bits;
91 }
92 #endif
93
94 #if defined(PNG_READ_INTERLACING_SUPPORTED) || \
95     defined(PNG_WRITE_INTERLACING_SUPPORTED)
96 int PNGAPI
97 png_set_interlace_handling(png_structp png_ptr)
98 {
99    png_debug(1, "in png_set_interlace handling");
100
101    if (png_ptr && png_ptr->interlaced)
102    {
103       png_ptr->transformations |= PNG_INTERLACE;
104       return (7);
105    }
106
107    return (1);
108 }
109 #endif
110
111 #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
112 /* Add a filler byte on read, or remove a filler or alpha byte on write.
113  * The filler type has changed in v0.95 to allow future 2-byte fillers
114  * for 48-bit input data, as well as to avoid problems with some compilers
115  * that don't like bytes as parameters.
116  */
117 void PNGAPI
118 png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
119 {
120    png_debug(1, "in png_set_filler");
121
122    if (png_ptr == NULL)
123       return;
124
125    png_ptr->transformations |= PNG_FILLER;
126    png_ptr->filler = (png_uint_16)filler;
127
128    if (filler_loc == PNG_FILLER_AFTER)
129       png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
130
131    else
132       png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
133
134    /* This should probably go in the "do_read_filler" routine.
135     * I attempted to do that in libpng-1.0.1a but that caused problems
136     * so I restored it in libpng-1.0.2a
137    */
138
139    if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
140    {
141       png_ptr->usr_channels = 4;
142    }
143
144    /* Also I added this in libpng-1.0.2a (what happens when we expand
145     * a less-than-8-bit grayscale to GA?) */
146
147    if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8)
148    {
149       png_ptr->usr_channels = 2;
150    }
151 }
152
153 /* Added to libpng-1.2.7 */
154 void PNGAPI
155 png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc)
156 {
157    png_debug(1, "in png_set_add_alpha");
158
159    if (png_ptr == NULL)
160       return;
161
162    png_set_filler(png_ptr, filler, filler_loc);
163    png_ptr->transformations |= PNG_ADD_ALPHA;
164 }
165
166 #endif
167
168 #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
169     defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
170 void PNGAPI
171 png_set_swap_alpha(png_structp png_ptr)
172 {
173    png_debug(1, "in png_set_swap_alpha");
174
175    if (png_ptr == NULL)
176       return;
177
178    png_ptr->transformations |= PNG_SWAP_ALPHA;
179 }
180 #endif
181
182 #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
183     defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
184 void PNGAPI
185 png_set_invert_alpha(png_structp png_ptr)
186 {
187    png_debug(1, "in png_set_invert_alpha");
188
189    if (png_ptr == NULL)
190       return;
191
192    png_ptr->transformations |= PNG_INVERT_ALPHA;
193 }
194 #endif
195
196 #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
197 void PNGAPI
198 png_set_invert_mono(png_structp png_ptr)
199 {
200    png_debug(1, "in png_set_invert_mono");
201
202    if (png_ptr == NULL)
203       return;
204
205    png_ptr->transformations |= PNG_INVERT_MONO;
206 }
207
208 /* Invert monochrome grayscale data */
209 void /* PRIVATE */
210 png_do_invert(png_row_infop row_info, png_bytep row)
211 {
212    png_debug(1, "in png_do_invert");
213
214   /* This test removed from libpng version 1.0.13 and 1.2.0:
215    *   if (row_info->bit_depth == 1 &&
216    */
217    if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
218    {
219       png_bytep rp = row;
220       png_size_t i;
221       png_size_t istop = row_info->rowbytes;
222
223       for (i = 0; i < istop; i++)
224       {
225          *rp = (png_byte)(~(*rp));
226          rp++;
227       }
228    }
229
230    else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
231       row_info->bit_depth == 8)
232    {
233       png_bytep rp = row;
234       png_size_t i;
235       png_size_t istop = row_info->rowbytes;
236
237       for (i = 0; i < istop; i += 2)
238       {
239          *rp = (png_byte)(~(*rp));
240          rp += 2;
241       }
242    }
243
244 #ifdef PNG_16BIT_SUPPORTED
245    else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
246       row_info->bit_depth == 16)
247    {
248       png_bytep rp = row;
249       png_size_t i;
250       png_size_t istop = row_info->rowbytes;
251
252       for (i = 0; i < istop; i += 4)
253       {
254          *rp = (png_byte)(~(*rp));
255          *(rp + 1) = (png_byte)(~(*(rp + 1)));
256          rp += 4;
257       }
258    }
259 #endif
260 }
261 #endif
262
263 #ifdef PNG_16BIT_SUPPORTED
264 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
265 /* Swaps byte order on 16 bit depth images */
266 void /* PRIVATE */
267 png_do_swap(png_row_infop row_info, png_bytep row)
268 {
269    png_debug(1, "in png_do_swap");
270
271    if (row_info->bit_depth == 16)
272    {
273       png_bytep rp = row;
274       png_uint_32 i;
275       png_uint_32 istop= row_info->width * row_info->channels;
276
277       for (i = 0; i < istop; i++, rp += 2)
278       {
279          png_byte t = *rp;
280          *rp = *(rp + 1);
281          *(rp + 1) = t;
282       }
283    }
284 }
285 #endif
286 #endif
287
288 #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
289 static PNG_CONST png_byte onebppswaptable[256] = {
290    0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
291    0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
292    0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
293    0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
294    0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
295    0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
296    0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
297    0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
298    0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
299    0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
300    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
301    0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
302    0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
303    0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
304    0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
305    0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
306    0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
307    0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
308    0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
309    0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
310    0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
311    0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
312    0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
313    0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
314    0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
315    0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
316    0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
317    0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
318    0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
319    0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
320    0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
321    0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
322 };
323
324 static PNG_CONST png_byte twobppswaptable[256] = {
325    0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
326    0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
327    0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
328    0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
329    0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
330    0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
331    0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
332    0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
333    0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
334    0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
335    0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
336    0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
337    0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
338    0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
339    0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
340    0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
341    0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
342    0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
343    0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
344    0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
345    0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
346    0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
347    0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
348    0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
349    0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
350    0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
351    0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
352    0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
353    0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
354    0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
355    0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
356    0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
357 };
358
359 static PNG_CONST png_byte fourbppswaptable[256] = {
360    0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
361    0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
362    0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
363    0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
364    0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
365    0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
366    0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
367    0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
368    0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
369    0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
370    0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
371    0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
372    0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
373    0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
374    0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
375    0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
376    0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
377    0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
378    0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
379    0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
380    0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
381    0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
382    0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
383    0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
384    0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
385    0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
386    0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
387    0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
388    0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
389    0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
390    0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
391    0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
392 };
393
394 /* Swaps pixel packing order within bytes */
395 void /* PRIVATE */
396 png_do_packswap(png_row_infop row_info, png_bytep row)
397 {
398    png_debug(1, "in png_do_packswap");
399
400    if (row_info->bit_depth < 8)
401    {
402       png_bytep rp;
403       png_const_bytep end, table;
404
405       end = row + row_info->rowbytes;
406
407       if (row_info->bit_depth == 1)
408          table = onebppswaptable;
409
410       else if (row_info->bit_depth == 2)
411          table = twobppswaptable;
412
413       else if (row_info->bit_depth == 4)
414          table = fourbppswaptable;
415
416       else
417          return;
418
419       for (rp = row; rp < end; rp++)
420          *rp = table[*rp];
421    }
422 }
423 #endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
424
425 #if defined(PNG_WRITE_FILLER_SUPPORTED) || \
426     defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
427 /* Remove a channel - this used to be 'png_do_strip_filler' but it used a
428  * somewhat weird combination of flags to determine what to do.  All the calls
429  * to png_do_strip_filler are changed in 1.5.2 to call this instead with the
430  * correct arguments.
431  *
432  * The routine isn't general - the channel must be the channel at the start or
433  * end (not in the middle) of each pixel.
434  */
435 void /* PRIVATE */
436 png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
437 {
438    png_bytep sp = row; /* source pointer */
439    png_bytep dp = row; /* destination pointer */
440    png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */
441
442    /* At the start sp will point to the first byte to copy and dp to where
443     * it is copied to.  ep always points just beyond the end of the row, so
444     * the loop simply copies (channels-1) channels until sp reaches ep.
445     *
446     * at_start:        0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc.
447     *            nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc.
448     */
449
450    /* GA, GX, XG cases */
451    if (row_info->channels == 2)
452    {
453       if (row_info->bit_depth == 8)
454       {
455          if (at_start) /* Skip initial filler */
456             ++sp;
457          else          /* Skip initial channel and, for sp, the filler */
458             sp += 2, ++dp;
459
460          /* For a 1 pixel wide image there is nothing to do */
461          while (sp < ep)
462             *dp++ = *sp, sp += 2;
463
464          row_info->pixel_depth = 8;
465       }
466
467       else if (row_info->bit_depth == 16)
468       {
469          if (at_start) /* Skip initial filler */
470             sp += 2;
471          else          /* Skip initial channel and, for sp, the filler */
472             sp += 4, dp += 2;
473
474          while (sp < ep)
475             *dp++ = *sp++, *dp++ = *sp, sp += 3;
476
477          row_info->pixel_depth = 16;
478       }
479
480       else
481          return; /* bad bit depth */
482
483       row_info->channels = 1;
484
485       /* Finally fix the color type if it records an alpha channel */
486       if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
487          row_info->color_type = PNG_COLOR_TYPE_GRAY;
488    }
489
490    /* RGBA, RGBX, XRGB cases */
491    else if (row_info->channels == 4)
492    {
493       if (row_info->bit_depth == 8)
494       {
495          if (at_start) /* Skip initial filler */
496             ++sp;
497          else          /* Skip initial channels and, for sp, the filler */
498             sp += 4, dp += 3;
499
500          /* Note that the loop adds 3 to dp and 4 to sp each time. */
501          while (sp < ep)
502             *dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2;
503
504          row_info->pixel_depth = 24;
505       }
506
507       else if (row_info->bit_depth == 16)
508       {
509          if (at_start) /* Skip initial filler */
510             sp += 2;
511          else          /* Skip initial channels and, for sp, the filler */
512             sp += 8, dp += 6;
513
514          while (sp < ep)
515          {
516             /* Copy 6 bytes, skip 2 */
517             *dp++ = *sp++, *dp++ = *sp++;
518             *dp++ = *sp++, *dp++ = *sp++;
519             *dp++ = *sp++, *dp++ = *sp, sp += 3;
520          }
521
522          row_info->pixel_depth = 48;
523       }
524
525       else
526          return; /* bad bit depth */
527
528       row_info->channels = 3;
529
530       /* Finally fix the color type if it records an alpha channel */
531       if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
532          row_info->color_type = PNG_COLOR_TYPE_RGB;
533    }
534
535    else
536       return; /* The filler channel has gone already */
537
538    /* Fix the rowbytes value. */
539    row_info->rowbytes = dp-row;
540 }
541 #endif
542
543 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
544 /* Swaps red and blue bytes within a pixel */
545 void /* PRIVATE */
546 png_do_bgr(png_row_infop row_info, png_bytep row)
547 {
548    png_debug(1, "in png_do_bgr");
549
550    if ((row_info->color_type & PNG_COLOR_MASK_COLOR))
551    {
552       png_uint_32 row_width = row_info->width;
553       if (row_info->bit_depth == 8)
554       {
555          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
556          {
557             png_bytep rp;
558             png_uint_32 i;
559
560             for (i = 0, rp = row; i < row_width; i++, rp += 3)
561             {
562                png_byte save = *rp;
563                *rp = *(rp + 2);
564                *(rp + 2) = save;
565             }
566          }
567
568          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
569          {
570             png_bytep rp;
571             png_uint_32 i;
572
573             for (i = 0, rp = row; i < row_width; i++, rp += 4)
574             {
575                png_byte save = *rp;
576                *rp = *(rp + 2);
577                *(rp + 2) = save;
578             }
579          }
580       }
581
582 #ifdef PNG_16BIT_SUPPORTED
583       else if (row_info->bit_depth == 16)
584       {
585          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
586          {
587             png_bytep rp;
588             png_uint_32 i;
589
590             for (i = 0, rp = row; i < row_width; i++, rp += 6)
591             {
592                png_byte save = *rp;
593                *rp = *(rp + 4);
594                *(rp + 4) = save;
595                save = *(rp + 1);
596                *(rp + 1) = *(rp + 5);
597                *(rp + 5) = save;
598             }
599          }
600
601          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
602          {
603             png_bytep rp;
604             png_uint_32 i;
605
606             for (i = 0, rp = row; i < row_width; i++, rp += 8)
607             {
608                png_byte save = *rp;
609                *rp = *(rp + 4);
610                *(rp + 4) = save;
611                save = *(rp + 1);
612                *(rp + 1) = *(rp + 5);
613                *(rp + 5) = save;
614             }
615          }
616       }
617 #endif
618    }
619 }
620 #endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
621
622 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
623     defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
624 #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
625 void PNGAPI
626 png_set_user_transform_info(png_structp png_ptr, png_voidp
627    user_transform_ptr, int user_transform_depth, int user_transform_channels)
628 {
629    png_debug(1, "in png_set_user_transform_info");
630
631    if (png_ptr == NULL)
632       return;
633    png_ptr->user_transform_ptr = user_transform_ptr;
634    png_ptr->user_transform_depth = (png_byte)user_transform_depth;
635    png_ptr->user_transform_channels = (png_byte)user_transform_channels;
636 }
637 #endif
638
639 /* This function returns a pointer to the user_transform_ptr associated with
640  * the user transform functions.  The application should free any memory
641  * associated with this pointer before png_write_destroy and png_read_destroy
642  * are called.
643  */
644 #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
645 png_voidp PNGAPI
646 png_get_user_transform_ptr(png_const_structp png_ptr)
647 {
648    if (png_ptr == NULL)
649       return (NULL);
650
651    return ((png_voidp)png_ptr->user_transform_ptr);
652 }
653 #endif
654
655 #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED
656 png_uint_32 PNGAPI
657 png_get_current_row_number(png_const_structp png_ptr)
658 {
659    /* See the comments in png.h - this is the sub-image row when reading and
660     * interlaced image.
661     */
662    if (png_ptr != NULL)
663       return png_ptr->row_number;
664
665    return PNG_UINT_32_MAX; /* help the app not to fail silently */
666 }
667
668 png_byte PNGAPI
669 png_get_current_pass_number(png_const_structp png_ptr)
670 {
671    if (png_ptr != NULL)
672       return png_ptr->pass;
673    return 8; /* invalid */
674 }
675 #endif /* PNG_USER_TRANSFORM_INFO_SUPPORTED */
676 #endif /* PNG_READ_USER_TRANSFORM_SUPPORTED ||
677           PNG_WRITE_USER_TRANSFORM_SUPPORTED */
678 #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */