Back to index

tetex-bin  3.0
pngwtran.c
Go to the documentation of this file.
00001 
00002 /* pngwtran.c - transforms the data in a row for PNG writers
00003  *
00004  * libpng version 1.2.8 - December 3, 2004
00005  * For conditions of distribution and use, see copyright notice in png.h
00006  * Copyright (c) 1998-2004 Glenn Randers-Pehrson
00007  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
00008  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
00009  */
00010 
00011 #define PNG_INTERNAL
00012 #include "png.h"
00013 #ifdef PNG_WRITE_SUPPORTED
00014 
00015 /* Transform the data according to the user's wishes.  The order of
00016  * transformations is significant.
00017  */
00018 void /* PRIVATE */
00019 png_do_write_transformations(png_structp png_ptr)
00020 {
00021    png_debug(1, "in png_do_write_transformations\n");
00022 
00023    if (png_ptr == NULL)
00024       return;
00025 
00026 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
00027    if (png_ptr->transformations & PNG_USER_TRANSFORM)
00028       if(png_ptr->write_user_transform_fn != NULL)
00029         (*(png_ptr->write_user_transform_fn)) /* user write transform function */
00030           (png_ptr,                    /* png_ptr */
00031            &(png_ptr->row_info),       /* row_info:     */
00032              /*  png_uint_32 width;          width of row */
00033              /*  png_uint_32 rowbytes;       number of bytes in row */
00034              /*  png_byte color_type;        color type of pixels */
00035              /*  png_byte bit_depth;         bit depth of samples */
00036              /*  png_byte channels;          number of channels (1-4) */
00037              /*  png_byte pixel_depth;       bits per pixel (depth*channels) */
00038            png_ptr->row_buf + 1);      /* start of pixel data for row */
00039 #endif
00040 #if defined(PNG_WRITE_FILLER_SUPPORTED)
00041    if (png_ptr->transformations & PNG_FILLER)
00042       png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
00043          png_ptr->flags);
00044 #endif
00045 #if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
00046    if (png_ptr->transformations & PNG_PACKSWAP)
00047       png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
00048 #endif
00049 #if defined(PNG_WRITE_PACK_SUPPORTED)
00050    if (png_ptr->transformations & PNG_PACK)
00051       png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
00052          (png_uint_32)png_ptr->bit_depth);
00053 #endif
00054 #if defined(PNG_WRITE_SWAP_SUPPORTED)
00055    if (png_ptr->transformations & PNG_SWAP_BYTES)
00056       png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
00057 #endif
00058 #if defined(PNG_WRITE_SHIFT_SUPPORTED)
00059    if (png_ptr->transformations & PNG_SHIFT)
00060       png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
00061          &(png_ptr->shift));
00062 #endif
00063 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
00064    if (png_ptr->transformations & PNG_INVERT_ALPHA)
00065       png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
00066 #endif
00067 #if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
00068    if (png_ptr->transformations & PNG_SWAP_ALPHA)
00069       png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
00070 #endif
00071 #if defined(PNG_WRITE_BGR_SUPPORTED)
00072    if (png_ptr->transformations & PNG_BGR)
00073       png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
00074 #endif
00075 #if defined(PNG_WRITE_INVERT_SUPPORTED)
00076    if (png_ptr->transformations & PNG_INVERT_MONO)
00077       png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
00078 #endif
00079 }
00080 
00081 #if defined(PNG_WRITE_PACK_SUPPORTED)
00082 /* Pack pixels into bytes.  Pass the true bit depth in bit_depth.  The
00083  * row_info bit depth should be 8 (one pixel per byte).  The channels
00084  * should be 1 (this only happens on grayscale and paletted images).
00085  */
00086 void /* PRIVATE */
00087 png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
00088 {
00089    png_debug(1, "in png_do_pack\n");
00090    if (row_info->bit_depth == 8 &&
00091 #if defined(PNG_USELESS_TESTS_SUPPORTED)
00092        row != NULL && row_info != NULL &&
00093 #endif
00094       row_info->channels == 1)
00095    {
00096       switch ((int)bit_depth)
00097       {
00098          case 1:
00099          {
00100             png_bytep sp, dp;
00101             int mask, v;
00102             png_uint_32 i;
00103             png_uint_32 row_width = row_info->width;
00104 
00105             sp = row;
00106             dp = row;
00107             mask = 0x80;
00108             v = 0;
00109 
00110             for (i = 0; i < row_width; i++)
00111             {
00112                if (*sp != 0)
00113                   v |= mask;
00114                sp++;
00115                if (mask > 1)
00116                   mask >>= 1;
00117                else
00118                {
00119                   mask = 0x80;
00120                   *dp = (png_byte)v;
00121                   dp++;
00122                   v = 0;
00123                }
00124             }
00125             if (mask != 0x80)
00126                *dp = (png_byte)v;
00127             break;
00128          }
00129          case 2:
00130          {
00131             png_bytep sp, dp;
00132             int shift, v;
00133             png_uint_32 i;
00134             png_uint_32 row_width = row_info->width;
00135 
00136             sp = row;
00137             dp = row;
00138             shift = 6;
00139             v = 0;
00140             for (i = 0; i < row_width; i++)
00141             {
00142                png_byte value;
00143 
00144                value = (png_byte)(*sp & 0x03);
00145                v |= (value << shift);
00146                if (shift == 0)
00147                {
00148                   shift = 6;
00149                   *dp = (png_byte)v;
00150                   dp++;
00151                   v = 0;
00152                }
00153                else
00154                   shift -= 2;
00155                sp++;
00156             }
00157             if (shift != 6)
00158                *dp = (png_byte)v;
00159             break;
00160          }
00161          case 4:
00162          {
00163             png_bytep sp, dp;
00164             int shift, v;
00165             png_uint_32 i;
00166             png_uint_32 row_width = row_info->width;
00167 
00168             sp = row;
00169             dp = row;
00170             shift = 4;
00171             v = 0;
00172             for (i = 0; i < row_width; i++)
00173             {
00174                png_byte value;
00175 
00176                value = (png_byte)(*sp & 0x0f);
00177                v |= (value << shift);
00178 
00179                if (shift == 0)
00180                {
00181                   shift = 4;
00182                   *dp = (png_byte)v;
00183                   dp++;
00184                   v = 0;
00185                }
00186                else
00187                   shift -= 4;
00188 
00189                sp++;
00190             }
00191             if (shift != 4)
00192                *dp = (png_byte)v;
00193             break;
00194          }
00195       }
00196       row_info->bit_depth = (png_byte)bit_depth;
00197       row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
00198       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
00199          row_info->width);
00200    }
00201 }
00202 #endif
00203 
00204 #if defined(PNG_WRITE_SHIFT_SUPPORTED)
00205 /* Shift pixel values to take advantage of whole range.  Pass the
00206  * true number of bits in bit_depth.  The row should be packed
00207  * according to row_info->bit_depth.  Thus, if you had a row of
00208  * bit depth 4, but the pixels only had values from 0 to 7, you
00209  * would pass 3 as bit_depth, and this routine would translate the
00210  * data to 0 to 15.
00211  */
00212 void /* PRIVATE */
00213 png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
00214 {
00215    png_debug(1, "in png_do_shift\n");
00216 #if defined(PNG_USELESS_TESTS_SUPPORTED)
00217    if (row != NULL && row_info != NULL &&
00218 #else
00219    if (
00220 #endif
00221       row_info->color_type != PNG_COLOR_TYPE_PALETTE)
00222    {
00223       int shift_start[4], shift_dec[4];
00224       int channels = 0;
00225 
00226       if (row_info->color_type & PNG_COLOR_MASK_COLOR)
00227       {
00228          shift_start[channels] = row_info->bit_depth - bit_depth->red;
00229          shift_dec[channels] = bit_depth->red;
00230          channels++;
00231          shift_start[channels] = row_info->bit_depth - bit_depth->green;
00232          shift_dec[channels] = bit_depth->green;
00233          channels++;
00234          shift_start[channels] = row_info->bit_depth - bit_depth->blue;
00235          shift_dec[channels] = bit_depth->blue;
00236          channels++;
00237       }
00238       else
00239       {
00240          shift_start[channels] = row_info->bit_depth - bit_depth->gray;
00241          shift_dec[channels] = bit_depth->gray;
00242          channels++;
00243       }
00244       if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
00245       {
00246          shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
00247          shift_dec[channels] = bit_depth->alpha;
00248          channels++;
00249       }
00250 
00251       /* with low row depths, could only be grayscale, so one channel */
00252       if (row_info->bit_depth < 8)
00253       {
00254          png_bytep bp = row;
00255          png_uint_32 i;
00256          png_byte mask;
00257          png_uint_32 row_bytes = row_info->rowbytes;
00258 
00259          if (bit_depth->gray == 1 && row_info->bit_depth == 2)
00260             mask = 0x55;
00261          else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
00262             mask = 0x11;
00263          else
00264             mask = 0xff;
00265 
00266          for (i = 0; i < row_bytes; i++, bp++)
00267          {
00268             png_uint_16 v;
00269             int j;
00270 
00271             v = *bp;
00272             *bp = 0;
00273             for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
00274             {
00275                if (j > 0)
00276                   *bp |= (png_byte)((v << j) & 0xff);
00277                else
00278                   *bp |= (png_byte)((v >> (-j)) & mask);
00279             }
00280          }
00281       }
00282       else if (row_info->bit_depth == 8)
00283       {
00284          png_bytep bp = row;
00285          png_uint_32 i;
00286          png_uint_32 istop = channels * row_info->width;
00287 
00288          for (i = 0; i < istop; i++, bp++)
00289          {
00290 
00291             png_uint_16 v;
00292             int j;
00293             int c = (int)(i%channels);
00294 
00295             v = *bp;
00296             *bp = 0;
00297             for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
00298             {
00299                if (j > 0)
00300                   *bp |= (png_byte)((v << j) & 0xff);
00301                else
00302                   *bp |= (png_byte)((v >> (-j)) & 0xff);
00303             }
00304          }
00305       }
00306       else
00307       {
00308          png_bytep bp;
00309          png_uint_32 i;
00310          png_uint_32 istop = channels * row_info->width;
00311 
00312          for (bp = row, i = 0; i < istop; i++)
00313          {
00314             int c = (int)(i%channels);
00315             png_uint_16 value, v;
00316             int j;
00317 
00318             v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
00319             value = 0;
00320             for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
00321             {
00322                if (j > 0)
00323                   value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
00324                else
00325                   value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
00326             }
00327             *bp++ = (png_byte)(value >> 8);
00328             *bp++ = (png_byte)(value & 0xff);
00329          }
00330       }
00331    }
00332 }
00333 #endif
00334 
00335 #if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
00336 void /* PRIVATE */
00337 png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
00338 {
00339    png_debug(1, "in png_do_write_swap_alpha\n");
00340 #if defined(PNG_USELESS_TESTS_SUPPORTED)
00341    if (row != NULL && row_info != NULL)
00342 #endif
00343    {
00344       if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
00345       {
00346          /* This converts from ARGB to RGBA */
00347          if (row_info->bit_depth == 8)
00348          {
00349             png_bytep sp, dp;
00350             png_uint_32 i;
00351             png_uint_32 row_width = row_info->width;
00352             for (i = 0, sp = dp = row; i < row_width; i++)
00353             {
00354                png_byte save = *(sp++);
00355                *(dp++) = *(sp++);
00356                *(dp++) = *(sp++);
00357                *(dp++) = *(sp++);
00358                *(dp++) = save;
00359             }
00360          }
00361          /* This converts from AARRGGBB to RRGGBBAA */
00362          else
00363          {
00364             png_bytep sp, dp;
00365             png_uint_32 i;
00366             png_uint_32 row_width = row_info->width;
00367 
00368             for (i = 0, sp = dp = row; i < row_width; i++)
00369             {
00370                png_byte save[2];
00371                save[0] = *(sp++);
00372                save[1] = *(sp++);
00373                *(dp++) = *(sp++);
00374                *(dp++) = *(sp++);
00375                *(dp++) = *(sp++);
00376                *(dp++) = *(sp++);
00377                *(dp++) = *(sp++);
00378                *(dp++) = *(sp++);
00379                *(dp++) = save[0];
00380                *(dp++) = save[1];
00381             }
00382          }
00383       }
00384       else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
00385       {
00386          /* This converts from AG to GA */
00387          if (row_info->bit_depth == 8)
00388          {
00389             png_bytep sp, dp;
00390             png_uint_32 i;
00391             png_uint_32 row_width = row_info->width;
00392 
00393             for (i = 0, sp = dp = row; i < row_width; i++)
00394             {
00395                png_byte save = *(sp++);
00396                *(dp++) = *(sp++);
00397                *(dp++) = save;
00398             }
00399          }
00400          /* This converts from AAGG to GGAA */
00401          else
00402          {
00403             png_bytep sp, dp;
00404             png_uint_32 i;
00405             png_uint_32 row_width = row_info->width;
00406 
00407             for (i = 0, sp = dp = row; i < row_width; i++)
00408             {
00409                png_byte save[2];
00410                save[0] = *(sp++);
00411                save[1] = *(sp++);
00412                *(dp++) = *(sp++);
00413                *(dp++) = *(sp++);
00414                *(dp++) = save[0];
00415                *(dp++) = save[1];
00416             }
00417          }
00418       }
00419    }
00420 }
00421 #endif
00422 
00423 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
00424 void /* PRIVATE */
00425 png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
00426 {
00427    png_debug(1, "in png_do_write_invert_alpha\n");
00428 #if defined(PNG_USELESS_TESTS_SUPPORTED)
00429    if (row != NULL && row_info != NULL)
00430 #endif
00431    {
00432       if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
00433       {
00434          /* This inverts the alpha channel in RGBA */
00435          if (row_info->bit_depth == 8)
00436          {
00437             png_bytep sp, dp;
00438             png_uint_32 i;
00439             png_uint_32 row_width = row_info->width;
00440             for (i = 0, sp = dp = row; i < row_width; i++)
00441             {
00442                *(dp++) = *(sp++);
00443                *(dp++) = *(sp++);
00444                *(dp++) = *(sp++);
00445                *(dp++) = (png_byte)(255 - *(sp++));
00446             }
00447          }
00448          /* This inverts the alpha channel in RRGGBBAA */
00449          else
00450          {
00451             png_bytep sp, dp;
00452             png_uint_32 i;
00453             png_uint_32 row_width = row_info->width;
00454 
00455             for (i = 0, sp = dp = row; i < row_width; i++)
00456             {
00457                *(dp++) = *(sp++);
00458                *(dp++) = *(sp++);
00459                *(dp++) = *(sp++);
00460                *(dp++) = *(sp++);
00461                *(dp++) = *(sp++);
00462                *(dp++) = *(sp++);
00463                *(dp++) = (png_byte)(255 - *(sp++));
00464                *(dp++) = (png_byte)(255 - *(sp++));
00465             }
00466          }
00467       }
00468       else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
00469       {
00470          /* This inverts the alpha channel in GA */
00471          if (row_info->bit_depth == 8)
00472          {
00473             png_bytep sp, dp;
00474             png_uint_32 i;
00475             png_uint_32 row_width = row_info->width;
00476 
00477             for (i = 0, sp = dp = row; i < row_width; i++)
00478             {
00479                *(dp++) = *(sp++);
00480                *(dp++) = (png_byte)(255 - *(sp++));
00481             }
00482          }
00483          /* This inverts the alpha channel in GGAA */
00484          else
00485          {
00486             png_bytep sp, dp;
00487             png_uint_32 i;
00488             png_uint_32 row_width = row_info->width;
00489 
00490             for (i = 0, sp = dp = row; i < row_width; i++)
00491             {
00492                *(dp++) = *(sp++);
00493                *(dp++) = *(sp++);
00494                *(dp++) = (png_byte)(255 - *(sp++));
00495                *(dp++) = (png_byte)(255 - *(sp++));
00496             }
00497          }
00498       }
00499    }
00500 }
00501 #endif
00502 
00503 #if defined(PNG_MNG_FEATURES_SUPPORTED)
00504 /* undoes intrapixel differencing  */
00505 void /* PRIVATE */
00506 png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
00507 {
00508    png_debug(1, "in png_do_write_intrapixel\n");
00509    if (
00510 #if defined(PNG_USELESS_TESTS_SUPPORTED)
00511        row != NULL && row_info != NULL &&
00512 #endif
00513        (row_info->color_type & PNG_COLOR_MASK_COLOR))
00514    {
00515       int bytes_per_pixel;
00516       png_uint_32 row_width = row_info->width;
00517       if (row_info->bit_depth == 8)
00518       {
00519          png_bytep rp;
00520          png_uint_32 i;
00521 
00522          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
00523             bytes_per_pixel = 3;
00524          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
00525             bytes_per_pixel = 4;
00526          else
00527             return;
00528 
00529          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
00530          {
00531             *(rp)   = (png_byte)((*rp     - *(rp+1))&0xff);
00532             *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
00533          }
00534       }
00535       else if (row_info->bit_depth == 16)
00536       {
00537          png_bytep rp;
00538          png_uint_32 i;
00539 
00540          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
00541             bytes_per_pixel = 6;
00542          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
00543             bytes_per_pixel = 8;
00544          else
00545             return;
00546 
00547          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
00548          {
00549             png_uint_32 s0   = (*(rp  ) << 8) | *(rp+1);
00550             png_uint_32 s1   = (*(rp+2) << 8) | *(rp+3);
00551             png_uint_32 s2   = (*(rp+4) << 8) | *(rp+5);
00552             png_uint_32 red  = (png_uint_32)((s0-s1) & 0xffffL);
00553             png_uint_32 blue = (png_uint_32)((s2-s1) & 0xffffL);
00554             *(rp  ) = (png_byte)((red >> 8) & 0xff);
00555             *(rp+1) = (png_byte)(red & 0xff);
00556             *(rp+4) = (png_byte)((blue >> 8) & 0xff);
00557             *(rp+5) = (png_byte)(blue & 0xff);
00558          }
00559       }
00560    }
00561 }
00562 #endif /* PNG_MNG_FEATURES_SUPPORTED */
00563 #endif /* PNG_WRITE_SUPPORTED */