1<?php 2////////////////////////////////////////////////////////////// 3//// 4//// Unsharp Mask for PHP - version 2.1.1 5//// 6//// Unsharp mask algorithm by Torstein Hønsi 2003-07. 7//// thoensi_at_netcom_dot_no. 8//// Please leave this notice. 9//// 10////////////////////////////////////////////////////////////// 11// From: http://vikjavev.no/computing/ump.php // 12// // 13// Reformatted by James Heinrich <info@silisoftware.com> // 14// for use in phpThumb() on 3 February 2003. // 15// updated to v2.1.1 on 24 April 2011 // 16// // 17// phpThumb() is found at http://phpthumb.sourceforge.net // 18// and/or https://github.com/JamesHeinrich/phpThumb // 19////////////////////////////////////////////////////////////// 20 21/* 22New: 23- In version 2.1 (February 26 2007) Tom Bishop has done some important speed enhancements. 24- From version 2 (July 17 2006) the script uses the imageconvolution function in PHP 25 version >= 5.1, which improves the performance considerably. 26 27Unsharp masking is a traditional darkroom technique that has proven very suitable for 28digital imaging. The principle of unsharp masking is to create a blurred copy of the image 29and compare it to the underlying original. The difference in colour values 30between the two images is greatest for the pixels near sharp edges. When this 31difference is subtracted from the original image, the edges will be 32accentuated. 33 34The Amount parameter simply says how much of the effect you want. 100 is 'normal'. 35Radius is the radius of the blurring circle of the mask. 'Threshold' is the least 36difference in colour values that is allowed between the original and the mask. In practice 37this means that low-contrast areas of the picture are left unrendered whereas edges 38are treated normally. This is good for pictures of e.g. skin or blue skies. 39 40Any suggenstions for improvement of the algorithm, especially regarding the speed 41and the roundoff errors in the Gaussian blur process, are welcome. 42*/ 43 44class phpUnsharpMask { 45 46 public static function applyUnsharpMask(&$img, $amount, $radius, $threshold) { 47 48 // $img is an image that is already created within php using 49 // imgcreatetruecolor. No url! $img must be a truecolor image. 50 51 // Attempt to calibrate the parameters to Photoshop: 52 $amount = min($amount, 500) * 0.016; 53 $radius = abs(round(min(50, $radius) * 2)); // Only integers make sense. 54 $threshold = min(255, $threshold); 55 if ($radius == 0) { 56 return true; 57 } 58 $w = imagesx($img); 59 $h = imagesy($img); 60 $imgCanvas = imagecreatetruecolor($w, $h); 61 $imgBlur = imagecreatetruecolor($w, $h); 62 63 // Gaussian blur matrix: 64 // 65 // 1 2 1 66 // 2 4 2 67 // 1 2 1 68 // 69 ////////////////////////////////////////////////// 70 71 if (function_exists('imageconvolution')) { // PHP >= 5.1 72 $matrix = array( 73 array(1, 2, 1), 74 array(2, 4, 2), 75 array(1, 2, 1) 76 ); 77 imagecopy($imgBlur, $img, 0, 0, 0, 0, $w, $h); 78 imageconvolution($imgBlur, $matrix, 16, 0); 79 80 } else { 81 82 // Move copies of the image around one pixel at the time and merge them with weight 83 // according to the matrix. The same matrix is simply repeated for higher radii. 84 for ($i = 0; $i < $radius; $i++) { 85 imagecopy( $imgBlur, $img, 0, 0, 1, 0, $w - 1, $h); // left 86 imagecopymerge($imgBlur, $img, 1, 0, 0, 0, $w , $h, 50); // right 87 imagecopymerge($imgBlur, $img, 0, 0, 0, 0, $w , $h, 50); // center 88 imagecopy( $imgCanvas, $imgBlur, 0, 0, 0, 0, $w , $h); 89 imagecopymerge($imgBlur, $imgCanvas, 0, 0, 0, 1, $w , $h - 1, 33.33333); // up 90 imagecopymerge($imgBlur, $imgCanvas, 0, 1, 0, 0, $w , $h, 25); // down 91 } 92 } 93 94 if ($threshold > 0){ 95 // Calculate the difference between the blurred pixels and the original 96 // and set the pixels 97 for ($x = 0; $x < $w-1; $x++) { // each row 98 for ($y = 0; $y < $h; $y++) { // each pixel 99 100 $rgbOrig = imagecolorat($img, $x, $y); 101 $rOrig = (($rgbOrig >> 16) & 0xFF); 102 $gOrig = (($rgbOrig >> 8) & 0xFF); 103 $bOrig = ($rgbOrig & 0xFF); 104 105 $rgbBlur = imagecolorat($imgBlur, $x, $y); 106 107 $rBlur = (($rgbBlur >> 16) & 0xFF); 108 $gBlur = (($rgbBlur >> 8) & 0xFF); 109 $bBlur = ($rgbBlur & 0xFF); 110 111 // When the masked pixels differ less from the original 112 // than the threshold specifies, they are set to their original value. 113 $rNew = ((abs($rOrig - $rBlur) >= $threshold) ? max(0, min(255, ($amount * ($rOrig - $rBlur)) + $rOrig)) : $rOrig); 114 $gNew = ((abs($gOrig - $gBlur) >= $threshold) ? max(0, min(255, ($amount * ($gOrig - $gBlur)) + $gOrig)) : $gOrig); 115 $bNew = ((abs($bOrig - $bBlur) >= $threshold) ? max(0, min(255, ($amount * ($bOrig - $bBlur)) + $bOrig)) : $bOrig); 116 117 if (($rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew)) { 118 $pixCol = imagecolorallocate($img, $rNew, $gNew, $bNew); 119 imagesetpixel($img, $x, $y, $pixCol); 120 } 121 } 122 } 123 } else { 124 for ($x = 0; $x < $w; $x++) { // each row 125 for ($y = 0; $y < $h; $y++) { // each pixel 126 $rgbOrig = imagecolorat($img, $x, $y); 127 $rOrig = (($rgbOrig >> 16) & 0xFF); 128 $gOrig = (($rgbOrig >> 8) & 0xFF); 129 $bOrig = ($rgbOrig & 0xFF); 130 131 $rgbBlur = imagecolorat($imgBlur, $x, $y); 132 133 $rBlur = (($rgbBlur >> 16) & 0xFF); 134 $gBlur = (($rgbBlur >> 8) & 0xFF); 135 $bBlur = ($rgbBlur & 0xFF); 136 137 $rNew = min(255, max(0, ($amount * ($rOrig - $rBlur)) + $rOrig)); 138 $gNew = min(255, max(0, ($amount * ($gOrig - $gBlur)) + $gOrig)); 139 $bNew = min(255, max(0, ($amount * ($bOrig - $bBlur)) + $bOrig)); 140 $rgbNew = ($rNew << 16) + ($gNew <<8) + $bNew; 141 imagesetpixel($img, $x, $y, $rgbNew); 142 } 143 } 144 } 145 imagedestroy($imgCanvas); 146 imagedestroy($imgBlur); 147 return true; 148 } 149} 150