1 <?php
  2 
  3 ////////////////////////////////////////////////////////////////////////////////////////////////
  4 ////
  5 ////                  Unsharp Mask for PHP - version 2.1.1
  6 ////
  7 ////    Unsharp mask algorithm by Torstein Hönsi 2003-07.
  8 ////             thoensi_at_netcom_dot_no.
  9 ////               Please leave this notice.
 10 ////
 11 ///////////////////////////////////////////////////////////////////////////////////////////////
 12 
 13 // $img is an image that is already created within php using
 14 // imgcreatetruecolor. No url! $img must be a truecolor image.
 15 
 16 /**
 17  * @package redaxo\media-manager
 18  */
 19 class rex_effect_filter_sharpen extends rex_effect_abstract
 20 {
 21     public function execute()
 22     {
 23         $this->media->asImage();
 24 
 25         // do not sharpen gifs, results in black image
 26         if (strtolower($this->media->getFormat()) === 'gif') {
 27             return;
 28         }
 29 
 30         // Attempt to calibrate the parameters to Photoshop:
 31         if ($this->params['amount'] > 500) {
 32             $this->params['amount'] = 500;
 33         }
 34         $this->params['amount'] = ((float) $this->params['amount']) * 0.016;
 35 
 36         if ($this->params['radius'] > 50) {
 37             $this->params['radius'] = 50;
 38         }
 39         $this->params['radius'] = ((float) $this->params['radius']) * 2;
 40         if ($this->params['threshold'] > 255) {
 41             $this->params['threshold'] = 255;
 42         }
 43         $this->params['radius'] = abs(round($this->params['radius']));     // Only integers make sense.
 44 
 45         if ($this->params['radius'] == 0) {
 46             return;
 47         }
 48 
 49         $gdimage = $this->media->getImage();
 50         $w = $this->media->getWidth();
 51         $h = $this->media->getHeight();
 52 
 53         $imgCanvas = imagecreatetruecolor($w, $h);
 54         $imgBlur = imagecreatetruecolor($w, $h);
 55 
 56         // Gaussian blur matrix:
 57 
 58         //    1    2    1
 59         //    2    4    2
 60         //    1    2    1
 61 
 62         //////////////////////////////////////////////////
 63 
 64         if (function_exists('imageconvolution')) {
 65             // PHP >= 5.1
 66             $matrix = [
 67                 [1, 2, 1],
 68                 [2, 4, 2],
 69                 [1, 2, 1],
 70             ];
 71             imagecopy($imgBlur, $gdimage, 0, 0, 0, 0, $w, $h);
 72             imageconvolution($imgBlur, $matrix, 16, 0);
 73         } else {
 74             // Move copies of the image around one pixel at the time and merge them with weight
 75             // according to the matrix. The same matrix is simply repeated for higher radii.
 76             for ($i = 0; $i < $this->params['radius']; ++$i) {
 77                 imagecopy($imgBlur, $gdimage, 0, 0, 1, 0, $w - 1, $h); // left
 78                 imagecopymerge($imgBlur, $gdimage, 1, 0, 0, 0, $w, $h, 50); // right
 79                 imagecopymerge($imgBlur, $gdimage, 0, 0, 0, 0, $w, $h, 50); // center
 80                 imagecopy($imgCanvas, $imgBlur, 0, 0, 0, 0, $w, $h);
 81                 imagecopymerge($imgBlur, $imgCanvas, 0, 0, 0, 1, $w, $h - 1, 33.33333); // up
 82                 imagecopymerge($imgBlur, $imgCanvas, 0, 1, 0, 0, $w, $h, 25); // down
 83             }
 84         }
 85 
 86         if ($this->params['threshold'] > 0) {
 87             // Calculate the difference between the blurred pixels and the original
 88             // and set the pixels
 89             for ($x = 0; $x < $w - 1; ++$x) {
 90                 // each row
 91                 for ($y = 0; $y < $h; ++$y) {
 92                     // each pixel
 93 
 94                     $rgbOrig = imagecolorat($gdimage, $x, $y);
 95                     $rOrig = (($rgbOrig >> 16) & 0xFF);
 96                     $gOrig = (($rgbOrig >> 8) & 0xFF);
 97                     $bOrig = ($rgbOrig & 0xFF);
 98 
 99                     $rgbBlur = imagecolorat($imgBlur, $x, $y);
100 
101                     $rBlur = (($rgbBlur >> 16) & 0xFF);
102                     $gBlur = (($rgbBlur >> 8) & 0xFF);
103                     $bBlur = ($rgbBlur & 0xFF);
104 
105                     // When the masked pixels differ less from the original
106                     // than the threshold specifies, they are set to their original value.
107                     $rNew = (abs($rOrig - $rBlur) >= $this->params['threshold'])
108                     ? max(0, min(255, ($this->params['amount'] * ($rOrig - $rBlur)) + $rOrig))
109                     : $rOrig;
110                     $gNew = (abs($gOrig - $gBlur) >= $this->params['threshold'])
111                     ? max(0, min(255, ($this->params['amount'] * ($gOrig - $gBlur)) + $gOrig))
112                     : $gOrig;
113                     $bNew = (abs($bOrig - $bBlur) >= $this->params['threshold'])
114                     ? max(0, min(255, ($this->params['amount'] * ($bOrig - $bBlur)) + $bOrig))
115                     : $bOrig;
116 
117                     if (($rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew)) {
118                         $pixCol = imagecolorallocate($gdimage, $rNew, $gNew, $bNew);
119                         imagesetpixel($gdimage, $x, $y, $pixCol);
120                     }
121                 }
122             }
123         } else {
124             for ($x = 0; $x < $w; ++$x) {
125                 // each row
126                 for ($y = 0; $y < $h; ++$y) {
127                     // each pixel
128                     $rgbOrig = imagecolorat($gdimage, $x, $y);
129                     $rOrig = (($rgbOrig >> 16) & 0xFF);
130                     $gOrig = (($rgbOrig >> 8) & 0xFF);
131                     $bOrig = ($rgbOrig & 0xFF);
132 
133                     $rgbBlur = imagecolorat($imgBlur, $x, $y);
134 
135                     $rBlur = (($rgbBlur >> 16) & 0xFF);
136                     $gBlur = (($rgbBlur >> 8) & 0xFF);
137                     $bBlur = ($rgbBlur & 0xFF);
138 
139                     $rNew = ($this->params['amount'] * ($rOrig - $rBlur)) + $rOrig;
140                     if ($rNew > 255) {
141                         $rNew = 255;
142                     } elseif ($rNew < 0) {
143                         $rNew = 0;
144                     }
145                     $gNew = ($this->params['amount'] * ($gOrig - $gBlur)) + $gOrig;
146                     if ($gNew > 255) {
147                         $gNew = 255;
148                     } elseif ($gNew < 0) {
149                         $gNew = 0;
150                     }
151                     $bNew = ($this->params['amount'] * ($bOrig - $bBlur)) + $bOrig;
152                     if ($bNew > 255) {
153                         $bNew = 255;
154                     } elseif ($bNew < 0) {
155                         $bNew = 0;
156                     }
157                     $rgbNew = ($rNew << 16) + ($gNew << 8) + $bNew;
158                     imagesetpixel($gdimage, $x, $y, $rgbNew);
159                 }
160             }
161         }
162         imagedestroy($imgCanvas);
163         imagedestroy($imgBlur);
164         $this->media->setImage($gdimage);
165     }
166 
167     public function getName()
168     {
169         return rex_i18n::msg('media_manager_effect_sharpen');
170     }
171 
172     public function getParams()
173     {
174         return [
175             [
176                 'label' => rex_i18n::msg('media_manager_effect_sharpen_amount'),
177                 'name' => 'amount',
178                 'type' => 'int',
179                 'default' => '80',
180             ],
181             [
182                 'label' => rex_i18n::msg('media_manager_effect_sharpen_radius'),
183                 'name' => 'radius',
184                 'type' => 'int',
185                 'default' => '0.5',
186             ],
187             [
188                 'label' => rex_i18n::msg('media_manager_effect_sharpen_threshold'),
189                 'name' => 'threshold',
190                 'type' => 'int',
191                 'default' => '3',
192             ],
193         ];
194     }
195 }
196