Home | History | Annotate | Download | only in libpng
      1 
      2 /* pngwtran.c - transforms the data in a row for PNG writers
      3  *
      4  * Last changed in libpng 1.6.24 [August 4, 2016]
      5  * Copyright (c) 1998-2002,2004,2006-2016 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
     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             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  */
    171 static void
    172 png_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
    310 static void
    311 png_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
    404 static void
    405 png_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  */
    501 void /* PRIVATE */
    502 png_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