phpThumb() PHP Cross Reference Image Galleries

Source: /phpthumb.class.php - 4092 lines - 188085 bytes - Summary - Text - Print

   1  <?php
   2  //////////////////////////////////////////////////////////////
   3  ///  phpThumb() by James Heinrich <info@silisoftware.com>   //
   4  //        available at http://phpthumb.sourceforge.net     ///
   5  //////////////////////////////////////////////////////////////
   6  ///                                                         //
   7  // See: phpthumb.readme.txt for usage instructions          //
   8  //                                                         ///
   9  //////////////////////////////////////////////////////////////
  10  
  11  ob_start();
  12  if (!include_once(dirname(__FILE__).'/phpthumb.functions.php')) {
  13      ob_end_flush();
  14      die('failed to include_once("'.realpath(dirname(__FILE__).'/phpthumb.functions.php').'")');
  15  }
  16  ob_end_clean();
  17  
  18  class phpthumb {
  19  
  20      // public:
  21      // START PARAMETERS (for object mode and phpThumb.php)
  22      // See phpthumb.readme.txt for descriptions of what each of these values are
  23      var $src  = null;     // SouRCe filename
  24      var $new  = null;     // NEW image (phpThumb.php only)
  25      var $w    = null;     // Width
  26      var $h    = null;     // Height
  27      var $wp   = null;     // Width  (Portrait Images Only)
  28      var $hp   = null;     // Height (Portrait Images Only)
  29      var $wl   = null;     // Width  (Landscape Images Only)
  30      var $hl   = null;     // Height (Landscape Images Only)
  31      var $ws   = null;     // Width  (Square Images Only)
  32      var $hs   = null;     // Height (Square Images Only)
  33      var $f    = null;     // output image Format
  34      var $q    = 75;       // jpeg output Quality
  35      var $sx   = null;     // Source crop top-left X position
  36      var $sy   = null;     // Source crop top-left Y position
  37      var $sw   = null;     // Source crop Width
  38      var $sh   = null;     // Source crop Height
  39      var $zc   = null;     // Zoom Crop
  40      var $bc   = null;     // Border Color
  41      var $bg   = null;     // BackGround color
  42      var $fltr = array();  // FiLTeRs
  43      var $goto = null;     // GO TO url after processing
  44      var $err  = null;     // default ERRor image filename
  45      var $xto  = null;     // extract eXif Thumbnail Only
  46      var $ra   = null;     // Rotate by Angle
  47      var $ar   = null;     // Auto Rotate
  48      var $aoe  = null;     // Allow Output Enlargement
  49      var $far  = null;     // Fixed Aspect Ratio
  50      var $iar  = null;     // Ignore Aspect Ratio
  51      var $maxb = null;     // MAXimum Bytes
  52      var $down = null;     // DOWNload thumbnail filename
  53      var $md5s = null;     // MD5 hash of Source image
  54      var $sfn  = 0;        // Source Frame Number
  55      var $dpi  = 150;      // Dots Per Inch for vector source formats
  56      var $sia  = null;     // Save Image As filename
  57  
  58      var $file = null;     // >>>deprecated, DO NOT USE, will be removed in future versions<<<
  59  
  60      var $phpThumbDebug = null;
  61      // END PARAMETERS
  62  
  63  
  64      // public:
  65      // START CONFIGURATION OPTIONS (for object mode only)
  66      // See phpThumb.config.php for descriptions of what each of these settings do
  67  
  68      // * Directory Configuration
  69      var $config_cache_directory                      = null;
  70      var $config_cache_directory_depth                = 0;
  71      var $config_cache_disable_warning                = true;
  72      var $config_cache_source_enabled                 = false;
  73      var $config_cache_source_directory               = null;
  74      var $config_temp_directory                       = null;
  75      var $config_document_root                        = null;
  76  
  77      // * Default output configuration:
  78      var $config_output_format                        = 'jpeg';
  79      var $config_output_maxwidth                      = 0;
  80      var $config_output_maxheight                     = 0;
  81      var $config_output_interlace                     = true;
  82  
  83      // * Error message configuration
  84      var $config_error_image_width                    = 400;
  85      var $config_error_image_height                   = 100;
  86      var $config_error_message_image_default          = '';
  87      var $config_error_bgcolor                        = 'CCCCFF';
  88      var $config_error_textcolor                      = 'FF0000';
  89      var $config_error_fontsize                       = 1;
  90      var $config_error_die_on_error                   = false;
  91      var $config_error_silent_die_on_error            = false;
  92      var $config_error_die_on_source_failure          = true;
  93  
  94      // * Anti-Hotlink Configuration:
  95      var $config_nohotlink_enabled                    = true;
  96      var $config_nohotlink_valid_domains              = array();
  97      var $config_nohotlink_erase_image                = true;
  98      var $config_nohotlink_text_message               = 'Off-server thumbnailing is not allowed';
  99      // * Off-server Linking Configuration:
 100      var $config_nooffsitelink_enabled                = false;
 101      var $config_nooffsitelink_valid_domains          = array();
 102      var $config_nooffsitelink_require_refer          = false;
 103      var $config_nooffsitelink_erase_image            = true;
 104      var $config_nooffsitelink_watermark_src          = '';
 105      var $config_nooffsitelink_text_message           = 'Off-server linking is not allowed';
 106  
 107      // * Border & Background default colors
 108      var $config_border_hexcolor                      = '000000';
 109      var $config_background_hexcolor                  = 'FFFFFF';
 110  
 111      // * TrueType Fonts
 112      var $config_ttf_directory                        = './fonts';
 113  
 114      var $config_max_source_pixels                    = null;
 115      var $config_use_exif_thumbnail_for_speed         = false;
 116      var $allow_local_http_src                        = false;
 117  
 118      var $config_imagemagick_path                     = null;
 119      var $config_prefer_imagemagick                   = true;
 120      var $config_imagemagick_use_thumbnail            = true;
 121  
 122      var $config_cache_maxage                         = null;
 123      var $config_cache_maxsize                        = null;
 124      var $config_cache_maxfiles                       = null;
 125      var $config_cache_source_filemtime_ignore_local  = false;
 126      var $config_cache_source_filemtime_ignore_remote = true;
 127      var $config_cache_default_only_suffix            = false;
 128      var $config_cache_force_passthru                 = true;
 129      var $config_cache_prefix                         = '';    // default value set in the constructor below
 130  
 131      // * MySQL
 132      var $config_mysql_query                          = null;
 133      var $config_mysql_hostname                       = null;
 134      var $config_mysql_username                       = null;
 135      var $config_mysql_password                       = null;
 136      var $config_mysql_database                       = null;
 137  
 138      // * Security
 139      var $config_high_security_enabled                = false;
 140      var $config_high_security_password               = null;
 141      var $config_disable_debug                        = true;
 142      var $config_allow_src_above_docroot              = false;
 143      var $config_allow_src_above_phpthumb             = true;
 144  
 145      // * HTTP fopen
 146      var $config_http_fopen_timeout                   = 10;
 147      var $config_http_follow_redirect                 = true;
 148  
 149      // * Compatability
 150      var $config_disable_pathinfo_parsing             = false;
 151      var $config_disable_imagecopyresampled           = false;
 152      var $config_disable_onlycreateable_passthru      = false;
 153  
 154      var $config_http_user_agent                      = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7';
 155  
 156      // END CONFIGURATION OPTIONS
 157  
 158  
 159      // public: error messages (read-only; persistant)
 160      var $debugmessages = array();
 161      var $debugtiming   = array();
 162      var $fatalerror    = null;
 163  
 164  
 165      // private: (should not be modified directly)
 166      var $thumbnailQuality = 75;
 167      var $thumbnailFormat  = null;
 168  
 169      var $sourceFilename   = null;
 170      var $rawImageData     = null;
 171      var $IMresizedData    = null;
 172      var $outputImageData  = null;
 173  
 174      var $useRawIMoutput   = false;
 175  
 176      var $gdimg_output     = null;
 177      var $gdimg_source     = null;
 178  
 179      var $getimagesizeinfo = null;
 180  
 181      var $source_width  = null;
 182      var $source_height = null;
 183  
 184      var $thumbnailCropX = null;
 185      var $thumbnailCropY = null;
 186      var $thumbnailCropW = null;
 187      var $thumbnailCropH = null;
 188  
 189      var $exif_thumbnail_width  = null;
 190      var $exif_thumbnail_height = null;
 191      var $exif_thumbnail_type   = null;
 192      var $exif_thumbnail_data   = null;
 193      var $exif_raw_data         = null;
 194  
 195      var $thumbnail_width        = null;
 196      var $thumbnail_height       = null;
 197      var $thumbnail_image_width  = null;
 198      var $thumbnail_image_height = null;
 199  
 200      var $tempFilesToDelete = array();
 201      var $cache_filename    = null;
 202  
 203      var $AlphaCapableFormats = array('png', 'ico', 'gif');
 204      var $is_alpha = false;
 205  
 206      var $iswindows  = null;
 207      var $issafemode = null;
 208  
 209      var $phpthumb_version = '1.7.11-201108081537';
 210  
 211      //////////////////////////////////////////////////////////////////////
 212  
 213      // public: constructor
 214  	function phpThumb() {
 215          $this->DebugTimingMessage('phpThumb() constructor', __FILE__, __LINE__);
 216          $this->DebugMessage('phpThumb() v'.$this->phpthumb_version, __FILE__, __LINE__);
 217          $this->config_max_source_pixels = round(max(intval(ini_get('memory_limit')), intval(get_cfg_var('memory_limit'))) * 1048576 * 0.20); // 20% of memory_limit
 218          $this->iswindows  = (bool) (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
 219          $this->issafemode = (bool) preg_match('#(1|ON)#i', ini_get('safe_mode'));
 220          $this->config_document_root = (!empty($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT']   : $this->config_document_root);
 221          $this->config_cache_prefix  = ( isset($_SERVER['SERVER_NAME'])   ? $_SERVER['SERVER_NAME'].'_' : '');
 222  
 223          $this->purgeTempFiles(); // purge existing temp files if re-initializing object
 224  
 225          $php_sapi_name = strtolower(function_exists('php_sapi_name') ? php_sapi_name() : '');
 226          if ($php_sapi_name == 'cli') {
 227              $this->config_allow_src_above_docroot = true;
 228          }
 229      }
 230  
 231  	function __destruct() {
 232          $this->purgeTempFiles();
 233      }
 234  
 235      // public:
 236  	function purgeTempFiles() {
 237          foreach ($this->tempFilesToDelete as $tempFileToDelete) {
 238              if (file_exists($tempFileToDelete)) {
 239                  $this->DebugMessage('Deleting temp file "'.$tempFileToDelete.'"', __FILE__, __LINE__);
 240                  @unlink($tempFileToDelete);
 241              }
 242          }
 243          $this->tempFilesToDelete = array();
 244          return true;
 245      }
 246  
 247      // public:
 248  	function setSourceFilename($sourceFilename) {
 249          //$this->resetObject();
 250          //$this->rawImageData   = null;
 251          $this->sourceFilename = $sourceFilename;
 252          $this->src            = $sourceFilename;
 253          if (is_null($this->config_output_format)) {
 254              $sourceFileExtension = strtolower(substr(strrchr($sourceFilename, '.'), 1));
 255              if (preg_match('#^[a-z]{3,4}$#', $sourceFileExtension)) {
 256                  $this->config_output_format = $sourceFileExtension;
 257                  $this->DebugMessage('setSourceFilename('.$sourceFilename.') set $this->config_output_format to "'.$sourceFileExtension.'"', __FILE__, __LINE__);
 258              } else {
 259                  $this->DebugMessage('setSourceFilename('.$sourceFilename.') did NOT set $this->config_output_format to "'.$sourceFileExtension.'" because it did not seem like an appropriate image format', __FILE__, __LINE__);
 260              }
 261          }
 262          $this->DebugMessage('setSourceFilename('.$sourceFilename.') set $this->sourceFilename to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
 263          return true;
 264      }
 265  
 266      // public:
 267  	function setSourceData($rawImageData, $sourceFilename='') {
 268          //$this->resetObject();
 269          //$this->sourceFilename = null;
 270          $this->rawImageData   = $rawImageData;
 271          $this->DebugMessage('setSourceData() setting $this->rawImageData ('.strlen($this->rawImageData).' bytes; magic="'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).'))', __FILE__, __LINE__);
 272          if ($this->config_cache_source_enabled) {
 273              $sourceFilename = ($sourceFilename ? $sourceFilename : md5($rawImageData));
 274              if (!is_dir($this->config_cache_source_directory)) {
 275                  $this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not a directory');
 276              } elseif (!@is_writable($this->config_cache_source_directory)) {
 277                  $this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not writable');
 278              }
 279              $this->DebugMessage('setSourceData() attempting to save source image to "'.$this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename).'"', __FILE__, __LINE__);
 280              if ($fp = @fopen($this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename), 'wb')) {
 281                  fwrite($fp, $rawImageData);
 282                  fclose($fp);
 283              } elseif (!$this->phpThumbDebug) {
 284                  $this->ErrorImage('setSourceData() failed to write to source cache ('.$this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename).')');
 285              }
 286          }
 287          return true;
 288      }
 289  
 290      // public:
 291  	function setSourceImageResource($gdimg) {
 292          //$this->resetObject();
 293          $this->gdimg_source = $gdimg;
 294          return true;
 295      }
 296  
 297      // public:
 298  	function setParameter($param, $value) {
 299          if ($param == 'src') {
 300              $this->setSourceFilename($this->ResolveFilenameToAbsolute($value));
 301          } elseif (@is_array($this->$param)) {
 302              if (is_array($value)) {
 303                  foreach ($value as $arraykey => $arrayvalue) {
 304                      array_push($this->$param, $arrayvalue);
 305                  }
 306              } else {
 307                  array_push($this->$param, $value);
 308              }
 309          } else {
 310              $this->$param = $value;
 311          }
 312          return true;
 313      }
 314  
 315      // public:
 316  	function getParameter($param) {
 317          //if (property_exists('phpThumb', $param)) {
 318              return $this->$param;
 319          //}
 320          //$this->DebugMessage('setParameter() attempting to get non-existant parameter "'.$param.'"', __FILE__, __LINE__);
 321          //return false;
 322      }
 323  
 324  
 325      // public:
 326  	function GenerateThumbnail() {
 327  
 328          $this->setOutputFormat();
 329              $this->phpThumbDebug('8a');
 330          $this->ResolveSource();
 331              $this->phpThumbDebug('8b');
 332          $this->SetCacheFilename();
 333              $this->phpThumbDebug('8c');
 334          $this->ExtractEXIFgetImageSize();
 335              $this->phpThumbDebug('8d');
 336          if ($this->useRawIMoutput) {
 337              $this->DebugMessage('Skipping rest of GenerateThumbnail() because ($this->useRawIMoutput == true)', __FILE__, __LINE__);
 338              return true;
 339          }
 340              $this->phpThumbDebug('8e');
 341          if (!$this->SourceImageToGD()) {
 342              $this->DebugMessage('SourceImageToGD() failed', __FILE__, __LINE__);
 343              return false;
 344          }
 345              $this->phpThumbDebug('8f');
 346          $this->Rotate();
 347              $this->phpThumbDebug('8g');
 348          $this->CreateGDoutput();
 349              $this->phpThumbDebug('8h');
 350  
 351          switch ($this->far) {
 352              case 'L':
 353              case 'TL':
 354              case 'BL':
 355                  $destination_offset_x = 0;
 356                  $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
 357                  break;
 358              case 'R':
 359              case 'TR':
 360              case 'BR':
 361                  $destination_offset_x =  round($this->thumbnail_width  - $this->thumbnail_image_width);
 362                  $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
 363                  break;
 364              case 'T':
 365              case 'TL':
 366              case 'TR':
 367                  $destination_offset_x = round(($this->thumbnail_width  - $this->thumbnail_image_width)  / 2);
 368                  $destination_offset_y = 0;
 369                  break;
 370              case 'B':
 371              case 'BL':
 372              case 'BR':
 373                  $destination_offset_x = round(($this->thumbnail_width  - $this->thumbnail_image_width)  / 2);
 374                  $destination_offset_y =  round($this->thumbnail_height - $this->thumbnail_image_height);
 375                  break;
 376              case 'C':
 377              default:
 378                  $destination_offset_x = round(($this->thumbnail_width  - $this->thumbnail_image_width)  / 2);
 379                  $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
 380          }
 381  
 382  //        // copy/resize image to appropriate dimensions
 383  //        $borderThickness = 0;
 384  //        if (!empty($this->fltr)) {
 385  //            foreach ($this->fltr as $key => $value) {
 386  //                if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
 387  //                    $borderThickness = $matches[1];
 388  //                    break;
 389  //                }
 390  //            }
 391  //        }
 392  //        if ($borderThickness > 0) {
 393  //            //$this->DebugMessage('Skipping ImageResizeFunction() because BorderThickness="'.$borderThickness.'"', __FILE__, __LINE__);
 394  //            $this->thumbnail_image_height /= 2;
 395  //        }
 396          $this->ImageResizeFunction(
 397              $this->gdimg_output,
 398              $this->gdimg_source,
 399              $destination_offset_x,
 400              $destination_offset_y,
 401              $this->thumbnailCropX,
 402              $this->thumbnailCropY,
 403              $this->thumbnail_image_width,
 404              $this->thumbnail_image_height,
 405              $this->thumbnailCropW,
 406              $this->thumbnailCropH
 407          );
 408  
 409          $this->DebugMessage('memory_get_usage() after copy-resize = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
 410          ImageDestroy($this->gdimg_source);
 411          $this->DebugMessage('memory_get_usage() after ImageDestroy = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
 412  
 413              $this->phpThumbDebug('8i');
 414          $this->AntiOffsiteLinking();
 415              $this->phpThumbDebug('8j');
 416          $this->ApplyFilters();
 417              $this->phpThumbDebug('8k');
 418          $this->AlphaChannelFlatten();
 419              $this->phpThumbDebug('8l');
 420          $this->MaxFileSize();
 421              $this->phpThumbDebug('8m');
 422  
 423          $this->DebugMessage('GenerateThumbnail() completed successfully', __FILE__, __LINE__);
 424          return true;
 425      }
 426  
 427  
 428      // public:
 429  	function RenderOutput() {
 430          if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
 431              $this->DebugMessage('RenderOutput() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
 432              return false;
 433          }
 434          if (!$this->thumbnailFormat) {
 435              $this->DebugMessage('RenderOutput() failed because $this->thumbnailFormat is empty', __FILE__, __LINE__);
 436              return false;
 437          }
 438          if ($this->useRawIMoutput) {
 439              $this->DebugMessage('RenderOutput copying $this->IMresizedData ('.strlen($this->IMresizedData).' bytes) to $this->outputImage', __FILE__, __LINE__);
 440              $this->outputImageData = $this->IMresizedData;
 441              return true;
 442          }
 443  
 444          $builtin_formats = array();
 445          if (function_exists('ImageTypes')) {
 446              $imagetypes = ImageTypes();
 447              $builtin_formats['wbmp'] = (bool) ($imagetypes & IMG_WBMP);
 448              $builtin_formats['jpg']  = (bool) ($imagetypes & IMG_JPG);
 449              $builtin_formats['gif']  = (bool) ($imagetypes & IMG_GIF);
 450              $builtin_formats['png']  = (bool) ($imagetypes & IMG_PNG);
 451          }
 452          $this->DebugMessage('RenderOutput() attempting Image'.strtoupper(@$this->thumbnailFormat).'($this->gdimg_output)', __FILE__, __LINE__);
 453          ob_start();
 454          switch ($this->thumbnailFormat) {
 455              case 'wbmp':
 456                  if (!@$builtin_formats['wbmp']) {
 457                      $this->DebugMessage('GD does not have required built-in support for WBMP output', __FILE__, __LINE__);
 458                      ob_end_clean();
 459                      return false;
 460                  }
 461                  ImageJPEG($this->gdimg_output, null, $this->thumbnailQuality);
 462                  $this->outputImageData = ob_get_contents();
 463                  break;
 464  
 465              case 'jpeg':
 466              case 'jpg':  // should be "jpeg" not "jpg" but just in case...
 467                  if (!@$builtin_formats['jpg']) {
 468                      $this->DebugMessage('GD does not have required built-in support for JPEG output', __FILE__, __LINE__);
 469                      ob_end_clean();
 470                      return false;
 471                  }
 472                  ImageJPEG($this->gdimg_output, null, $this->thumbnailQuality);
 473                  $this->outputImageData = ob_get_contents();
 474                  break;
 475  
 476              case 'png':
 477                  if (!@$builtin_formats['png']) {
 478                      $this->DebugMessage('GD does not have required built-in support for PNG output', __FILE__, __LINE__);
 479                      ob_end_clean();
 480                      return false;
 481                  }
 482                  ImagePNG($this->gdimg_output);
 483                  $this->outputImageData = ob_get_contents();
 484                  break;
 485  
 486              case 'gif':
 487                  if (!@$builtin_formats['gif']) {
 488                      $this->DebugMessage('GD does not have required built-in support for GIF output', __FILE__, __LINE__);
 489                      ob_end_clean();
 490                      return false;
 491                  }
 492                  ImageGIF($this->gdimg_output);
 493                  $this->outputImageData = ob_get_contents();
 494                  break;
 495  
 496              case 'bmp':
 497                  $ImageOutFunction = '"builtin BMP output"';
 498                  if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) {
 499                      $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
 500                      ob_end_clean();
 501                      return false;
 502                  }
 503                  $phpthumb_bmp = new phpthumb_bmp();
 504                  $this->outputImageData = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
 505                  unset($phpthumb_bmp);
 506                  break;
 507  
 508              case 'ico':
 509                  $ImageOutFunction = '"builtin ICO output"';
 510                  if (!@include_once(dirname(__FILE__).'/phpthumb.ico.php')) {
 511                      $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
 512                      ob_end_clean();
 513                      return false;
 514                  }
 515                  $phpthumb_ico = new phpthumb_ico();
 516                  $arrayOfOutputImages = array($this->gdimg_output);
 517                  $this->outputImageData = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
 518                  unset($phpthumb_ico);
 519                  break;
 520  
 521              default:
 522                  $this->DebugMessage('RenderOutput failed because $this->thumbnailFormat "'.$this->thumbnailFormat.'" is not valid', __FILE__, __LINE__);
 523                  ob_end_clean();
 524                  return false;
 525          }
 526          ob_end_clean();
 527          if (!$this->outputImageData) {
 528              $this->DebugMessage('RenderOutput() for "'.$this->thumbnailFormat.'" failed', __FILE__, __LINE__);
 529              ob_end_clean();
 530              return false;
 531          }
 532          $this->DebugMessage('RenderOutput() completing with $this->outputImageData = '.strlen($this->outputImageData).' bytes', __FILE__, __LINE__);
 533          return true;
 534      }
 535  
 536  
 537      // public:
 538  	function RenderToFile($filename) {
 539          if (preg_match('#^(f|ht)tps?\://#i', $filename)) {
 540              $this->DebugMessage('RenderToFile() failed because $filename ('.$filename.') is a URL', __FILE__, __LINE__);
 541              return false;
 542          }
 543          // render thumbnail to this file only, do not cache, do not output to browser
 544          //$renderfilename = $this->ResolveFilenameToAbsolute(dirname($filename)).DIRECTORY_SEPARATOR.basename($filename);
 545          $renderfilename = $filename;
 546          if (($filename{0} != '/') && ($filename{0} != '\\') && ($filename{1} != ':')) {
 547              $renderfilename = $this->ResolveFilenameToAbsolute($renderfilename);
 548          }
 549          if (!@is_writable(dirname($renderfilename))) {
 550              $this->DebugMessage('RenderToFile() failed because "'.dirname($renderfilename).'/" is not writable', __FILE__, __LINE__);
 551              return false;
 552          }
 553          if (@is_file($renderfilename) && !@is_writable($renderfilename)) {
 554              $this->DebugMessage('RenderToFile() failed because "'.$renderfilename.'" is not writable', __FILE__, __LINE__);
 555              return false;
 556          }
 557  
 558          if ($this->RenderOutput()) {
 559              if (file_put_contents($renderfilename, $this->outputImageData)) {
 560                  $this->DebugMessage('RenderToFile('.$renderfilename.') succeeded', __FILE__, __LINE__);
 561                  return true;
 562              }
 563              if (!@file_exists($renderfilename)) {
 564                  $this->DebugMessage('RenderOutput ['.$this->thumbnailFormat.'('.$renderfilename.')] did not appear to fail, but the output image does not exist either...', __FILE__, __LINE__);
 565              }
 566          } else {
 567              $this->DebugMessage('RenderOutput ['.$this->thumbnailFormat.'('.$renderfilename.')] failed', __FILE__, __LINE__);
 568          }
 569          return false;
 570      }
 571  
 572  
 573      // public:
 574  	function OutputThumbnail() {
 575          $this->purgeTempFiles();
 576  
 577          if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
 578              $this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
 579              return false;
 580          }
 581          if (headers_sent()) {
 582              return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
 583              exit;
 584          }
 585  
 586          $downloadfilename = phpthumb_functions::SanitizeFilename(is_string($this->sia) ? $this->sia : ($this->down ? $this->down : 'phpThumb_generated_thumbnail'.'.'.$this->thumbnailFormat));
 587          $this->DebugMessage('Content-Disposition header filename set to "'.$downloadfilename.'"', __FILE__, __LINE__);
 588          if ($downloadfilename) {
 589              header('Content-Disposition: '.($this->down ? 'attachment' : 'inline').'; filename="'.$downloadfilename.'"');
 590          } else {
 591              $this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__, __LINE__);
 592          }
 593  
 594          if ($this->useRawIMoutput) {
 595  
 596              header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
 597              echo $this->IMresizedData;
 598  
 599          } else {
 600  
 601              $this->DebugMessage('ImageInterlace($this->gdimg_output, '.intval($this->config_output_interlace).')', __FILE__, __LINE__);
 602              ImageInterlace($this->gdimg_output, intval($this->config_output_interlace));
 603              switch ($this->thumbnailFormat) {
 604                  case 'jpeg':
 605                      header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
 606                      $ImageOutFunction = 'image'.$this->thumbnailFormat;
 607                      @$ImageOutFunction($this->gdimg_output, '', $this->thumbnailQuality);
 608                      break;
 609  
 610                  case 'png':
 611                  case 'gif':
 612                      header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
 613                      $ImageOutFunction = 'image'.$this->thumbnailFormat;
 614                      @$ImageOutFunction($this->gdimg_output);
 615                      break;
 616  
 617                  case 'bmp':
 618                      if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) {
 619                          $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
 620                          return false;
 621                      }
 622                      $phpthumb_bmp = new phpthumb_bmp();
 623                      if (is_object($phpthumb_bmp)) {
 624                          $bmp_data = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
 625                          unset($phpthumb_bmp);
 626                          if (!$bmp_data) {
 627                              $this->DebugMessage('$phpthumb_bmp->GD2BMPstring() failed', __FILE__, __LINE__);
 628                              return false;
 629                          }
 630                          header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
 631                          echo $bmp_data;
 632                      } else {
 633                          $this->DebugMessage('new phpthumb_bmp() failed', __FILE__, __LINE__);
 634                          return false;
 635                      }
 636                      break;
 637  
 638                  case 'ico':
 639                      if (!@include_once(dirname(__FILE__).'/phpthumb.ico.php')) {
 640                          $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
 641                          return false;
 642                      }
 643                      $phpthumb_ico = new phpthumb_ico();
 644                      if (is_object($phpthumb_ico)) {
 645                          $arrayOfOutputImages = array($this->gdimg_output);
 646                          $ico_data = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
 647                          unset($phpthumb_ico);
 648                          if (!$ico_data) {
 649                              $this->DebugMessage('$phpthumb_ico->GD2ICOstring() failed', __FILE__, __LINE__);
 650                              return false;
 651                          }
 652                          header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
 653                          echo $ico_data;
 654                      } else {
 655                          $this->DebugMessage('new phpthumb_ico() failed', __FILE__, __LINE__);
 656                          return false;
 657                      }
 658                      break;
 659  
 660                  default:
 661                      $this->DebugMessage('OutputThumbnail failed because $this->thumbnailFormat "'.$this->thumbnailFormat.'" is not valid', __FILE__, __LINE__);
 662                      return false;
 663                      break;
 664              }
 665  
 666          }
 667          return true;
 668      }
 669  
 670  
 671      // public:
 672  	function CleanUpCacheDirectory() {
 673          $this->DebugMessage('CleanUpCacheDirectory() set to purge ('.(is_null($this->config_cache_maxage) ? 'NULL' : number_format($this->config_cache_maxage / 86400, 1)).' days; '.(is_null($this->config_cache_maxsize) ? 'NULL' : number_format($this->config_cache_maxsize / 1048576, 2)).' MB; '.(is_null($this->config_cache_maxfiles) ? 'NULL' : number_format($this->config_cache_maxfiles)).' files)', __FILE__, __LINE__);
 674  
 675          if (!is_writable($this->config_cache_directory)) {
 676              $this->DebugMessage('CleanUpCacheDirectory() skipped because "'.$this->config_cache_directory.'" is not writable', __FILE__, __LINE__);
 677              return true;
 678          }
 679  
 680          // cache status of cache directory for 1 hour to avoid hammering the filesystem functions
 681          $phpThumbCacheStats_filename = $this->config_cache_directory.DIRECTORY_SEPARATOR.'phpThumbCacheStats.txt';
 682          if (file_exists($phpThumbCacheStats_filename) && is_readable($phpThumbCacheStats_filename) && (filemtime($phpThumbCacheStats_filename) >= (time() - 3600))) {
 683              $this->DebugMessage('CleanUpCacheDirectory() skipped because "'.$phpThumbCacheStats_filename.'" is recently modified', __FILE__, __LINE__);
 684              return true;
 685          }
 686          touch($phpThumbCacheStats_filename);
 687  
 688          $DeletedKeys = array();
 689          $AllFilesInCacheDirectory = array();
 690          if (($this->config_cache_maxage > 0) || ($this->config_cache_maxsize > 0) || ($this->config_cache_maxfiles > 0)) {
 691              $CacheDirOldFilesAge  = array();
 692              $CacheDirOldFilesSize = array();
 693              $AllFilesInCacheDirectory = phpthumb_functions::GetAllFilesInSubfolders($this->config_cache_directory);
 694              foreach ($AllFilesInCacheDirectory as $fullfilename) {
 695                  if (preg_match('#^'.preg_quote($this->config_cache_prefix).'#i', $fullfilename) && file_exists($fullfilename)) {
 696                      $CacheDirOldFilesAge[$fullfilename] = @fileatime($fullfilename);
 697                      if ($CacheDirOldFilesAge[$fullfilename] == 0) {
 698                          $CacheDirOldFilesAge[$fullfilename] = @filemtime($fullfilename);
 699                      }
 700                      $CacheDirOldFilesSize[$fullfilename] = @filesize($fullfilename);
 701                  }
 702              }
 703              if (empty($CacheDirOldFilesSize)) {
 704                  return true;
 705              }
 706              $DeletedKeys['zerobyte'] = array();
 707              foreach ($CacheDirOldFilesSize as $fullfilename => $filesize) {
 708                  // purge all zero-size files more than an hour old (to prevent trying to delete just-created and/or in-use files)
 709                  $cutofftime = time() - 3600;
 710                  if (($filesize == 0) && ($CacheDirOldFilesAge[$fullfilename] < $cutofftime)) {
 711                      $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
 712                      if (@unlink($fullfilename)) {
 713                          $DeletedKeys['zerobyte'][] = $fullfilename;
 714                          unset($CacheDirOldFilesSize[$fullfilename]);
 715                          unset($CacheDirOldFilesAge[$fullfilename]);
 716                      }
 717                  }
 718              }
 719              $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['zerobyte']).' zero-byte files', __FILE__, __LINE__);
 720              asort($CacheDirOldFilesAge);
 721  
 722              if ($this->config_cache_maxfiles > 0) {
 723                  $TotalCachedFiles = count($CacheDirOldFilesAge);
 724                  $DeletedKeys['maxfiles'] = array();
 725                  foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
 726                      if ($TotalCachedFiles > $this->config_cache_maxfiles) {
 727                          $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
 728                          if (@unlink($fullfilename)) {
 729                              $TotalCachedFiles--;
 730                              $DeletedKeys['maxfiles'][] = $fullfilename;
 731                          }
 732                      } else {
 733                          // there are few enough files to keep the rest
 734                          break;
 735                      }
 736                  }
 737                  $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxfiles']).' files based on (config_cache_maxfiles='.$this->config_cache_maxfiles.')', __FILE__, __LINE__);
 738                  foreach ($DeletedKeys['maxfiles'] as $fullfilename) {
 739                      unset($CacheDirOldFilesAge[$fullfilename]);
 740                      unset($CacheDirOldFilesSize[$fullfilename]);
 741                  }
 742              }
 743  
 744              if ($this->config_cache_maxage > 0) {
 745                  $mindate = time() - $this->config_cache_maxage;
 746                  $DeletedKeys['maxage'] = array();
 747                  foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
 748                      if ($filedate > 0) {
 749                          if ($filedate < $mindate) {
 750                              $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
 751                              if (@unlink($fullfilename)) {
 752                                  $DeletedKeys['maxage'][] = $fullfilename;
 753                              }
 754                          } else {
 755                              // the rest of the files are new enough to keep
 756                              break;
 757                          }
 758                      }
 759                  }
 760                  $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxage']).' files based on (config_cache_maxage='.$this->config_cache_maxage.')', __FILE__, __LINE__);
 761                  foreach ($DeletedKeys['maxage'] as $fullfilename) {
 762                      unset($CacheDirOldFilesAge[$fullfilename]);
 763                      unset($CacheDirOldFilesSize[$fullfilename]);
 764                  }
 765              }
 766  
 767              if ($this->config_cache_maxsize > 0) {
 768                  $TotalCachedFileSize = array_sum($CacheDirOldFilesSize);
 769                  $DeletedKeys['maxsize'] = array();
 770                  foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
 771                      if ($TotalCachedFileSize > $this->config_cache_maxsize) {
 772                          $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
 773                          if (@unlink($fullfilename)) {
 774                              $TotalCachedFileSize -= $CacheDirOldFilesSize[$fullfilename];
 775                              $DeletedKeys['maxsize'][] = $fullfilename;
 776                          }
 777                      } else {
 778                          // the total filesizes are small enough to keep the rest of the files
 779                          break;
 780                      }
 781                  }
 782                  $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxsize']).' files based on (config_cache_maxsize='.$this->config_cache_maxsize.')', __FILE__, __LINE__);
 783                  foreach ($DeletedKeys['maxsize'] as $fullfilename) {
 784                      unset($CacheDirOldFilesAge[$fullfilename]);
 785                      unset($CacheDirOldFilesSize[$fullfilename]);
 786                  }
 787              }
 788  
 789          } else {
 790              $this->DebugMessage('skipping CleanUpCacheDirectory() because config set to not use it', __FILE__, __LINE__);
 791          }
 792          $totalpurged = 0;
 793          foreach ($DeletedKeys as $key => $value) {
 794              $totalpurged += count($value);
 795          }
 796          $this->DebugMessage('CleanUpCacheDirectory() purged '.$totalpurged.' files (from '.count($AllFilesInCacheDirectory).') based on config settings', __FILE__, __LINE__);
 797          if ($totalpurged > 0) {
 798              $empty_dirs = array();
 799              foreach ($AllFilesInCacheDirectory as $fullfilename) {
 800                  if (is_dir($fullfilename)) {
 801                      $empty_dirs[realpath($fullfilename)] = 1;
 802                  } else {
 803                      unset($empty_dirs[realpath(dirname($fullfilename))]);
 804                  }
 805              }
 806              krsort($empty_dirs);
 807              $totalpurgeddirs = 0;
 808              foreach ($empty_dirs as $empty_dir => $dummy) {
 809                  if ($empty_dir == $this->config_cache_directory) {
 810                      // shouldn't happen, but just in case, don't let it delete actual cache directory
 811                      continue;
 812                  } elseif (@rmdir($empty_dir)) {
 813                      $totalpurgeddirs++;
 814                  } else {
 815                      $this->DebugMessage('failed to rmdir('.$empty_dir.')', __FILE__, __LINE__);
 816                  }
 817              }
 818              $this->DebugMessage('purged '.$totalpurgeddirs.' empty directories', __FILE__, __LINE__);
 819          }
 820          return true;
 821      }
 822  
 823      //////////////////////////////////////////////////////////////////////
 824  
 825      // private: re-initializator (call between rendering multiple images with one object)
 826  	function resetObject() {
 827          $class_vars = get_class_vars(get_class($this));
 828          foreach ($class_vars as $key => $value) {
 829              // do not clobber debug or config info
 830              if (!preg_match('#^(config_|debug|fatalerror)#i', $key)) {
 831                  $this->$key = $value;
 832              }
 833          }
 834          $this->phpThumb(); // re-initialize some class variables
 835          return true;
 836      }
 837  
 838      //////////////////////////////////////////////////////////////////////
 839  
 840  	function ResolveSource() {
 841          if (is_resource($this->gdimg_source)) {
 842              $this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__, __LINE__);
 843              return true;
 844          }
 845          if ($this->rawImageData) {
 846              $this->sourceFilename = null;
 847              $this->DebugMessage('ResolveSource() exiting because $this->rawImageData is set ('.number_format(strlen($this->rawImageData)).' bytes)', __FILE__, __LINE__);
 848              return true;
 849          }
 850          if ($this->sourceFilename) {
 851              $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->sourceFilename);
 852              $this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
 853          } elseif ($this->src) {
 854              $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
 855              $this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'" from $this->src ('.$this->src.')', __FILE__, __LINE__);
 856          } else {
 857              return $this->ErrorImage('$this->sourceFilename and $this->src are both empty');
 858          }
 859          if ($this->iswindows && ((substr($this->sourceFilename, 0, 2) == '//') || (substr($this->sourceFilename, 0, 2) == '\\\\'))) {
 860              // Windows \\share\filename.ext
 861          } elseif (preg_match('#^(f|ht)tps?\://#i', $this->sourceFilename)) {
 862              // URL
 863              if ($this->config_http_user_agent) {
 864                  ini_set('user_agent', $this->config_http_user_agent);
 865              }
 866          } elseif (!@file_exists($this->sourceFilename)) {
 867              return $this->ErrorImage('"'.$this->sourceFilename.'" does not exist');
 868          } elseif (!@is_file($this->sourceFilename)) {
 869              return $this->ErrorImage('"'.$this->sourceFilename.'" is not a file');
 870          }
 871          return true;
 872      }
 873  
 874  	function setOutputFormat() {
 875          static $alreadyCalled = false;
 876          if ($this->thumbnailFormat && $alreadyCalled) {
 877              return true;
 878          }
 879          $alreadyCalled = true;
 880  
 881          $AvailableImageOutputFormats = array();
 882          $AvailableImageOutputFormats[] = 'text';
 883          if (@is_readable(dirname(__FILE__).'/phpthumb.ico.php')) {
 884              $AvailableImageOutputFormats[] = 'ico';
 885          }
 886          if (@is_readable(dirname(__FILE__).'/phpthumb.bmp.php')) {
 887              $AvailableImageOutputFormats[] = 'bmp';
 888          }
 889  
 890          $this->thumbnailFormat = 'ico';
 891  
 892          // Set default output format based on what image types are available
 893          if (function_exists('ImageTypes')) {
 894              $imagetypes = ImageTypes();
 895              if ($imagetypes & IMG_WBMP) {
 896                  $this->thumbnailFormat         = 'wbmp';
 897                  $AvailableImageOutputFormats[] = 'wbmp';
 898              }
 899              if ($imagetypes & IMG_GIF) {
 900                  $this->thumbnailFormat         = 'gif';
 901                  $AvailableImageOutputFormats[] = 'gif';
 902              }
 903              if ($imagetypes & IMG_PNG) {
 904                  $this->thumbnailFormat         = 'png';
 905                  $AvailableImageOutputFormats[] = 'png';
 906              }
 907              if ($imagetypes & IMG_JPG) {
 908                  $this->thumbnailFormat         = 'jpeg';
 909                  $AvailableImageOutputFormats[] = 'jpeg';
 910              }
 911          } else {
 912              //return $this->ErrorImage('ImageTypes() does not exist - GD support might not be enabled?');
 913              $this->DebugMessage('ImageTypes() does not exist - GD support might not be enabled?',  __FILE__, __LINE__);
 914          }
 915          if ($this->ImageMagickVersion()) {
 916              $IMformats = array('jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp');
 917              $this->DebugMessage('Addding ImageMagick formats to $AvailableImageOutputFormats ('.implode(';', $AvailableImageOutputFormats).')', __FILE__, __LINE__);
 918              foreach ($IMformats as $key => $format) {
 919                  $AvailableImageOutputFormats[] = $format;
 920              }
 921          }
 922          $AvailableImageOutputFormats = array_unique($AvailableImageOutputFormats);
 923          $this->DebugMessage('$AvailableImageOutputFormats = array('.implode(';', $AvailableImageOutputFormats).')', __FILE__, __LINE__);
 924  
 925          $this->f = preg_replace('#[^a-z]#', '', strtolower($this->f));
 926          if (strtolower($this->config_output_format) == 'jpg') {
 927              $this->config_output_format = 'jpeg';
 928          }
 929          if (strtolower($this->f) == 'jpg') {
 930              $this->f = 'jpeg';
 931          }
 932          if (phpthumb_functions::CaseInsensitiveInArray($this->config_output_format, $AvailableImageOutputFormats)) {
 933              // set output format to config default if that format is available
 934              $this->DebugMessage('$this->thumbnailFormat set to $this->config_output_format "'.strtolower($this->config_output_format).'"', __FILE__, __LINE__);
 935              $this->thumbnailFormat = strtolower($this->config_output_format);
 936          } elseif ($this->config_output_format) {
 937              $this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->config_output_format ('.strtolower($this->config_output_format).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
 938          }
 939          if ($this->f && (phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats))) {
 940              // override output format if $this->f is set and that format is available
 941              $this->DebugMessage('$this->thumbnailFormat set to $this->f "'.strtolower($this->f).'"', __FILE__, __LINE__);
 942              $this->thumbnailFormat = strtolower($this->f);
 943          } elseif ($this->f) {
 944              $this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->f ('.strtolower($this->f).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
 945          }
 946  
 947          // for JPEG images, quality 1 (worst) to 99 (best)
 948          // quality < 25 is nasty, with not much size savings - not recommended
 949          // problems with 100 - invalid JPEG?
 950          $this->thumbnailQuality = max(1, min(99, ($this->q ? intval($this->q) : 75)));
 951          $this->DebugMessage('$this->thumbnailQuality set to "'.$this->thumbnailQuality.'"', __FILE__, __LINE__);
 952  
 953          return true;
 954      }
 955  
 956  	function setCacheDirectory() {
 957          // resolve cache directory to absolute pathname
 958          $this->DebugMessage('setCacheDirectory() starting with config_cache_directory = "'.$this->config_cache_directory.'"', __FILE__, __LINE__);
 959          if (substr($this->config_cache_directory, 0, 1) == '.') {
 960              if (preg_match('#^(f|ht)tps?\://#i', $this->src)) {
 961                  if (!$this->config_cache_disable_warning) {
 962                      $this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') cannot be used for remote images. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
 963                  }
 964              } elseif ($this->src) {
 965                  // resolve relative cache directory to source image
 966                  $this->config_cache_directory = dirname($this->ResolveFilenameToAbsolute($this->src)).DIRECTORY_SEPARATOR.$this->config_cache_directory;
 967              } else {
 968                  // $this->new is probably set
 969              }
 970          }
 971          if (substr($this->config_cache_directory, -1) == '/') {
 972              $this->config_cache_directory = substr($this->config_cache_directory, 0, -1);
 973          }
 974          if ($this->iswindows) {
 975              $this->config_cache_directory = str_replace('/', DIRECTORY_SEPARATOR, $this->config_cache_directory);
 976          }
 977          if ($this->config_cache_directory) {
 978              $real_cache_path = realpath($this->config_cache_directory);
 979              if (!$real_cache_path) {
 980                  $this->DebugMessage('realpath($this->config_cache_directory) failed for "'.$this->config_cache_directory.'"', __FILE__, __LINE__);
 981                  if (!is_dir($this->config_cache_directory)) {
 982                      $this->DebugMessage('!is_dir('.$this->config_cache_directory.')', __FILE__, __LINE__);
 983                  }
 984              }
 985              if ($real_cache_path) {
 986                  $this->DebugMessage('setting config_cache_directory to realpath('.$this->config_cache_directory.') = "'.$real_cache_path.'"', __FILE__, __LINE__);
 987                  $this->config_cache_directory = $real_cache_path;
 988              }
 989          }
 990          if (!is_dir($this->config_cache_directory)) {
 991              if (!$this->config_cache_disable_warning) {
 992                  $this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
 993              }
 994              $this->DebugMessage('$this->config_cache_directory ('.$this->config_cache_directory.') is not a directory', __FILE__, __LINE__);
 995              $this->config_cache_directory = null;
 996          } elseif (!@is_writable($this->config_cache_directory)) {
 997              $this->DebugMessage('$this->config_cache_directory is not writable ('.$this->config_cache_directory.')', __FILE__, __LINE__);
 998          }
 999  
1000          $this->InitializeTempDirSetting();
1001          if (!@is_dir($this->config_temp_directory) && !@is_writable($this->config_temp_directory) && @is_dir($this->config_cache_directory) && @is_writable($this->config_cache_directory)) {
1002              $this->DebugMessage('setting $this->config_temp_directory = $this->config_cache_directory ('.$this->config_cache_directory.')', __FILE__, __LINE__);
1003              $this->config_temp_directory = $this->config_cache_directory;
1004          }
1005          return true;
1006      }
1007  
1008  
1009  	function ResolveFilenameToAbsolute($filename) {
1010          if (empty($filename)) {
1011              return false;
1012          }
1013  
1014          if (preg_match('#^[a-z0-9]+\:/{1,2}#i', $filename)) {
1015              // eg: http://host/path/file.jpg (HTTP URL)
1016              // eg: ftp://host/path/file.jpg  (FTP URL)
1017              // eg: data1:/path/file.jpg      (Netware path)
1018  
1019              //$AbsoluteFilename = $filename;
1020              return $filename;
1021  
1022          } elseif ($this->iswindows && isset($filename{1}) && ($filename{1} == ':')) {
1023  
1024              // absolute pathname (Windows)
1025              $AbsoluteFilename = $filename;
1026  
1027          } elseif ($this->iswindows && ((substr($filename, 0, 2) == '//') || (substr($filename, 0, 2) == '\\\\'))) {
1028  
1029              // absolute pathname (Windows)
1030              $AbsoluteFilename = $filename;
1031  
1032          } elseif ($filename{0} == '/') {
1033  
1034              if (@is_readable($filename) && !@is_readable($this->config_document_root.$filename)) {
1035  
1036                  // absolute filename (*nix)
1037                  $AbsoluteFilename = $filename;
1038  
1039              } elseif (isset($filename{1}) && ($filename{1} == '~')) {
1040  
1041                  // /~user/path
1042                  if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) {
1043                      $AbsoluteFilename = $ApacheLookupURIarray['filename'];
1044                  } else {
1045                      $AbsoluteFilename = realpath($filename);
1046                      if (@is_readable($AbsoluteFilename)) {
1047                          $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with realpath($filename)', __FILE__, __LINE__);
1048                      } elseif (is_dir(dirname($AbsoluteFilename))) {
1049                          $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname($filename).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with realpath(.)', __FILE__, __LINE__);
1050                      } else {
1051                          return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'". This has been known to fail on Apache2 - try using the absolute filename for the source image (ex: "/home/user/httpdocs/image.jpg" instead of "/~user/image.jpg")');
1052                      }
1053                  }
1054  
1055              } else {
1056  
1057                  // relative filename (any OS)
1058                  if (preg_match('#^'.preg_quote($this->config_document_root).'#', $filename)) {
1059                      $AbsoluteFilename = $filename;
1060                      $this->DebugMessage('ResolveFilenameToAbsolute() NOT prepending $this->config_document_root ('.$this->config_document_root.') to $filename ('.$filename.') resulting in ($AbsoluteFilename = "'.$AbsoluteFilename.'")', __FILE__, __LINE__);
1061                  } else {
1062                      $AbsoluteFilename = $this->config_document_root.$filename;
1063                      $this->DebugMessage('ResolveFilenameToAbsolute() prepending $this->config_document_root ('.$this->config_document_root.') to $filename ('.$filename.') resulting in ($AbsoluteFilename = "'.$AbsoluteFilename.'")', __FILE__, __LINE__);
1064                  }
1065  
1066              }
1067  
1068          } else {
1069  
1070              // relative to current directory (any OS)
1071              //$AbsoluteFilename = $this->config_document_root.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, dirname(@$_SERVER['PHP_SELF'])).DIRECTORY_SEPARATOR.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1072              $AbsoluteFilename = dirname(__FILE__).DIRECTORY_SEPARATOR.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1073  
1074              //if (!@file_exists($AbsoluteFilename) && @file_exists(realpath($this->DotPadRelativeDirectoryPath($filename)))) {
1075              //    $AbsoluteFilename = realpath($this->DotPadRelativeDirectoryPath($filename));
1076              //}
1077  
1078              if (substr(dirname(@$_SERVER['PHP_SELF']), 0, 2) == '/~') {
1079                  if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
1080                      $AbsoluteFilename = $ApacheLookupURIarray['filename'].DIRECTORY_SEPARATOR.$filename;
1081                  } else {
1082                      $AbsoluteFilename = realpath('.').DIRECTORY_SEPARATOR.$filename;
1083                      if (@is_readable($AbsoluteFilename)) {
1084                          $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with realpath(.)/$filename', __FILE__, __LINE__);
1085                      } elseif (is_dir(dirname($AbsoluteFilename))) {
1086                          $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with realpath(.)', __FILE__, __LINE__);
1087                      } else {
1088                          return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'". This has been known to fail on Apache2 - try using the absolute filename for the source image');
1089                      }
1090                  }
1091              }
1092  
1093          }
1094          if (is_link($AbsoluteFilename)) {
1095              $this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__);
1096              $AbsoluteFilename = readlink($AbsoluteFilename);
1097          }
1098          if (realpath($AbsoluteFilename)) {
1099              $AbsoluteFilename = realpath($AbsoluteFilename);
1100          }
1101          if ($this->iswindows) {
1102              $AbsoluteFilename = preg_replace('#^'.preg_quote(realpath($this->config_document_root)).'#i', realpath($this->config_document_root), $AbsoluteFilename);
1103              $AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename);
1104          }
1105          if (!$this->config_allow_src_above_docroot && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath($this->config_document_root))).'#', $AbsoluteFilename)) {
1106              $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "'.$AbsoluteFilename.'" (outside "'.realpath($this->config_document_root).'") to null', __FILE__, __LINE__);
1107              return false;
1108          }
1109          if (!$this->config_allow_src_above_phpthumb && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__))).'#', $AbsoluteFilename)) {
1110              $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "'.$AbsoluteFilename.'" (outside "'.dirname(__FILE__).'") to null', __FILE__, __LINE__);
1111              return false;
1112          }
1113          return $AbsoluteFilename;
1114      }
1115  
1116  	function file_exists_ignoreopenbasedir($filename, $cached=true) {
1117          static $open_basedirs = null;
1118          static $file_exists_cache = array();
1119          if (!$cached || !isset($file_exists_cache[$filename])) {
1120              if (is_null($open_basedirs)) {
1121                  $open_basedirs = explode(';', ini_get('open_basedir'));
1122              }
1123              if (empty($open_basedirs) || in_array(dirname($filename), $open_basedirs)) {
1124                  $file_exists_cache[$filename] = file_exists($filename);
1125              } elseif ($this->iswindows) {
1126                  $ls_filename = trim(phpthumb_functions::SafeExec('dir '.escapeshellarg($filename)));
1127                  $file_exists_cache[$filename] = !preg_match('#File Not Found#i', $ls_filename);
1128              } else {
1129                  $ls_filename = trim(phpthumb_functions::SafeExec('ls '.escapeshellarg($filename)));
1130                  $file_exists_cache[$filename] = ($ls_filename == $filename);
1131              }
1132          }
1133          return $file_exists_cache[$filename];
1134      }
1135  
1136  	function ImageMagickWhichConvert() {
1137          static $WhichConvert = null;
1138          if (is_null($WhichConvert)) {
1139              if ($this->iswindows) {
1140                  $WhichConvert = false;
1141              } else {
1142                  $WhichConvert = trim(phpthumb_functions::SafeExec('which convert'));
1143              }
1144          }
1145          return $WhichConvert;
1146      }
1147  
1148  	function ImageMagickCommandlineBase() {
1149          static $commandline = null;
1150          if (is_null($commandline)) {
1151              if ($this->issafemode) {
1152                  $commandline = '';
1153                  return $commandline;
1154              }
1155              $commandline = (!is_null($this->config_imagemagick_path) ? $this->config_imagemagick_path : '');
1156  
1157              if ($this->config_imagemagick_path && ($this->config_imagemagick_path != realpath($this->config_imagemagick_path))) {
1158                  if (@is_executable(realpath($this->config_imagemagick_path))) {
1159                      $this->DebugMessage('Changing $this->config_imagemagick_path ('.$this->config_imagemagick_path.') to realpath($this->config_imagemagick_path) ('.realpath($this->config_imagemagick_path).')', __FILE__, __LINE__);
1160                      $this->config_imagemagick_path = realpath($this->config_imagemagick_path);
1161                  } else {
1162                      $this->DebugMessage('Leaving $this->config_imagemagick_path as ('.$this->config_imagemagick_path.') because !is_execuatable(realpath($this->config_imagemagick_path)) ('.realpath($this->config_imagemagick_path).')', __FILE__, __LINE__);
1163                  }
1164              }
1165              $this->DebugMessage('                  file_exists('.$this->config_imagemagick_path.') = '.intval(                        @file_exists($this->config_imagemagick_path)), __FILE__, __LINE__);
1166              $this->DebugMessage('file_exists_ignoreopenbasedir('.$this->config_imagemagick_path.') = '.intval($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)), __FILE__, __LINE__);
1167              $this->DebugMessage('                      is_file('.$this->config_imagemagick_path.') = '.intval(                            @is_file($this->config_imagemagick_path)), __FILE__, __LINE__);
1168              $this->DebugMessage('                is_executable('.$this->config_imagemagick_path.') = '.intval(                      @is_executable($this->config_imagemagick_path)), __FILE__, __LINE__);
1169  
1170              if ($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)) {
1171                  $this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path ('.$this->config_imagemagick_path.')', __FILE__, __LINE__);
1172                  if ($this->iswindows) {
1173                      $commandline = substr($this->config_imagemagick_path, 0, 2).' && cd '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, substr(dirname($this->config_imagemagick_path), 2))).' && '.escapeshellarg(basename($this->config_imagemagick_path));
1174                  } else {
1175                      $commandline = escapeshellarg($this->config_imagemagick_path);
1176                  }
1177                  return $commandline;
1178              }
1179  
1180              $which_convert = $this->ImageMagickWhichConvert();
1181              $IMversion     = $this->ImageMagickVersion();
1182  
1183              if ($which_convert && ($which_convert{0} == '/') && $this->file_exists_ignoreopenbasedir($which_convert)) {
1184  
1185                  // `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
1186                  // other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
1187                  // so only do this if the value returned exists as a file
1188                  $this->DebugMessage('using ImageMagick path from `which convert` ('.$which_convert.')', __FILE__, __LINE__);
1189                  $commandline = 'convert';
1190  
1191              } elseif ($IMversion) {
1192  
1193                  $this->DebugMessage('setting ImageMagick path to $this->config_imagemagick_path ('.$this->config_imagemagick_path.') ['.$IMversion.']', __FILE__, __LINE__);
1194                  $commandline = $this->config_imagemagick_path;
1195  
1196              } else {
1197  
1198                  $this->DebugMessage('ImageMagickThumbnailToGD() aborting because cannot find convert in $this->config_imagemagick_path ('.$this->config_imagemagick_path.'), and `which convert` returned ('.$which_convert.')', __FILE__, __LINE__);
1199                  $commandline = '';
1200  
1201              }
1202          }
1203          return $commandline;
1204      }
1205  
1206  	function ImageMagickVersion($returnRAW=false) {
1207          static $versionstring = null;
1208          if (is_null($versionstring)) {
1209              $versionstring = array(0=>false, 1=>false);
1210              $commandline = $this->ImageMagickCommandlineBase();
1211              $commandline = (!is_null($commandline) ? $commandline : '');
1212  
1213              if ($commandline) {
1214                  $commandline .= ' --version';
1215                  $this->DebugMessage('ImageMagick version checked with "'.$commandline.'"', __FILE__, __LINE__);
1216                  $versionstring[1] = trim(phpthumb_functions::SafeExec($commandline));
1217                  if (preg_match('#^Version: [^0-9]*([ 0-9\\.\\:Q/\\-]+) (http|file)\:#i', $versionstring[1], $matches)) {
1218                      $versionstring[0] = $matches[1];
1219                  } else {
1220                      $versionstring[0] = false;
1221                      $this->DebugMessage('ImageMagick did not return recognized version string ('.$versionstring[1].')', __FILE__, __LINE__);
1222                  }
1223                  $this->DebugMessage('ImageMagick convert --version says "'.@$matches[0].'"', __FILE__, __LINE__);
1224              }
1225          }
1226          return $versionstring[intval($returnRAW)];
1227      }
1228  
1229  	function ImageMagickSwitchAvailable($switchname) {
1230          static $IMoptions = null;
1231          if (is_null($IMoptions)) {
1232              $IMoptions = array();
1233              $commandline = $this->ImageMagickCommandlineBase();
1234              if (!is_null($commandline)) {
1235                  $commandline .= ' -help';
1236                  $IMhelp_lines = explode("\n", phpthumb_functions::SafeExec($commandline));
1237                  foreach ($IMhelp_lines as $line) {
1238                      if (preg_match('#^[\\+\\-]([a-z\\-]+) #', trim($line), $matches)) {
1239                          $IMoptions[$matches[1]] = true;
1240                      }
1241                  }
1242              }
1243          }
1244          if (is_array($switchname)) {
1245              $allOK = true;
1246              foreach ($switchname as $key => $value) {
1247                  if (!isset($IMoptions[$value])) {
1248                      $allOK = false;
1249                      break;
1250                  }
1251              }
1252              $this->DebugMessage('ImageMagickSwitchAvailable('.implode(';', $switchname).') = '.intval($allOK).'', __FILE__, __LINE__);
1253          } else {
1254              $allOK = isset($IMoptions[$switchname]);
1255              $this->DebugMessage('ImageMagickSwitchAvailable('.$switchname.') = '.intval($allOK).'', __FILE__, __LINE__);
1256          }
1257          return $allOK;
1258      }
1259  
1260  	function ImageMagickFormatsList() {
1261          static $IMformatsList = null;
1262          if (is_null($IMformatsList)) {
1263              $IMformatsList = '';
1264              $commandline = $this->ImageMagickCommandlineBase();
1265              if (!is_null($commandline)) {
1266                  $commandline = dirname($commandline).DIRECTORY_SEPARATOR.str_replace('convert', 'identify', basename($commandline));
1267                  $commandline .= ' -list format';
1268                  $IMformatsList = phpthumb_functions::SafeExec($commandline);
1269              }
1270          }
1271          return $IMformatsList;
1272      }
1273  
1274  	function SourceDataToTempFile() {
1275          if ($IMtempSourceFilename = $this->phpThumb_tempnam()) {
1276              $IMtempSourceFilename = realpath($IMtempSourceFilename);
1277              ob_start();
1278              $fp_tempfile = fopen($IMtempSourceFilename, 'wb');
1279              $tempfile_open_error  = ob_get_contents();
1280              ob_end_clean();
1281              if ($fp_tempfile) {
1282                  fwrite($fp_tempfile, $this->rawImageData);
1283                  fclose($fp_tempfile);
1284                  $this->sourceFilename = $IMtempSourceFilename;
1285                  $this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "'.$IMtempSourceFilename.'" from $this->rawImageData ('.strlen($this->rawImageData).' bytes)', __FILE__, __LINE__);
1286              } else {
1287                  $this->DebugMessage('ImageMagickThumbnailToGD() FAILED setting $this->sourceFilename to "'.$IMtempSourceFilename.'" (failed to open for writing: "'.$tempfile_open_error.'")', __FILE__, __LINE__);
1288              }
1289              unset($tempfile_open_error, $IMtempSourceFilename);
1290              return true;
1291          }
1292          $this->DebugMessage('SourceDataToTempFile() FAILED because $this->phpThumb_tempnam() failed', __FILE__, __LINE__);
1293          return false;
1294      }
1295  
1296  	function ImageMagickThumbnailToGD() {
1297          // http://www.imagemagick.org/script/command-line-options.php
1298  
1299          $this->useRawIMoutput = true;
1300          if (phpthumb_functions::gd_version()) {
1301              // if GD is not available, must use whatever ImageMagick can output
1302  
1303              // $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick
1304              // note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below
1305              $UnAllowedParameters = array('xto', 'ar', 'bg', 'bc');
1306              // 'ra' may be part of this list, if not a multiple of 90
1307              foreach ($UnAllowedParameters as $parameter) {
1308                  if (isset($this->$parameter)) {
1309                      $this->DebugMessage('$this->useRawIMoutput=false because "'.$parameter.'" is set', __FILE__, __LINE__);
1310                      $this->useRawIMoutput = false;
1311                      break;
1312                  }
1313              }
1314          }
1315          $this->DebugMessage('$this->useRawIMoutput='.($this->useRawIMoutput ? 'true' : 'false').' after checking $UnAllowedParameters', __FILE__, __LINE__);
1316          $outputFormat = $this->thumbnailFormat;
1317          if (phpthumb_functions::gd_version()) {
1318              if ($this->useRawIMoutput) {
1319                  switch ($this->thumbnailFormat) {
1320                      case 'gif':
1321                          $ImageCreateFunction = 'ImageCreateFromGIF';
1322                          $this->is_alpha = true;
1323                          break;
1324                      case 'png':
1325                          $ImageCreateFunction = 'ImageCreateFromPNG';
1326                          $this->is_alpha = true;
1327                          break;
1328                      case 'jpg':
1329                      case 'jpeg':
1330                          $ImageCreateFunction = 'ImageCreateFromJPEG';
1331                          break;
1332                      default:
1333                          $this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat ('.$this->thumbnailFormat.' is not a GD-supported format)', __FILE__, __LINE__);
1334                          $outputFormat = 'png';
1335                          $ImageCreateFunction = 'ImageCreateFromPNG';
1336                          $this->is_alpha = true;
1337                          $this->useRawIMoutput = false;
1338                          break;
1339                  }
1340                  if (!function_exists(@$ImageCreateFunction)) {
1341                      // ImageMagickThumbnailToGD() depends on ImageCreateFromPNG/ImageCreateFromGIF
1342                      //$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__);
1343                      $this->useRawIMoutput = true;
1344                      //return false;
1345                  }
1346              } else {
1347                  $outputFormat = 'png';
1348                  $ImageCreateFunction = 'ImageCreateFromPNG';
1349                  $this->is_alpha = true;
1350                  $this->useRawIMoutput = false;
1351              }
1352          }
1353  
1354          // http://freealter.org/doc_distrib/ImageMagick-5.1.1/www/convert.html
1355          if (!$this->sourceFilename && $this->rawImageData) {
1356              $this->SourceDataToTempFile();
1357          }
1358          if (!$this->sourceFilename) {
1359              $this->DebugMessage('ImageMagickThumbnailToGD() aborting because $this->sourceFilename is empty', __FILE__, __LINE__);
1360              $this->useRawIMoutput = false;
1361              return false;
1362          }
1363          if ($this->issafemode) {
1364              $this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__, __LINE__);
1365              $this->useRawIMoutput = false;
1366              return false;
1367          }
1368  // TO BE FIXED
1369  //if (true) {
1370  //    $this->DebugMessage('ImageMagickThumbnailToGD() aborting it is broken right now', __FILE__, __LINE__);
1371  //    $this->useRawIMoutput = false;
1372  //    return false;
1373  //}
1374  
1375          $commandline = $this->ImageMagickCommandlineBase();
1376          if ($commandline) {
1377              if ($IMtempfilename = $this->phpThumb_tempnam()) {
1378                  $IMtempfilename = realpath($IMtempfilename);
1379  
1380                  $IMuseExplicitImageOutputDimensions = false;
1381                  if ($this->ImageMagickSwitchAvailable('thumbnail') && $this->config_imagemagick_use_thumbnail) {
1382                      $IMresizeParameter = 'thumbnail';
1383                  } else {
1384                      $IMresizeParameter = 'resize';
1385  
1386                      // some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100"
1387                      $commandline_test = $this->ImageMagickCommandlineBase().' logo: -resize 1x '.escapeshellarg($IMtempfilename).' 2>&1';
1388                      $IMresult_test = phpthumb_functions::SafeExec($commandline_test);
1389                      $IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', $IMresult_test);
1390                      $this->DebugMessage('IMuseExplicitImageOutputDimensions = '.intval($IMuseExplicitImageOutputDimensions), __FILE__, __LINE__);
1391                      if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) {
1392                          // erase temp image so ImageMagick logo doesn't get output if other processing fails
1393                          fclose($fp_im_temp);
1394                      }
1395                  }
1396  
1397  
1398                  if (!is_null($this->dpi) && $this->ImageMagickSwitchAvailable('density')) {
1399                      // for raster source formats only (WMF, PDF, etc)
1400                      $commandline .= ' -density '.escapeshellarg($this->dpi);
1401                  }
1402                  ob_start();
1403                  $getimagesize = GetImageSize($this->sourceFilename);
1404                  $GetImageSizeError = ob_get_contents();
1405                  ob_end_clean();
1406                  if (is_array($getimagesize)) {
1407                      $this->DebugMessage('GetImageSize('.$this->sourceFilename.') SUCCEEDED: '.print_r($getimagesize, true), __FILE__, __LINE__);
1408                  } else {
1409                      $this->DebugMessage('GetImageSize('.$this->sourceFilename.') FAILED with error "'.$GetImageSizeError.'"', __FILE__, __LINE__);
1410                  }
1411                  if (is_array($getimagesize)) {
1412                      $this->DebugMessage('GetImageSize('.$this->sourceFilename.') returned [w='.$getimagesize[0].';h='.$getimagesize[1].';f='.$getimagesize[2].']', __FILE__, __LINE__);
1413                      $this->source_width  = $getimagesize[0];
1414                      $this->source_height = $getimagesize[1];
1415                      $this->DebugMessage('source dimensions set to '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
1416                      $this->SetOrientationDependantWidthHeight();
1417  
1418                      if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) {
1419                          // not a transparency-capable format
1420                          $commandline .= ' -background '.escapeshellarg('#'.($this->bg ? $this->bg : 'FFFFFF'));
1421                          if ($getimagesize[2] == IMAGETYPE_GIF) {
1422                              $commandline .= ' -flatten';
1423                          }
1424                      }
1425                      if ($getimagesize[2] == IMAGETYPE_GIF) {
1426                          $commandline .= ' -coalesce'; // may be needed for animated GIFs
1427                      }
1428                      if ($this->source_width || $this->source_height) {
1429                          if ($this->zc) {
1430  
1431                              $borderThickness = 0;
1432                              if (!empty($this->fltr)) {
1433                                  foreach ($this->fltr as $key => $value) {
1434                                      if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
1435                                          $borderThickness = $matches[1];
1436                                          break;
1437                                      }
1438                                  }
1439                              }
1440                              $wAll = intval(max($this->w, $this->wp, $this->wl, $this->ws)) - (2 * $borderThickness);
1441                              $hAll = intval(max($this->h, $this->hp, $this->hl, $this->hs)) - (2 * $borderThickness);
1442                              $imAR = $this->source_width / $this->source_height;
1443                              $zcAR = (($wAll && $hAll) ? $wAll / $hAll : 1);
1444                              $side  = phpthumb_functions::nonempty_min($this->source_width, $this->source_height, max($wAll, $hAll));
1445                              $sideX = phpthumb_functions::nonempty_min($this->source_width,                       $wAll, round($hAll * $zcAR));
1446                              $sideY = phpthumb_functions::nonempty_min(                     $this->source_height, $hAll, round($wAll / $zcAR));
1447  
1448                              $thumbnailH = round(max($sideY, ($sideY * $zcAR) / $imAR));
1449                              $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '').'x'.$thumbnailH);
1450  
1451                              switch (strtoupper($this->zc)) {
1452                                  case 'T':
1453                                      $commandline .= ' -gravity north';
1454                                      break;
1455                                  case 'B':
1456                                      $commandline .= ' -gravity south';
1457                                      break;
1458                                  case 'L':
1459                                      $commandline .= ' -gravity west';
1460                                      break;
1461                                  case 'R':
1462                                      $commandline .= ' -gravity east';
1463                                      break;
1464                                  case 'TL':
1465                                      $commandline .= ' -gravity northwest';
1466                                      break;
1467                                  case 'TR':
1468                                      $commandline .= ' -gravity northeast';
1469                                      break;
1470                                  case 'BL':
1471                                      $commandline .= ' -gravity southwest';
1472                                      break;
1473                                  case 'BR':
1474                                      $commandline .= ' -gravity southeast';
1475                                      break;
1476                                  case '1':
1477                                  case 'C':
1478                                  default:
1479                                      $commandline .= ' -gravity center';
1480                                      break;
1481                              }
1482  
1483                              if (($wAll > 0) && ($hAll > 0)) {
1484                                  $commandline .= ' -crop '.escapeshellarg($wAll.'x'.$hAll.'+0+0');
1485                              } else {
1486                                  $commandline .= ' -crop '.escapeshellarg($side.'x'.$side.'+0+0');
1487                              }
1488                              if ($this->ImageMagickSwitchAvailable('repage')) {
1489                                  $commandline .= ' +repage';
1490                              } else {
1491                                  $this->DebugMessage('Skipping "+repage" because ImageMagick (v'.$this->ImageMagickVersion().') does not support it', __FILE__, __LINE__);
1492                              }
1493  
1494                          } elseif ($this->sw || $this->sh || $this->sx || $this->sy) {
1495  
1496                              $crop_param   = '';
1497                              $crop_param  .=     ($this->sw ? (($this->sw < 2) ? round($this->sw * $this->source_width)  : $this->sw) : $this->source_width);
1498                              $crop_param  .= 'x'.($this->sh ? (($this->sh < 2) ? round($this->sh * $this->source_height) : $this->sh) : $this->source_height);
1499                              $crop_param  .= '+'.(($this->sx < 2) ? round($this->sx * $this->source_width)  : $this->sx);
1500                              $crop_param  .= '+'.(($this->sy < 2) ? round($this->sy * $this->source_height) : $this->sy);
1501  // TO BE FIXED
1502  // makes 1x1 output
1503  // http://trainspotted.com/phpThumb/phpThumb.php?src=/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg&w=100&h=100&far=1&f=png&fltr[]=lvl&sx=0.05&sy=0.25&sw=0.92&sh=0.42
1504  // '/usr/bin/convert' -density 150 -thumbnail 100x100 -contrast-stretch '0.1%' '/var/www/vhosts/trainspotted.com/httpdocs/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg[0]' png:'/var/www/vhosts/trainspotted.com/httpdocs/phpThumb/_cache/pThumbIIUlvj'
1505  //                            $commandline .= ' -crop '.escapeshellarg($crop_param);
1506  
1507                              // this is broken for aoe=1, but unsure how to fix. Send advice to info@silisoftware.com
1508                              if ($this->w || $this->h) {
1509                                  //if ($this->ImageMagickSwitchAvailable('repage')) {
1510  if (false) {
1511  // TO BE FIXED
1512  // newer versions of ImageMagick require -repage <geometry>
1513                                      $commandline .= ' -repage';
1514                                  } else {
1515                                      $this->DebugMessage('Skipping "-repage" because ImageMagick (v'.$this->ImageMagickVersion().') does not support it', __FILE__, __LINE__);
1516                                  }
1517                                  if ($IMuseExplicitImageOutputDimensions) {
1518                                      if ($this->w && !$this->h) {
1519                                          $this->h = ceil($this->w / ($this->source_width / $this->source_height));
1520                                      } elseif ($this->h && !$this->w) {
1521                                          $this->w = ceil($this->h * ($this->source_width / $this->source_height));
1522                                      }
1523                                  }
1524                                  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($this->w.'x'.$this->h);
1525                              }
1526  
1527                          } else {
1528  
1529                              if ($this->iar && (intval($this->w) > 0) && (intval($this->h) > 0)) {
1530                                  list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1531                                  $nw = ((round($nw) != 0) ? round($nw) : '');
1532                                  $nh = ((round($nh) != 0) ? round($nh) : '');
1533                                  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($nw.'x'.$nh.'!');
1534                              } else {
1535                                  $this->w = ((($this->aoe || $this->far) && $this->w) ? $this->w : ($this->w ? phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) : ''));
1536                                  $this->h = ((($this->aoe || $this->far) && $this->h) ? $this->h : ($this->h ? phpthumb_functions::nonempty_min($this->h, $getimagesize[1]) : ''));
1537                                  if ($this->w || $this->h) {
1538                                      if ($IMuseExplicitImageOutputDimensions) {
1539                                          if ($this->w && !$this->h) {
1540                                              $this->h = ceil($this->w / ($this->source_width / $this->source_height));
1541                                          } elseif ($this->h && !$this->w) {
1542                                              $this->w = ceil($this->h * ($this->source_width / $this->source_height));
1543                                          }
1544                                      }
1545                                      list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1546                                      $nw = ((round($nw) != 0) ? round($nw) : '');
1547                                      $nh = ((round($nh) != 0) ? round($nh) : '');
1548                                      $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($nw.'x'.$nh);
1549                                  }
1550                              }
1551                          }
1552                      }
1553  
1554                  } else {
1555  
1556                      $this->DebugMessage('GetImageSize('.$this->sourceFilename.') failed', __FILE__, __LINE__);
1557                      if ($this->w || $this->h) {
1558                          $exactDimensionsBang = (($this->iar && (intval($this->w) > 0) && (intval($this->h) > 0)) ? '!' : '');
1559                          if ($IMuseExplicitImageOutputDimensions) {
1560                              // unknown source aspect ratio, just put large number and hope IM figures it out
1561                              $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg(($this->w ? $this->w : '9999').'x'.($this->h ? $this->h : '9999').$exactDimensionsBang);
1562                          } else {
1563                              $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($this->w.'x'.$this->h.$exactDimensionsBang);
1564                          }
1565                      }
1566  
1567                  }
1568  
1569                  if ($this->ra) {
1570                      $this->ra = intval($this->ra);
1571                      if ($this->ImageMagickSwitchAvailable('rotate')) {
1572                          if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat) || phpthumb_functions::version_compare_replacement($this->ImageMagickVersion(), '6.3.7', '>=')) {
1573                              $this->DebugMessage('Using ImageMagick rotate', __FILE__, __LINE__);
1574                              $commandline .= ' -rotate '.escapeshellarg($this->ra);
1575                              if (($this->ra % 90) != 0) {
1576                                  if (preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) {
1577                                      // alpha-capable format
1578                                      $commandline .= ' -background rgba(255,255,255,0)';
1579                                  } else {
1580                                      $commandline .= ' -background '.escapeshellarg('#'.($this->bg ? $this->bg : 'FFFFFF'));
1581                                  }
1582                              }
1583                              $this->ra = 0;
1584                          } else {
1585                              $this->DebugMessage('Not using ImageMagick rotate because alpha background buggy before v6.3.7', __FILE__, __LINE__);
1586                          }
1587                      } else {
1588                          $this->DebugMessage('Not using ImageMagick rotate because not supported', __FILE__, __LINE__);
1589                      }
1590                  }
1591  
1592                  $successfullyProcessedFilters = array();
1593                  foreach ($this->fltr as $filterkey => $filtercommand) {
1594                      @list($command, $parameter) = explode('|', $filtercommand, 2);
1595                      switch ($command) {
1596                          case 'brit':
1597                              if ($this->ImageMagickSwitchAvailable('modulate')) {
1598                                  $commandline .= ' -modulate '.escapeshellarg((100 + intval($parameter)).',100,100');
1599                                  $successfullyProcessedFilters[] = $filterkey;
1600                              }
1601                              break;
1602  
1603                          case 'cont':
1604                              if ($this->ImageMagickSwitchAvailable('contrast')) {
1605                                  $contDiv10 = round(intval($parameter) / 10);
1606                                  if ($contDiv10 > 0) {
1607                                      $contDiv10 = min($contDiv10, 100);
1608                                      for ($i = 0; $i < $contDiv10; $i++) {
1609                                          $commandline .= ' -contrast'; // increase contrast by 10%
1610                                      }
1611                                  } elseif ($contDiv10 < 0) {
1612                                      $contDiv10 = max($contDiv10, -100);
1613                                      for ($i = $contDiv10; $i < 0; $i++) {
1614                                          $commandline .= ' +contrast'; // decrease contrast by 10%
1615                                      }
1616                                  } else {
1617                                      // do nothing
1618                                  }
1619                                  $successfullyProcessedFilters[] = $filterkey;
1620                              }
1621                              break;
1622  
1623                          case 'ds':
1624                              if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1625                                  if ($parameter == 100) {
1626                                      $commandline .= ' -colorspace GRAY';
1627                                      $commandline .= ' -modulate 100,0,100';
1628                                  } else {
1629                                      $commandline .= ' -modulate '.escapeshellarg('100,'.(100 - intval($parameter)).',100');
1630                                  }
1631                                  $successfullyProcessedFilters[] = $filterkey;
1632                              }
1633                              break;
1634  
1635                          case 'sat':
1636                              if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1637                                  if ($parameter == -100) {
1638                                      $commandline .= ' -colorspace GRAY';
1639                                      $commandline .= ' -modulate 100,0,100';
1640                                  } else {
1641                                      $commandline .= ' -modulate '.escapeshellarg('100,'.(100 + intval($parameter)).',100');
1642                                  }
1643                                  $successfullyProcessedFilters[] = $filterkey;
1644                              }
1645                              break;
1646  
1647                          case 'gray':
1648                              if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1649                                  $commandline .= ' -colorspace GRAY';
1650                                  $commandline .= ' -modulate 100,0,100';
1651                                  $successfullyProcessedFilters[] = $filterkey;
1652                              }
1653                              break;
1654  
1655                          case 'clr':
1656                              if ($this->ImageMagickSwitchAvailable(array('fill', 'colorize'))) {
1657                                  @list($amount, $color) = explode('|', $parameter);
1658                                  $commandline .= ' -fill '.escapeshellarg('#'.preg_replace('#[^0-9A-F]#i', '', $color));
1659                                  $commandline .= ' -colorize '.escapeshellarg(min(max(intval($amount), 0), 100));
1660                              }
1661                              break;
1662  
1663                          case 'sep':
1664                              if ($this->ImageMagickSwitchAvailable('sepia-tone')) {
1665                                  @list($amount, $color) = explode('|', $parameter);
1666                                  $amount = ($amount ? $amount : 80);
1667                                  if (!$color) {
1668                                      $commandline .= ' -sepia-tone '.escapeshellarg(min(max(intval($amount), 0), 100).'%');
1669                                      $successfullyProcessedFilters[] = $filterkey;
1670                                  }
1671                              }
1672                              break;
1673  
1674                          case 'gam':
1675                              @list($amount) = explode('|', $parameter);
1676                              $amount = min(max(floatval($amount), 0.001), 10);
1677                              if (number_format($amount, 3) != '1.000') {
1678                                  if ($this->ImageMagickSwitchAvailable('gamma')) {
1679                                      $commandline .= ' -gamma '.escapeshellarg($amount);
1680                                      $successfullyProcessedFilters[] = $filterkey;
1681                                  }
1682                              }
1683                              break;
1684  
1685                          case 'neg':
1686                              if ($this->ImageMagickSwitchAvailable('negate')) {
1687                                  $commandline .= ' -negate';
1688                                  $successfullyProcessedFilters[] = $filterkey;
1689                              }
1690                              break;
1691  
1692                          case 'th':
1693                              @list($amount) = explode('|', $parameter);
1694                              if ($this->ImageMagickSwitchAvailable(array('threshold', 'dither', 'monochrome'))) {
1695                                  $commandline .= ' -threshold '.escapeshellarg(round(min(max(intval($amount), 0), 255) / 2.55).'%');
1696                                  $commandline .= ' -dither';
1697                                  $commandline .= ' -monochrome';
1698                                  $successfullyProcessedFilters[] = $filterkey;
1699                              }
1700                              break;
1701  
1702                          case 'rcd':
1703                              if ($this->ImageMagickSwitchAvailable(array('colors', 'dither'))) {
1704                                  @list($colors, $dither) = explode('|', $parameter);
1705                                  $colors = ($colors                ?  (int) $colors : 256);
1706                                  $dither  = ((strlen($dither) > 0) ? (bool) $dither : true);
1707                                  $commandline .= ' -colors '.escapeshellarg(max($colors, 8)); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors"
1708                                  $commandline .= ($dither ? ' -dither' : ' +dither');
1709                                  $successfullyProcessedFilters[] = $filterkey;
1710                              }
1711                              break;
1712  
1713                          case 'flip':
1714                              if ($this->ImageMagickSwitchAvailable(array('flip', 'flop'))) {
1715                                  if (strpos(strtolower($parameter), 'x') !== false) {
1716                                      $commandline .= ' -flop';
1717                                  }
1718                                  if (strpos(strtolower($parameter), 'y') !== false) {
1719                                      $commandline .= ' -flip';
1720                                  }
1721                                  $successfullyProcessedFilters[] = $filterkey;
1722                              }
1723                              break;
1724  
1725                          case 'edge':
1726                              if ($this->ImageMagickSwitchAvailable('edge')) {
1727                                  $parameter = (!empty($parameter) ? $parameter : 2);
1728                                  $commandline .= ' -edge '.escapeshellarg(!empty($parameter) ? intval($parameter) : 1);
1729                                  $successfullyProcessedFilters[] = $filterkey;
1730                              }
1731                              break;
1732  
1733                          case 'emb':
1734                              if ($this->ImageMagickSwitchAvailable(array('emboss', 'negate'))) {
1735                                  $parameter = (!empty($parameter) ? $parameter : 2);
1736                                  $commandline .= ' -emboss '.escapeshellarg(intval($parameter));
1737                                  if ($parameter < 2) {
1738                                      $commandline .= ' -negate'; // ImageMagick negates the image for some reason with '-emboss 1';
1739                                  }
1740                                  $successfullyProcessedFilters[] = $filterkey;
1741                              }
1742                              break;
1743  
1744                          case 'lvl':
1745                              @list($band, $method, $threshold) = explode('|', $parameter);
1746                              $band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band))       : '*');
1747                              $method    = ((strlen($method) > 0)    ? intval($method)                        :   2);
1748                              $threshold = ((strlen($threshold) > 0) ? min(max(floatval($threshold), 0), 100) : 0.1);
1749  
1750                              $band = preg_replace('#[^RGBA\\*]#', '', strtoupper($band));
1751  
1752                              if (($method > 1) && !$this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) {
1753                                  // Because ImageMagick processing happens before PHP-GD filters, and because some
1754                                  // clipping is involved in the "lvl" filter, if "lvl" happens before "wb" then the
1755                                  // "wb" filter will have (almost) no effect. Therefore, if "wb" is enabled then
1756                                  // force the "lvl" filter to be processed by GD, not ImageMagick.
1757                                  foreach ($this->fltr as $fltr_key => $fltr_value) {
1758                                      list($fltr_cmd) = explode('|', $fltr_value);
1759                                      if ($fltr_cmd == 'wb') {
1760                                          $this->DebugMessage('Setting "lvl" filter method to "0" (from "'.$method.'") because white-balance filter also enabled', __FILE__, __LINE__);
1761                                          $method = 0;
1762                                      }
1763                                  }
1764                              }
1765  
1766                              switch ($method) {
1767                                  case 0: // internal RGB
1768                                  case 1: // internal grayscale
1769                                      break;
1770                                  case 2: // ImageMagick "contrast-stretch"
1771                                      if ($this->ImageMagickSwitchAvailable('contrast-stretch')) {
1772                                          if ($band != '*') {
1773                                              $commandline .= ' -channel '.escapeshellarg(strtoupper($band));
1774                                          }
1775                                          $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
1776                                          //$commandline .= ' -contrast-stretch '.escapeshellarg($threshold.'%');
1777                                          $commandline .= ' -contrast-stretch \''.$threshold.'%\'';
1778                                          if ($band != '*') {
1779                                              $commandline .= ' +channel';
1780                                          }
1781                                          $successfullyProcessedFilters[] = $filterkey;
1782                                      }
1783                                      break;
1784                                  case 3: // ImageMagick "normalize"
1785                                      if ($this->ImageMagickSwitchAvailable('normalize')) {
1786                                          if ($band != '*') {
1787                                              $commandline .= ' -channel '.escapeshellarg(strtoupper($band));
1788                                          }
1789                                          $commandline .= ' -normalize';
1790                                          if ($band != '*') {
1791                                              $commandline .= ' +channel';
1792                                          }
1793                                          $successfullyProcessedFilters[] = $filterkey;
1794                                      }
1795                                      break;
1796                                  default:
1797                                      $this->DebugMessage('unsupported method ('.$method.') for "lvl" filter', __FILE__, __LINE__);
1798                                      break;
1799                              }
1800                              if (isset($this->fltr[$filterkey]) && ($method > 1)) {
1801                                  $this->fltr[$filterkey] = $command.'|'.$band.'|0|'.$threshold;
1802                                  $this->DebugMessage('filter "lvl" remapped from method "'.$method.'" to method "0" because ImageMagick support is missing', __FILE__, __LINE__);
1803                              }
1804                              break;
1805  
1806                          case 'wb':
1807                              if ($this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) {
1808                                  @list($threshold) = explode('|', $parameter);
1809                                  $threshold = (!empty($threshold) ? min(max(floatval($threshold), 0), 100) : 0.1);
1810                                  $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
1811                                  //$commandline .= ' -channel R -contrast-stretch '.escapeshellarg($threshold.'%'); // doesn't work on Windows because most versions of PHP do not properly
1812                                  //$commandline .= ' -channel G -contrast-stretch '.escapeshellarg($threshold.'%'); // escape special characters (such as %) and just replace them with spaces
1813                                  //$commandline .= ' -channel B -contrast-stretch '.escapeshellarg($threshold.'%'); // https://bugs.php.net/bug.php?id=43261
1814                                  $commandline .= ' -channel R -contrast-stretch \''.$threshold.'%\'';
1815                                  $commandline .= ' -channel G -contrast-stretch \''.$threshold.'%\'';
1816                                  $commandline .= ' -channel B -contrast-stretch \''.$threshold.'%\'';
1817                                  $commandline .= ' +channel';
1818                                  $successfullyProcessedFilters[] = $filterkey;
1819                              }
1820                              break;
1821  
1822                          case 'blur':
1823                              if ($this->ImageMagickSwitchAvailable('blur')) {
1824                                  @list($radius) = explode('|', $parameter);
1825                                  $radius = (!empty($radius) ? min(max(intval($radius), 0), 25) : 1);
1826                                  $commandline .= ' -blur '.escapeshellarg($radius);
1827                                  $successfullyProcessedFilters[] = $filterkey;
1828                              }
1829                              break;
1830  
1831                          case 'gblr':
1832                              @list($radius) = explode('|', $parameter);
1833                              $radius = (!empty($radius) ? min(max(intval($radius), 0), 25) : 1);
1834                              // "-gaussian" changed to "-gaussian-blur" sometime around 2009
1835                              if ($this->ImageMagickSwitchAvailable('gaussian-blur')) {
1836                                  $commandline .= ' -gaussian-blur '.escapeshellarg($radius);
1837                                  $successfullyProcessedFilters[] = $filterkey;
1838                              } elseif ($this->ImageMagickSwitchAvailable('gaussian')) {
1839                                  $commandline .= ' -gaussian '.escapeshellarg($radius);
1840                                  $successfullyProcessedFilters[] = $filterkey;
1841                              }
1842                              break;
1843  
1844                          case 'usm':
1845                              if ($this->ImageMagickSwitchAvailable('unsharp')) {
1846                                  @list($amount, $radius, $threshold) = explode('|', $parameter);
1847                                  $amount    = ($amount            ? min(max(intval($radius), 0), 255) : 80);
1848                                  $radius    = ($radius            ? min(max(intval($radius), 0), 10)  : 0.5);
1849                                  $threshold = (strlen($threshold) ? min(max(intval($radius), 0), 50)  : 3);
1850                                  $commandline .= ' -unsharp '.escapeshellarg(number_format(($radius * 2) - 1, 2, '.', '').'x1+'.number_format($amount / 100, 2, '.', '').'+'.number_format($threshold / 100, 2, '.', ''));
1851                                  $successfullyProcessedFilters[] = $filterkey;
1852                              }
1853                              break;
1854  
1855                          case 'bord':
1856                              if ($this->ImageMagickSwitchAvailable(array('border', 'bordercolor', 'thumbnail', 'crop'))) {
1857                                  if (!$this->zc) {
1858                                      @list($width, $rX, $rY, $color) = explode('|', $parameter);
1859                                      $width = intval($width);
1860                                      $rX    = intval($rX);
1861                                      $rY    = intval($rY);
1862                                      if ($width && !$rX && !$rY) {
1863                                          if (!phpthumb_functions::IsHexColor($color)) {
1864                                              $color = ((!empty($this->bc) && phpthumb_functions::IsHexColor($this->bc)) ? $this->bc : '000000');
1865                                          }
1866                                          $commandline .= ' -border '.escapeshellarg(intval($width));
1867                                          $commandline .= ' -bordercolor '.escapeshellarg('#'.$color);
1868  
1869                                          if (preg_match('# \\-crop "([0-9]+)x([0-9]+)\\+0\\+0" #', $commandline, $matches)) {
1870                                              $commandline = str_replace(' -crop "'.$matches[1].'x'.$matches[2].'+0+0" ', ' -crop '.escapeshellarg(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width)).'+0+0').' ', $commandline);
1871                                          } elseif (preg_match('# \\-'.$IMresizeParameter.' "([0-9]+)x([0-9]+)" #', $commandline, $matches)) {
1872                                              $commandline = str_replace(' -'.$IMresizeParameter.' "'.$matches[1].'x'.$matches[2].'" ', ' -'.$IMresizeParameter.' '.escapeshellarg(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width))).' ', $commandline);
1873                                          }
1874                                          $successfullyProcessedFilters[] = $filterkey;
1875                                      }
1876                                  }
1877                              }
1878                              break;
1879  
1880                          case 'crop':
1881                              break;
1882  
1883                          case 'sblr':
1884                              break;
1885  
1886                          case 'mean':
1887                              break;
1888  
1889                          case 'smth':
1890                              break;
1891  
1892                          case 'bvl':
1893                              break;
1894  
1895                          case 'wmi':
1896                              break;
1897  
1898                          case 'wmt':
1899                              break;
1900  
1901                          case 'over':
1902                              break;
1903  
1904                          case 'hist':
1905                              break;
1906  
1907                          case 'fram':
1908                              break;
1909  
1910                          case 'drop':
1911                              break;
1912  
1913                          case 'mask':
1914                              break;
1915  
1916                          case 'elip':
1917                              break;
1918  
1919                          case 'ric':
1920                              break;
1921  
1922                          case 'stc':
1923                              break;
1924  
1925                          case 'size':
1926                              break;
1927  
1928                          default:
1929                              $this->DebugMessage('Unknown $this->fltr['.$filterkey.'] ('.$filtercommand.') -- deleting filter command', __FILE__, __LINE__);
1930                              $successfullyProcessedFilters[] = $filterkey;
1931                              break;
1932                      }
1933                      if (!isset($this->fltr[$filterkey])) {
1934                          $this->DebugMessage('Processed $this->fltr['.$filterkey.'] ('.$filtercommand.') with ImageMagick', __FILE__, __LINE__);
1935                      } else {
1936                          $this->DebugMessage('Skipping $this->fltr['.$filterkey.'] ('.$filtercommand.') with ImageMagick', __FILE__, __LINE__);
1937                      }
1938                  }
1939                  $this->DebugMessage('Remaining $this->fltr after ImageMagick: ('.$this->phpThumbDebugVarDump($this->fltr).')', __FILE__, __LINE__);
1940                  if (count($this->fltr) > 0) {
1941                      $this->useRawIMoutput = false;
1942                  }
1943  
1944                  if (preg_match('#jpe?g#i', $outputFormat) && $this->q) {
1945                      if ($this->ImageMagickSwitchAvailable(array('quality', 'interlace'))) {
1946                          $commandline .= ' -quality '.escapeshellarg($this->thumbnailQuality);
1947                          if ($this->config_output_interlace) {
1948                              // causes weird things with animated GIF... leave for JPEG only
1949                              $commandline .= ' -interlace line '; // Use Line or Plane to create an interlaced PNG or GIF or progressive JPEG image
1950                          }
1951                      }
1952                  }
1953                  $commandline .= ' '.escapeshellarg(preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $this->sourceFilename).(($outputFormat == 'gif') ? '' : '['.intval($this->sfn).']')); // [0] means first frame of (GIF) animation, can be ignored
1954                  $commandline .= ' '.$outputFormat.':'.escapeshellarg($IMtempfilename);
1955                  if (!$this->iswindows) {
1956                      $commandline .= ' 2>&1';
1957                  }
1958                  $this->DebugMessage('ImageMagick called as ('.$commandline.')', __FILE__, __LINE__);
1959                  $IMresult = phpthumb_functions::SafeExec($commandline);
1960                  clearstatcache();
1961                  if (!@file_exists($IMtempfilename) || !@filesize($IMtempfilename)) {
1962                      $this->FatalError('ImageMagick failed with message ('.trim($IMresult).')');
1963                      $this->DebugMessage('ImageMagick failed with message ('.trim($IMresult).')', __FILE__, __LINE__);
1964                      if ($this->iswindows && !$IMresult) {
1965                          $this->DebugMessage('Check to make sure that PHP has read+write permissions to "'.dirname($IMtempfilename).'"', __FILE__, __LINE__);
1966                      }
1967  
1968                  } else {
1969  
1970                      foreach ($successfullyProcessedFilters as $dummy => $filterkey) {
1971                          unset($this->fltr[$filterkey]);
1972                      }
1973                      $this->IMresizedData = file_get_contents($IMtempfilename);
1974                      $getimagesize_imresized = @GetImageSize($IMtempfilename);
1975                      $this->DebugMessage('GetImageSize('.$IMtempfilename.') returned [w='.$getimagesize_imresized[0].';h='.$getimagesize_imresized[1].';f='.$getimagesize_imresized[2].']', __FILE__, __LINE__);
1976                      if (($this->config_max_source_pixels > 0) && (($getimagesize_imresized[0] * $getimagesize_imresized[1]) > $this->config_max_source_pixels)) {
1977                          $this->DebugMessage('skipping ImageMagickThumbnailToGD::'.$ImageCreateFunction.'() because IM output is too large ('.$getimagesize_imresized[0].'x'.$getimagesize_imresized[0].' = '.($getimagesize_imresized[0] * $getimagesize_imresized[1]).' > '.$this->config_max_source_pixels.')', __FILE__, __LINE__);
1978                      } elseif (function_exists(@$ImageCreateFunction) && ($this->gdimg_source = @$ImageCreateFunction($IMtempfilename))) {
1979                          $this->source_width  = ImageSX($this->gdimg_source);
1980                          $this->source_height = ImageSY($this->gdimg_source);
1981                          $this->DebugMessage('ImageMagickThumbnailToGD::'.$ImageCreateFunction.'() succeeded, $this->gdimg_source is now ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__);
1982                          $this->DebugMessage('ImageMagickThumbnailToGD() returning $this->IMresizedData ('.strlen($this->IMresizedData).' bytes)', __FILE__, __LINE__);
1983                      } else {
1984                          $this->useRawIMoutput = true;
1985                          $this->DebugMessage('$this->useRawIMoutput set to TRUE because '.@$ImageCreateFunction.'('.$IMtempfilename.') failed', __FILE__, __LINE__);
1986                      }
1987                      return true;
1988  
1989                  }
1990                  if (file_exists($IMtempfilename)) {
1991                      $this->DebugMessage('deleting "'.$IMtempfilename.'"', __FILE__, __LINE__);
1992                      @unlink($IMtempfilename);
1993                  }
1994  
1995              } elseif ($this->issafemode) {
1996                  $this->DebugMessage('ImageMagickThumbnailToGD() aborting because PHP safe_mode is enabled and phpThumb_tempnam() failed', __FILE__, __LINE__);
1997                  $this->useRawIMoutput = false;
1998              } else {
1999                  if (file_exists($IMtempfilename)) {
2000                      $this->DebugMessage('deleting "'.$IMtempfilename.'"', __FILE__, __LINE__);
2001                      @unlink($IMtempfilename);
2002                  }
2003                  $this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__, __LINE__);
2004              }
2005          } else {
2006              $this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__, __LINE__);
2007          }
2008          $this->useRawIMoutput = false;
2009          return false;
2010      }
2011  
2012  
2013  	function Rotate() {
2014          if ($this->ra || $this->ar) {
2015              if (!function_exists('ImageRotate')) {
2016                  $this->DebugMessage('!function_exists(ImageRotate)', __FILE__, __LINE__);
2017                  return false;
2018              }
2019              if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
2020                  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
2021                  return false;
2022              }
2023  
2024              $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2025              if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2026                  return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
2027              }
2028  
2029              $rotate_angle = 0;
2030              if ($this->ra) {
2031  
2032                  $rotate_angle = floatval($this->ra);
2033  
2034              } else {
2035  
2036                  if ($this->ar == 'x') {
2037                      if (phpthumb_functions::version_compare_replacement(phpversion(), '4.2.0', '>=')) {
2038                          if ($this->sourceFilename) {
2039                              if (function_exists('exif_read_data')) {
2040                                  if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) {
2041                                      // http://sylvana.net/jpegcrop/exif_orientation.html
2042                                      switch (@$exif_data['Orientation']) {
2043                                          case 1:
2044                                              $rotate_angle = 0;
2045                                              break;
2046                                          case 3:
2047                                              $rotate_angle = 180;
2048                                              break;
2049                                          case 6:
2050                                              $rotate_angle = 270;
2051                                              break;
2052                                          case 8:
2053                                              $rotate_angle = 90;
2054                                              break;
2055  
2056                                          default:
2057                                              $this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "'.@$exif_data['Orientation'].'"', __FILE__, __LINE__);
2058                                              return false;
2059                                              break;
2060                                      }
2061                                      $this->DebugMessage('EXIF auto-rotate set to '.$rotate_angle.' degrees ($exif_data[Orientation] = "'.@$exif_data['Orientation'].'")', __FILE__, __LINE__);
2062                                  } else {
2063                                      $this->DebugMessage('failed: exif_read_data('.$this->sourceFilename.')', __FILE__, __LINE__);
2064                                      return false;
2065                                  }
2066                              } else {
2067                                  $this->DebugMessage('!function_exists(exif_read_data)', __FILE__, __LINE__);
2068                                  return false;
2069                              }
2070                          } else {
2071                              $this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__, __LINE__);
2072                              return false;
2073                          }
2074                      } else {
2075                          $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 ('.phpversion().')', __FILE__, __LINE__);
2076                          return false;
2077                      }
2078                  } elseif (($this->ar == 'l') && ($this->source_height > $this->source_width)) {
2079                      $rotate_angle = 270;
2080                  } elseif (($this->ar == 'L') && ($this->source_height > $this->source_width)) {
2081                      $rotate_angle = 90;
2082                  } elseif (($this->ar == 'p') && ($this->source_width > $this->source_height)) {
2083                      $rotate_angle = 90;
2084                  } elseif (($this->ar == 'P') && ($this->source_width > $this->source_height)) {
2085                      $rotate_angle = 270;
2086                  }
2087  
2088              }
2089              if ($rotate_angle % 90) {
2090                  $this->is_alpha = true;
2091              }
2092              phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg);
2093              $this->source_width  = ImageSX($this->gdimg_source);
2094              $this->source_height = ImageSY($this->gdimg_source);
2095          }
2096          return true;
2097      }
2098  
2099  
2100  	function FixedAspectRatio() {
2101          // optional fixed-dimension images (regardless of aspect ratio)
2102  
2103          if (!$this->far) {
2104              // do nothing
2105              return true;
2106          }
2107  
2108          if (!$this->w || !$this->h) {
2109              return false;
2110          }
2111          $this->thumbnail_width  = $this->w;
2112          $this->thumbnail_height = $this->h;
2113          $this->is_alpha = true;
2114          if ($this->thumbnail_image_width >= $this->thumbnail_width) {
2115  
2116              if ($this->w) {
2117                  $aspectratio = $this->thumbnail_image_height / $this->thumbnail_image_width;
2118                  $this->thumbnail_image_height = round($this->thumbnail_image_width * $aspectratio);
2119                  $this->thumbnail_height = ($this->h ? $this->h : $this->thumbnail_image_height);
2120              } elseif ($this->thumbnail_image_height < $this->thumbnail_height) {
2121                  $this->thumbnail_image_height = $this->thumbnail_height;
2122                  $this->thumbnail_image_width  = round($this->thumbnail_image_height / $aspectratio);
2123              }
2124  
2125          } else {
2126              if ($this->h) {
2127                  $aspectratio = $this->thumbnail_image_width / $this->thumbnail_image_height;
2128                  $this->thumbnail_image_width = round($this->thumbnail_image_height * $aspectratio);
2129              } elseif ($this->thumbnail_image_width < $this->thumbnail_width) {
2130                  $this->thumbnail_image_width = $this->thumbnail_width;
2131                  $this->thumbnail_image_height  = round($this->thumbnail_image_width / $aspectratio);
2132              }
2133  
2134          }
2135          return true;
2136      }
2137  
2138  
2139  	function OffsiteDomainIsAllowed($hostname, $allowed_domains) {
2140          static $domain_is_allowed = array();
2141          $hostname = strtolower($hostname);
2142          if (!isset($domain_is_allowed[$hostname])) {
2143              $domain_is_allowed[$hostname] = false;
2144              foreach ($allowed_domains as $valid_domain) {
2145                  $starpos = strpos($valid_domain, '*');
2146                  if ($starpos !== false) {
2147                      $valid_domain = substr($valid_domain, $starpos + 1);
2148                      if (preg_match('#'.preg_quote($valid_domain).'$#', $hostname)) {
2149                          $domain_is_allowed[$hostname] = true;
2150                          break;
2151                      }
2152                  } else {
2153                      if (strtolower($valid_domain) === $hostname) {
2154                          $domain_is_allowed[$hostname] = true;
2155                          break;
2156                      }
2157                  }
2158              }
2159          }
2160          return $domain_is_allowed[$hostname];
2161      }
2162  
2163  
2164  	function AntiOffsiteLinking() {
2165          // Optional anti-offsite hijacking of the thumbnail script
2166          $allow = true;
2167          if ($allow && $this->config_nooffsitelink_enabled && (@$_SERVER['HTTP_REFERER'] || $this->config_nooffsitelink_require_refer)) {
2168              $this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "'.@$_SERVER['HTTP_REFERER'].'"', __FILE__, __LINE__);
2169              foreach ($this->config_nooffsitelink_valid_domains as $key => $valid_domain) {
2170                  // $_SERVER['HTTP_HOST'] contains the port number, so strip it out here to make default configuration work
2171                  list($clean_domain) = explode(':', $valid_domain);
2172                  $this->config_nooffsitelink_valid_domains[$key] = $clean_domain;
2173              }
2174              $parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
2175              if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) {
2176                  $allow = false;
2177                  $erase   = $this->config_nooffsitelink_erase_image;
2178                  $message = $this->config_nooffsitelink_text_message;
2179  $this->ErrorImage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')');
2180  exit;
2181                  $this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2182              } else {
2183                  $this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2184              }
2185          }
2186  
2187          if ($allow && $this->config_nohotlink_enabled && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
2188              $parsed_url = phpthumb_functions::ParseURLbetter($this->src);
2189              //if (!phpthumb_functions::CaseInsensitiveInArray(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2190              if ($this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2191                  // This domain is not allowed
2192                  $allow = false;
2193                  $erase   = $this->config_nohotlink_erase_image;
2194                  $message = $this->config_nohotlink_text_message;
2195                  $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is NOT in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
2196              } else {
2197                  $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
2198              }
2199          }
2200  
2201          if ($allow) {
2202              $this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__, __LINE__);
2203              return true;
2204          }
2205  
2206          if (!phpthumb_functions::IsHexColor($this->config_error_bgcolor)) {
2207              return $this->ErrorImage('Invalid hex color string "'.$this->config_error_bgcolor.'" for $this->config_error_bgcolor');
2208          }
2209          if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) {
2210              return $this->ErrorImage('Invalid hex color string "'.$this->config_error_textcolor.'" for $this->config_error_textcolor');
2211          }
2212          if ($erase) {
2213  
2214              return $this->ErrorImage($message, $this->thumbnail_width, $this->thumbnail_height, $this->config_error_bgcolor, $this->config_error_textcolor, $this->config_error_fontsize);
2215  
2216          } else {
2217  
2218              $this->config_nooffsitelink_watermark_src = $this->ResolveFilenameToAbsolute($this->config_nooffsitelink_watermark_src);
2219              if (is_file($this->config_nooffsitelink_watermark_src)) {
2220  
2221                  if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
2222                      $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying watermark', __FILE__, __LINE__);
2223                      return false;
2224                  }
2225                  $watermark_img = $this->ImageCreateFromStringReplacement(file_get_contents($this->config_nooffsitelink_watermark_src));
2226                  $phpthumbFilters = new phpthumb_filters();
2227                  $phpthumbFilters->phpThumbObject = &$this;
2228                  $opacity = 50;
2229                  $margin  = 5;
2230                  $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin);
2231                  ImageDestroy($watermark_img);
2232                  unset($phpthumbFilters);
2233  
2234              } else {
2235  
2236                  $nohotlink_text_array = explode("\n", wordwrap($message, floor($this->thumbnail_width / ImageFontWidth($this->config_error_fontsize)), "\n"));
2237                  $nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor);
2238  
2239                  $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * ImageFontHeight($this->config_error_fontsize))) / 2);
2240  
2241                  $rowcounter = 0;
2242                  $this->DebugMessage('AntiOffsiteLinking() writing '.count($nohotlink_text_array).' lines of text "'.$message.'" (in #'.$this->config_error_textcolor.') on top of image', __FILE__, __LINE__);
2243                  foreach ($nohotlink_text_array as $textline) {
2244                      $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * ImageFontWidth($this->config_error_fontsize))) / 2));
2245                      ImageString($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * ImageFontHeight($this->config_error_fontsize)), $textline, $nohotlink_text_color);
2246                  }
2247  
2248              }
2249  
2250          }
2251          return true;
2252      }
2253  
2254  
2255  	function AlphaChannelFlatten() {
2256          if (!$this->is_alpha) {
2257              // image doesn't have alpha transparency, no need to flatten
2258              $this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__);
2259              return false;
2260          }
2261          switch ($this->thumbnailFormat) {
2262              case 'png':
2263              case 'ico':
2264                  // image has alpha transparency, but output as PNG or ICO which can handle it
2265                  $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'")', __FILE__, __LINE__);
2266                  return false;
2267                  break;
2268  
2269              case 'gif':
2270                  // image has alpha transparency, but output as GIF which can handle only single-color transparency
2271                  $CurrentImageColorTransparent = ImageColorTransparent($this->gdimg_output);
2272                  if ($CurrentImageColorTransparent == -1) {
2273                      // no transparent color defined
2274  
2275                      if (phpthumb_functions::gd_version() < 2.0) {
2276                          $this->DebugMessage('AlphaChannelFlatten() failed because GD version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2277                          return false;
2278                      }
2279  
2280                      if ($img_alpha_mixdown_dither = @ImageCreateTrueColor(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) {
2281  
2282                          for ($i = 0; $i <= 255; $i++) {
2283                              $dither_color[$i] = ImageColorAllocate($img_alpha_mixdown_dither, $i, $i, $i);
2284                          }
2285  
2286                          // scan through current truecolor image copy alpha channel to temp image as grayscale
2287                          for ($x = 0; $x < $this->thumbnail_width; $x++) {
2288                              for ($y = 0; $y < $this->thumbnail_height; $y++) {
2289                                  $PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y);
2290                                  ImageSetPixel($img_alpha_mixdown_dither, $x, $y, $dither_color[($PixelColor['alpha'] * 2)]);
2291                              }
2292                          }
2293  
2294                          // dither alpha channel grayscale version down to 2 colors
2295                          ImageTrueColorToPalette($img_alpha_mixdown_dither, true, 2);
2296  
2297                          // reduce color palette to 256-1 colors (leave one palette position for transparent color)
2298                          ImageTrueColorToPalette($this->gdimg_output, true, 255);
2299  
2300                          // allocate a new color for transparent color index
2301                          $TransparentColor = ImageColorAllocate($this->gdimg_output, 1, 254, 253);
2302                          ImageColorTransparent($this->gdimg_output, $TransparentColor);
2303  
2304                          // scan through alpha channel image and note pixels with >50% transparency
2305                          $TransparentPixels = array();
2306                          for ($x = 0; $x < $this->thumbnail_width; $x++) {
2307                              for ($y = 0; $y < $this->thumbnail_height; $y++) {
2308                                  $AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y);
2309                                  if ($AlphaChannelPixel['red'] > 127) {
2310                                      ImageSetPixel($this->gdimg_output, $x, $y, $TransparentColor);
2311                                  }
2312                              }
2313                          }
2314                          ImageDestroy($img_alpha_mixdown_dither);
2315  
2316                          $this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__);
2317                          return true;
2318  
2319                      } else {
2320                          $this->DebugMessage('AlphaChannelFlatten() failed ImageCreate('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__);
2321                          return false;
2322                      }
2323  
2324                  } else {
2325                      // a single transparent color already defined, leave as-is
2326                      $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'") and ImageColorTransparent returned "'.$CurrentImageColorTransparent.'"', __FILE__, __LINE__);
2327                      return true;
2328                  }
2329                  break;
2330          }
2331          $this->DebugMessage('continuing AlphaChannelFlatten() for output format "'.$this->thumbnailFormat.'"', __FILE__, __LINE__);
2332          // image has alpha transparency, and is being output in a format that doesn't support it -- flatten
2333          if ($gdimg_flatten_temp = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height)) {
2334  
2335              $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2336              if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2337                  return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
2338              }
2339              $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
2340              ImageFilledRectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
2341              ImageCopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2342  
2343              ImageAlphaBlending($this->gdimg_output, true);
2344              ImageSaveAlpha($this->gdimg_output, false);
2345              ImageColorTransparent($this->gdimg_output, -1);
2346              ImageCopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2347  
2348              ImageDestroy($gdimg_flatten_temp);
2349              return true;
2350  
2351          } else {
2352              $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
2353          }
2354          return false;
2355      }
2356  
2357  
2358  	function ApplyFilters() {
2359          if ($this->fltr && is_array($this->fltr)) {
2360              if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
2361                  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
2362                  return false;
2363              }
2364              $phpthumbFilters = new phpthumb_filters();
2365              $phpthumbFilters->phpThumbObject = &$this;
2366              foreach ($this->fltr as $filtercommand) {
2367                  @list($command, $parameter) = explode('|', $filtercommand, 2);
2368                  $this->DebugMessage('Attempting to process filter command "'.$command.'('.$parameter.')"', __FILE__, __LINE__);
2369                  switch ($command) {
2370                      case 'brit': // Brightness
2371                          $phpthumbFilters->Brightness($this->gdimg_output, $parameter);
2372                          break;
2373  
2374                      case 'cont': // Contrast
2375                          $phpthumbFilters->Contrast($this->gdimg_output, $parameter);
2376                          break;
2377  
2378                      case 'ds': // Desaturation
2379                          $phpthumbFilters->Desaturate($this->gdimg_output, $parameter, '');
2380                          break;
2381  
2382                      case 'sat': // Saturation
2383                          $phpthumbFilters->Saturation($this->gdimg_output, $parameter, '');
2384                          break;
2385  
2386                      case 'gray': // Grayscale
2387                          $phpthumbFilters->Grayscale($this->gdimg_output);
2388                          break;
2389  
2390                      case 'clr': // Colorize
2391                          if (phpthumb_functions::gd_version() < 2) {
2392                              $this->DebugMessage('Skipping Colorize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2393                              break;
2394                          }
2395                          @list($amount, $color) = explode('|', $parameter, 2);
2396                          $phpthumbFilters->Colorize($this->gdimg_output, $amount, $color);
2397                          break;
2398  
2399                      case 'sep': // Sepia
2400                          if (phpthumb_functions::gd_version() < 2) {
2401                              $this->DebugMessage('Skipping Sepia() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2402                              break;
2403                          }
2404                          @list($amount, $color) = explode('|', $parameter, 2);
2405                          $phpthumbFilters->Sepia($this->gdimg_output, $amount, $color);
2406                          break;
2407  
2408                      case 'gam': // Gamma correction
2409                          $phpthumbFilters->Gamma($this->gdimg_output, $parameter);
2410                          break;
2411  
2412                      case 'neg': // Negative colors
2413                          $phpthumbFilters->Negative($this->gdimg_output);
2414                          break;
2415  
2416                      case 'th': // Threshold
2417                          $phpthumbFilters->Threshold($this->gdimg_output, $parameter);
2418                          break;
2419  
2420                      case 'rcd': // ReduceColorDepth
2421                          if (phpthumb_functions::gd_version() < 2) {
2422                              $this->DebugMessage('Skipping ReduceColorDepth() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2423                              break;
2424                          }
2425                          @list($colors, $dither) = explode('|', $parameter, 2);
2426                          $colors = ($colors                ?  (int) $colors : 256);
2427                          $dither  = ((strlen($dither) > 0) ? (bool) $dither : true);
2428                          $phpthumbFilters->ReduceColorDepth($this->gdimg_output, $colors, $dither);
2429                          break;
2430  
2431                      case 'flip': // Flip
2432                          $phpthumbFilters->Flip($this->gdimg_output, (strpos(strtolower($parameter), 'x') !== false), (strpos(strtolower($parameter), 'y') !== false));
2433                          break;
2434  
2435                      case 'edge': // EdgeDetect
2436                          $phpthumbFilters->EdgeDetect($this->gdimg_output);
2437                          break;
2438  
2439                      case 'emb': // Emboss
2440                          $phpthumbFilters->Emboss($this->gdimg_output);
2441                          break;
2442  
2443                      case 'bvl': // Bevel
2444                          @list($width, $color1, $color2) = explode('|', $parameter, 3);
2445                          $phpthumbFilters->Bevel($this->gdimg_output, $width, $color1, $color2);
2446                          break;
2447  
2448                      case 'lvl': // autoLevels
2449                          @list($band, $method, $threshold) = explode('|', $parameter, 3);
2450                          $band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
2451                          $method    = ((strlen($method) > 0)    ? intval($method)                  :   2);
2452                          $threshold = ((strlen($threshold) > 0) ? floatval($threshold)             : 0.1);
2453  
2454                          $phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold);
2455                          break;
2456  
2457                      case 'wb': // WhiteBalance
2458                          $phpthumbFilters->WhiteBalance($this->gdimg_output, $parameter);
2459                          break;
2460  
2461                      case 'hist': // Histogram overlay
2462                          if (phpthumb_functions::gd_version() < 2) {
2463                              $this->DebugMessage('Skipping HistogramOverlay() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2464                              break;
2465                          }
2466                          @list($bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y) = explode('|', $parameter, 8);
2467                          $bands     = ($bands     ? $bands     :  '*');
2468                          $colors    = ($colors    ? $colors    :   '');
2469                          $width     = ($width     ? $width     : 0.25);
2470                          $height    = ($height    ? $height    : 0.25);
2471                          $alignment = ($alignment ? $alignment : 'BR');
2472                          $opacity   = ($opacity   ? $opacity   :   50);
2473                          $margin_x  = ($margin_x  ? $margin_x  :    5);
2474                          $margin_y  = $margin_y; // just to note it wasn't forgotten, but let the value always pass unchanged
2475                          $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y);
2476                          break;
2477  
2478                      case 'fram': // Frame
2479                          @list($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter, 5);
2480                          $phpthumbFilters->Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
2481                          break;
2482  
2483                      case 'drop': // DropShadow
2484                          if (phpthumb_functions::gd_version() < 2) {
2485                              $this->DebugMessage('Skipping DropShadow() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2486                              return false;
2487                          }
2488                          $this->is_alpha = true;
2489                          @list($distance, $width, $color, $angle, $fade) = explode('|', $parameter, 5);
2490                          $phpthumbFilters->DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
2491                          break;
2492  
2493                      case 'mask': // Mask cropping
2494                          if (phpthumb_functions::gd_version() < 2) {
2495                              $this->DebugMessage('Skipping Mask() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2496                              return false;
2497                          }
2498                          $mask_filename = $this->ResolveFilenameToAbsolute($parameter);
2499                          if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
2500                              $MaskImageData = '';
2501                              do {
2502                                  $buffer = fread($fp_mask, 8192);
2503                                  $MaskImageData .= $buffer;
2504                              } while (strlen($buffer) > 0);
2505                              fclose($fp_mask);
2506                              if ($gdimg_mask = $this->ImageCreateFromStringReplacement($MaskImageData)) {
2507                                  $this->is_alpha = true;
2508                                  $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
2509                                  ImageDestroy($gdimg_mask);
2510                              } else {
2511                                  $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$mask_filename.'"', __FILE__, __LINE__);
2512                              }
2513                          } else {
2514                              $this->DebugMessage('Cannot open mask file "'.$mask_filename.'"', __FILE__, __LINE__);
2515                          }
2516                          break;
2517  
2518                      case 'elip': // Elipse cropping
2519                          if (phpthumb_functions::gd_version() < 2) {
2520                              $this->DebugMessage('Skipping Elipse() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2521                              return false;
2522                          }
2523                          $this->is_alpha = true;
2524                          $phpthumbFilters->Elipse($this->gdimg_output);
2525                          break;
2526  
2527                      case 'ric': // RoundedImageCorners
2528                          if (phpthumb_functions::gd_version() < 2) {
2529                              $this->DebugMessage('Skipping RoundedImageCorners() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2530                              return false;
2531                          }
2532                          @list($radius_x, $radius_y) = explode('|', $parameter, 2);
2533                          if (($radius_x < 1) || ($radius_y < 1)) {
2534                              $this->DebugMessage('Skipping RoundedImageCorners('.$radius_x.', '.$radius_y.') because x/y radius is less than 1', __FILE__, __LINE__);
2535                              break;
2536                          }
2537                          $this->is_alpha = true;
2538                          $phpthumbFilters->RoundedImageCorners($this->gdimg_output, $radius_x, $radius_y);
2539                          break;
2540  
2541                      case 'crop': // Crop
2542                          @list($left, $right, $top, $bottom) = explode('|', $parameter, 4);
2543                          $phpthumbFilters->Crop($this->gdimg_output, $left, $right, $top, $bottom);
2544                          break;
2545  
2546                      case 'bord': // Border
2547                          @list($border_width, $radius_x, $radius_y, $hexcolor_border) = explode('|', $parameter, 4);
2548                          $this->is_alpha = true;
2549                          $phpthumbFilters->ImageBorder($this->gdimg_output, $border_width, $radius_x, $radius_y, $hexcolor_border);
2550                          break;
2551  
2552                      case 'over': // Overlay
2553                          @list($filename, $underlay, $margin, $opacity) = explode('|', $parameter, 4);
2554                          $underlay = (bool) ($underlay              ? $underlay : false);
2555                          $margin   =        ((strlen($margin)  > 0) ? $margin   : ($underlay ? 0.1 : 0.0));
2556                          $opacity  =        ((strlen($opacity) > 0) ? $opacity  : 100);
2557                          if (($margin > 0) && ($margin < 1)) {
2558                              $margin = min(0.499, $margin);
2559                          } elseif (($margin > -1) && ($margin < 0)) {
2560                              $margin = max(-0.499, $margin);
2561                          }
2562  
2563                          $filename = $this->ResolveFilenameToAbsolute($filename);
2564                          if (@is_readable($filename) && ($fp_watermark = @fopen($filename, 'rb'))) {
2565                              $WatermarkImageData = '';
2566                              do {
2567                                  $buffer = fread($fp_watermark, 8192);
2568                                  $WatermarkImageData .= $buffer;
2569                              } while (strlen($buffer) > 0);
2570                              fclose($fp_watermark);
2571                              if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) {
2572                                  if ($margin < 1) {
2573                                      $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * (ImageSX($this->gdimg_output) * $margin)));
2574                                      $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * (ImageSY($this->gdimg_output) * $margin)));
2575                                  } else {
2576                                      $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * $margin));
2577                                      $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * $margin));
2578                                  }
2579  
2580                                  if ($underlay) {
2581  
2582                                      if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) {
2583                                          ImageAlphaBlending($img_watermark_resized, false);
2584                                          ImageSaveAlpha($img_watermark_resized, true);
2585                                          $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark));
2586                                          if ($img_source_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
2587                                              ImageAlphaBlending($img_source_resized, false);
2588                                              ImageSaveAlpha($img_source_resized, true);
2589                                              $this->ImageResizeFunction($img_source_resized, $this->gdimg_output, 0, 0, 0, 0, ImageSX($img_source_resized), ImageSY($img_source_resized), ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
2590                                              $phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin);
2591                                              ImageCopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
2592                                          } else {
2593                                              $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
2594                                          }
2595                                          ImageDestroy($img_watermark_resized);
2596                                      } else {
2597                                          $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__);
2598                                      }
2599  
2600                                  } else { // overlay
2601  
2602                                      if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
2603                                          ImageAlphaBlending($img_watermark_resized, false);
2604                                          ImageSaveAlpha($img_watermark_resized, true);
2605                                          $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark));
2606                                          $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin);
2607                                          ImageDestroy($img_watermark_resized);
2608                                      } else {
2609                                          $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
2610                                      }
2611  
2612                                  }
2613                                  ImageDestroy($img_watermark);
2614  
2615                              } else {
2616                                  $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$filename.'"', __FILE__, __LINE__);
2617                              }
2618                          } else {
2619                              $this->DebugMessage('Cannot open overlay file "'.$filename.'"', __FILE__, __LINE__);
2620                          }
2621                          break;
2622  
2623                      case 'wmi': // WaterMarkImage
2624                          @list($filename, $alignment, $opacity, $margin['x'], $margin['y'], $rotate_angle) = explode('|', $parameter, 6);
2625                          // $margin can be pixel margin or percent margin if $alignment is text, or max width/height if $alignment is position like "50x75"
2626                          $alignment    = ($alignment            ? $alignment            : 'BR');
2627                          $opacity      = (strlen($opacity)      ? intval($opacity)      : 50);
2628                          $rotate_angle = (strlen($rotate_angle) ? intval($rotate_angle) : 0);
2629                          if (!preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
2630                              $margins = array('x', 'y');
2631                              foreach ($margins as $xy) {
2632                                  $margin[$xy] = (strlen($margin[$xy]) ? $margin[$xy] : 5);
2633                                  if (($margin[$xy] > 0) && ($margin[$xy] < 1)) {
2634                                      $margin[$xy] = min(0.499, $margin[$xy]);
2635                                  } elseif (($margin[$xy] > -1) && ($margin[$xy] < 0)) {
2636                                      $margin[$xy] = max(-0.499, $margin[$xy]);
2637                                  }
2638                              }
2639                          }
2640  
2641                          $filename = $this->ResolveFilenameToAbsolute($filename);
2642                          if (@is_readable($filename)) {
2643                              if ($img_watermark = $this->ImageCreateFromFilename($filename)) {
2644                                  if ($rotate_angle !== 0) {
2645                                      $phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle);
2646                                  }
2647                                  if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
2648                                      $watermark_max_width  = intval($margin['x'] ? $margin['x'] : ImageSX($img_watermark));
2649                                      $watermark_max_height = intval($margin['y'] ? $margin['y'] : ImageSY($img_watermark));
2650                                      $scale = phpthumb_functions::ScaleToFitInBox(ImageSX($img_watermark), ImageSY($img_watermark), $watermark_max_width, $watermark_max_height, true, true);
2651                                      $this->DebugMessage('Scaling watermark by a factor of '.number_format($scale, 4), __FILE__, __LINE__);
2652                                      if (($scale > 1) || ($scale < 1)) {
2653                                          if ($img_watermark2 = phpthumb_functions::ImageCreateFunction($scale * ImageSX($img_watermark), $scale * ImageSY($img_watermark))) {
2654                                              ImageAlphaBlending($img_watermark2, false);
2655                                              ImageSaveAlpha($img_watermark2, true);
2656                                              $this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark2), ImageSY($img_watermark2), ImageSX($img_watermark), ImageSY($img_watermark));
2657                                              $img_watermark = $img_watermark2;
2658                                          } else {
2659                                              $this->DebugMessage('ImageCreateFunction('.($scale * ImageSX($img_watermark)).', '.($scale * ImageSX($img_watermark)).') failed', __FILE__, __LINE__);
2660                                          }
2661                                      }
2662                                      $watermark_dest_x = round($matches[1] - (ImageSX($img_watermark) / 2));
2663                                      $watermark_dest_y = round($matches[2] - (ImageSY($img_watermark) / 2));
2664                                      $alignment = $watermark_dest_x.'x'.$watermark_dest_y;
2665                                  }
2666                                  $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin['x'], $margin['y']);
2667                                  ImageDestroy($img_watermark);
2668                                  if (isset($img_watermark2) && is_resource($img_watermark2)) {
2669                                      ImageDestroy($img_watermark2);
2670                                  }
2671                              } else {
2672                                  $this->DebugMessage('ImageCreateFromFilename() failed for "'.$filename.'"', __FILE__, __LINE__);
2673                              }
2674                          } else {
2675                              $this->DebugMessage('!is_readable('.$filename.')', __FILE__, __LINE__);
2676                          }
2677                          break;
2678  
2679                      case 'wmt': // WaterMarkText
2680                          @list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend) = explode('|', $parameter, 11);
2681                          $text       = ($text            ? $text       : '');
2682                          $size       = ($size            ? $size       : 3);
2683                          $alignment  = ($alignment       ? $alignment  : 'BR');
2684                          $hex_color  = ($hex_color       ? $hex_color  : '000000');
2685                          $ttffont    = ($ttffont         ? $ttffont    : '');
2686                          $opacity    = (strlen($opacity) ? $opacity    : 50);
2687                          $margin     = (strlen($margin)  ? $margin     : 5);
2688                          $angle      = (strlen($angle)   ? $angle      : 0);
2689                          $bg_color   = ($bg_color        ? $bg_color   : false);
2690                          $bg_opacity = ($bg_opacity      ? $bg_opacity : 0);
2691                          $fillextend = ($fillextend      ? $fillextend : '');
2692  
2693                          if (basename($ttffont) == $ttffont) {
2694                              $ttffont = realpath($this->config_ttf_directory.DIRECTORY_SEPARATOR.$ttffont);
2695                          } else {
2696                              $ttffont = $this->ResolveFilenameToAbsolute($ttffont);
2697                          }
2698                          $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend);
2699                          break;
2700  
2701                      case 'blur': // Blur
2702                          @list($radius) = explode('|', $parameter, 1);
2703                          $radius = ($radius ? $radius : 1);
2704                          if (phpthumb_functions::gd_version() >= 2) {
2705                              $phpthumbFilters->Blur($this->gdimg_output, $radius);
2706                          } else {
2707                              $this->DebugMessage('Skipping Blur() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2708                          }
2709                          break;
2710  
2711                      case 'gblr': // Gaussian Blur
2712                          $phpthumbFilters->BlurGaussian($this->gdimg_output);
2713                          break;
2714  
2715                      case 'sblr': // Selective Blur
2716                          $phpthumbFilters->BlurSelective($this->gdimg_output);
2717                          break;
2718  
2719                      case 'mean': // MeanRemoval blur
2720                          $phpthumbFilters->MeanRemoval($this->gdimg_output);
2721                          break;
2722  
2723                      case 'smth': // Smooth blur
2724                          $phpthumbFilters->Smooth($this->gdimg_output, $parameter);
2725                          break;
2726  
2727                      case 'usm': // UnSharpMask sharpening
2728                          @list($amount, $radius, $threshold) = explode('|', $parameter, 3);
2729                          $amount    = ($amount            ? $amount    : 80);
2730                          $radius    = ($radius            ?