1<?php 2////////////////////////////////////////////////////////////// 3// phpThumb() by James Heinrich <info@silisoftware.com> // 4// available at http://phpthumb.sourceforge.net // 5// and/or https://github.com/JamesHeinrich/phpThumb // 6////////////////////////////////////////////////////////////// 7/// // 8// phpthumb.filters.php - image processing filter functions // 9// /// 10////////////////////////////////////////////////////////////// 11 12class phpthumb_filters { 13 14 /** 15 * @var phpthumb 16 */ 17 18 public $phpThumbObject = null; 19 20 21 public function DebugMessage($message, $file='', $line='') { 22 if (is_object($this->phpThumbObject)) { 23 return $this->phpThumbObject->DebugMessage($message, $file, $line); 24 } 25 return false; 26 } 27 28 29 public function ApplyMask(&$gdimg_mask, &$gdimg_image) { 30 if (phpthumb_functions::gd_version() < 2) { 31 $this->DebugMessage('Skipping ApplyMask() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__); 32 return false; 33 } 34 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.2', '>=')) { 35 36 $this->DebugMessage('Using alpha ApplyMask() technique', __FILE__, __LINE__); 37 if ($gdimg_mask_resized = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_image), imagesy($gdimg_image))) { 38 39 imagecopyresampled($gdimg_mask_resized, $gdimg_mask, 0, 0, 0, 0, imagesx($gdimg_image), imagesy($gdimg_image), imagesx($gdimg_mask), imagesy($gdimg_mask)); 40 if ($gdimg_mask_blendtemp = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_image), imagesy($gdimg_image))) { 41 42 $color_background = imagecolorallocate($gdimg_mask_blendtemp, 0, 0, 0); 43 imagefilledrectangle($gdimg_mask_blendtemp, 0, 0, imagesx($gdimg_mask_blendtemp), imagesy($gdimg_mask_blendtemp), $color_background); 44 imagealphablending($gdimg_mask_blendtemp, false); 45 imagesavealpha($gdimg_mask_blendtemp, true); 46 for ($x = 0, $xMax = imagesx($gdimg_image); $x < $xMax; $x++) { 47 for ($y = 0, $yMax = imagesy($gdimg_image); $y < $yMax; $y++) { 48 //$RealPixel = phpthumb_functions::GetPixelColor($gdimg_mask_blendtemp, $x, $y); 49 $RealPixel = phpthumb_functions::GetPixelColor($gdimg_image, $x, $y); 50 $MaskPixel = phpthumb_functions::GrayscalePixel(phpthumb_functions::GetPixelColor($gdimg_mask_resized, $x, $y)); 51 $MaskAlpha = 127 - (floor($MaskPixel['red'] / 2) * (1 - ($RealPixel['alpha'] / 127))); 52 $newcolor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_mask_blendtemp, $RealPixel['red'], $RealPixel['green'], $RealPixel['blue'], $MaskAlpha); 53 imagesetpixel($gdimg_mask_blendtemp, $x, $y, $newcolor); 54 } 55 } 56 imagealphablending($gdimg_image, false); 57 imagesavealpha($gdimg_image, true); 58 imagecopy($gdimg_image, $gdimg_mask_blendtemp, 0, 0, 0, 0, imagesx($gdimg_mask_blendtemp), imagesy($gdimg_mask_blendtemp)); 59 imagedestroy($gdimg_mask_blendtemp); 60 61 } else { 62 $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__); 63 } 64 imagedestroy($gdimg_mask_resized); 65 66 } else { 67 $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__); 68 } 69 70 } else { 71 // alpha merging requires PHP v4.3.2+ 72 $this->DebugMessage('Skipping ApplyMask() technique because PHP is v"'. PHP_VERSION .'"', __FILE__, __LINE__); 73 } 74 return true; 75 } 76 77 78 public function Bevel(&$gdimg, $width, $hexcolor1, $hexcolor2) { 79 $width = ($width ? $width : 5); 80 $hexcolor1 = ($hexcolor1 ? $hexcolor1 : 'FFFFFF'); 81 $hexcolor2 = ($hexcolor2 ? $hexcolor2 : '000000'); 82 83 imagealphablending($gdimg, true); 84 for ($i = 0; $i < $width; $i++) { 85 $alpha = round(($i / $width) * 127); 86 $color1 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor1, false, $alpha); 87 $color2 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor2, false, $alpha); 88 89 imageline($gdimg, $i, $i + 1, $i, imagesy($gdimg) - $i - 1, $color1); // left 90 imageline($gdimg, $i, $i , imagesx($gdimg) - $i, $i , $color1); // top 91 imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i - 1, imagesx($gdimg) - $i, $i + 1, $color2); // right 92 imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i , $i, imagesy($gdimg) - $i , $color2); // bottom 93 } 94 return true; 95 } 96 97 98 public function Blur(&$gdimg, $radius=0.5) { 99 // Taken from Torstein Hønsi's phpUnsharpMask (see phpthumb.unsharp.php) 100 101 $radius = round(max(0, min($radius, 50)) * 2); 102 if (!$radius) { 103 return false; 104 } 105 106 $w = imagesx($gdimg); 107 $h = imagesy($gdimg); 108 if ($imgBlur = imagecreatetruecolor($w, $h)) { 109 // Gaussian blur matrix: 110 // 1 2 1 111 // 2 4 2 112 // 1 2 1 113 114 // Move copies of the image around one pixel at the time and merge them with weight 115 // according to the matrix. The same matrix is simply repeated for higher radii. 116 for ($i = 0; $i < $radius; $i++) { 117 imagecopy ($imgBlur, $gdimg, 0, 0, 1, 1, $w - 1, $h - 1); // up left 118 imagecopymerge($imgBlur, $gdimg, 1, 1, 0, 0, $w, $h, 50.00000); // down right 119 imagecopymerge($imgBlur, $gdimg, 0, 1, 1, 0, $w - 1, $h, 33.33333); // down left 120 imagecopymerge($imgBlur, $gdimg, 1, 0, 0, 1, $w, $h - 1, 25.00000); // up right 121 imagecopymerge($imgBlur, $gdimg, 0, 0, 1, 0, $w - 1, $h, 33.33333); // left 122 imagecopymerge($imgBlur, $gdimg, 1, 0, 0, 0, $w, $h, 25.00000); // right 123 imagecopymerge($imgBlur, $gdimg, 0, 0, 0, 1, $w, $h - 1, 20.00000); // up 124 imagecopymerge($imgBlur, $gdimg, 0, 1, 0, 0, $w, $h, 16.666667); // down 125 imagecopymerge($imgBlur, $gdimg, 0, 0, 0, 0, $w, $h, 50.000000); // center 126 imagecopy ($gdimg, $imgBlur, 0, 0, 0, 0, $w, $h); 127 } 128 return true; 129 } 130 return false; 131 } 132 133 134 public function BlurGaussian(&$gdimg) { 135 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 136 if (imagefilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)) { 137 return true; 138 } 139 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)', __FILE__, __LINE__); 140 // fall through and try it the hard way 141 } 142 $this->DebugMessage('FAILED: phpthumb_filters::BlurGaussian($gdimg) [using phpthumb_filters::Blur() instead]', __FILE__, __LINE__); 143 return $this->Blur($gdimg, 0.5); 144 } 145 146 147 public function BlurSelective(&$gdimg) { 148 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 149 if (imagefilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)) { 150 return true; 151 } 152 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)', __FILE__, __LINE__); 153 // fall through and try it the hard way 154 } 155 // currently not implemented "the hard way" 156 $this->DebugMessage('FAILED: phpthumb_filters::BlurSelective($gdimg) [function not implemented]', __FILE__, __LINE__); 157 return false; 158 } 159 160 161 public function Brightness(&$gdimg, $amount=0) { 162 if ($amount == 0) { 163 return true; 164 } 165 $amount = max(-255, min(255, $amount)); 166 167 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 168 if (imagefilter($gdimg, IMG_FILTER_BRIGHTNESS, $amount)) { 169 return true; 170 } 171 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_BRIGHTNESS, '.$amount.')', __FILE__, __LINE__); 172 // fall through and try it the hard way 173 } 174 175 $scaling = (255 - abs($amount)) / 255; 176 $baseamount = (($amount > 0) ? $amount : 0); 177 for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { 178 for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { 179 $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 180 $NewPixel = array(); 181 foreach ($OriginalPixel as $key => $value) { 182 $NewPixel[$key] = round($baseamount + ($OriginalPixel[$key] * $scaling)); 183 } 184 $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); 185 imagesetpixel($gdimg, $x, $y, $newColor); 186 } 187 } 188 return true; 189 } 190 191 192 public function Contrast(&$gdimg, $amount=0) { 193 if ($amount == 0) { 194 return true; 195 } 196 $amount = max(-255, min(255, $amount)); 197 198 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 199 // imagefilter(IMG_FILTER_CONTRAST) has range +100 to -100 (positive numbers make it darker!) 200 $amount = ($amount / 255) * -100; 201 if (imagefilter($gdimg, IMG_FILTER_CONTRAST, $amount)) { 202 return true; 203 } 204 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_CONTRAST, '.$amount.')', __FILE__, __LINE__); 205 // fall through and try it the hard way 206 } 207 208 if ($amount > 0) { 209 $scaling = 1 + ($amount / 255); 210 } else { 211 $scaling = (255 - abs($amount)) / 255; 212 } 213 for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { 214 for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { 215 $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 216 $NewPixel = array(); 217 foreach ($OriginalPixel as $key => $value) { 218 $NewPixel[$key] = min(255, max(0, round($OriginalPixel[$key] * $scaling))); 219 } 220 $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); 221 imagesetpixel($gdimg, $x, $y, $newColor); 222 } 223 } 224 return true; 225 } 226 227 228 public function Colorize(&$gdimg, $amount, $targetColor) { 229 $amount = (is_numeric($amount) ? $amount : 25); 230 $amountPct = $amount / 100; 231 $targetColor = (phpthumb_functions::IsHexColor($targetColor) ? $targetColor : 'gray'); 232 233 if ($amount == 0) { 234 return true; 235 } 236 237 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 238 if ($targetColor == 'gray') { 239 $targetColor = '808080'; 240 } 241 $r = round($amountPct * hexdec(substr($targetColor, 0, 2))); 242 $g = round($amountPct * hexdec(substr($targetColor, 2, 2))); 243 $b = round($amountPct * hexdec(substr($targetColor, 4, 2))); 244 if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) { 245 return true; 246 } 247 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__); 248 // fall through and try it the hard way 249 } 250 251 // overridden below for grayscale 252 $TargetPixel = array(); 253 if ($targetColor != 'gray') { 254 $TargetPixel['red'] = hexdec(substr($targetColor, 0, 2)); 255 $TargetPixel['green'] = hexdec(substr($targetColor, 2, 2)); 256 $TargetPixel['blue'] = hexdec(substr($targetColor, 4, 2)); 257 } 258 259 for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { 260 for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { 261 $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 262 if ($targetColor == 'gray') { 263 $TargetPixel = phpthumb_functions::GrayscalePixel($OriginalPixel); 264 } 265 $NewPixel = array(); 266 foreach ($TargetPixel as $key => $value) { 267 $NewPixel[$key] = round(max(0, min(255, ($OriginalPixel[$key] * ((100 - $amount) / 100)) + ($TargetPixel[$key] * $amountPct)))); 268 } 269 //$newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue'], $OriginalPixel['alpha']); 270 $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); 271 imagesetpixel($gdimg, $x, $y, $newColor); 272 } 273 } 274 return true; 275 } 276 277 278 public function Crop(&$gdimg, $left=0, $right=0, $top=0, $bottom=0) { 279 if (!$left && !$right && !$top && !$bottom) { 280 return true; 281 } 282 $oldW = imagesx($gdimg); 283 $oldH = imagesy($gdimg); 284 if (($left > 0) && ($left < 1)) { $left = round($left * $oldW); } 285 if (($right > 0) && ($right < 1)) { $right = round($right * $oldW); } 286 if (($top > 0) && ($top < 1)) { $top = round($top * $oldH); } 287 if (($bottom > 0) && ($bottom < 1)) { $bottom = round($bottom * $oldH); } 288 $right = min($oldW - $left - 1, $right); 289 $bottom = min($oldH - $top - 1, $bottom); 290 $newW = $oldW - $left - $right; 291 $newH = $oldH - $top - $bottom; 292 293 if ($imgCropped = imagecreatetruecolor($newW, $newH)) { 294 imagecopy($imgCropped, $gdimg, 0, 0, $left, $top, $newW, $newH); 295 if ($gdimg = imagecreatetruecolor($newW, $newH)) { 296 imagecopy($gdimg, $imgCropped, 0, 0, 0, 0, $newW, $newH); 297 imagedestroy($imgCropped); 298 return true; 299 } 300 imagedestroy($imgCropped); 301 } 302 return false; 303 } 304 305 306 public function Desaturate(&$gdimg, $amount, $color='') { 307 if ($amount == 0) { 308 return true; 309 } 310 return $this->Colorize($gdimg, $amount, (phpthumb_functions::IsHexColor($color) ? $color : 'gray')); 311 } 312 313 314 public function DropShadow(&$gdimg, $distance, $width, $hexcolor, $angle, $alpha) { 315 if (phpthumb_functions::gd_version() < 2) { 316 return false; 317 } 318 $distance = ($distance ? $distance : 10); 319 $width = ($width ? $width : 10); 320 $hexcolor = ($hexcolor ? $hexcolor : '000000'); 321 $angle = ($angle ? $angle : 225) % 360; 322 $alpha = max(0, min(100, ($alpha ? $alpha : 100))); 323 324 if ($alpha <= 0) { 325 // invisible shadow, nothing to do 326 return true; 327 } 328 if ($distance <= 0) { 329 // shadow completely obscured by source image, nothing to do 330 return true; 331 } 332 333 //$width_shadow = cos(deg2rad($angle)) * ($distance + $width); 334 //$height_shadow = sin(deg2rad($angle)) * ($distance + $width); 335 //$scaling = min(imagesx($gdimg) / (imagesx($gdimg) + abs($width_shadow)), imagesy($gdimg) / (imagesy($gdimg) + abs($height_shadow))); 336 337 $Offset = array(); 338 for ($i = 0; $i < $width; $i++) { 339 $WidthAlpha[$i] = (abs(($width / 2) - $i) / $width); 340 $Offset['x'] = cos(deg2rad($angle)) * ($distance + $i); 341 $Offset['y'] = sin(deg2rad($angle)) * ($distance + $i); 342 } 343 344 $tempImageWidth = imagesx($gdimg) + abs($Offset['x']); 345 $tempImageHeight = imagesy($gdimg) + abs($Offset['y']); 346 347 if ($gdimg_dropshadow_temp = phpthumb_functions::ImageCreateFunction($tempImageWidth, $tempImageHeight)) { 348 349 imagealphablending($gdimg_dropshadow_temp, false); 350 imagesavealpha($gdimg_dropshadow_temp, true); 351 $transparent1 = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_dropshadow_temp, 0, 0, 0, 127); 352 imagefill($gdimg_dropshadow_temp, 0, 0, $transparent1); 353 354 $PixelMap = array(); 355 for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { 356 for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { 357 $PixelMap[$x][$y] = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 358 } 359 } 360 for ($x = 0; $x < $tempImageWidth; $x++) { 361 for ($y = 0; $y < $tempImageHeight; $y++) { 362 //for ($i = 0; $i < $width; $i++) { 363 for ($i = 0; $i < 1; $i++) { 364 if (!isset($PixelMap[$x][$y]['alpha']) || ($PixelMap[$x][$y]['alpha'] > 0)) { 365 if (isset($PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha']) && ($PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha'] < 127)) { 366 $thisColor = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor, false, $PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha']); 367 imagesetpixel($gdimg_dropshadow_temp, $x, $y, $thisColor); 368 } 369 } 370 } 371 } 372 } 373 374 imagealphablending($gdimg_dropshadow_temp, true); 375 for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { 376 for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { 377 if ($PixelMap[$x][$y]['alpha'] < 127) { 378 $thisColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_dropshadow_temp, $PixelMap[$x][$y]['red'], $PixelMap[$x][$y]['green'], $PixelMap[$x][$y]['blue'], $PixelMap[$x][$y]['alpha']); 379 imagesetpixel($gdimg_dropshadow_temp, $x, $y, $thisColor); 380 } 381 } 382 } 383 384 imagesavealpha($gdimg, true); 385 imagealphablending($gdimg, false); 386 //$this->is_alpha = true; 387 $transparent2 = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0, 0, 0, 127); 388 imagefilledrectangle($gdimg, 0, 0, imagesx($gdimg), imagesy($gdimg), $transparent2); 389 imagecopyresampled($gdimg, $gdimg_dropshadow_temp, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg), imagesx($gdimg_dropshadow_temp), imagesy($gdimg_dropshadow_temp)); 390 391 imagedestroy($gdimg_dropshadow_temp); 392 } 393 return true; 394 } 395 396 397 public function EdgeDetect(&$gdimg) { 398 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 399 if (imagefilter($gdimg, IMG_FILTER_EDGEDETECT)) { 400 return true; 401 } 402 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_EDGEDETECT)', __FILE__, __LINE__); 403 // fall through and try it the hard way 404 } 405 // currently not implemented "the hard way" 406 $this->DebugMessage('FAILED: phpthumb_filters::EdgeDetect($gdimg) [function not implemented]', __FILE__, __LINE__); 407 return false; 408 } 409 410 411 public function Ellipse($gdimg) { 412 if (phpthumb_functions::gd_version() < 2) { 413 return false; 414 } 415 // generate mask at twice desired resolution and downsample afterwards for easy antialiasing 416 if ($gdimg_ellipsemask_double = phpthumb_functions::ImageCreateFunction(imagesx($gdimg) * 2, imagesy($gdimg) * 2)) { 417 if ($gdimg_ellipsemask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) { 418 419 $color_transparent = imagecolorallocate($gdimg_ellipsemask_double, 255, 255, 255); 420 imagefilledellipse($gdimg_ellipsemask_double, imagesx($gdimg), imagesy($gdimg), (imagesx($gdimg) - 1) * 2, (imagesy($gdimg) - 1) * 2, $color_transparent); 421 imagecopyresampled($gdimg_ellipsemask, $gdimg_ellipsemask_double, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg), imagesx($gdimg) * 2, imagesy($gdimg) * 2); 422 423 $this->ApplyMask($gdimg_ellipsemask, $gdimg); 424 imagedestroy($gdimg_ellipsemask); 425 return true; 426 427 } else { 428 $this->DebugMessage('$gdimg_ellipsemask = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__); 429 } 430 imagedestroy($gdimg_ellipsemask_double); 431 } else { 432 $this->DebugMessage('$gdimg_ellipsemask_double = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__); 433 } 434 return false; 435 } 436 437 438 public function Emboss(&$gdimg) { 439 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 440 if (imagefilter($gdimg, IMG_FILTER_EMBOSS)) { 441 return true; 442 } 443 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_EMBOSS)', __FILE__, __LINE__); 444 // fall through and try it the hard way 445 } 446 // currently not implemented "the hard way" 447 $this->DebugMessage('FAILED: phpthumb_filters::Emboss($gdimg) [function not implemented]', __FILE__, __LINE__); 448 return false; 449 } 450 451 452 public function Flip(&$gdimg, $x=false, $y=false) { 453 if (!$x && !$y) { 454 return false; 455 } 456 if ($tempImage = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) { 457 if ($x) { 458 imagecopy($tempImage, $gdimg, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg)); 459 for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { 460 imagecopy($gdimg, $tempImage, imagesx($gdimg) - 1 - $x, 0, $x, 0, 1, imagesy($gdimg)); 461 } 462 } 463 if ($y) { 464 imagecopy($tempImage, $gdimg, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg)); 465 for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { 466 imagecopy($gdimg, $tempImage, 0, imagesy($gdimg) - 1 - $y, 0, $y, imagesx($gdimg), 1); 467 } 468 } 469 imagedestroy($tempImage); 470 } 471 return true; 472 } 473 474 475 public function Frame(&$gdimg, $frame_width, $edge_width, $hexcolor_frame, $hexcolor1, $hexcolor2) { 476 $frame_width = ($frame_width ? $frame_width : 5); 477 $edge_width = ($edge_width ? $edge_width : 1); 478 $hexcolor_frame = ($hexcolor_frame ? $hexcolor_frame : 'CCCCCC'); 479 $hexcolor1 = ($hexcolor1 ? $hexcolor1 : 'FFFFFF'); 480 $hexcolor2 = ($hexcolor2 ? $hexcolor2 : '000000'); 481 482 $color_frame = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor_frame); 483 $color1 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor1); 484 $color2 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor2); 485 for ($i = 0; $i < $edge_width; $i++) { 486 // outer bevel 487 imageline($gdimg, $i, $i, $i, imagesy($gdimg) - $i, $color1); // left 488 imageline($gdimg, $i, $i, imagesx($gdimg) - $i, $i, $color1); // top 489 imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i, imagesx($gdimg) - $i, $i, $color2); // right 490 imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i, $i, imagesy($gdimg) - $i, $color2); // bottom 491 } 492 for ($i = 0; $i < $frame_width; $i++) { 493 // actual frame 494 imagerectangle($gdimg, $edge_width + $i, $edge_width + $i, imagesx($gdimg) - $edge_width - $i, imagesy($gdimg) - $edge_width - $i, $color_frame); 495 } 496 for ($i = 0; $i < $edge_width; $i++) { 497 // inner bevel 498 imageline($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $color2); // left 499 imageline($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, imagesx($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color2); // top 500 imageline($gdimg, imagesx($gdimg) - $frame_width - $edge_width - $i, imagesy($gdimg) - $frame_width - $edge_width - $i, imagesx($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color1); // right 501 imageline($gdimg, imagesx($gdimg) - $frame_width - $edge_width - $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $color1); // bottom 502 } 503 return true; 504 } 505 506 507 public function Gamma(&$gdimg, $amount) { 508 if (number_format($amount, 4) == '1.0000') { 509 return true; 510 } 511 return imagegammacorrect($gdimg, 1.0, $amount); 512 } 513 514 515 public function Grayscale(&$gdimg) { 516 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 517 if (imagefilter($gdimg, IMG_FILTER_GRAYSCALE)) { 518 return true; 519 } 520 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__); 521 // fall through and try it the hard way 522 } 523 return $this->Colorize($gdimg, 100, 'gray'); 524 } 525 526 527 public function HistogramAnalysis(&$gdimg, $calculateGray=false) { 528 $ImageSX = imagesx($gdimg); 529 $ImageSY = imagesy($gdimg); 530 $Analysis = array(); 531 for ($x = 0; $x < $ImageSX; $x++) { 532 for ($y = 0; $y < $ImageSY; $y++) { 533 $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 534 @$Analysis['red'][$OriginalPixel['red']]++; 535 @$Analysis['green'][$OriginalPixel['green']]++; 536 @$Analysis['blue'][$OriginalPixel['blue']]++; 537 @$Analysis['alpha'][$OriginalPixel['alpha']]++; 538 if ($calculateGray) { 539 $GrayPixel = phpthumb_functions::GrayscalePixel($OriginalPixel); 540 @$Analysis['gray'][$GrayPixel['red']]++; 541 } 542 } 543 } 544 $keys = array('red', 'green', 'blue', 'alpha'); 545 if ($calculateGray) { 546 $keys[] = 'gray'; 547 } 548 foreach ($keys as $dummy => $key) { 549 ksort($Analysis[$key]); 550 } 551 return $Analysis; 552 } 553 554 555 public function HistogramStretch(&$gdimg, $band='*', $method=0, $threshold=0.1) { 556 // equivalent of "Auto Contrast" in Adobe Photoshop 557 // method 0 stretches according to RGB colors. Gives a more conservative stretch. 558 // method 1 band stretches according to grayscale which is color-biased (59% green, 30% red, 11% blue). May give a punchier / more aggressive stretch, possibly appearing over-saturated 559 $Analysis = $this->HistogramAnalysis($gdimg, true); 560 $keys = array('r'=>'red', 'g'=>'green', 'b'=>'blue', 'a'=>'alpha', '*'=> ($method == 0) ? 'all' : 'gray' ); 561 $band = $band[ 0 ]; 562 if (!isset($keys[$band])) { 563 return false; 564 } 565 $key = $keys[$band]; 566 567 // If the absolute brightest and darkest pixels are used then one random 568 // pixel in the image could throw off the whole system. Instead, count up/down 569 // from the limit and allow <threshold> (default = 0.1%) of brightest/darkest 570 // pixels to be clipped to min/max 571 $threshold = (float) $threshold / 100; 572 $clip_threshold = imagesx($gdimg) * imagesx($gdimg) * $threshold; 573 574 $countsum = 0; 575 $range_min = 0; 576 for ($i = 0; $i <= 255; $i++) { 577 if ($method == 0) { 578 $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]); 579 } else { 580 $countsum += @$Analysis[$key][$i]; 581 } 582 if ($countsum >= $clip_threshold) { 583 $range_min = $i - 1; 584 break; 585 } 586 } 587 $range_min = max($range_min, 0); 588 589 $countsum = 0; 590 $range_max = 255; 591 for ($i = 255; $i >= 0; $i--) { 592 if ($method == 0) { 593 $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]); 594 } else { 595 $countsum += @$Analysis[$key][$i]; 596 } 597 if ($countsum >= $clip_threshold) { 598 $range_max = $i + 1; 599 break; 600 } 601 } 602 $range_max = min($range_max, 255); 603 604 $range_scale = (($range_max == $range_min) ? 1 : (255 / ($range_max - $range_min))); 605 if (($range_min == 0) && ($range_max == 255)) { 606 // no adjustment necessary - don't waste CPU time! 607 return true; 608 } 609 610 $ImageSX = imagesx($gdimg); 611 $ImageSY = imagesy($gdimg); 612 for ($x = 0; $x < $ImageSX; $x++) { 613 for ($y = 0; $y < $ImageSY; $y++) { 614 $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 615 if ($band == '*') { 616 $new['red'] = min(255, max(0, ($OriginalPixel['red'] - $range_min) * $range_scale)); 617 $new['green'] = min(255, max(0, ($OriginalPixel['green'] - $range_min) * $range_scale)); 618 $new['blue'] = min(255, max(0, ($OriginalPixel['blue'] - $range_min) * $range_scale)); 619 $new['alpha'] = min(255, max(0, ($OriginalPixel['alpha'] - $range_min) * $range_scale)); 620 } else { 621 $new = $OriginalPixel; 622 $new[$key] = min(255, max(0, ($OriginalPixel[$key] - $range_min) * $range_scale)); 623 } 624 $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $new['red'], $new['green'], $new['blue'], $new['alpha']); 625 imagesetpixel($gdimg, $x, $y, $newColor); 626 } 627 } 628 629 return true; 630 } 631 632 633 public function HistogramOverlay(&$gdimg, $bands='*', $colors='', $width=0.25, $height=0.25, $alignment='BR', $opacity=50, $margin_x=5, $margin_y=null) { 634 $margin_y = (null === $margin_y ? $margin_x : $margin_y); 635 636 $Analysis = $this->HistogramAnalysis($gdimg, true); 637 $histW = round(($width > 1) ? min($width, imagesx($gdimg)) : imagesx($gdimg) * $width); 638 $histH = round(($width > 1) ? min($width, imagesx($gdimg)) : imagesx($gdimg) * $width); 639 if ($gdHist = imagecreatetruecolor($histW, $histH)) { 640 $color_back = phpthumb_functions::ImageColorAllocateAlphaSafe($gdHist, 0, 0, 0, 127); 641 imagefilledrectangle($gdHist, 0, 0, $histW, $histH, $color_back); 642 imagealphablending($gdHist, false); 643 imagesavealpha($gdHist, true); 644 645 $HistogramTempWidth = 256; 646 $HistogramTempHeight = 100; 647 if ($gdHistTemp = imagecreatetruecolor($HistogramTempWidth, $HistogramTempHeight)) { 648 $color_back_temp = phpthumb_functions::ImageColorAllocateAlphaSafe($gdHistTemp, 255, 0, 255, 127); 649 imagealphablending($gdHistTemp, false); 650 imagesavealpha($gdHistTemp, true); 651 imagefilledrectangle($gdHistTemp, 0, 0, imagesx($gdHistTemp), imagesy($gdHistTemp), $color_back_temp); 652 653 $DefaultColors = array('r'=>'FF0000', 'g'=>'00FF00', 'b'=>'0000FF', 'a'=>'999999', '*'=>'FFFFFF'); 654 $Colors = explode(';', $colors); 655 $BandsToGraph = array_unique(preg_split('##', $bands)); 656 $keys = array('r'=>'red', 'g'=>'green', 'b'=>'blue', 'a'=>'alpha', '*'=>'gray'); 657 foreach ($BandsToGraph as $key => $band) { 658 if (!isset($keys[$band])) { 659 continue; 660 } 661 $PeakValue = max($Analysis[$keys[$band]]); 662 $thisColor = phpthumb_functions::ImageHexColorAllocate($gdHistTemp, phpthumb_functions::IsHexColor(@$Colors[$key]) ? $Colors[$key] : $DefaultColors[$band]); 663 for ($x = 0; $x < $HistogramTempWidth; $x++) { 664 imageline($gdHistTemp, $x, $HistogramTempHeight - 1, $x, $HistogramTempHeight - 1 - round(@$Analysis[$keys[$band]][$x] / $PeakValue * $HistogramTempHeight), $thisColor); 665 } 666 imageline($gdHistTemp, 0, $HistogramTempHeight - 1, $HistogramTempWidth - 1, $HistogramTempHeight - 1, $thisColor); 667 imageline($gdHistTemp, 0, $HistogramTempHeight - 2, $HistogramTempWidth - 1, $HistogramTempHeight - 2, $thisColor); 668 } 669 imagecopyresampled($gdHist, $gdHistTemp, 0, 0, 0, 0, imagesx($gdHist), imagesy($gdHist), imagesx($gdHistTemp), imagesy($gdHistTemp)); 670 imagedestroy($gdHistTemp); 671 } else { 672 return false; 673 } 674 675 $this->WatermarkOverlay($gdimg, $gdHist, $alignment, $opacity, $margin_x, $margin_y); 676 imagedestroy($gdHist); 677 return true; 678 } 679 return false; 680 } 681 682 683 public function ImageBorder(&$gdimg, $border_width, $radius_x, $radius_y, $hexcolor_border) { 684 $border_width = ($border_width ? $border_width : 1); 685 $radius_x = ($radius_x ? $radius_x : 0); 686 $radius_y = ($radius_y ? $radius_y : 0); 687 688 $output_width = imagesx($gdimg); 689 $output_height = imagesy($gdimg); 690 691 list($new_width, $new_height) = phpthumb_functions::ProportionalResize($output_width, $output_height, $output_width - max($border_width * 2, $radius_x), $output_height - max($border_width * 2, $radius_y)); 692 $offset_x = ($radius_x ? $output_width - $new_width - $radius_x : 0); 693 694 if ($gd_border_canvas = phpthumb_functions::ImageCreateFunction($output_width, $output_height)) { 695 696 imagesavealpha($gd_border_canvas, true); 697 imagealphablending($gd_border_canvas, false); 698 $color_background = phpthumb_functions::ImageColorAllocateAlphaSafe($gd_border_canvas, 255, 255, 255, 127); 699 imagefilledrectangle($gd_border_canvas, 0, 0, $output_width, $output_height, $color_background); 700 701 $color_border = phpthumb_functions::ImageHexColorAllocate($gd_border_canvas, (phpthumb_functions::IsHexColor($hexcolor_border) ? $hexcolor_border : '000000')); 702 703 for ($i = 0; $i < $border_width; $i++) { 704 imageline($gd_border_canvas, floor($offset_x / 2) + $radius_x, $i, $output_width - $radius_x - ceil($offset_x / 2), $i, $color_border); // top 705 imageline($gd_border_canvas, floor($offset_x / 2) + $radius_x, $output_height - 1 - $i, $output_width - $radius_x - ceil($offset_x / 2), $output_height - 1 - $i, $color_border); // bottom 706 imageline($gd_border_canvas, floor($offset_x / 2) + $i, $radius_y, floor($offset_x / 2) + $i, $output_height - $radius_y, $color_border); // left 707 imageline($gd_border_canvas, $output_width - 1 - $i - ceil($offset_x / 2), $radius_y, $output_width - 1 - $i - ceil($offset_x / 2), $output_height - $radius_y, $color_border); // right 708 } 709 710 if ($radius_x && $radius_y) { 711 712 // PHP bug: imagearc() with thicknesses > 1 give bad/undesirable/unpredicatable results 713 // Solution: Draw multiple 1px arcs side-by-side. 714 715 // Problem: parallel arcs give strange/ugly antialiasing problems 716 // Solution: draw non-parallel arcs, from one side of the line thickness at the start angle 717 // to the opposite edge of the line thickness at the terminating angle 718 for ($thickness_offset = 0; $thickness_offset < $border_width; $thickness_offset++) { 719 imagearc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left 720 imagearc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right 721 imagearc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right 722 imagearc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left 723 } 724 if ($border_width > 1) { 725 for ($thickness_offset = 0; $thickness_offset < $border_width; $thickness_offset++) { 726 imagearc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left 727 imagearc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right 728 imagearc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right 729 imagearc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left 730 } 731 } 732 733 } 734 $this->phpThumbObject->ImageResizeFunction($gd_border_canvas, $gdimg, floor(($output_width - $new_width) / 2), round(($output_height - $new_height) / 2), 0, 0, $new_width, $new_height, $output_width, $output_height); 735 736 imagedestroy($gdimg); 737 $gdimg = phpthumb_functions::ImageCreateFunction($output_width, $output_height); 738 imagesavealpha($gdimg, true); 739 imagealphablending($gdimg, false); 740 $gdimg_color_background = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 255, 255, 255, 127); 741 imagefilledrectangle($gdimg, 0, 0, $output_width, $output_height, $gdimg_color_background); 742 743 imagecopy($gdimg, $gd_border_canvas, 0, 0, 0, 0, $output_width, $output_height); 744 imagedestroy($gd_border_canvas); 745 return true; 746 747 748 } else { 749 $this->DebugMessage('FAILED: $gd_border_canvas = phpthumb_functions::ImageCreateFunction('.$output_width.', '.$output_height.')', __FILE__, __LINE__); 750 } 751 return false; 752 } 753 754 755 public static function ImprovedImageRotate(&$gdimg_source, $rotate_angle, $config_background_hexcolor, $bg, &$phpThumbObject) { 756 while ($rotate_angle < 0) { 757 $rotate_angle += 360; 758 } 759 $rotate_angle %= 360; 760 if ($rotate_angle != 0) { 761 762 $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_source, $config_background_hexcolor); 763 764 if ((phpthumb_functions::gd_version() >= 2) && !$bg && ($rotate_angle % 90)) { 765 766 //$this->DebugMessage('Using alpha rotate', __FILE__, __LINE__); 767 if ($gdimg_rotate_mask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_source), imagesy($gdimg_source))) { 768 769 $color_mask = array(); 770 for ($i = 0; $i <= 255; $i++) { 771 $color_mask[$i] = imagecolorallocate($gdimg_rotate_mask, $i, $i, $i); 772 } 773 imagefilledrectangle($gdimg_rotate_mask, 0, 0, imagesx($gdimg_rotate_mask), imagesy($gdimg_rotate_mask), $color_mask[255]); 774 $imageX = imagesx($gdimg_source); 775 $imageY = imagesy($gdimg_source); 776 for ($x = 0; $x < $imageX; $x++) { 777 for ($y = 0; $y < $imageY; $y++) { 778 $pixelcolor = phpthumb_functions::GetPixelColor($gdimg_source, $x, $y); 779 imagesetpixel($gdimg_rotate_mask, $x, $y, $color_mask[255 - round($pixelcolor['alpha'] * 255 / 127)]); 780 } 781 } 782 $gdimg_rotate_mask = imagerotate($gdimg_rotate_mask, $rotate_angle, $color_mask[0]); 783 $gdimg_source = imagerotate($gdimg_source, $rotate_angle, $background_color); 784 785 imagealphablending($gdimg_source, false); 786 imagesavealpha($gdimg_source, true); 787 //$this->is_alpha = true; 788 $phpThumbFilters = new self(); 789 //$phpThumbFilters->phpThumbObject = $this; 790 $phpThumbFilters->phpThumbObject = $phpThumbObject; 791 $phpThumbFilters->ApplyMask($gdimg_rotate_mask, $gdimg_source); 792 793 imagedestroy($gdimg_rotate_mask); 794 795 } else { 796 //$this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__); 797 } 798 799 } else { 800 801 if (phpthumb_functions::gd_version() < 2) { 802 //$this->DebugMessage('Using non-alpha rotate because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__); 803 } elseif ($bg) { 804 //$this->DebugMessage('Using non-alpha rotate because $this->bg is "'.$bg.'"', __FILE__, __LINE__); 805 } elseif ($rotate_angle % 90) { 806 //$this->DebugMessage('Using non-alpha rotate because ($rotate_angle % 90) = "'.($rotate_angle % 90).'"', __FILE__, __LINE__); 807 } else { 808 //$this->DebugMessage('Using non-alpha rotate because $this->thumbnailFormat is "'.$this->thumbnailFormat.'"', __FILE__, __LINE__); 809 } 810 811 if (imagecolortransparent($gdimg_source) >= 0) { 812 // imagerotate() forgets all about an image's transparency and sets the transparent color to black 813 // To compensate, flood-fill the transparent color of the source image with the specified background color first 814 // then rotate and the colors should match 815 816 if (!function_exists('imageistruecolor') || !imageistruecolor($gdimg_source)) { 817 // convert paletted image to true-color before rotating to prevent nasty aliasing artifacts 818 819 //$this->source_width = imagesx($gdimg_source); 820 //$this->source_height = imagesy($gdimg_source); 821 $gdimg_newsrc = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_source), imagesy($gdimg_source)); 822 $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $config_background_hexcolor); 823 imagefilledrectangle($gdimg_newsrc, 0, 0, imagesx($gdimg_source), imagesy($gdimg_source), phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $config_background_hexcolor)); 824 imagecopy($gdimg_newsrc, $gdimg_source, 0, 0, 0, 0, imagesx($gdimg_source), imagesy($gdimg_source)); 825 imagedestroy($gdimg_source); 826 unset($gdimg_source); 827 $gdimg_source = $gdimg_newsrc; 828 unset($gdimg_newsrc); 829 830 } else { 831 832 imagecolorset( 833 $gdimg_source, 834 imagecolortransparent($gdimg_source), 835 hexdec(substr($config_background_hexcolor, 0, 2)), 836 hexdec(substr($config_background_hexcolor, 2, 2)), 837 hexdec(substr($config_background_hexcolor, 4, 2))); 838 839 imagecolortransparent($gdimg_source, -1); 840 841 } 842 } 843 844 $gdimg_source = imagerotate($gdimg_source, $rotate_angle, $background_color); 845 846 } 847 } 848 return true; 849 } 850 851 852 public function MeanRemoval(&$gdimg) { 853 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 854 if (imagefilter($gdimg, IMG_FILTER_MEAN_REMOVAL)) { 855 return true; 856 } 857 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_MEAN_REMOVAL)', __FILE__, __LINE__); 858 // fall through and try it the hard way 859 } 860 // currently not implemented "the hard way" 861 $this->DebugMessage('FAILED: phpthumb_filters::MeanRemoval($gdimg) [function not implemented]', __FILE__, __LINE__); 862 return false; 863 } 864 865 866 public function Negative(&$gdimg) { 867 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 868 if (imagefilter($gdimg, IMG_FILTER_NEGATE)) { 869 return true; 870 } 871 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_NEGATE)', __FILE__, __LINE__); 872 // fall through and try it the hard way 873 } 874 $ImageSX = imagesx($gdimg); 875 $ImageSY = imagesy($gdimg); 876 for ($x = 0; $x < $ImageSX; $x++) { 877 for ($y = 0; $y < $ImageSY; $y++) { 878 $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 879 $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, ~$currentPixel[ 'red'] & 0xFF, ~$currentPixel[ 'green'] & 0xFF, ~$currentPixel[ 'blue'] & 0xFF, $currentPixel[ 'alpha']); 880 imagesetpixel($gdimg, $x, $y, $newColor); 881 } 882 } 883 return true; 884 } 885 886 887 public function RoundedImageCorners(&$gdimg, $radius_x, $radius_y) { 888 // generate mask at twice desired resolution and downsample afterwards for easy antialiasing 889 // mask is generated as a white double-size ellipse on a triple-size black background and copy-paste-resampled 890 // onto a correct-size mask image as 4 corners due to errors when the entire mask is resampled at once (gray edges) 891 if ($gdimg_cornermask_triple = phpthumb_functions::ImageCreateFunction($radius_x * 6, $radius_y * 6)) { 892 if ($gdimg_cornermask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) { 893 894 $color_transparent = imagecolorallocate($gdimg_cornermask_triple, 255, 255, 255); 895 imagefilledellipse($gdimg_cornermask_triple, $radius_x * 3, $radius_y * 3, $radius_x * 4, $radius_y * 4, $color_transparent); 896 897 imagefilledrectangle($gdimg_cornermask, 0, 0, imagesx($gdimg), imagesy($gdimg), $color_transparent); 898 899 imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, 0, $radius_x, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); 900 imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, imagesy($gdimg) - $radius_y, $radius_x, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); 901 imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, imagesx($gdimg) - $radius_x, imagesy($gdimg) - $radius_y, $radius_x * 3, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); 902 imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, imagesx($gdimg) - $radius_x, 0, $radius_x * 3, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); 903 904 $this->ApplyMask($gdimg_cornermask, $gdimg); 905 imagedestroy($gdimg_cornermask); 906 $this->DebugMessage('RoundedImageCorners('.$radius_x.', '.$radius_y.') succeeded', __FILE__, __LINE__); 907 return true; 908 909 } else { 910 $this->DebugMessage('FAILED: $gdimg_cornermask = phpthumb_functions::ImageCreateFunction('.imagesx($gdimg).', '.imagesy($gdimg).')', __FILE__, __LINE__); 911 } 912 imagedestroy($gdimg_cornermask_triple); 913 914 } else { 915 $this->DebugMessage('FAILED: $gdimg_cornermask_triple = phpthumb_functions::ImageCreateFunction('.($radius_x * 6).', '.($radius_y * 6).')', __FILE__, __LINE__); 916 } 917 return false; 918 } 919 920 921 public function Saturation(&$gdimg, $amount, $color='') { 922 if ($amount == 0) { 923 return true; 924 } elseif ($amount > 0) { 925 $amount = 0 - $amount; 926 } else { 927 $amount = abs($amount); 928 } 929 return $this->Desaturate($gdimg, $amount, $color); 930 } 931 932 933 public function Sepia(&$gdimg, $amount, $targetColor) { 934 $amount = (is_numeric($amount) ? max(0, min(100, $amount)) : 50); 935 $amountPct = $amount / 100; 936 $targetColor = (phpthumb_functions::IsHexColor($targetColor) ? $targetColor : 'A28065'); 937 938 if ($amount == 0) { 939 return true; 940 } 941 942 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 943 if (imagefilter($gdimg, IMG_FILTER_GRAYSCALE)) { 944 945 $r = round($amountPct * hexdec(substr($targetColor, 0, 2))); 946 $g = round($amountPct * hexdec(substr($targetColor, 2, 2))); 947 $b = round($amountPct * hexdec(substr($targetColor, 4, 2))); 948 if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) { 949 return true; 950 } 951 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__); 952 // fall through and try it the hard way 953 954 } else { 955 956 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__); 957 // fall through and try it the hard way 958 959 } 960 } 961 962 $TargetPixel['red'] = hexdec(substr($targetColor, 0, 2)); 963 $TargetPixel['green'] = hexdec(substr($targetColor, 2, 2)); 964 $TargetPixel['blue'] = hexdec(substr($targetColor, 4, 2)); 965 966 $ImageSX = imagesx($gdimg); 967 $ImageSY = imagesy($gdimg); 968 for ($x = 0; $x < $ImageSX; $x++) { 969 for ($y = 0; $y < $ImageSY; $y++) { 970 $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 971 $GrayPixel = phpthumb_functions::GrayscalePixel($OriginalPixel); 972 973 // http://www.gimpguru.org/Tutorials/SepiaToning/ 974 // "In the traditional sepia toning process, the tinting occurs most in 975 // the mid-tones: the lighter and darker areas appear to be closer to B&W." 976 $SepiaAmount = ((128 - abs($GrayPixel['red'] - 128)) / 128) * $amountPct; 977 978 $NewPixel = array(); 979 foreach ($TargetPixel as $key => $value) { 980 $NewPixel[$key] = round(max(0, min(255, $GrayPixel[$key] * (1 - $SepiaAmount) + ($TargetPixel[$key] * $SepiaAmount)))); 981 } 982 $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue'], $OriginalPixel['alpha']); 983 imagesetpixel($gdimg, $x, $y, $newColor); 984 } 985 } 986 return true; 987 } 988 989 990 public function Smooth(&$gdimg, $amount=6) { 991 $amount = min(25, max(0, $amount)); 992 if ($amount == 0) { 993 return true; 994 } 995 if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { 996 if (imagefilter($gdimg, IMG_FILTER_SMOOTH, $amount)) { 997 return true; 998 } 999 $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_SMOOTH, '.$amount.')', __FILE__, __LINE__); 1000 // fall through and try it the hard way 1001 } 1002 // currently not implemented "the hard way" 1003 $this->DebugMessage('FAILED: phpthumb_filters::Smooth($gdimg, '.$amount.') [function not implemented]', __FILE__, __LINE__); 1004 return false; 1005 } 1006 1007 1008 public function SourceTransparentColorMask(&$gdimg, $hexcolor, $min_limit=5, $max_limit=10) { 1009 $width = imagesx($gdimg); 1010 $height = imagesy($gdimg); 1011 if ($gdimg_mask = imagecreatetruecolor($width, $height)) { 1012 $R = hexdec(substr($hexcolor, 0, 2)); 1013 $G = hexdec(substr($hexcolor, 2, 2)); 1014 $B = hexdec(substr($hexcolor, 4, 2)); 1015 $targetPixel = array('red'=>$R, 'green'=>$G, 'blue'=>$B); 1016 $cutoffRange = $max_limit - $min_limit; 1017 for ($x = 0; $x < $width; $x++) { 1018 for ($y = 0; $y < $height; $y++) { 1019 $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 1020 $colorDiff = phpthumb_functions::PixelColorDifferencePercent($currentPixel, $targetPixel); 1021 $grayLevel = min($cutoffRange, max(0, -$min_limit + $colorDiff)) * (255 / max(1, $cutoffRange)); 1022 $newColor = imagecolorallocate($gdimg_mask, $grayLevel, $grayLevel, $grayLevel); 1023 imagesetpixel($gdimg_mask, $x, $y, $newColor); 1024 } 1025 } 1026 return $gdimg_mask; 1027 } 1028 return false; 1029 } 1030 1031 1032 public function Threshold(&$gdimg, $cutoff) { 1033 $width = imagesx($gdimg); 1034 $height = imagesy($gdimg); 1035 $cutoff = min(255, max(0, ($cutoff ? $cutoff : 128))); 1036 for ($x = 0; $x < $width; $x++) { 1037 for ($y = 0; $y < $height; $y++) { 1038 $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 1039 $grayPixel = phpthumb_functions::GrayscalePixel($currentPixel); 1040 if ($grayPixel['red'] < $cutoff) { 1041 $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0x00, 0x00, 0x00, $currentPixel['alpha']); 1042 } else { 1043 $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0xFF, 0xFF, 0xFF, $currentPixel['alpha']); 1044 } 1045 imagesetpixel($gdimg, $x, $y, $newColor); 1046 } 1047 } 1048 return true; 1049 } 1050 1051 1052 public function ImageTrueColorToPalette2(&$image, $dither, $ncolors) { 1053 // http://www.php.net/manual/en/function.imagetruecolortopalette.php 1054 // zmorris at zsculpt dot com (17-Aug-2004 06:58) 1055 $width = imagesx($image); 1056 $height = imagesy($image); 1057 $image_copy = imagecreatetruecolor($width, $height); 1058 //imagecopymerge($image_copy, $image, 0, 0, 0, 0, $width, $height, 100); 1059 imagecopy($image_copy, $image, 0, 0, 0, 0, $width, $height); 1060 imagetruecolortopalette($image, $dither, $ncolors); 1061 imagecolormatch($image_copy, $image); 1062 imagedestroy($image_copy); 1063 return true; 1064 } 1065 1066 public function ReduceColorDepth(&$gdimg, $colors=256, $dither=true) { 1067 $colors = max(min($colors, 256), 2); 1068 // imagetruecolortopalette usually makes ugly colors, the replacement is a bit better 1069 //imagetruecolortopalette($gdimg, $dither, $colors); 1070 $this->ImageTrueColorToPalette2($gdimg, $dither, $colors); 1071 return true; 1072 } 1073 1074 1075 public function WhiteBalance(&$gdimg, $targetColor='') { 1076 if (phpthumb_functions::IsHexColor($targetColor)) { 1077 $targetPixel = array( 1078 'red' => hexdec(substr($targetColor, 0, 2)), 1079 'green' => hexdec(substr($targetColor, 2, 2)), 1080 'blue' => hexdec(substr($targetColor, 4, 2)) 1081 ); 1082 } else { 1083 $Analysis = $this->HistogramAnalysis($gdimg, false); 1084 $targetPixel = array( 1085 'red' => max(array_keys($Analysis['red'])), 1086 'green' => max(array_keys($Analysis['green'])), 1087 'blue' => max(array_keys($Analysis['blue'])) 1088 ); 1089 } 1090 $grayValue = phpthumb_functions::GrayscaleValue($targetPixel['red'], $targetPixel['green'], $targetPixel['blue']); 1091 $scaleR = $grayValue / $targetPixel['red']; 1092 $scaleG = $grayValue / $targetPixel['green']; 1093 $scaleB = $grayValue / $targetPixel['blue']; 1094 1095 for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { 1096 for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { 1097 $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); 1098 $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe( 1099 $gdimg, 1100 max(0, min(255, round($currentPixel['red'] * $scaleR))), 1101 max(0, min(255, round($currentPixel['green'] * $scaleG))), 1102 max(0, min(255, round($currentPixel['blue'] * $scaleB))), 1103 $currentPixel['alpha'] 1104 ); 1105 imagesetpixel($gdimg, $x, $y, $newColor); 1106 } 1107 } 1108 return true; 1109 } 1110 1111 1112 public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000000', $ttffont='', $opacity=100, $margin=5, $angle=0, $bg_color=false, $bg_opacity=0, $fillextend='', $lineheight=1.0) { 1113 // text watermark requested 1114 if (!$text) { 1115 return false; 1116 } 1117 imagealphablending($gdimg, true); 1118 1119 if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)(@[LCR])?$#i', $alignment, $matches)) { 1120 $originOffsetX = (int) $matches[ 1]; 1121 $originOffsetY = (int) $matches[ 2]; 1122 $alignment = (@$matches[4] ? $matches[4] : 'L'); 1123 $margin = 0; 1124 } else { 1125 $originOffsetX = 0; 1126 $originOffsetY = 0; 1127 } 1128 $lineheight = min(100.0, max(0.01, (float) $lineheight)); 1129 1130 $metaTextArray = array( 1131 '^Fb' => $this->phpThumbObject->getimagesizeinfo['filesize'], 1132 '^Fk' => round($this->phpThumbObject->getimagesizeinfo['filesize'] / 1024), 1133 '^Fm' => round($this->phpThumbObject->getimagesizeinfo['filesize'] / 1048576), 1134 '^X' => $this->phpThumbObject->getimagesizeinfo[0], 1135 '^Y' => $this->phpThumbObject->getimagesizeinfo[1], 1136 '^x' => imagesx($gdimg), 1137 '^y' => imagesy($gdimg), 1138 '^^' => '^', 1139 ); 1140 $text = strtr($text, $metaTextArray); 1141 1142 $text = str_replace(array( 1143 "\r\n", 1144 "\r" 1145 ), "\n", $text); 1146 $textlines = explode("\n", $text); 1147 $this->DebugMessage('Processing '.count($textlines).' lines of text', __FILE__, __LINE__); 1148 1149 if (@is_readable($ttffont) && is_file($ttffont)) { 1150 1151 $opacity = 100 - (int) max(min($opacity, 100), 0); 1152 $letter_color_text = phpthumb_functions::ImageHexColorAllocate($gdimg, $hex_color, false, $opacity * 1.27); 1153 1154 $this->DebugMessage('Using TTF font "'.$ttffont.'"', __FILE__, __LINE__); 1155 1156 $TTFbox = imagettfbbox($size, $angle, $ttffont, $text); 1157 1158 $min_x = min($TTFbox[0], $TTFbox[2], $TTFbox[4], $TTFbox[6]); 1159 $max_x = max($TTFbox[0], $TTFbox[2], $TTFbox[4], $TTFbox[6]); 1160 //$text_width = round($max_x - $min_x + ($size * 0.5)); 1161 $text_width = round($max_x - $min_x); 1162 1163 $min_y = min($TTFbox[1], $TTFbox[3], $TTFbox[5], $TTFbox[7]); 1164 $max_y = max($TTFbox[1], $TTFbox[3], $TTFbox[5], $TTFbox[7]); 1165 //$text_height = round($max_y - $min_y + ($size * 0.5)); 1166 $text_height = round($max_y - $min_y); 1167 1168 $TTFboxChar = imagettfbbox($size, $angle, $ttffont, 'jH'); 1169 $char_min_y = min($TTFboxChar[1], $TTFboxChar[3], $TTFboxChar[5], $TTFboxChar[7]); 1170 $char_max_y = max($TTFboxChar[1], $TTFboxChar[3], $TTFboxChar[5], $TTFboxChar[7]); 1171 $char_height = round($char_max_y - $char_min_y); 1172 1173 if ($alignment == '*') { 1174 1175 $text_origin_y = $char_height + $margin; 1176 while (($text_origin_y - $text_height) < imagesy($gdimg)) { 1177 $text_origin_x = $margin; 1178 while ($text_origin_x < imagesx($gdimg)) { 1179 imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text); 1180 $text_origin_x += ($text_width + $margin); 1181 } 1182 $text_origin_y += ($text_height + $margin) * $lineheight; 1183 } 1184 1185 } else { 1186 1187 // this block for background color only 1188 1189 $text_origin_x = 0; 1190 $text_origin_y = 0; 1191 switch ($alignment) { 1192 case '*': 1193 // handled separately 1194 break; 1195 1196 case 'T': 1197 $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2)); 1198 $text_origin_y = $char_height + $margin + $originOffsetY; 1199 break; 1200 1201 case 'B': 1202 $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2)); 1203 $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY; 1204 break; 1205 1206 case 'L': 1207 $text_origin_x = $margin + $originOffsetX; 1208 $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height); 1209 break; 1210 1211 case 'R': 1212 $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); 1213 $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height); 1214 break; 1215 1216 case 'C': 1217 $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2)); 1218 $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height); 1219 break; 1220 1221 case 'TL': 1222 $text_origin_x = $margin + $originOffsetX; 1223 $text_origin_y = $char_height + $margin + $originOffsetY; 1224 break; 1225 1226 case 'TR': 1227 $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); 1228 $text_origin_y = $char_height + $margin + $originOffsetY; 1229 break; 1230 1231 case 'BL': 1232 $text_origin_x = $margin + $originOffsetX; 1233 $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY; 1234 break; 1235 1236 case 'BR': 1237 default: 1238 $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); 1239 $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY; 1240 break; 1241 } 1242 1243 if (phpthumb_functions::IsHexColor($bg_color)) { 1244 $text_background_alpha = round(127 * ((100 - min(max(0, $bg_opacity), 100)) / 100)); 1245 $text_color_background = phpthumb_functions::ImageHexColorAllocate($gdimg, $bg_color, false, $text_background_alpha); 1246 } else { 1247 $text_color_background = phpthumb_functions::ImageHexColorAllocate($gdimg, 'FFFFFF', false, 127); 1248 } 1249 $x1 = $text_origin_x + $min_x; 1250 $y1 = $text_origin_y + $TTFbox[1]; 1251 $x2 = $text_origin_x + $min_x + $text_width; 1252 $y2 = $text_origin_y + $TTFbox[1] - $text_height; 1253 $x_TL = false !== stripos($fillextend, 'x') ? 0 : min($x1, $x2); 1254 $y_TL = false !== stripos($fillextend, 'y') ? 0 : min($y1, $y2); 1255 $x_BR = false !== stripos($fillextend, 'x') ? imagesx($gdimg) : max($x1, $x2); 1256 $y_BR = false !== stripos($fillextend, 'y') ? imagesy($gdimg) : max($y1, $y2); 1257 $this->DebugMessage('WatermarkText() calling imagefilledrectangle($gdimg, '.$x_TL.', '.$y_TL.', '.$x_BR.', '.$y_BR.', $text_color_background)', __FILE__, __LINE__); 1258 imagefilledrectangle($gdimg, $x_TL, $y_TL, $x_BR, $y_BR, $text_color_background); 1259 1260 // end block for background color only 1261 1262 1263 $y_offset = 0; 1264 foreach ($textlines as $dummy => $line) { 1265 1266 $TTFboxLine = imagettfbbox($size, $angle, $ttffont, $line); 1267 $min_x_line = min($TTFboxLine[0], $TTFboxLine[2], $TTFboxLine[4], $TTFboxLine[6]); 1268 $max_x_line = max($TTFboxLine[0], $TTFboxLine[2], $TTFboxLine[4], $TTFboxLine[6]); 1269 $text_width_line = round($max_x_line - $min_x_line); 1270 1271 switch ($alignment) { 1272 // $text_origin_y set above, just re-set $text_origin_x here as needed 1273 1274 case 'L': 1275 case 'TL': 1276 case 'BL': 1277 // no change necessary 1278 break; 1279 1280 case 'C': 1281 case 'T': 1282 case 'B': 1283 $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width_line / 2) : round((imagesx($gdimg) - $text_width_line) / 2)); 1284 break; 1285 1286 case 'R': 1287 case 'TR': 1288 case 'BR': 1289 $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width_line : imagesx($gdimg) - $text_width_line + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); 1290 break; 1291 } 1292 1293 //imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text); 1294 $this->DebugMessage('WatermarkText() calling imagettftext($gdimg, '.$size.', '.$angle.', '.$text_origin_x.', '.($text_origin_y + $y_offset).', $letter_color_text, '.$ttffont.', '.$line.')', __FILE__, __LINE__); 1295 imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y + $y_offset, $letter_color_text, $ttffont, $line); 1296 1297 $y_offset += $char_height * $lineheight; 1298 } 1299 1300 } 1301 return true; 1302 1303 } else { 1304 1305 $size = min(5, max(1, $size)); 1306 $this->DebugMessage('Using built-in font (size='.$size.') for text watermark'.($ttffont ? ' because $ttffont !is_readable('.$ttffont.')' : ''), __FILE__, __LINE__); 1307 1308 $text_width = 0; 1309 $text_height = 0; 1310 foreach ($textlines as $dummy => $line) { 1311 $text_width = max($text_width, imagefontwidth($size) * strlen($line)); 1312 $text_height += imagefontheight($size); 1313 } 1314 if ($img_watermark = phpthumb_functions::ImageCreateFunction($text_width, $text_height)) { 1315 imagealphablending($img_watermark, false); 1316 if (phpthumb_functions::IsHexColor($bg_color)) { 1317 $text_background_alpha = round(127 * ((100 - min(max(0, $bg_opacity), 100)) / 100)); 1318 $text_color_background = phpthumb_functions::ImageHexColorAllocate($img_watermark, $bg_color, false, $text_background_alpha); 1319 } else { 1320 $text_color_background = phpthumb_functions::ImageHexColorAllocate($img_watermark, 'FFFFFF', false, 127); 1321 } 1322 $this->DebugMessage('WatermarkText() calling imagefilledrectangle($img_watermark, 0, 0, '.imagesx($img_watermark).', '.imagesy($img_watermark).', $text_color_background)', __FILE__, __LINE__); 1323 imagefilledrectangle($img_watermark, 0, 0, imagesx($img_watermark), imagesy($img_watermark), $text_color_background); 1324 1325 $img_watermark_mask = false; 1326 $mask_color_background = false; 1327 $mask_color_watermark = false; 1328 if ($angle && function_exists('imagerotate')) { 1329 // using $img_watermark_mask is pointless if imagerotate function isn't available 1330 if ($img_watermark_mask = phpthumb_functions::ImageCreateFunction($text_width, $text_height)) { 1331 $mask_color_background = imagecolorallocate($img_watermark_mask, 0, 0, 0); 1332 imagealphablending($img_watermark_mask, false); 1333 imagefilledrectangle($img_watermark_mask, 0, 0, imagesx($img_watermark_mask), imagesy($img_watermark_mask), $mask_color_background); 1334 $mask_color_watermark = imagecolorallocate($img_watermark_mask, 255, 255, 255); 1335 } 1336 } 1337 1338 $text_color_watermark = phpthumb_functions::ImageHexColorAllocate($img_watermark, $hex_color); 1339 $x_offset = 0; 1340 foreach ($textlines as $key => $line) { 1341 switch ($alignment) { 1342 case 'C': 1343 $x_offset = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2); 1344 $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2; 1345 $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2; 1346 break; 1347 1348 case 'T': 1349 $x_offset = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2); 1350 $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2; 1351 $originOffsetY = $margin; 1352 break; 1353 1354 case 'B': 1355 $x_offset = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2); 1356 $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2; 1357 $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin; 1358 break; 1359 1360 case 'L': 1361 $x_offset = 0; 1362 $originOffsetX = $margin; 1363 $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2; 1364 break; 1365 1366 case 'TL': 1367 $x_offset = 0; 1368 $originOffsetX = $margin; 1369 $originOffsetY = $margin; 1370 break; 1371 1372 case 'BL': 1373 $x_offset = 0; 1374 $originOffsetX = $margin; 1375 $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin; 1376 break; 1377 1378 case 'R': 1379 $x_offset = $text_width - (imagefontwidth($size) * strlen($line)); 1380 $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin; 1381 $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2; 1382 break; 1383 1384 case 'TR': 1385 $x_offset = $text_width - (imagefontwidth($size) * strlen($line)); 1386 $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin; 1387 $originOffsetY = $margin; 1388 break; 1389 1390 case 'BR': 1391 default: 1392 if (!empty($originOffsetX) || !empty($originOffsetY)) { 1393 // absolute pixel positioning 1394 } else { 1395 $x_offset = $text_width - (imagefontwidth($size) * strlen($line)); 1396 $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin; 1397 $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin; 1398 } 1399 break; 1400 } 1401 $this->DebugMessage('WatermarkText() calling imagestring($img_watermark, '.$size.', '.$x_offset.', '.($key * imagefontheight($size)).', '.$line.', $text_color_watermark)', __FILE__, __LINE__); 1402 imagestring($img_watermark, $size, $x_offset, $key * imagefontheight($size), $line, $text_color_watermark); 1403 if ($angle && $img_watermark_mask) { 1404 $this->DebugMessage('WatermarkText() calling imagestring($img_watermark_mask, '.$size.', '.$x_offset.', '.($key * imagefontheight($size) * $lineheight).', '.$text.', $mask_color_watermark)', __FILE__, __LINE__); 1405 imagestring($img_watermark_mask, $size, $x_offset, $key * imagefontheight($size) * $lineheight, $text, $mask_color_watermark); 1406 } 1407 } 1408 if ($angle && $img_watermark_mask) { 1409 $img_watermark = imagerotate($img_watermark, $angle, $text_color_background); 1410 $img_watermark_mask = imagerotate($img_watermark_mask, $angle, $mask_color_background); 1411 $this->ApplyMask($img_watermark_mask, $img_watermark); 1412 } 1413 //phpthumb_filters::WatermarkOverlay($gdimg, $img_watermark, $alignment, $opacity, $margin); 1414 $this->DebugMessage('WatermarkText() calling phpthumb_filters::WatermarkOverlay($gdimg, $img_watermark, '.($originOffsetX.'x'.$originOffsetY).', '.$opacity.', 0)', __FILE__, __LINE__); 1415 $this->WatermarkOverlay($gdimg, $img_watermark, $originOffsetX.'x'.$originOffsetY, $opacity, 0); 1416 imagedestroy($img_watermark); 1417 return true; 1418 } 1419 1420 } 1421 return false; 1422 } 1423 1424 1425 public function WatermarkOverlay(&$gdimg_dest, &$img_watermark, $alignment='*', $opacity=50, $margin_x=5, $margin_y=null) { 1426 1427 if ((is_resource($gdimg_dest) || (is_object($gdimg_dest) && $gdimg_dest instanceOf \GdImage)) && (is_resource($img_watermark) || (is_object($img_watermark) && $img_watermark instanceOf \GdImage))) { 1428 $img_source_width = imagesx($gdimg_dest); 1429 $img_source_height = imagesy($gdimg_dest); 1430 $watermark_source_width = imagesx($img_watermark); 1431 $watermark_source_height = imagesy($img_watermark); 1432 $watermark_opacity_percent = max(0, min(100, $opacity)); 1433 $margin_y = (null === $margin_y ? $margin_x : $margin_y); 1434 $watermark_margin_x = ((($margin_x > 0) && ($margin_x < 1)) ? round((1 - $margin_x) * $img_source_width) : $margin_x); 1435 $watermark_margin_y = ((($margin_y > 0) && ($margin_y < 1)) ? round((1 - $margin_y) * $img_source_height) : $margin_y); 1436 $watermark_destination_x = 0; 1437 $watermark_destination_y = 0; 1438 if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) { 1439 $watermark_destination_x = (int) $matches[ 1]; 1440 $watermark_destination_y = (int) $matches[ 2]; 1441 } else { 1442 switch ($alignment) { 1443 case '*': 1444 if ($gdimg_tiledwatermark = phpthumb_functions::ImageCreateFunction($img_source_width, $img_source_height)) { 1445 1446 imagealphablending($gdimg_tiledwatermark, false); 1447 imagesavealpha($gdimg_tiledwatermark, true); 1448 $text_color_transparent = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_tiledwatermark, 255, 0, 255, 127); 1449 imagefill($gdimg_tiledwatermark, 0, 0, $text_color_transparent); 1450 1451 // set the tiled image transparent color to whatever the untiled image transparency index is 1452 // imagecolortransparent($gdimg_tiledwatermark, imagecolortransparent($img_watermark)); 1453 1454 // a "cleaner" way of doing it, but can't handle the margin feature :( 1455 // imagesettile($gdimg_tiledwatermark, $img_watermark); 1456 // imagefill($gdimg_tiledwatermark, 0, 0, IMG_COLOR_TILED); 1457 // break; 1458 1459 // imagefill($gdimg_tiledwatermark, 0, 0, imagecolortransparent($gdimg_tiledwatermark)); 1460 // tile the image as many times as can fit 1461 for ($x = $watermark_margin_x; $x < ($img_source_width + $watermark_source_width); $x += ($watermark_source_width + $watermark_margin_x)) { 1462 for ($y = $watermark_margin_y; $y < ($img_source_height + $watermark_source_height); $y += ($watermark_source_height + $watermark_margin_y)) { 1463 imagecopy( 1464 $gdimg_tiledwatermark, 1465 $img_watermark, 1466 $x, 1467 $y, 1468 0, 1469 0, 1470 min($watermark_source_width, $img_source_width - $x - $watermark_margin_x), 1471 min($watermark_source_height, $img_source_height - $y - $watermark_margin_y) 1472 ); 1473 } 1474 } 1475 1476 $watermark_source_width = imagesx($gdimg_tiledwatermark); 1477 $watermark_source_height = imagesy($gdimg_tiledwatermark); 1478 $watermark_destination_x = 0; 1479 $watermark_destination_y = 0; 1480 1481 imagedestroy($img_watermark); 1482 $img_watermark = $gdimg_tiledwatermark; 1483 } 1484 break; 1485 1486 case 'T': 1487 $watermark_destination_x = round((($img_source_width / 2) - ($watermark_source_width / 2)) + $watermark_margin_x); 1488 $watermark_destination_y = $watermark_margin_y; 1489 break; 1490 1491 case 'B': 1492 $watermark_destination_x = round((($img_source_width / 2) - ($watermark_source_width / 2)) + $watermark_margin_x); 1493 $watermark_destination_y = $img_source_height - $watermark_source_height - $watermark_margin_y; 1494 break; 1495 1496 case 'L': 1497 $watermark_destination_x = $watermark_margin_x; 1498 $watermark_destination_y = round((($img_source_height / 2) - ($watermark_source_height / 2)) + $watermark_margin_y); 1499 break; 1500 1501 case 'R': 1502 $watermark_destination_x = $img_source_width - $watermark_source_width - $watermark_margin_x; 1503 $watermark_destination_y = round((($img_source_height / 2) - ($watermark_source_height / 2)) + $watermark_margin_y); 1504 break; 1505 1506 case 'C': 1507 $watermark_destination_x = round(($img_source_width / 2) - ($watermark_source_width / 2)); 1508 $watermark_destination_y = round(($img_source_height / 2) - ($watermark_source_height / 2)); 1509 break; 1510 1511 case 'TL': 1512 $watermark_destination_x = $watermark_margin_x; 1513 $watermark_destination_y = $watermark_margin_y; 1514 break; 1515 1516 case 'TR': 1517 $watermark_destination_x = $img_source_width - $watermark_source_width - $watermark_margin_x; 1518 $watermark_destination_y = $watermark_margin_y; 1519 break; 1520 1521 case 'BL': 1522 $watermark_destination_x = $watermark_margin_x; 1523 $watermark_destination_y = $img_source_height - $watermark_source_height - $watermark_margin_y; 1524 break; 1525 1526 case 'BR': 1527 default: 1528 $watermark_destination_x = $img_source_width - $watermark_source_width - $watermark_margin_x; 1529 $watermark_destination_y = $img_source_height - $watermark_source_height - $watermark_margin_y; 1530 break; 1531 } 1532 } 1533 imagealphablending($gdimg_dest, false); 1534 imagesavealpha($gdimg_dest, true); 1535 imagesavealpha($img_watermark, true); 1536 phpthumb_functions::ImageCopyRespectAlpha($gdimg_dest, $img_watermark, $watermark_destination_x, $watermark_destination_y, 0, 0, $watermark_source_width, $watermark_source_height, $watermark_opacity_percent); 1537 1538 return true; 1539 } 1540 return false; 1541 } 1542 1543} 1544