"Fossies" - the Fresh Open Source Software Archive

Member "libgd-2.3.2/src/gd_filter.c" (3 Mar 2021, 24685 Bytes) of package /linux/www/libgd-2.3.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gd_filter.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.1_vs_2.3.2.

    1 /**
    2  * File: Image Filters
    3  */
    4 
    5 
    6 #ifdef HAVE_CONFIG_H
    7 #include "config.h"
    8 #endif
    9 
   10 #include "gd.h"
   11 #include "gdhelpers.h"
   12 #include "gd_intern.h"
   13 
   14 #ifdef _WIN32
   15 # include <windows.h>
   16 #else
   17 # include <unistd.h>
   18 #endif
   19 #include <stdlib.h>
   20 #include <time.h>
   21 #include <math.h>
   22 
   23 #undef NDEBUG
   24 /* Comment out this line to enable asserts.
   25  * TODO: This logic really belongs in cmake and configure.
   26  */
   27 #define NDEBUG 1
   28 #include <assert.h>
   29 
   30 typedef int (BGD_STDCALL *FuncPtr)(gdImagePtr, int, int);
   31 
   32 #define GET_PIXEL_FUNCTION(src)(src->trueColor?gdImageGetTrueColorPixel:gdImageGetPixel)
   33 
   34 #ifdef _WIN32
   35 # define GD_SCATTER_SEED() (unsigned int)(time(0) * GetCurrentProcessId())
   36 #else
   37 # define GD_SCATTER_SEED() (unsigned int)(time(0) * getpid())
   38 #endif
   39 
   40 /*
   41     Function: gdImageScatter
   42  */
   43 BGD_DECLARE(int) gdImageScatter(gdImagePtr im, int sub, int plus)
   44 {
   45     gdScatter s;
   46 
   47     s.sub  = sub;
   48     s.plus = plus;
   49     s.num_colors = 0;
   50     s.seed = GD_SCATTER_SEED();
   51     return gdImageScatterEx(im, &s);
   52 }
   53 
   54 /*
   55     Function: gdImageScatterColor
   56  */
   57 BGD_DECLARE(int) gdImageScatterColor(gdImagePtr im, int sub, int plus, int colors[], unsigned int num_colors)
   58 {
   59     gdScatter s;
   60 
   61     s.sub  = sub;
   62     s.plus = plus;
   63     s.colors = colors;
   64     s.num_colors = num_colors;
   65     s.seed = GD_SCATTER_SEED();
   66     return gdImageScatterEx(im, &s);
   67 }
   68 
   69 /*
   70     Function: gdImageScatterEx
   71  */
   72 BGD_DECLARE(int) gdImageScatterEx(gdImagePtr im, gdScatterPtr scatter)
   73 {
   74     register int x, y;
   75     int dest_x, dest_y;
   76     int pxl, new_pxl;
   77     unsigned int n;
   78     int sub = scatter->sub, plus = scatter->plus;
   79 
   80     if (plus == 0 && sub == 0) {
   81         return 1;
   82     } else if (sub >= plus) {
   83         return 0;
   84     }
   85 
   86     (void)srand(scatter->seed);
   87 
   88     if (scatter->num_colors) {
   89         for (y = 0; y < im->sy; y++) {
   90             for (x = 0; x < im->sx; x++) {
   91                 dest_x = (int) (x + ((rand() % (plus - sub)) + sub));
   92                 dest_y = (int) (y + ((rand() % (plus - sub)) + sub));
   93 
   94                 if (!gdImageBoundsSafe(im, dest_x, dest_y)) {
   95                     continue;
   96                 }
   97 
   98                 pxl = gdImageGetPixel(im, x, y);
   99                 new_pxl = gdImageGetPixel(im, dest_x, dest_y);
  100 
  101                 for (n = 0; n < scatter->num_colors; n++) {
  102                     if (pxl == scatter->colors[n]) {
  103                         gdImageSetPixel(im, dest_x, dest_y, pxl);
  104                         gdImageSetPixel(im, x, y, new_pxl);
  105                     }
  106                 }
  107             }
  108         }
  109     } else {
  110         for (y = 0; y < im->sy; y++) {
  111             for (x = 0; x < im->sx; x++) {
  112                 dest_x = (int) (x + ((rand() % (plus - sub)) + sub));
  113                 dest_y = (int) (y + ((rand() % (plus - sub)) + sub));
  114 
  115                 if (!gdImageBoundsSafe(im, dest_x, dest_y)) {
  116                     continue;
  117                 }
  118 
  119                 pxl = gdImageGetPixel(im, x, y);
  120                 new_pxl = gdImageGetPixel(im, dest_x, dest_y);
  121 
  122                 gdImageSetPixel(im, dest_x, dest_y, pxl);
  123                 gdImageSetPixel(im, x, y, new_pxl);
  124             }
  125         }
  126     }
  127 
  128     return 1;
  129 }
  130 
  131 /*
  132     Function: gdImagePixelate
  133  */
  134 BGD_DECLARE(int) gdImagePixelate(gdImagePtr im, int block_size, const unsigned int mode)
  135 {
  136     int x, y;
  137 
  138     if (block_size <= 0) {
  139         return 0;
  140     } else if (block_size == 1) {
  141         return 1;
  142     }
  143     switch (mode) {
  144     case GD_PIXELATE_UPPERLEFT:
  145         for (y = 0; y < im->sy; y += block_size) {
  146             for (x = 0; x < im->sx; x += block_size) {
  147                 if (gdImageBoundsSafe(im, x, y)) {
  148                     int c = gdImageGetPixel(im, x, y);
  149                     gdImageFilledRectangle(im, x, y, x + block_size - 1, y + block_size - 1, c);
  150                 }
  151             }
  152         }
  153         break;
  154     case GD_PIXELATE_AVERAGE:
  155         for (y = 0; y < im->sy; y += block_size) {
  156             for (x = 0; x < im->sx; x += block_size) {
  157                 int a, r, g, b, c;
  158                 int total;
  159                 int cx, cy;
  160 
  161                 a = r = g = b = c = total = 0;
  162                 /* sampling */
  163                 for (cy = 0; cy < block_size; cy++) {
  164                     for (cx = 0; cx < block_size; cx++) {
  165                         if (!gdImageBoundsSafe(im, x + cx, y + cy)) {
  166                             continue;
  167                         }
  168                         c = gdImageGetPixel(im, x + cx, y + cy);
  169                         a += gdImageAlpha(im, c);
  170                         r += gdImageRed(im, c);
  171                         g += gdImageGreen(im, c);
  172                         b += gdImageBlue(im, c);
  173                         total++;
  174                     }
  175                 }
  176                 /* drawing */
  177                 if (total > 0) {
  178                     c = gdImageColorResolveAlpha(im, r / total, g / total, b / total, a / total);
  179                     gdImageFilledRectangle(im, x, y, x + block_size - 1, y + block_size - 1, c);
  180                 }
  181             }
  182         }
  183         break;
  184     default:
  185         return 0;
  186     }
  187     return 1;
  188 }
  189 
  190 /**
  191  * Function: gdImageNegate
  192  *
  193  * Invert an image
  194  *
  195  * Parameters:
  196  *   src - The image.
  197  *
  198  * Returns:
  199  *   Non-zero on success, zero on failure.
  200  */
  201 BGD_DECLARE(int) gdImageNegate(gdImagePtr src)
  202 {
  203     int x, y;
  204     int r,g,b,a;
  205     int new_pxl, pxl;
  206     FuncPtr f;
  207 
  208     if (src==NULL) {
  209         return 0;
  210     }
  211 
  212     f = GET_PIXEL_FUNCTION(src);
  213 
  214     for (y=0; y<src->sy; ++y) {
  215         for (x=0; x<src->sx; ++x) {
  216             pxl = f (src, x, y);
  217             r = gdImageRed(src, pxl);
  218             g = gdImageGreen(src, pxl);
  219             b = gdImageBlue(src, pxl);
  220             a = gdImageAlpha(src, pxl);
  221 
  222             new_pxl = gdImageColorAllocateAlpha(src, 255-r, 255-g, 255-b, a);
  223             if (new_pxl == -1) {
  224                 new_pxl = gdImageColorClosestAlpha(src, 255-r, 255-g, 255-b, a);
  225             }
  226             gdImageSetPixel (src, x, y, new_pxl);
  227         }
  228     }
  229     return 1;
  230 }
  231 
  232 /**
  233  * Function: gdImageGrayScale
  234  *
  235  * Convert an image to grayscale
  236  *
  237  * The red, green and blue components of each pixel are replaced by their
  238  * weighted sum using the same coefficients as the REC.601 luma (Y')
  239  * calculation. The alpha components are retained.
  240  *
  241  * For palette images the result may differ due to palette limitations.
  242  *
  243  * Parameters:
  244  *   src - The image.
  245  *
  246  * Returns:
  247  *   Non-zero on success, zero on failure.
  248  */
  249 BGD_DECLARE(int) gdImageGrayScale(gdImagePtr src)
  250 {
  251     int x, y;
  252     int r,g,b,a;
  253     int new_pxl, pxl;
  254     FuncPtr f;
  255     int alpha_blending;
  256 
  257     if (src==NULL) {
  258         return 0;
  259     }
  260 
  261     alpha_blending = src->alphaBlendingFlag;
  262     gdImageAlphaBlending(src, gdEffectReplace);
  263 
  264     f = GET_PIXEL_FUNCTION(src);
  265 
  266     for (y=0; y<src->sy; ++y) {
  267         for (x=0; x<src->sx; ++x) {
  268             pxl = f (src, x, y);
  269             r = gdImageRed(src, pxl);
  270             g = gdImageGreen(src, pxl);
  271             b = gdImageBlue(src, pxl);
  272             a = gdImageAlpha(src, pxl);
  273             r = g = b = (int) (.299 * r + .587 * g + .114 * b);
  274 
  275             new_pxl = gdImageColorAllocateAlpha(src, r, g, b, a);
  276             if (new_pxl == -1) {
  277                 new_pxl = gdImageColorClosestAlpha(src, r, g, b, a);
  278             }
  279             gdImageSetPixel (src, x, y, new_pxl);
  280         }
  281     }
  282     gdImageAlphaBlending(src, alpha_blending);
  283 
  284     return 1;
  285 }
  286 
  287 /**
  288  * Function: gdImageBrightness
  289  *
  290  * Change the brightness of an image
  291  *
  292  * Parameters:
  293  *   src        - The image.
  294  *   brightness - The value to add to the color channels of all pixels.
  295  *
  296  * Returns:
  297  *   Non-zero on success, zero on failure.
  298  *
  299  * See also:
  300  *   - <gdImageContrast>
  301  *   - <gdImageColor>
  302  */
  303 BGD_DECLARE(int) gdImageBrightness(gdImagePtr src, int brightness)
  304 {
  305     int x, y;
  306     int r,g,b,a;
  307     int new_pxl, pxl;
  308     FuncPtr f;
  309 
  310     if (src==NULL || (brightness < -255 || brightness > 255)) {
  311         return 0;
  312     }
  313 
  314     if (brightness==0) {
  315         return 1;
  316     }
  317 
  318     f = GET_PIXEL_FUNCTION(src);
  319 
  320     for (y=0; y<src->sy; ++y) {
  321         for (x=0; x<src->sx; ++x) {
  322             pxl = f (src, x, y);
  323 
  324             r = gdImageRed(src, pxl);
  325             g = gdImageGreen(src, pxl);
  326             b = gdImageBlue(src, pxl);
  327             a = gdImageAlpha(src, pxl);
  328 
  329             r = r + brightness;
  330             g = g + brightness;
  331             b = b + brightness;
  332 
  333             r = (r > 255)? 255 : ((r < 0)? 0:r);
  334             g = (g > 255)? 255 : ((g < 0)? 0:g);
  335             b = (b > 255)? 255 : ((b < 0)? 0:b);
  336 
  337             new_pxl = gdImageColorAllocateAlpha(src, (int)r, (int)g, (int)b, a);
  338             if (new_pxl == -1) {
  339                 new_pxl = gdImageColorClosestAlpha(src, (int)r, (int)g, (int)b, a);
  340             }
  341             gdImageSetPixel (src, x, y, new_pxl);
  342         }
  343     }
  344     return 1;
  345 }
  346 
  347 
  348 /**
  349  * Function: gdImageContrast
  350  *
  351  * Change the contrast of an image
  352  *
  353  * Parameters:
  354  *   src      - The image.
  355  *   contrast - The contrast adjustment value. Negative values increase, postive
  356  *              values decrease the contrast. The larger the absolute value, the
  357  *              stronger the effect.
  358  *
  359  * Returns:
  360  *   Non-zero on success, zero on failure.
  361  *
  362  * See also:
  363  *   - <gdImageBrightness>
  364  */
  365 BGD_DECLARE(int) gdImageContrast(gdImagePtr src, double contrast)
  366 {
  367     int x, y;
  368     int r,g,b,a;
  369     double rf,gf,bf;
  370     int new_pxl, pxl;
  371 
  372     FuncPtr f;
  373 
  374     if (src==NULL) {
  375         return 0;
  376     }
  377 
  378     f = GET_PIXEL_FUNCTION(src);
  379 
  380     contrast = (double)(100.0-contrast)/100.0;
  381     contrast = contrast*contrast;
  382 
  383     for (y=0; y<src->sy; ++y) {
  384         for (x=0; x<src->sx; ++x) {
  385             pxl = f(src, x, y);
  386 
  387             r = gdImageRed(src, pxl);
  388             g = gdImageGreen(src, pxl);
  389             b = gdImageBlue(src, pxl);
  390             a = gdImageAlpha(src, pxl);
  391 
  392             rf = (double)r/255.0;
  393             rf = rf-0.5;
  394             rf = rf*contrast;
  395             rf = rf+0.5;
  396             rf = rf*255.0;
  397 
  398             bf = (double)b/255.0;
  399             bf = bf-0.5;
  400             bf = bf*contrast;
  401             bf = bf+0.5;
  402             bf = bf*255.0;
  403 
  404             gf = (double)g/255.0;
  405             gf = gf-0.5;
  406             gf = gf*contrast;
  407             gf = gf+0.5;
  408             gf = gf*255.0;
  409 
  410             rf = (rf > 255.0)? 255.0 : ((rf < 0.0)? 0.0:rf);
  411             gf = (gf > 255.0)? 255.0 : ((gf < 0.0)? 0.0:gf);
  412             bf = (bf > 255.0)? 255.0 : ((bf < 0.0)? 0.0:bf);
  413 
  414             new_pxl = gdImageColorAllocateAlpha(src, (int)rf, (int)gf, (int)bf, a);
  415             if (new_pxl == -1) {
  416                 new_pxl = gdImageColorClosestAlpha(src, (int)rf, (int)gf, (int)bf, a);
  417             }
  418             gdImageSetPixel (src, x, y, new_pxl);
  419         }
  420     }
  421     return 1;
  422 }
  423 
  424 
  425 /**
  426  * Function: gdImageColor
  427  *
  428  * Change channel values of an image
  429  *
  430  * Parameters:
  431  *   src   - The image.
  432  *   red   - The value to add to the red channel of all pixels.
  433  *   green - The value to add to the green channel of all pixels.
  434  *   blue  - The value to add to the blue channel of all pixels.
  435  *   alpha - The value to add to the alpha channel of all pixels.
  436  *
  437  * Returns:
  438  *   Non-zero on success, zero on failure.
  439  *
  440  * See also:
  441  *   - <gdImageBrightness>
  442  */
  443 BGD_DECLARE(int) gdImageColor(gdImagePtr src, const int red, const int green, const int blue, const int alpha)
  444 {
  445     int x, y;
  446     int new_pxl, pxl;
  447     FuncPtr f;
  448 
  449     if (src == NULL) {
  450         return 0;
  451     }
  452 
  453     f = GET_PIXEL_FUNCTION(src);
  454 
  455     for (y=0; y<src->sy; ++y) {
  456         for (x=0; x<src->sx; ++x) {
  457             int r,g,b,a;
  458 
  459             pxl = f(src, x, y);
  460             r = gdImageRed(src, pxl);
  461             g = gdImageGreen(src, pxl);
  462             b = gdImageBlue(src, pxl);
  463             a = gdImageAlpha(src, pxl);
  464 
  465             r = r + red;
  466             g = g + green;
  467             b = b + blue;
  468             a = a + alpha;
  469 
  470             r = (r > 255)? 255 : ((r < 0)? 0 : r);
  471             g = (g > 255)? 255 : ((g < 0)? 0 : g);
  472             b = (b > 255)? 255 : ((b < 0)? 0 : b);
  473             a = (a > 127)? 127 : ((a < 0)? 0 : a);
  474 
  475             new_pxl = gdImageColorAllocateAlpha(src, r, g, b, a);
  476             if (new_pxl == -1) {
  477                 new_pxl = gdImageColorClosestAlpha(src, r, g, b, a);
  478             }
  479             gdImageSetPixel (src, x, y, new_pxl);
  480         }
  481     }
  482     return 1;
  483 }
  484 
  485 /**
  486  * Function: gdImageConvolution
  487  *
  488  * Apply a convolution matrix to an image
  489  *
  490  * Depending on the matrix a wide range of effects can be accomplished, e.g.
  491  * blurring, sharpening, embossing and edge detection.
  492  *
  493  * Parameters:
  494  *   src        - The image.
  495  *   filter     - The 3x3 convolution matrix.
  496  *   filter_div - The value to divide the convoluted channel values by.
  497  *   offset     - The value to add to the convoluted channel values.
  498  *
  499  * Returns:
  500  *   Non-zero on success, zero on failure.
  501  *
  502  * See also:
  503  *   - <gdImageEdgeDetectQuick>
  504  *   - <gdImageGaussianBlur>
  505  *   - <gdImageEmboss>
  506  *   - <gdImageMeanRemoval>
  507  *   - <gdImageSmooth>
  508  */
  509 BGD_DECLARE(int) gdImageConvolution(gdImagePtr src, float filter[3][3], float filter_div, float offset)
  510 {
  511     int         x, y, i, j, new_a;
  512     float       new_r, new_g, new_b;
  513     int         new_pxl, pxl=0;
  514     gdImagePtr  srcback;
  515     FuncPtr f;
  516 
  517     if (src==NULL) {
  518         return 0;
  519     }
  520 
  521     /* We need the orinal image with each safe neoghb. pixel */
  522     srcback = gdImageCreateTrueColor (src->sx, src->sy);
  523     if (srcback==NULL) {
  524         return 0;
  525     }
  526 
  527     gdImageSaveAlpha(srcback, 1);
  528     new_pxl = gdImageColorAllocateAlpha(srcback, 0, 0, 0, 127);
  529     gdImageFill(srcback, 0, 0, new_pxl);
  530 
  531     gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);
  532 
  533     f = GET_PIXEL_FUNCTION(src);
  534 
  535     for ( y=0; y<src->sy; y++) {
  536         for(x=0; x<src->sx; x++) {
  537             new_r = new_g = new_b = 0;
  538             pxl = f(srcback, x, y);
  539             new_a = gdImageAlpha(srcback, pxl);
  540 
  541             for (j=0; j<3; j++) {
  542                 int yv = MIN(MAX(y - 1 + j, 0), src->sy - 1);
  543                 for (i=0; i<3; i++) {
  544                         pxl = f(srcback, MIN(MAX(x - 1 + i, 0), src->sx - 1), yv);
  545                     new_r += (float)gdImageRed(srcback, pxl) * filter[j][i];
  546                     new_g += (float)gdImageGreen(srcback, pxl) * filter[j][i];
  547                     new_b += (float)gdImageBlue(srcback, pxl) * filter[j][i];
  548                 }
  549             }
  550 
  551             new_r = (new_r/filter_div)+offset;
  552             new_g = (new_g/filter_div)+offset;
  553             new_b = (new_b/filter_div)+offset;
  554 
  555             new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
  556             new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
  557             new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
  558 
  559             new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
  560             if (new_pxl == -1) {
  561                 new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
  562             }
  563             gdImageSetPixel (src, x, y, new_pxl);
  564         }
  565     }
  566     gdImageDestroy(srcback);
  567     return 1;
  568 }
  569 
  570 /*
  571     Function: gdImageSelectiveBlur
  572  */
  573 BGD_DECLARE(int) gdImageSelectiveBlur( gdImagePtr src)
  574 {
  575     int         x, y, i, j;
  576     float       new_r, new_g, new_b;
  577     int         new_pxl, cpxl, pxl, new_a=0;
  578     float flt_r [3][3];
  579     float flt_g [3][3];
  580     float flt_b [3][3];
  581     float flt_r_sum, flt_g_sum, flt_b_sum;
  582 
  583     gdImagePtr srcback;
  584     FuncPtr f;
  585 
  586     if (src==NULL) {
  587         return 0;
  588     }
  589 
  590     /* We need the orinal image with each safe neoghb. pixel */
  591     srcback = gdImageCreateTrueColor (src->sx, src->sy);
  592     if (srcback==NULL) {
  593         return 0;
  594     }
  595     gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);
  596 
  597     f = GET_PIXEL_FUNCTION(src);
  598 
  599     for(y = 0; y<src->sy; y++) {
  600         for (x=0; x<src->sx; x++) {
  601               flt_r_sum = flt_g_sum = flt_b_sum = 0.0;
  602             cpxl = f(src, x, y);
  603 
  604             for (j=0; j<3; j++) {
  605                 for (i=0; i<3; i++) {
  606                     if ((j == 1) && (i == 1)) {
  607                         flt_r[1][1] = flt_g[1][1] = flt_b[1][1] = 0.5;
  608                     } else {
  609                         pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
  610                         new_a = gdImageAlpha(srcback, pxl);
  611 
  612                         new_r = ((float)gdImageRed(srcback, cpxl)) - ((float)gdImageRed (srcback, pxl));
  613 
  614                         if (new_r < 0.0f) {
  615                             new_r = -new_r;
  616                         }
  617                         if (new_r != 0) {
  618                             flt_r[j][i] = 1.0f/new_r;
  619                         } else {
  620                             flt_r[j][i] = 1.0f;
  621                         }
  622 
  623                         new_g = ((float)gdImageGreen(srcback, cpxl)) - ((float)gdImageGreen(srcback, pxl));
  624 
  625                         if (new_g < 0.0f) {
  626                             new_g = -new_g;
  627                         }
  628                         if (new_g != 0) {
  629                             flt_g[j][i] = 1.0f/new_g;
  630                         } else {
  631                             flt_g[j][i] = 1.0f;
  632                         }
  633 
  634                         new_b = ((float)gdImageBlue(srcback, cpxl)) - ((float)gdImageBlue(srcback, pxl));
  635 
  636                         if (new_b < 0.0f) {
  637                             new_b = -new_b;
  638                         }
  639                         if (new_b != 0) {
  640                             flt_b[j][i] = 1.0f/new_b;
  641                         } else {
  642                             flt_b[j][i] = 1.0f;
  643                         }
  644                     }
  645 
  646                     flt_r_sum += flt_r[j][i];
  647                     flt_g_sum += flt_g[j][i];
  648                     flt_b_sum += flt_b [j][i];
  649                 }
  650             }
  651 
  652             for (j=0; j<3; j++) {
  653                 for (i=0; i<3; i++) {
  654                     if (flt_r_sum != 0.0) {
  655                         flt_r[j][i] /= flt_r_sum;
  656                     }
  657                     if (flt_g_sum != 0.0) {
  658                         flt_g[j][i] /= flt_g_sum;
  659                     }
  660                     if (flt_b_sum != 0.0) {
  661                         flt_b [j][i] /= flt_b_sum;
  662                     }
  663                 }
  664             }
  665 
  666             new_r = new_g = new_b = 0.0;
  667 
  668             for (j=0; j<3; j++) {
  669                 for (i=0; i<3; i++) {
  670                     pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
  671                     new_r += (float)gdImageRed(srcback, pxl) * flt_r[j][i];
  672                     new_g += (float)gdImageGreen(srcback, pxl) * flt_g[j][i];
  673                     new_b += (float)gdImageBlue(srcback, pxl) * flt_b[j][i];
  674                 }
  675             }
  676 
  677             new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
  678             new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
  679             new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
  680             new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
  681             if (new_pxl == -1) {
  682                 new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
  683             }
  684             gdImageSetPixel (src, x, y, new_pxl);
  685         }
  686     }
  687     gdImageDestroy(srcback);
  688     return 1;
  689 }
  690 
  691 /**
  692  * Function: gdImageEdgeDetectQuick
  693  *
  694  * Edge detection of an image
  695  *
  696  * (see edge_detect_quick.jpg)
  697  *
  698  * Parameters:
  699  *   src - The image.
  700  *
  701  * Returns:
  702  *   Non-zero on success, zero on failure.
  703  *
  704  * See also:
  705  *   - <gdImageMeanRemoval>
  706  *   - <gdImageConvolution>
  707  */
  708 BGD_DECLARE(int) gdImageEdgeDetectQuick(gdImagePtr src)
  709 {
  710     float filter[3][3] =    {{-1.0,0.0,-1.0},
  711                 {0.0,4.0,0.0},
  712                 {-1.0,0.0,-1.0}};
  713 
  714     return gdImageConvolution(src, filter, 1, 127);
  715 }
  716 
  717 /*
  718   Function: gdImageGaussianBlur
  719 
  720     <gdImageGaussianBlur> performs a Gaussian blur of radius 1 on the
  721     image.  The image is modified in place.
  722 
  723     *NOTE:* You will almost certain want to use
  724     <gdImageCopyGaussianBlurred> instead, as it allows you to change
  725     your kernel size and sigma value.  Future versions of this
  726     function may fall back to calling it instead of
  727     <gdImageConvolution>, causing subtle changes so be warned.
  728 
  729   Parameters:
  730     im  - The image to blur
  731 
  732   Returns:
  733     GD_TRUE (1) on success, GD_FALSE (0) on failure.
  734 
  735 */
  736 
  737 BGD_DECLARE(int) gdImageGaussianBlur(gdImagePtr im)
  738 {
  739     float filter[3][3] = {
  740         {1.0, 2.0, 1.0},
  741         {2.0, 4.0, 2.0},
  742         {1.0, 2.0, 1.0}
  743     };
  744 
  745     return gdImageConvolution(im, filter, 16, 0);
  746 }
  747 
  748 /**
  749  * Function: gdImageEmboss
  750  *
  751  * Emboss an image
  752  *
  753  * (see emboss.jpg)
  754  *
  755  * Parameters:
  756  *   im - The image.
  757  *
  758  * Returns:
  759  *   Non-zero on success, zero on failure.
  760  *
  761  * See also:
  762  *   - <gdImageConvolution>
  763  */
  764 BGD_DECLARE(int) gdImageEmboss(gdImagePtr im)
  765 {
  766 /*
  767     float filter[3][3] =    {{1.0,1.0,1.0},
  768                 {0.0,0.0,0.0},
  769                 {-1.0,-1.0,-1.0}};
  770 */
  771     float filter[3][3] =    {{ 1.5, 0.0, 0.0},
  772                  { 0.0, 0.0, 0.0},
  773                  { 0.0, 0.0,-1.5}};
  774 
  775     return gdImageConvolution(im, filter, 1, 127);
  776 }
  777 
  778 /**
  779  * Function: gdImageMeanRemoval
  780  *
  781  * Mean removal of an image
  782  *
  783  * (see mean_removal.jpg)
  784  *
  785  * Parameters:
  786  *   im - The image.
  787  *
  788  * Returns:
  789  *   Non-zero on success, zero on failure.
  790  *
  791  * See also:
  792  *   - <gdImageEdgeDetectQuick>
  793  *   - <gdImageConvolution>
  794  */
  795 BGD_DECLARE(int) gdImageMeanRemoval(gdImagePtr im)
  796 {
  797     float filter[3][3] =    {{-1.0,-1.0,-1.0},
  798                 {-1.0,9.0,-1.0},
  799                 {-1.0,-1.0,-1.0}};
  800 
  801     return gdImageConvolution(im, filter, 1, 0);
  802 }
  803 
  804 /**
  805  * Function: gdImageSmooth
  806  *
  807  * Smooth an image
  808  *
  809  * (see smooth.jpg)
  810  *
  811  * Parameters:
  812  *   im     - The image.
  813  *   weight - The strength of the smoothing.
  814  *
  815  * Returns:
  816  *   Non-zero on success, zero on failure.
  817  *
  818  * See also:
  819  *   - <gdImageConvolution>
  820  */
  821 BGD_DECLARE(int) gdImageSmooth(gdImagePtr im, float weight)
  822 {
  823     float filter[3][3] =    {{1.0,1.0,1.0},
  824                 {1.0,0.0,1.0},
  825                 {1.0,1.0,1.0}};
  826 
  827     filter[1][1] = weight;
  828 
  829     return gdImageConvolution(im, filter, weight+8, 0);
  830 }
  831 
  832 
  833 /* ======================== Gaussian Blur Code ======================== */
  834 
  835 /* Return an array of coefficients for 'radius' and 'sigma' (sigma >=
  836  * 0 means compute it).  Result length is 2*radius+1. */
  837 static double *
  838 gaussian_coeffs(int radius, double sigmaArg) {
  839     const double sigma = (sigmaArg <= 0.0) ? (2.0/3.0)*radius : sigmaArg;
  840     const double s = 2.0 * sigma * sigma;
  841     double *result;
  842     double sum = 0;
  843     int x, n, count;
  844 
  845     count = 2*radius + 1;
  846 
  847     result = gdMalloc(sizeof(double) * count);
  848     if (!result) {
  849         return NULL;
  850     }/* if */
  851 
  852     for (x = -radius; x <= radius; x++) {
  853         double coeff = exp(-(x*x)/s);
  854 
  855         sum += coeff;
  856         result[x + radius] = coeff;
  857     }/* for */
  858 
  859     for (n = 0; n < count; n++) {
  860         result[n] /= sum;
  861     }/* for */
  862 
  863     return result;
  864 }/* gaussian_coeffs*/
  865 
  866 
  867 
  868 static inline int
  869 reflect(int max, int x)
  870 {
  871     assert(x > -max && x < 2*max);
  872 
  873     if(x < 0) return -x;
  874     if(x >= max) return max - (x - max) - 1;
  875     return x;
  876 }/* reflect*/
  877 
  878 
  879 
  880 static inline void
  881 applyCoeffsLine(gdImagePtr src, gdImagePtr dst, int line, int linelen,
  882                 double *coeffs, int radius, gdAxis axis)
  883 {
  884     int ndx;
  885 
  886     for (ndx = 0; ndx < linelen; ndx++) {
  887         double r = 0, g = 0, b = 0, a = 0;
  888         int cndx;
  889         int *dest = (axis == HORIZONTAL) ?
  890             &dst->tpixels[line][ndx] :
  891             &dst->tpixels[ndx][line];
  892 
  893         for (cndx = -radius; cndx <= radius; cndx++) {
  894             const double coeff = coeffs[cndx + radius];
  895             const int rndx = reflect(linelen, ndx + cndx);
  896 
  897             const int srcpx = (axis == HORIZONTAL) ?
  898                 src->tpixels[line][rndx] :
  899                 src->tpixels[rndx][line];
  900 
  901             r += coeff * (double)gdTrueColorGetRed(srcpx);
  902             g += coeff * (double)gdTrueColorGetGreen(srcpx);
  903             b += coeff * (double)gdTrueColorGetBlue(srcpx);
  904             a += coeff * (double)gdTrueColorGetAlpha(srcpx);
  905         }/* for */
  906 
  907         *dest = gdTrueColorAlpha(uchar_clamp(r, 0xFF), uchar_clamp(g, 0xFF),
  908                                  uchar_clamp(b, 0xFF), uchar_clamp(a, 0x7F));
  909     }/* for */
  910 }/* applyCoeffsLine*/
  911 
  912 
  913 static void
  914 applyCoeffs(gdImagePtr src, gdImagePtr dst, double *coeffs, int radius,
  915             gdAxis axis)
  916 {
  917     int line, numlines, linelen;
  918 
  919     if (axis == HORIZONTAL) {
  920         numlines = src->sy;
  921         linelen = src->sx;
  922     } else {
  923         numlines = src->sx;
  924         linelen = src->sy;
  925     }/* if .. else*/
  926 
  927     for (line = 0; line < numlines; line++) {
  928         applyCoeffsLine(src, dst, line, linelen, coeffs, radius, axis);
  929     }/* for */
  930 }/* applyCoeffs*/
  931 
  932 /*
  933   Function: gdImageCopyGaussianBlurred
  934 
  935     Return a copy of the source image _src_ blurred according to the
  936     parameters using the Gaussian Blur algorithm.
  937 
  938     _radius_ is a radius, not a diameter so a radius of 2 (for
  939     example) will blur across a region 5 pixels across (2 to the
  940     center, 1 for the center itself and another 2 to the other edge).
  941 
  942     _sigma_ represents the "fatness" of the curve (lower == fatter).
  943     If _sigma_ is less than or equal to 0,
  944     <gdImageCopyGaussianBlurred> ignores it and instead computes an
  945     "optimal" value.  Be warned that future versions of this function
  946     may compute sigma differently.
  947 
  948     The resulting image is always truecolor.
  949 
  950   More Details:
  951 
  952     A Gaussian Blur is generated by replacing each pixel's color
  953     values with the average of the surrounding pixels' colors.  This
  954     region is a circle whose radius is given by argument _radius_.
  955     Thus, a larger radius will yield a blurrier image.
  956 
  957     This average is not a simple mean of the values.  Instead, values
  958     are weighted using the Gaussian function (roughly a bell curve
  959     centered around the destination pixel) giving it much more
  960     influence on the result than its neighbours.  Thus, a fatter curve
  961     will give the center pixel more weight and make the image less
  962     blurry; lower _sigma_ values will yield flatter curves.
  963 
  964     Currently, <gdImageCopyGaussianBlurred> computes the default sigma
  965     as
  966 
  967         (2/3)*radius
  968 
  969     Note, however that we reserve the right to change this if we find
  970     a better ratio.  If you absolutely need the current sigma value,
  971     you should set it yourself.
  972 
  973   Parameters:
  974 
  975     src     - the source image
  976     radius  - the blur radius (*not* diameter--range is 2*radius + 1)
  977     sigma   - the sigma value or a value <= 0.0 to use the computed default
  978 
  979   Returns:
  980 
  981     The new image or NULL if an error occurred.  The result is always
  982     truecolor.
  983 
  984   Example:
  985     (start code)
  986 
  987     FILE *in;
  988     gdImagePtr result, src;
  989 
  990     in = fopen("foo.png", "rb");
  991     src = gdImageCreateFromPng(in);
  992 
  993     result = gdImageCopyGaussianBlurred(im, src->sx / 10, -1.0);
  994 
  995     (end code)
  996 */
  997 
  998 /* TODO: Look into turning this into a generic seperable filter
  999  * function with Gaussian Blur being one special case.  (At the
 1000  * moment, I can't find any other useful separable filter so for not,
 1001  * it's just blur.) */
 1002 BGD_DECLARE(gdImagePtr)
 1003 gdImageCopyGaussianBlurred(gdImagePtr src, int radius, double sigma)
 1004 {
 1005     gdImagePtr tmp = NULL, result = NULL;
 1006     double *coeffs;
 1007     int freeSrc = 0;
 1008 
 1009     if (radius < 1) {
 1010         return NULL;
 1011     }/* if */
 1012 
 1013     /* Compute the coefficients. */
 1014     coeffs = gaussian_coeffs(radius, sigma);
 1015     if (!coeffs) {
 1016         return NULL;
 1017     }/* if */
 1018 
 1019     /* If the image is not truecolor, we first make a truecolor
 1020      * scratch copy. */
 1021     if (!src->trueColor) {
 1022         int tcstat;
 1023 
 1024         src = gdImageClone(src);
 1025         if (!src) {
 1026             gdFree(coeffs);
 1027             return NULL;
 1028         }
 1029 
 1030         tcstat = gdImagePaletteToTrueColor(src);
 1031         if (!tcstat) {
 1032             gdImageDestroy(src);
 1033             gdFree(coeffs);
 1034             return NULL;
 1035         }/* if */
 1036 
 1037         freeSrc = 1;
 1038     }/* if */
 1039 
 1040     /* Apply the filter horizontally. */
 1041     tmp = gdImageCreateTrueColor(src->sx, src->sy);
 1042     if (!tmp) {
 1043         gdFree(coeffs);
 1044         return NULL;
 1045     }
 1046     applyCoeffs(src, tmp, coeffs, radius, HORIZONTAL);
 1047 
 1048     /* Apply the filter vertically. */
 1049     result = gdImageCreateTrueColor(src->sx, src->sy);
 1050     if (result) {
 1051         applyCoeffs(tmp, result, coeffs, radius, VERTICAL);
 1052     }/* if */
 1053 
 1054     gdImageDestroy(tmp);
 1055     gdFree(coeffs);
 1056 
 1057     if (freeSrc) gdImageDestroy(src);
 1058 
 1059     return result;
 1060 }/* gdImageCopyGaussianBlurred*/