1
2/* pngwtran.c - transforms the data in a row for PNG writers
3 *
4 * libpng version 1.2.7 - September 12, 2004
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1998-2004 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#ifdef PNG_WRITE_SUPPORTED
14
15/* Transform the data according to the user's wishes.  The order of
16 * transformations is significant.
17 */
18void /* PRIVATE */
19png_do_write_transformations(png_structp png_ptr)
20{
21   png_debug(1, "in png_do_write_transformations\n");
22
23   if (png_ptr == NULL)
24      return;
25
26#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
27   if (png_ptr->transformations & PNG_USER_TRANSFORM)
28      if(png_ptr->write_user_transform_fn != NULL)
29        (*(png_ptr->write_user_transform_fn)) /* user write transform function */
30          (png_ptr,                    /* png_ptr */
31           &(png_ptr->row_info),       /* row_info:     */
32             /*  png_uint_32 width;          width of row */
33             /*  png_uint_32 rowbytes;       number of bytes in row */
34             /*  png_byte color_type;        color type of pixels */
35             /*  png_byte bit_depth;         bit depth of samples */
36             /*  png_byte channels;          number of channels (1-4) */
37             /*  png_byte pixel_depth;       bits per pixel (depth*channels) */
38           png_ptr->row_buf + 1);      /* start of pixel data for row */
39#endif
40#if defined(PNG_WRITE_FILLER_SUPPORTED)
41   if (png_ptr->transformations & PNG_FILLER)
42      png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
43         png_ptr->flags);
44#endif
45#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
46   if (png_ptr->transformations & PNG_PACKSWAP)
47      png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
48#endif
49#if defined(PNG_WRITE_PACK_SUPPORTED)
50   if (png_ptr->transformations & PNG_PACK)
51      png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
52         (png_uint_32)png_ptr->bit_depth);
53#endif
54#if defined(PNG_WRITE_SWAP_SUPPORTED)
55   if (png_ptr->transformations & PNG_SWAP_BYTES)
56      png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
57#endif
58#if defined(PNG_WRITE_SHIFT_SUPPORTED)
59   if (png_ptr->transformations & PNG_SHIFT)
60      png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
61         &(png_ptr->shift));
62#endif
63#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
64   if (png_ptr->transformations & PNG_INVERT_ALPHA)
65      png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
66#endif
67#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
68   if (png_ptr->transformations & PNG_SWAP_ALPHA)
69      png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
70#endif
71#if defined(PNG_WRITE_BGR_SUPPORTED)
72   if (png_ptr->transformations & PNG_BGR)
73      png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
74#endif
75#if defined(PNG_WRITE_INVERT_SUPPORTED)
76   if (png_ptr->transformations & PNG_INVERT_MONO)
77      png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
78#endif
79}
80
81#if defined(PNG_WRITE_PACK_SUPPORTED)
82/* Pack pixels into bytes.  Pass the true bit depth in bit_depth.  The
83 * row_info bit depth should be 8 (one pixel per byte).  The channels
84 * should be 1 (this only happens on grayscale and paletted images).
85 */
86void /* PRIVATE */
87png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
88{
89   png_debug(1, "in png_do_pack\n");
90   if (row_info->bit_depth == 8 &&
91#if defined(PNG_USELESS_TESTS_SUPPORTED)
92       row != NULL && row_info != NULL &&
93#endif
94      row_info->channels == 1)
95   {
96      switch ((int)bit_depth)
97      {
98         case 1:
99         {
100            png_bytep sp, dp;
101            int mask, v;
102            png_uint_32 i;
103            png_uint_32 row_width = row_info->width;
104
105            sp = row;
106            dp = row;
107            mask = 0x80;
108            v = 0;
109
110            for (i = 0; i < row_width; i++)
111            {
112               if (*sp != 0)
113                  v |= mask;
114               sp++;
115               if (mask > 1)
116                  mask >>= 1;
117               else
118               {
119                  mask = 0x80;
120                  *dp = (png_byte)v;
121                  dp++;
122                  v = 0;
123               }
124            }
125            if (mask != 0x80)
126               *dp = (png_byte)v;
127            break;
128         }
129         case 2:
130         {
131            png_bytep sp, dp;
132            int shift, v;
133            png_uint_32 i;
134            png_uint_32 row_width = row_info->width;
135
136            sp = row;
137            dp = row;
138            shift = 6;
139            v = 0;
140            for (i = 0; i < row_width; i++)
141            {
142               png_byte value;
143
144               value = (png_byte)(*sp & 0x03);
145               v |= (value << shift);
146               if (shift == 0)
147               {
148                  shift = 6;
149                  *dp = (png_byte)v;
150                  dp++;
151                  v = 0;
152               }
153               else
154                  shift -= 2;
155               sp++;
156            }
157            if (shift != 6)
158               *dp = (png_byte)v;
159            break;
160         }
161         case 4:
162         {
163            png_bytep sp, dp;
164            int shift, v;
165            png_uint_32 i;
166            png_uint_32 row_width = row_info->width;
167
168            sp = row;
169            dp = row;
170            shift = 4;
171            v = 0;
172            for (i = 0; i < row_width; i++)
173            {
174               png_byte value;
175
176               value = (png_byte)(*sp & 0x0f);
177               v |= (value << shift);
178
179               if (shift == 0)
180               {
181                  shift = 4;
182                  *dp = (png_byte)v;
183                  dp++;
184                  v = 0;
185               }
186               else
187                  shift -= 4;
188
189               sp++;
190            }
191            if (shift != 4)
192               *dp = (png_byte)v;
193            break;
194         }
195      }
196      row_info->bit_depth = (png_byte)bit_depth;
197      row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
198      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
199         row_info->width);
200   }
201}
202#endif
203
204#if defined(PNG_WRITE_SHIFT_SUPPORTED)
205/* Shift pixel values to take advantage of whole range.  Pass the
206 * true number of bits in bit_depth.  The row should be packed
207 * according to row_info->bit_depth.  Thus, if you had a row of
208 * bit depth 4, but the pixels only had values from 0 to 7, you
209 * would pass 3 as bit_depth, and this routine would translate the
210 * data to 0 to 15.
211 */
212void /* PRIVATE */
213png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
214{
215   png_debug(1, "in png_do_shift\n");
216#if defined(PNG_USELESS_TESTS_SUPPORTED)
217   if (row != NULL && row_info != NULL &&
218#else
219   if (
220#endif
221      row_info->color_type != PNG_COLOR_TYPE_PALETTE)
222   {
223      int shift_start[4], shift_dec[4];
224      int channels = 0;
225
226      if (row_info->color_type & PNG_COLOR_MASK_COLOR)
227      {
228         shift_start[channels] = row_info->bit_depth - bit_depth->red;
229         shift_dec[channels] = bit_depth->red;
230         channels++;
231         shift_start[channels] = row_info->bit_depth - bit_depth->green;
232         shift_dec[channels] = bit_depth->green;
233         channels++;
234         shift_start[channels] = row_info->bit_depth - bit_depth->blue;
235         shift_dec[channels] = bit_depth->blue;
236         channels++;
237      }
238      else
239      {
240         shift_start[channels] = row_info->bit_depth - bit_depth->gray;
241         shift_dec[channels] = bit_depth->gray;
242         channels++;
243      }
244      if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
245      {
246         shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
247         shift_dec[channels] = bit_depth->alpha;
248         channels++;
249      }
250
251      /* with low row depths, could only be grayscale, so one channel */
252      if (row_info->bit_depth < 8)
253      {
254         png_bytep bp = row;
255         png_uint_32 i;
256         png_byte mask;
257         png_uint_32 row_bytes = row_info->rowbytes;
258
259         if (bit_depth->gray == 1 && row_info->bit_depth == 2)
260            mask = 0x55;
261         else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
262            mask = 0x11;
263         else
264            mask = 0xff;
265
266         for (i = 0; i < row_bytes; i++, bp++)
267         {
268            png_uint_16 v;
269            int j;
270
271            v = *bp;
272            *bp = 0;
273            for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
274            {
275               if (j > 0)
276                  *bp |= (png_byte)((v << j) & 0xff);
277               else
278                  *bp |= (png_byte)((v >> (-j)) & mask);
279            }
280         }
281      }
282      else if (row_info->bit_depth == 8)
283      {
284         png_bytep bp = row;
285         png_uint_32 i;
286         png_uint_32 istop = channels * row_info->width;
287
288         for (i = 0; i < istop; i++, bp++)
289         {
290
291            png_uint_16 v;
292            int j;
293            int c = (int)(i%channels);
294
295            v = *bp;
296            *bp = 0;
297            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
298            {
299               if (j > 0)
300                  *bp |= (png_byte)((v << j) & 0xff);
301               else
302                  *bp |= (png_byte)((v >> (-j)) & 0xff);
303            }
304         }
305      }
306      else
307      {
308         png_bytep bp;
309         png_uint_32 i;
310         png_uint_32 istop = channels * row_info->width;
311
312         for (bp = row, i = 0; i < istop; i++)
313         {
314            int c = (int)(i%channels);
315            png_uint_16 value, v;
316            int j;
317
318            v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
319            value = 0;
320            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
321            {
322               if (j > 0)
323                  value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
324               else
325                  value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
326            }
327            *bp++ = (png_byte)(value >> 8);
328            *bp++ = (png_byte)(value & 0xff);
329         }
330      }
331   }
332}
333#endif
334
335#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
336void /* PRIVATE */
337png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
338{
339   png_debug(1, "in png_do_write_swap_alpha\n");
340#if defined(PNG_USELESS_TESTS_SUPPORTED)
341   if (row != NULL && row_info != NULL)
342#endif
343   {
344      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
345      {
346         /* This converts from ARGB to RGBA */
347         if (row_info->bit_depth == 8)
348         {
349            png_bytep sp, dp;
350            png_uint_32 i;
351            png_uint_32 row_width = row_info->width;
352            for (i = 0, sp = dp = row; i < row_width; i++)
353            {
354               png_byte save = *(sp++);
355               *(dp++) = *(sp++);
356               *(dp++) = *(sp++);
357               *(dp++) = *(sp++);
358               *(dp++) = save;
359            }
360         }
361         /* This converts from AARRGGBB to RRGGBBAA */
362         else
363         {
364            png_bytep sp, dp;
365            png_uint_32 i;
366            png_uint_32 row_width = row_info->width;
367
368            for (i = 0, sp = dp = row; i < row_width; i++)
369            {
370               png_byte save[2];
371               save[0] = *(sp++);
372               save[1] = *(sp++);
373               *(dp++) = *(sp++);
374               *(dp++) = *(sp++);
375               *(dp++) = *(sp++);
376               *(dp++) = *(sp++);
377               *(dp++) = *(sp++);
378               *(dp++) = *(sp++);
379               *(dp++) = save[0];
380               *(dp++) = save[1];
381            }
382         }
383      }
384      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
385      {
386         /* This converts from AG to GA */
387         if (row_info->bit_depth == 8)
388         {
389            png_bytep sp, dp;
390            png_uint_32 i;
391            png_uint_32 row_width = row_info->width;
392
393            for (i = 0, sp = dp = row; i < row_width; i++)
394            {
395               png_byte save = *(sp++);
396               *(dp++) = *(sp++);
397               *(dp++) = save;
398            }
399         }
400         /* This converts from AAGG to GGAA */
401         else
402         {
403            png_bytep sp, dp;
404            png_uint_32 i;
405            png_uint_32 row_width = row_info->width;
406
407            for (i = 0, sp = dp = row; i < row_width; i++)
408            {
409               png_byte save[2];
410               save[0] = *(sp++);
411               save[1] = *(sp++);
412               *(dp++) = *(sp++);
413               *(dp++) = *(sp++);
414               *(dp++) = save[0];
415               *(dp++) = save[1];
416            }
417         }
418      }
419   }
420}
421#endif
422
423#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
424void /* PRIVATE */
425png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
426{
427   png_debug(1, "in png_do_write_invert_alpha\n");
428#if defined(PNG_USELESS_TESTS_SUPPORTED)
429   if (row != NULL && row_info != NULL)
430#endif
431   {
432      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
433      {
434         /* This inverts the alpha channel in RGBA */
435         if (row_info->bit_depth == 8)
436         {
437            png_bytep sp, dp;
438            png_uint_32 i;
439            png_uint_32 row_width = row_info->width;
440            for (i = 0, sp = dp = row; i < row_width; i++)
441            {
442               *(dp++) = *(sp++);
443               *(dp++) = *(sp++);
444               *(dp++) = *(sp++);
445               *(dp++) = (png_byte)(255 - *(sp++));
446            }
447         }
448         /* This inverts the alpha channel in RRGGBBAA */
449         else
450         {
451            png_bytep sp, dp;
452            png_uint_32 i;
453            png_uint_32 row_width = row_info->width;
454
455            for (i = 0, sp = dp = row; i < row_width; i++)
456            {
457               *(dp++) = *(sp++);
458               *(dp++) = *(sp++);
459               *(dp++) = *(sp++);
460               *(dp++) = *(sp++);
461               *(dp++) = *(sp++);
462               *(dp++) = *(sp++);
463               *(dp++) = (png_byte)(255 - *(sp++));
464               *(dp++) = (png_byte)(255 - *(sp++));
465            }
466         }
467      }
468      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
469      {
470         /* This inverts the alpha channel in GA */
471         if (row_info->bit_depth == 8)
472         {
473            png_bytep sp, dp;
474            png_uint_32 i;
475            png_uint_32 row_width = row_info->width;
476
477            for (i = 0, sp = dp = row; i < row_width; i++)
478            {
479               *(dp++) = *(sp++);
480               *(dp++) = (png_byte)(255 - *(sp++));
481            }
482         }
483         /* This inverts the alpha channel in GGAA */
484         else
485         {
486            png_bytep sp, dp;
487            png_uint_32 i;
488            png_uint_32 row_width = row_info->width;
489
490            for (i = 0, sp = dp = row; i < row_width; i++)
491            {
492               *(dp++) = *(sp++);
493               *(dp++) = *(sp++);
494               *(dp++) = (png_byte)(255 - *(sp++));
495               *(dp++) = (png_byte)(255 - *(sp++));
496            }
497         }
498      }
499   }
500}
501#endif
502
503#if defined(PNG_MNG_FEATURES_SUPPORTED)
504/* undoes intrapixel differencing  */
505void /* PRIVATE */
506png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
507{
508   png_debug(1, "in png_do_write_intrapixel\n");
509   if (
510#if defined(PNG_USELESS_TESTS_SUPPORTED)
511       row != NULL && row_info != NULL &&
512#endif
513       (row_info->color_type & PNG_COLOR_MASK_COLOR))
514   {
515      int bytes_per_pixel;
516      png_uint_32 row_width = row_info->width;
517      if (row_info->bit_depth == 8)
518      {
519         png_bytep rp;
520         png_uint_32 i;
521
522         if (row_info->color_type == PNG_COLOR_TYPE_RGB)
523            bytes_per_pixel = 3;
524         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
525            bytes_per_pixel = 4;
526         else
527            return;
528
529         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
530         {
531            *(rp)   = (png_byte)((*rp     - *(rp+1))&0xff);
532            *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
533         }
534      }
535      else if (row_info->bit_depth == 16)
536      {
537         png_bytep rp;
538         png_uint_32 i;
539
540         if (row_info->color_type == PNG_COLOR_TYPE_RGB)
541            bytes_per_pixel = 6;
542         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
543            bytes_per_pixel = 8;
544         else
545            return;
546
547         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
548         {
549            png_uint_32 s0   = (*(rp  ) << 8) | *(rp+1);
550            png_uint_32 s1   = (*(rp+2) << 8) | *(rp+3);
551            png_uint_32 s2   = (*(rp+4) << 8) | *(rp+5);
552            png_uint_32 red  = (png_uint_32)((s0-s1) & 0xffffL);
553            png_uint_32 blue = (png_uint_32)((s2-s1) & 0xffffL);
554            *(rp  ) = (png_byte)((red >> 8) & 0xff);
555            *(rp+1) = (png_byte)(red & 0xff);
556            *(rp+4) = (png_byte)((blue >> 8) & 0xff);
557            *(rp+5) = (png_byte)(blue & 0xff);
558         }
559      }
560   }
561}
562#endif /* PNG_MNG_FEATURES_SUPPORTED */
563#endif /* PNG_WRITE_SUPPORTED */
564