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