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.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
     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
    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
    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
    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 */
    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