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