(root)/
libpng-1.6.40/
pngwtran.c
       1  
       2  /* pngwtran.c - transforms the data in a row for PNG writers
       3   *
       4   * Copyright (c) 2018 Cosmin Truta
       5   * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
       6   * Copyright (c) 1996-1997 Andreas Dilger
       7   * 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        unsigned 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           size_t i;
     216           unsigned int mask;
     217           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              unsigned int c = i%channels;
     258              int j;
     259              unsigned int v, out;
     260  
     261              v = *bp;
     262              out = 0;
     263  
     264              for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
     265              {
     266                 if (j > 0)
     267                    out |= v << j;
     268  
     269                 else
     270                    out |= v >> (-j);
     271              }
     272  
     273              *bp = (png_byte)(out & 0xff);
     274           }
     275        }
     276  
     277        else
     278        {
     279           png_bytep bp;
     280           png_uint_32 i;
     281           png_uint_32 istop = channels * row_info->width;
     282  
     283           for (bp = row, i = 0; i < istop; i++)
     284           {
     285              unsigned int c = i%channels;
     286              int j;
     287              unsigned int value, v;
     288  
     289              v = png_get_uint_16(bp);
     290              value = 0;
     291  
     292              for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
     293              {
     294                 if (j > 0)
     295                    value |= v << j;
     296  
     297                 else
     298                    value |= v >> (-j);
     299              }
     300              *bp++ = (png_byte)((value >> 8) & 0xff);
     301              *bp++ = (png_byte)(value & 0xff);
     302           }
     303        }
     304     }
     305  }
     306  #endif
     307  
     308  #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
     309  static void
     310  png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
     311  {
     312     png_debug(1, "in png_do_write_swap_alpha");
     313  
     314     {
     315        if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
     316        {
     317           if (row_info->bit_depth == 8)
     318           {
     319              /* This converts from ARGB to RGBA */
     320              png_bytep sp, dp;
     321              png_uint_32 i;
     322              png_uint_32 row_width = row_info->width;
     323  
     324              for (i = 0, sp = dp = row; i < row_width; i++)
     325              {
     326                 png_byte save = *(sp++);
     327                 *(dp++) = *(sp++);
     328                 *(dp++) = *(sp++);
     329                 *(dp++) = *(sp++);
     330                 *(dp++) = save;
     331              }
     332           }
     333  
     334  #ifdef PNG_WRITE_16BIT_SUPPORTED
     335           else
     336           {
     337              /* This converts from AARRGGBB to RRGGBBAA */
     338              png_bytep sp, dp;
     339              png_uint_32 i;
     340              png_uint_32 row_width = row_info->width;
     341  
     342              for (i = 0, sp = dp = row; i < row_width; i++)
     343              {
     344                 png_byte save[2];
     345                 save[0] = *(sp++);
     346                 save[1] = *(sp++);
     347                 *(dp++) = *(sp++);
     348                 *(dp++) = *(sp++);
     349                 *(dp++) = *(sp++);
     350                 *(dp++) = *(sp++);
     351                 *(dp++) = *(sp++);
     352                 *(dp++) = *(sp++);
     353                 *(dp++) = save[0];
     354                 *(dp++) = save[1];
     355              }
     356           }
     357  #endif /* WRITE_16BIT */
     358        }
     359  
     360        else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
     361        {
     362           if (row_info->bit_depth == 8)
     363           {
     364              /* This converts from AG to GA */
     365              png_bytep sp, dp;
     366              png_uint_32 i;
     367              png_uint_32 row_width = row_info->width;
     368  
     369              for (i = 0, sp = dp = row; i < row_width; i++)
     370              {
     371                 png_byte save = *(sp++);
     372                 *(dp++) = *(sp++);
     373                 *(dp++) = save;
     374              }
     375           }
     376  
     377  #ifdef PNG_WRITE_16BIT_SUPPORTED
     378           else
     379           {
     380              /* This converts from AAGG to GGAA */
     381              png_bytep sp, dp;
     382              png_uint_32 i;
     383              png_uint_32 row_width = row_info->width;
     384  
     385              for (i = 0, sp = dp = row; i < row_width; i++)
     386              {
     387                 png_byte save[2];
     388                 save[0] = *(sp++);
     389                 save[1] = *(sp++);
     390                 *(dp++) = *(sp++);
     391                 *(dp++) = *(sp++);
     392                 *(dp++) = save[0];
     393                 *(dp++) = save[1];
     394              }
     395           }
     396  #endif /* WRITE_16BIT */
     397        }
     398     }
     399  }
     400  #endif
     401  
     402  #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
     403  static void
     404  png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
     405  {
     406     png_debug(1, "in png_do_write_invert_alpha");
     407  
     408     {
     409        if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
     410        {
     411           if (row_info->bit_depth == 8)
     412           {
     413              /* This inverts the alpha channel in RGBA */
     414              png_bytep sp, dp;
     415              png_uint_32 i;
     416              png_uint_32 row_width = row_info->width;
     417  
     418              for (i = 0, sp = dp = row; i < row_width; i++)
     419              {
     420                 /* Does nothing
     421                 *(dp++) = *(sp++);
     422                 *(dp++) = *(sp++);
     423                 *(dp++) = *(sp++);
     424                 */
     425                 sp+=3; dp = sp;
     426                 *dp = (png_byte)(255 - *(sp++));
     427              }
     428           }
     429  
     430  #ifdef PNG_WRITE_16BIT_SUPPORTED
     431           else
     432           {
     433              /* This inverts the alpha channel in RRGGBBAA */
     434              png_bytep sp, dp;
     435              png_uint_32 i;
     436              png_uint_32 row_width = row_info->width;
     437  
     438              for (i = 0, sp = dp = row; i < row_width; i++)
     439              {
     440                 /* Does nothing
     441                 *(dp++) = *(sp++);
     442                 *(dp++) = *(sp++);
     443                 *(dp++) = *(sp++);
     444                 *(dp++) = *(sp++);
     445                 *(dp++) = *(sp++);
     446                 *(dp++) = *(sp++);
     447                 */
     448                 sp+=6; dp = sp;
     449                 *(dp++) = (png_byte)(255 - *(sp++));
     450                 *dp     = (png_byte)(255 - *(sp++));
     451              }
     452           }
     453  #endif /* WRITE_16BIT */
     454        }
     455  
     456        else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
     457        {
     458           if (row_info->bit_depth == 8)
     459           {
     460              /* This inverts the alpha channel in GA */
     461              png_bytep sp, dp;
     462              png_uint_32 i;
     463              png_uint_32 row_width = row_info->width;
     464  
     465              for (i = 0, sp = dp = row; i < row_width; i++)
     466              {
     467                 *(dp++) = *(sp++);
     468                 *(dp++) = (png_byte)(255 - *(sp++));
     469              }
     470           }
     471  
     472  #ifdef PNG_WRITE_16BIT_SUPPORTED
     473           else
     474           {
     475              /* This inverts the alpha channel in GGAA */
     476              png_bytep sp, dp;
     477              png_uint_32 i;
     478              png_uint_32 row_width = row_info->width;
     479  
     480              for (i = 0, sp = dp = row; i < row_width; i++)
     481              {
     482                 /* Does nothing
     483                 *(dp++) = *(sp++);
     484                 *(dp++) = *(sp++);
     485                 */
     486                 sp+=2; dp = sp;
     487                 *(dp++) = (png_byte)(255 - *(sp++));
     488                 *dp     = (png_byte)(255 - *(sp++));
     489              }
     490           }
     491  #endif /* WRITE_16BIT */
     492        }
     493     }
     494  }
     495  #endif
     496  
     497  /* Transform the data according to the user's wishes.  The order of
     498   * transformations is significant.
     499   */
     500  void /* PRIVATE */
     501  png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
     502  {
     503     png_debug(1, "in png_do_write_transformations");
     504  
     505     if (png_ptr == NULL)
     506        return;
     507  
     508  #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
     509     if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
     510        if (png_ptr->write_user_transform_fn != NULL)
     511           (*(png_ptr->write_user_transform_fn)) /* User write transform
     512                                                   function */
     513               (png_ptr,  /* png_ptr */
     514               row_info,  /* row_info: */
     515                  /*  png_uint_32 width;       width of row */
     516                  /*  size_t rowbytes;         number of bytes in row */
     517                  /*  png_byte color_type;     color type of pixels */
     518                  /*  png_byte bit_depth;      bit depth of samples */
     519                  /*  png_byte channels;       number of channels (1-4) */
     520                  /*  png_byte pixel_depth;    bits per pixel (depth*channels) */
     521               png_ptr->row_buf + 1);      /* start of pixel data for row */
     522  #endif
     523  
     524  #ifdef PNG_WRITE_FILLER_SUPPORTED
     525     if ((png_ptr->transformations & PNG_FILLER) != 0)
     526        png_do_strip_channel(row_info, png_ptr->row_buf + 1,
     527            !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
     528  #endif
     529  
     530  #ifdef PNG_WRITE_PACKSWAP_SUPPORTED
     531     if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
     532        png_do_packswap(row_info, png_ptr->row_buf + 1);
     533  #endif
     534  
     535  #ifdef PNG_WRITE_PACK_SUPPORTED
     536     if ((png_ptr->transformations & PNG_PACK) != 0)
     537        png_do_pack(row_info, png_ptr->row_buf + 1,
     538            (png_uint_32)png_ptr->bit_depth);
     539  #endif
     540  
     541  #ifdef PNG_WRITE_SWAP_SUPPORTED
     542  #  ifdef PNG_16BIT_SUPPORTED
     543     if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
     544        png_do_swap(row_info, png_ptr->row_buf + 1);
     545  #  endif
     546  #endif
     547  
     548  #ifdef PNG_WRITE_SHIFT_SUPPORTED
     549     if ((png_ptr->transformations & PNG_SHIFT) != 0)
     550        png_do_shift(row_info, png_ptr->row_buf + 1,
     551             &(png_ptr->shift));
     552  #endif
     553  
     554  #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
     555     if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
     556        png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
     557  #endif
     558  
     559  #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
     560     if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
     561        png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
     562  #endif
     563  
     564  #ifdef PNG_WRITE_BGR_SUPPORTED
     565     if ((png_ptr->transformations & PNG_BGR) != 0)
     566        png_do_bgr(row_info, png_ptr->row_buf + 1);
     567  #endif
     568  
     569  #ifdef PNG_WRITE_INVERT_SUPPORTED
     570     if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
     571        png_do_invert(row_info, png_ptr->row_buf + 1);
     572  #endif
     573  }
     574  #endif /* WRITE_TRANSFORMS */
     575  #endif /* WRITE */