Snippets

Create an account or login to be able to add, comment and rate snippets.

Navigation

Snippets tagged "plugin sfthumbnail" Snippets tagged "plugin sfthumbnail"

unsharp mask for sfThumbnail plugin

I modified some found code (http://vikjavev.no/computing/ump.php?id=35) to add a sharpening feature to sfThumbnail.

Simply add this code to the sfThumbnail class:

  /**
   * Unsharp Mask for PHP
   * Unsharp mask algorithm by Torstein Hønsi
   * Please leave this notice.
   * @author     Torstein Hønsi <thoensi@netcom.no>
   * @author     Modified for use with Symfony by Dave Furfero <furf@furf.com>
   * @version    2.0, 2003-06
   *
   * WARNING! Due to a known bug in PHP 4.3.2 this script is not working
   * well in this version. The sharpened images get too dark. The bug is
   * fixed in version 4.3.3. 
   *
   * From version 2 (July 17 2006) the script uses the imageconvolution
   * function in PHP version >= 5.1, which improves the performance
   * considerably. 
   * 
   * Unsharp masking is a traditional darkroom technique that has proven
   * very suitable for digital imaging. The principle of unsharp masking
   * is to create a blurred copy of the image and compare it to the
   * underlying original. The difference in colour values between the
   * two images is greatest for the pixels near sharp edges. When this
   * difference is subtracted from the original image, the edges will be 
   * accentuated. 
   *
   * Amount simply says how much of the effect you want. 100 is
   * 'normal'
   *
   * Radius is the radius of the blurring circle of the mask.
   *
   * Threshold is the least difference in colour values that is allowed
   * between the original and the mask. In practice this means that
   * low-contrast areas of the picture are left unrendered whereas edges
   * are treated normally. This is good for pictures of e.g. skin or
   * blue skies. 
   *
   * Any suggenstions for improvement of the algorithm, expecially
   * regarding the speed and the roundoff errors in the Gaussian blur
   * process, are welcome. 
   * 
   * @param int amount (0-500)
   * @param float radius (0-50)
   * @param int threshold (0-255)
   * @return void
   * @access public
   */
  public function unsharpMask ($amount, $radius, $threshold)
  {
    // Attempt to calibrate the parameters to Photoshop:
    $amount    = min($amount, 500) * 0.016;
    $radius    = min($radius, 50) * 2;
    $radius    = abs(round($radius)); // Only integers make sense
    $threshold = min($threshold, 255);
 
    if ($amount == 0 || $radius == 0) {
      return;
    }
 
    $w = $this->getThumbWidth();
    $h = $this->getThumbHeight();
 
    $imgCanvas  = imagecreatetruecolor($w, $h);
    $imgCanvas2 = imagecreatetruecolor($w, $h);
    $imgBlur    = imagecreatetruecolor($w, $h);
    $imgBlur2   = imagecreatetruecolor($w, $h);
 
    imagecopy($imgCanvas,  $this->thumb, 0, 0, 0, 0, $w, $h);
    imagecopy($imgCanvas2, $this->thumb, 0, 0, 0, 0, $w, $h);
 
    // Gaussian blur matrix:
    //  1  2  1
    //  2  4  2
    //  1  2  1
 
    imagecopy($imgBlur, $imgCanvas, 0, 0, 0, 0, $w, $h); // background
 
    for ($i = 0; $i < $radius; $i++)  {
 
      if (function_exists('imageconvolution')) { // PHP >= 5.1
        $matrix = array(
          array(1, 2, 1),
          array(2, 4, 2),
          array(1, 2, 1)
        );
        imageconvolution($imgCanvas, $matrix, 16, 0);
      } else {
 
        // Move copies of the image around one pixel at the time
        // and merge them with weight according to the matrix.
        // The same matrix is simply repeated for higher radii.      
        imagecopy($imgBlur, $imgCanvas, 0, 0, 1, 1, $w - 1, $h - 1);
        imagecopymerge($imgBlur, $imgCanvas, 1, 1, 0, 0, $w, $h, 50);
        imagecopymerge($imgBlur, $imgCanvas, 0, 1, 1, 0, $w - 1, $h, 33.33333); 
        imagecopymerge($imgBlur, $imgCanvas, 1, 0, 0, 1, $w, $h - 1, 25);
        imagecopymerge($imgBlur, $imgCanvas, 0, 0, 1, 0, $w - 1, $h, 33.33333); 
        imagecopymerge($imgBlur, $imgCanvas, 1, 0, 0, 0, $w, $h, 25);
        imagecopymerge($imgBlur, $imgCanvas, 0, 0, 0, 1, $w, $h - 1, 20 );
        imagecopymerge($imgBlur, $imgCanvas, 0, 1, 0, 0, $w, $h, 16.666667);
        imagecopymerge($imgBlur, $imgCanvas, 0, 0, 0, 0, $w, $h, 50);
        imagecopy($imgCanvas, $imgBlur, 0, 0, 0, 0, $w, $h);
 
        // During the loop above the blurred copy darkens,
        // possibly due to a roundoff error. Therefore the sharp
        // picture has to go through the same loop to produce a
        // similar image for comparison. This is not a good
        // thing, as processing time increases heavily.
        imagecopy($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h);
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 50);
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 33.33333);
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 25);
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 33.33333);
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 25);
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 20 );
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 16.666667);
        imagecopymerge($imgBlur2, $imgCanvas2, 0, 0, 0, 0, $w, $h, 50);
        imagecopy($imgCanvas2, $imgBlur2, 0, 0, 0, 0, $w, $h);
      }
    }
 
    // Calculate the difference between the blurred pixels
    // and the original and set the pixels
    for ($x = 0; $x < $w; $x++)  {
      for ($y = 0; $y < $h; $y++)  {
 
        $rgbOrig = imageColorAt($imgCanvas2, $x, $y);
        $rOrig = (($rgbOrig >> 16) & 0xFF);
        $gOrig = (($rgbOrig >> 8) & 0xFF);
        $bOrig = ($rgbOrig & 0xFF);
 
        $rgbBlur = imageColorAt($imgCanvas, $x, $y);
        $rBlur = (($rgbBlur >> 16) & 0xFF);
        $gBlur = (($rgbBlur >> 8) & 0xFF);
        $bBlur = ($rgbBlur & 0xFF);
 
        // When the masked pixels differ less from the original
        // than the threshold specifies, they are set to their original value.
        $rNew = (abs($rOrig - $rBlur) >= $threshold)
          ? max(0, min(255, ($amount * ($rOrig - $rBlur)) + $rOrig))
          : $rOrig;
        $gNew = (abs($gOrig - $gBlur) >= $threshold)
          ? max(0, min(255, ($amount * ($gOrig - $gBlur)) + $gOrig))
          : $gOrig;
        $bNew = (abs($bOrig - $bBlur) >= $threshold)
          ? max(0, min(255, ($amount * ($bOrig - $bBlur)) + $bOrig))
          : $bOrig;
 
        if (($rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew)) {
          $pixCol = imageColorAllocate($this->thumb, $rNew, $gNew, $bNew);
          imageSetPixel($this->thumb, $x, $y, $pixCol);
        }
      }
    }
  }

Then call it like this from your script:

$thumb = new sfThumbnail(160, 120);
$thumb->loadFile($original_img);
$thumb->unsharpMask(40, 0.5, 3);
$thumb->save($img_path, 'image/png');

The three parameters are amount (degree of sharpening from 0-500), radius (pixel radius of blur, from 0-50), and threshold (degree of difference between original and blur, from 0-255). Read the included comments for more info.

It could probably use some better validation and error checking, but it's worked flawlessly for me so far.

by dave furf on 2006-08-31, tagged plugin  sfthumbnail