Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:5697 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 28515 invoked by uid 1010); 24 Nov 2003 16:32:29 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 28490 invoked from network); 24 Nov 2003 16:32:29 -0000 Received: from unknown (HELO sphinx.mythic-beasts.com) (195.82.107.246) by pb1.pair.com with SMTP; 24 Nov 2003 16:32:29 -0000 Received: from [213.78.66.28] (helo=[213.78.66.28]) by sphinx.mythic-beasts.com with asmtp (Exim 3.33 #3) id 1AOJdR-0005zr-00; Mon, 24 Nov 2003 16:32:25 +0000 In-Reply-To: <3BE30005-1E90-11D8-A3ED-000A95D9ABDE@troughton.org> References: <3BE30005-1E90-11D8-A3ED-000A95D9ABDE@troughton.org> Mime-Version: 1.0 (Apple Message framework v606) Content-Type: multipart/mixed; boundary=Apple-Mail-23--957482105 Message-ID: Date: Mon, 24 Nov 2003 16:31:54 +0000 To: internals@lists.php.net X-Mailer: Apple Mail (2.606) Subject: Re: [PHP-DEV] [PATCH] Image sharpening function for ext/gd From: php@troughton.org (Paul Troughton) --Apple-Mail-23--957482105 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed Second attempt at posting, this time hopefully with the patch as a MIME type that won't be stripped... On Nov 24, 2003, at 15:09, Paul Troughton wrote: > Hello, > > I was surprised to find that, although the GD image-handling functions > shipped with PHP do many useful things very well, there's no function > to sharpen an image. I found a few posts bemoaning this absence, and > therefore attach a patch which adds the function > > int imagesharpen ( resource im, int pct ) > > It performs the sharpening in-place. pct is the degree of sharpening > to be applied: 0 does nothing; 100 gives a quite noticeable effect. > Values >100 can be used for stronger sharpening. Negative values are > treated as 0. > > The routine only sharpens truecolor images, as it rarely makes sense > to attempt the operation on palletted images. > > It's a simple linear sharpening routine using a 3x3 kernel, rather > than the more flexible, but slower, unsharp masking approach used in > e.g. Photoshop, Imagemagick. However it's very effective at making > resampled photographic images (such as thumbnails) look a little more > crisp. > > I've built and tested it using gcc 3.3 under Mac OS X 10.3.1. There's > nothing I'd expect to be platform-dependent in it. The attached patch > is against php4-STABLE-200311202030, but it should work with most > varieties of php-4.3.4, as the new code is fairly self-contained. > > This is my first patch for PHP. Is there anything else I should do, > beyond posting it here? > > Many thanks, > > > Paul. > > -- > Paul Troughton http://paul.troughton.org/ > mobile +44 7866 041144 home +44 1223 366900 --Apple-Mail-23--957482105 Content-Transfer-Encoding: 7bit Content-Type: text/plain; x-unix-mode=0644; name="php-4.3.4-sharpen.txt" Content-Disposition: attachment; filename=php-4.3.4-sharpen.txt diff -c3prb php4-STABLE-200311202030/ext/gd/gd.c php-4.3.4-mod-pt/ext/gd/gd.c *** php4-STABLE-200311202030/ext/gd/gd.c Wed Nov 19 16:06:33 2003 --- php-4.3.4-mod-pt/ext/gd/gd.c Thu Nov 20 00:59:58 2003 *************** function_entry gd_functions[] = { *** 166,171 **** --- 166,172 ---- PHP_FE(imagerotate, NULL) PHP_FE(imageantialias, NULL) #endif + PHP_FE(imagesharpen, NULL) #if HAVE_GD_IMAGESETTILE PHP_FE(imagesettile, NULL) *************** PHP_FUNCTION(imageantialias) *** 3852,3857 **** --- 3855,3884 ---- } /* }}} */ #endif + + /* {{{ proto int imagesharpen(int im, int pct) + Sharpen a GD image + Added by Paul Troughton 2003-11-19 */ + PHP_FUNCTION(imagesharpen) + { + zval **IM, **PCT; + gdImagePtr im; + int pct; + + if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &IM, &PCT) == FAILURE) { + ZEND_WRONG_PARAM_COUNT(); + } + + ZEND_FETCH_RESOURCE(im, gdImagePtr, IM, -1, "Image", le_gd); + convert_to_long_ex(PCT); + pct = Z_LVAL_PP(PCT); + + gdImageSharpen(im, pct); + RETURN_TRUE; + + } + /* }}} */ + #endif /* HAVE_LIBGD */ diff -c3prb php4-STABLE-200311202030/ext/gd/libgd/gd.c php-4.3.4-mod-pt/ext/gd/libgd/gd.c *** php4-STABLE-200311202030/ext/gd/libgd/gd.c Tue Nov 4 02:06:49 2003 --- php-4.3.4-mod-pt/ext/gd/libgd/gd.c Thu Nov 20 22:15:15 2003 *************** int gdImageColorClosestAlpha (gdImagePtr *** 255,261 **** gd = im->green[i] - g; bd = im->blue[i] - b; /* gd 2.02: whoops, was - b (thanks to David Marwood) */ ! ad = im->alpha[i] - a; dist = rd * rd + gd * gd + bd * bd + ad * ad; if (first || (dist < mindist)) { mindist = dist; --- 255,261 ---- gd = im->green[i] - g; bd = im->blue[i] - b; /* gd 2.02: whoops, was - b (thanks to David Marwood) */ ! ad = im->blue[i] - a; dist = rd * rd + gd * gd + bd * bd + ad * ad; if (first || (dist < mindist)) { mindist = dist; *************** void gdImageGetClip (gdImagePtr im, int *** 3365,3368 **** --- 3365,3486 ---- *y1P = im->cy1; *x2P = im->cx2; *y2P = im->cy2; + } + + + /* Called by gdImageSharpen to avoid excessive code repetition + Added on 2003-11-19 by + Paul Troughton (paultroughtonieeeorg) + Given filter coefficents and colours of three adjacent pixels, returns new colour for centre pixel + */ + + int gdImageSharpen_Sub (int pc, int c, int nc, float inner_coeff, float outer_coeff) { + float red, green, blue, alpha; + + red = inner_coeff * gdTrueColorGetRed (c) + outer_coeff * (gdTrueColorGetRed (pc) + gdTrueColorGetRed (nc)); + green = inner_coeff * gdTrueColorGetGreen (c) + outer_coeff * (gdTrueColorGetGreen (pc) + gdTrueColorGetGreen (nc)); + blue = inner_coeff * gdTrueColorGetBlue (c) + outer_coeff * (gdTrueColorGetBlue (pc) + gdTrueColorGetBlue (nc)); + alpha = gdTrueColorGetAlpha (c); + + /* Clamping, as can overshoot bounds in either direction */ + if (red > 255.0f) { + red = 255.0f; + } + if (green > 255.0f) { + green = 255.0f; + } + if (blue > 255.0f) { + blue = 255.0f; + } + if (red < 0.0f) { + red = 0.0f; + } + if (green < 0.0f) { + green = 0.0f; + } + if (blue < 0.0f) { + blue = 0.0f; + } + + return gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha); + } + + /* + * Sharpen function added on 2003-11-19 + * by Paul Troughton (paultroughtonieeeorg) + * Simple 3x3 convolution kernel + * Makes use of seperability + * Faster, but less flexible, than full-blown unsharp masking + * pct is sharpening percentage, and can be greater than 100 + * Silently does nothing to non-truecolor images + * Silently does nothing for pct<0, as not a useful blurring function + * Leaves transparency/alpha-channel untouched + */ + + void gdImageSharpen (gdImagePtr im, int pct) + { + int x, y; + int sx, sy; + float inner_coeff, outer_coeff; + + sx = im->sx; + sy = im->sy; + + /* Must sum to 1 to avoid overall change in brightness. + * Scaling chosen so that pct=100 gives 1-D filter [-1 6 -1]/4, + * resulting in a 2-D filter [1 -6 1; -6 36 -6; 1 -6 1]/16, + * which gives noticeable, but not excessive, sharpening + */ + + outer_coeff = -pct / 400.0; + inner_coeff = 1 - 2 * outer_coeff; + + /* Don't try to do anything with non-truecolor images, as pointless, + * nor for pct<=0, as small kernel size leads to nasty artefacts when blurring + */ + if ( (im->trueColor) && (pct>0) ) { + + /* First pass, 1-D convolution column-wise */ + for (x = 0; x < sx; x++) { + + /* pc is colour of previous pixel; c of the current pixel and nc of the next */ + int pc, c, nc; + + /* Replicate edge pixel at image boundary */ + pc = gdImageGetPixel (im, x, 0); + + /* Stop looping before last pixel to avoid conditional within loop */ + for (y = 0; y < sy-1; y++) { + + c = gdImageGetPixel (im, x, y); + + nc = gdImageGetTrueColorPixel (im, x, y+1); + + /* Update centre pixel to new colour */ + gdImageSetPixel(im, x, y, gdImageSubSharpen (pc, c, nc, inner_coeff, outer_coeff) ); + + /* Save original colour of current pixel for next time round */ + pc = c; + } + + /* Deal with last pixel, replicating current pixel at image boundary */ + c = gdImageGetPixel (im, x, y); + gdImageSetPixel(im, x, y, gdImageSharpen_Sub (pc, c, c, inner_coeff, outer_coeff) ); + } + + /* Second pass, 1-D convolution row-wise */ + for (y = 0; y < sy; y++) { + int pc, c, nc; + pc = gdImageGetPixel (im, 0, y); + for (x = 0; x < sx-1; x++) { + int c, nc; + c = gdImageGetPixel (im, x, y); + nc = gdImageGetTrueColorPixel (im, x+1, y); + gdImageSetPixel(im, x, y, gdImageSharpen_Sub (pc, c, nc, inner_coeff, outer_coeff) ); + pc = c; + } + c = gdImageGetPixel (im, x, y); + gdImageSetPixel(im, x, y, gdImageSubSharpen (pc, c, c, inner_coeff, outer_coeff) ); + } + } } diff -c3prb php4-STABLE-200311202030/ext/gd/libgd/gd.h php-4.3.4-mod-pt/ext/gd/libgd/gd.h *** php4-STABLE-200311202030/ext/gd/libgd/gd.h Wed Apr 9 04:05:40 2003 --- php-4.3.4-mod-pt/ext/gd/libgd/gd.h Wed Nov 19 17:18:59 2003 *************** void gdImageAlphaBlending(gdImagePtr im, *** 537,542 **** --- 537,553 ---- void gdImageAntialias(gdImagePtr im, int antialias); void gdImageSaveAlpha(gdImagePtr im, int saveAlphaArg); + /* + * Sharpen function added on 2003-11-19 + * by Paul Troughton (paultroughtonieeeorg) + * Simple 3x3 convolution kernel + * Makes use of seperability + * Faster, but less flexible, than full-blown unsharp masking + * pct is sharpening percentage + * Leaves transparency/alpha-channel untouched + */ + void gdImageSharpen (gdImagePtr im, int pct); + /* Macros to access information about images. */ /* Returns nonzero if the image is a truecolor image, diff -c3prb php4-STABLE-200311202030/ext/gd/php_gd.h php-4.3.4-mod-pt/ext/gd/php_gd.h *** php4-STABLE-200311202030/ext/gd/php_gd.h Mon Mar 31 10:05:59 2003 --- php-4.3.4-mod-pt/ext/gd/php_gd.h Thu Nov 20 22:24:09 2003 *************** PHP_FUNCTION(imagerotate); *** 108,113 **** --- 108,115 ---- PHP_FUNCTION(imageantialias); #endif + PHP_FUNCTION(imagesharpen); + PHP_FUNCTION(imagesetthickness); PHP_FUNCTION(imagecopymergegray); PHP_FUNCTION(imagesetbrush); --Apple-Mail-23--957482105 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed --Apple-Mail-23--957482105--