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