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