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