Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/lib/class.thumb.php - 445 lines - 18232 bytes - Summary - Text - Print

Description: class wet_thumb

   1  <?php
   2  /**
   3   * class wet_thumb
   4   * @author    C. Erdmann
   5   * @see        <a href="http://www.cerdmann.de/thumb">http://www.cerdmann.de/thumb</a>
   6   * @author    Robert Wetzlmayr
   7   *
   8   * refactored from function.thumb.php by C. Erdmann, which contained the following credit & licensing terms:
   9   * ===
  10   * Smarty plugin "Thumb"
  11   * Purpose: creates cached thumbnails
  12   * Home: http://www.cerdmann.com/thumb/
  13   * Copyright (C) 2005 Christoph Erdmann
  14   *
  15   * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
  16   *
  17   * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
  18   *
  19   * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
  20   * -------------------------------------------------------------
  21   * Author:   Christoph Erdmann (CE) <smarty@cerdmann.com>
  22   * Internet: http://www.cerdmann.com
  23   *
  24   * Author: Benjamin Fleckenstein (BF)
  25   * Internet: http://www.benjaminfleckenstein.de
  26   *
  27   * Author: Marcus Gueldenmeister (MG)
  28   * Internet: http://www.gueldenmeister.de/marcus/
  29   *
  30   * Author: Andreas Bösch (AB)
  31   *
  32   */
  33  
  34  /*
  35  $HeadURL: https://textpattern.googlecode.com/svn/releases/4.5.4/source/textpattern/lib/class.thumb.php $
  36  $LastChangedRevision: 3733 $
  37  */
  38  
  39  $verbose = false;
  40  
  41  
  42  class wet_thumb {
  43      var $width;      // The width of your thumbnail. The height (if not set) will be automatically calculated.
  44      var $height;    // The height of your thumbnail. The width (if not set) will be automatically calculated.
  45      var $longside;    // Set the longest side of the image if width, height and shortside is not set.
  46      var $shortside;    // Set the shortest side of the image if width, height and longside is not set.
  47      var $extrapolate;  // Set to 'false' if your source image is smaller than the calculated thumb and you do not want the image to get extrapolated.
  48      var $crop;    // If set to 'true', image will be cropped in the center to destination width and height params, while keeping aspect ratio. Otherwise the image will get resized.
  49      var $sharpen;    // Set to 'false' if you don't want to use the Unsharp-Mask. Thumbnail creation will be faster, but quality is reduced.
  50      var $hint;     // If set to 'false' the image will not have a lens-icon.
  51      var $addgreytohint; // Set to 'false' to get no lightgrey bottombar.
  52      var $quality;    // JPEG image quality (0...100, defaults to 80).
  53      // link related params
  54      var $linkurl;    // Set to your target URL (a href="linkurl")
  55      var $html;       // Will be inserted in the image-tag
  56  
  57      var $types = array('','.gif','.jpg','.png');
  58      var $_SRC;
  59      var $_DST;
  60  
  61      /**
  62       * constructor
  63       */
  64      function wet_thumb(  ) {
  65      $this->extrapolate = false;
  66      $this->crop = true;
  67      $this->sharpen = true;
  68      $this->hint = true;
  69      $this->addgreytohint = true;
  70      $this->quality = 80;
  71      $this->html = " alt=\"\" title=\"\" ";
  72      $this->link = true;
  73      }
  74  
  75      /**
  76       * write thumbnail file
  77       * @param    infile    image file name
  78       * @param    outfile    array of thumb file names (1...n)
  79       * @return    boolean, true indicates success
  80       */
  81      function write( $infile, $outfile ) {
  82          global $verbose;
  83  
  84          if( $verbose )echo "writing thumb nail...";
  85  
  86      ### fetch source (SRC) info
  87      $temp = getimagesize($infile);
  88  
  89      $this->_SRC['file']        = $infile;
  90      $this->_SRC['width']        = $temp[0];
  91      $this->_SRC['height']        = $temp[1];
  92      $this->_SRC['type']        = $temp[2]; // 1=GIF, 2=JPG, 3=PNG, SWF=4
  93      $this->_SRC['string']        = $temp[3];
  94      $this->_SRC['filename']     = basename($infile);
  95      //$this->_SRC['modified']     = filemtime($infile);
  96  
  97      //check image orientation
  98      if ($this->_SRC['width'] >= $this->_SRC['height']) {
  99          $this->_SRC['format'] = 'landscape';
 100      } else {
 101          $this->_SRC['format'] = 'portrait';
 102      }
 103  
 104      ### fetch destination (DST) info
 105      if (is_numeric($this->width) AND empty($this->height)) {
 106          $this->_DST['width']    = $this->width;
 107          $this->_DST['height']    = round($this->width/($this->_SRC['width']/$this->_SRC['height']));
 108      }
 109      elseif (is_numeric($this->height) AND empty($this->width)) {
 110          $this->_DST['height']    = $this->height;
 111          $this->_DST['width']    = round($this->height/($this->_SRC['height']/$this->_SRC['width']));
 112      }
 113      elseif (is_numeric($this->width) AND is_numeric($this->height)) {
 114          $this->_DST['width']    = $this->width;
 115          $this->_DST['height']    = $this->height;
 116      }
 117      elseif (is_numeric($this->longside) AND empty($this->shortside)) {
 118          // preserve aspect ratio based on provided height
 119          if ($this->_SRC['format'] == 'portrait') {
 120          $this->_DST['height']    = $this->longside;
 121          $this->_DST['width']    = round($this->longside/($this->_SRC['height']/$this->_SRC['width']));
 122          }
 123          else {
 124          $this->_DST['width']    = $this->longside;
 125          $this->_DST['height']    = round($this->longside/($this->_SRC['width']/$this->_SRC['height']));
 126          }
 127          }
 128      elseif (is_numeric($this->shortside)) {
 129          // preserve aspect ratio based on provided width
 130          if ($this->_SRC['format'] == 'portrait') {
 131          $this->_DST['width']    = $this->shortside;
 132          $this->_DST['height']    = round($this->shortside/($this->_SRC['width']/$this->_SRC['height']));
 133          }
 134          else {
 135          $this->_DST['height']    = $this->shortside;
 136          $this->_DST['width']    = round($this->shortside/($this->_SRC['height']/$this->_SRC['width']));
 137          }
 138          }
 139          else { // default dimensions
 140              $this->width = 100;
 141              $this->_DST['width'] = $this->width;
 142              $this->_DST['height'] = round($this->width/($this->_SRC['width']/$this->_SRC['height']));
 143          }
 144  
 145  
 146      // don't make the new image larger than the original image
 147      if ($this->extrapolate === false && $this->_DST['height'] > $this->_SRC['height'] &&
 148                          $this->_DST['width'] > $this->_SRC['width']) {
 149          $this->_DST['width'] = $this->_SRC['width'];
 150          $this->_DST['height'] = $this->_SRC['height'];
 151      }
 152  
 153      $this->_DST['type'] = $this->_SRC['type'];
 154      $this->_DST['file'] = $outfile;
 155  
 156      // make sure we have enough memory if the image is large
 157      if (max($this->_SRC['width'], $this->_SRC['height']) > 1024) {
 158          $shorthand = array('/K/i','/M/i','/G/i');
 159          $tens = array('000','000000', '000000000'); // A good enough decimal approximation of K, M, and G
 160  
 161          // Do not *decrease* memory_limit
 162          // TODO: Try str_ireplace instead of preg_replace once we are on PHP5
 163          list($ml, $extra) = preg_replace($shorthand, $tens, array(ini_get('memory_limit'), EXTRA_MEMORY));
 164          if ($ml < $extra) {
 165              // this won't work on all servers but it's worth a try
 166              ini_set('memory_limit', EXTRA_MEMORY);
 167          }
 168      }
 169  
 170      // read SRC
 171      if ($this->_SRC['type'] == 1)    $this->_SRC['image'] = imagecreatefromgif($this->_SRC['file']);
 172      elseif ($this->_SRC['type'] == 2)    $this->_SRC['image'] = imagecreatefromjpeg($this->_SRC['file']);
 173      elseif ($this->_SRC['type'] == 3)    $this->_SRC['image'] = imagecreatefrompng($this->_SRC['file']);
 174  
 175      // crop image?
 176      $off_w = 0;
 177      $off_h = 0;
 178      if($this->crop != false) {
 179          if($this->_SRC['height'] < $this->_SRC['width']) {
 180          $ratio = (double)($this->_SRC['height'] / $this->_DST['height']);
 181          $cpyWidth = round($this->_DST['width'] * $ratio);
 182          if ($cpyWidth > $this->_SRC['width']) {
 183              $ratio = (double)($this->_SRC['width'] / $this->_DST['width']);
 184              $cpyWidth = $this->_SRC['width'];
 185              $cpyHeight = round($this->_DST['height'] * $ratio);
 186              $off_w = 0;
 187              $off_h = round(($this->_SRC['height'] - $cpyHeight) / 2);
 188              $this->_SRC['height'] = $cpyHeight;
 189          }
 190          else {
 191              $cpyHeight = $this->_SRC['height'];
 192              $off_w = round(($this->_SRC['width'] - $cpyWidth) / 2);
 193              $off_h = 0;
 194              $this->_SRC['width']= $cpyWidth;
 195          }
 196          }
 197          else {
 198          $ratio = (double)($this->_SRC['width'] / $this->_DST['width']);
 199          $cpyHeight = round($this->_DST['height'] * $ratio);
 200          if ($cpyHeight > $this->_SRC['height']) {
 201              $ratio = (double)($this->_SRC['height'] / $this->_DST['height']);
 202              $cpyHeight = $this->_SRC['height'];
 203              $cpyWidth = round($this->_DST['width'] * $ratio);
 204              $off_w = round(($this->_SRC['width'] - $cpyWidth) / 2);
 205              $off_h = 0;
 206              $this->_SRC['width']= $cpyWidth;
 207          }
 208          else {
 209              $cpyWidth = $this->_SRC['width'];
 210              $off_w = 0;
 211              $off_h = round(($this->_SRC['height'] - $cpyHeight) / 2);
 212              $this->_SRC['height'] = $cpyHeight;
 213          }
 214          }
 215      }
 216  
 217      // ensure non-zero height/width
 218      if (!$this->_DST['height']) $this->_DST['height'] = 1;
 219      if (!$this->_DST['width'])  $this->_DST['width']  = 1;
 220  
 221      // create DST
 222      $this->_DST['image'] = imagecreatetruecolor($this->_DST['width'], $this->_DST['height']);
 223  
 224      // GIF or PNG destination, set the transparency up.
 225      if ($this->_DST['type'] == 1 || $this->_DST['type'] == 3) {
 226          $trans_idx = imagecolortransparent($this->_SRC['image']);
 227  
 228          // Is there a specific transparent colour?
 229          if ($trans_idx >= 0) {
 230              $trans_color = imagecolorsforindex($this->_SRC['image'], $trans_idx);
 231              $trans_idx = imagecolorallocate($this->_DST['image'], $trans_color['red'], $trans_color['green'], $trans_color['blue']);
 232              imagefill($this->_DST['image'], 0, 0, $trans_idx);
 233              imagecolortransparent($this->_DST['image'], $trans_idx);
 234          } else if ($this->_DST['type'] == 3) {
 235              imagealphablending($this->_DST['image'], false);
 236              $transparent = imagecolorallocatealpha($this->_DST['image'], 0, 0, 0, 127);
 237              imagefill($this->_DST['image'], 0, 0, $transparent);
 238              imagesavealpha($this->_DST['image'], true);
 239          }
 240      }
 241      imagecopyresampled($this->_DST['image'], $this->_SRC['image'], 0, 0, $off_w, $off_h, $this->_DST['width'], $this->_DST['height'], $this->_SRC['width'], $this->_SRC['height']);
 242      if ($this->sharpen === true) {
 243          $this->_DST['image'] = UnsharpMask($this->_DST['image'],80,.5,3);
 244      }
 245  
 246          // finally: the real dimensions
 247          $this->height =  $this->_DST['height'];
 248          $this->width =  $this->_DST['width'];
 249  
 250      // add magnifying glass?
 251      if ( $this->hint === true) {
 252          // should we really add white bars?
 253          if ( $this->addgreytohint === true ) {
 254          $trans = imagecolorallocatealpha($this->_DST['image'], 255, 255, 255, 25);
 255          imagefilledrectangle($this->_DST['image'], 0, $this->_DST['height']-9, $this->_DST['width'], $this->_DST['height'], $trans);
 256          }
 257  
 258          $magnifier = imagecreatefromstring(gzuncompress(base64_decode("eJzrDPBz5+WS4mJgYOD19HAJAtLcIMzBBiRXrilXA1IsxU6eIRxAUMOR0gHkcxZ4RBYD1QiBMOOlu3V/gIISJa4RJc5FqYklmfl5CiGZuakMBoZ6hkZ6RgYGJs77ex2BalRBaoLz00rKE4tSGXwTk4vyc1NTMhMV3DKLUsvzi7KLFXwjFEAa2svWnGdgYPTydHEMqZhTOsE++1CAyNHzm2NZjgau+dAmXlAwoatQmOld3t/NPxlLMvY7sovPzXHf7re05BPzjpQTMkZTPjm1HlHkv6clYWK43Zt16rcDjdZ/3j2cd7qD4/HHH3GaprFrw0QZDHicORXl2JsPsveVTDz//L3N+WpxJ5Hff+10Tjdd2/Vi17vea79Om5w9zzyne9GLnWGrN8atby/ayXPOsu2w4quvVtxNCVVz5nAf3nDpZckBCedpqSc28WTOWnT7rZNXZSlPvFybie9EFc6y3bIMCn3JAoJ+kyyfn9qWq+LZ9Las26Jv482cDRE6Ci0B6gVbo2oj9KabzD8vyMK4ZMqMs2kSvW4chz88SXNzmeGjtj1QZK9M3HHL8L7HITX3t19//VVY8CYDg9Kvy2vDXu+6mGGxNOiltMPsjn/t9eJr0ja/FOdi5TyQ9Lz3fOqstOr99/dnro2vZ1jy76D/vYivPsBoYPB09XNZ55TQBAAJjs5s</body>")));
 259          imagealphablending($this->_DST['image'], true);
 260          imagecopy($this->_DST['image'], $magnifier, $this->_DST['width']-15, $this->_DST['height']-14, 0, 0, 11, 11);
 261          imagedestroy($magnifier);
 262      }
 263  
 264          if ($verbose ) echo "... saving image ...";
 265  
 266          if ($this->_DST['type'] == 1)    {
 267          imagetruecolortopalette($this->_DST['image'], false, 256);
 268          if ( function_exists ('imagegif') ) {
 269              imagegif($this->_DST['image'], $this->_DST['file']);
 270          } else {
 271              imagedestroy($this->_DST['image']);
 272              imagedestroy($this->_SRC['image']);
 273              return false;
 274          }
 275      }
 276      elseif ($this->_DST['type'] == 2) {
 277          imagejpeg($this->_DST['image'], $this->_DST['file'], $this->quality);
 278      }
 279      elseif ($this->_DST['type'] == 3) {
 280          imagepng($this->_DST['image'], $this->_DST['file']);
 281      }
 282  
 283          if ($verbose ) echo "... image successfully saved ...";
 284  
 285      imagedestroy($this->_DST['image']);
 286      imagedestroy($this->_SRC['image']);
 287      return true;
 288      }
 289  
 290      /**
 291       * return a reference to the the thumbnailimage as a HTML <a> or <img> tag
 292       * @param    aslink    return an anchor tag to the source image
 293       * @param    aspopup    open link in new window
 294       * @return    string with suitable HTML markup
 295       */
 296      function asTag( $aslink = true, $aspopup = false  )
 297      {
 298          $imgtag = "<img src=\"" . $this->_DST['file']. "\" " .
 299                      $this->html . " " .
 300                      "width=\"".$this->width."\" " .
 301                      "height=\"".$this->height."\" " .
 302                      "/>";
 303  
 304          if ( $aslink === true ) {
 305              return "<a href=\"" . ((empty($this->linkurl)) ? $this->_SRC['file'] : $this->linkurl) . "\" " .
 306                      (($aspopup === true) ? "target=\"_blank\"" : "") . ">" .
 307                      $imgtag .
 308                      "</a>";
 309          }
 310          else {
 311              return $imgtag;
 312          }
 313      }
 314  }
 315  /**
 316   * class txp_thumb: wrapper for wet_thumb interfacing the TxP repository
 317   */
 318  class txp_thumb extends wet_thumb {
 319  
 320      var $m_ext;
 321      var $m_id;
 322  
 323      /***
 324       * constructor
 325       * @param    $id    image id
 326       */
 327      function txp_thumb ($id) {
 328          $id = assert_int($id);
 329          $rs = safe_row('*', 'txp_image', 'id = '.$id.' limit 1');
 330          if ($rs) {
 331              extract($rs);
 332              $this->m_ext = $ext;
 333              $this->m_id = $id;
 334          }
 335          $this->wet_thumb(); // construct base class instance
 336      }
 337  
 338      /**
 339       * create thumbnail image from source image
 340       * @return    boolean, true indicates success
 341       */
 342      function write( ) {
 343          if ( !isset($this->m_ext) ) return false;
 344  
 345          if ( parent::write ( IMPATH.$this->m_id.$this->m_ext, IMPATH.$this->m_id.'t'.$this->m_ext ) ) {
 346              safe_update('txp_image', "thumbnail = 1, thumb_w = $this->width, thumb_h = $this->height, date = now()", 'id = '.$this->m_id);
 347              chmod(IMPATH.$this->m_id.'t'.$this->m_ext, 0644);
 348              return true;
 349          }
 350          return false;
 351      }
 352  
 353       /**
 354       * delete thumbnail
 355       * @return    boolean, true indicates success
 356       */
 357      function delete( ) {
 358          if (!isset($this->m_ext)) return false;
 359  
 360          if (unlink(IMPATH.$this->m_id.'t'.$this->m_ext)) {
 361              safe_update('txp_image', 'thumbnail = 0', 'id = '.$this->m_id);
 362              return true;
 363          }
 364      return false;
 365      }
 366  
 367  }
 368  
 369  /**
 370   * Unsharp mask algorithm by Torstein Hønsi 2003 (thoensi_at_netcom_dot_no)
 371   * Christoph Erdmann: changed it a little, cause i could not reproduce the
 372   * darker blurred image, now it is up to 15% faster with same results
 373   * @param   img     image as a ressource
 374   * @param   amount  filter parameter
 375   * @param   radius  filter parameter
 376   * @param   treshold    filter parameter
 377   * @return  sharpened image as a ressource
 378   *
 379   *
 380   * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
 381  */
 382  
 383  function UnsharpMask($img, $amount, $radius, $threshold)    {
 384      // Attempt to calibrate the parameters to Photoshop:
 385      if ($amount > 500) $amount = 500;
 386      $amount = $amount * 0.016;
 387      if ($radius > 50) $radius = 50;
 388      $radius = $radius * 2;
 389      if ($threshold > 255) $threshold = 255;
 390  
 391      $radius = abs(round($radius));     // Only integers make sense.
 392      if ($radius == 0) {    return $img; imagedestroy($img); break;    }
 393      $w = imagesx($img); $h = imagesy($img);
 394      $imgCanvas = $img;
 395      $imgCanvas2 = $img;
 396      $imgBlur = imagecreatetruecolor($w, $h);
 397  
 398      // Gaussian blur matrix:
 399      //    1    2    1
 400      //    2    4    2
 401      //    1    2    1
 402  
 403      // Move copies of the image around one pixel at the time and merge them with weight
 404      // according to the matrix. The same matrix is simply repeated for higher radii.
 405      for ($i = 0; $i < $radius; $i++)
 406              {
 407              imagecopy      ($imgBlur, $imgCanvas, 0, 0, 1, 1, $w - 1, $h - 1); // up left
 408              imagecopymerge ($imgBlur, $imgCanvas, 1, 1, 0, 0, $w, $h, 50); // down right
 409              imagecopymerge ($imgBlur, $imgCanvas, 0, 1, 1, 0, $w - 1, $h, 33.33333); // down left
 410              imagecopymerge ($imgBlur, $imgCanvas, 1, 0, 0, 1, $w, $h - 1, 25); // up right
 411              imagecopymerge ($imgBlur, $imgCanvas, 0, 0, 1, 0, $w - 1, $h, 33.33333); // left
 412              imagecopymerge ($imgBlur, $imgCanvas, 1, 0, 0, 0, $w, $h, 25); // right
 413              imagecopymerge ($imgBlur, $imgCanvas, 0, 0, 0, 1, $w, $h - 1, 20 ); // up
 414              imagecopymerge ($imgBlur, $imgCanvas, 0, 1, 0, 0, $w, $h, 16.666667); // down
 415              imagecopymerge ($imgBlur, $imgCanvas, 0, 0, 0, 0, $w, $h, 50); // center
 416              }
 417      $imgCanvas = $imgBlur;
 418  
 419      // Calculate the difference between the blurred pixels and the original
 420      // and set the pixels
 421      for ($x = 0; $x < $w; $x++) { // each row
 422          for ($y = 0; $y < $h; $y++) { // each pixel
 423              $rgbOrig = ImageColorAt($imgCanvas2, $x, $y);
 424              $rOrig = (($rgbOrig >> 16) & 0xFF);
 425              $gOrig = (($rgbOrig >> 8) & 0xFF);
 426              $bOrig = ($rgbOrig & 0xFF);
 427              $rgbBlur = ImageColorAt($imgCanvas, $x, $y);
 428              $rBlur = (($rgbBlur >> 16) & 0xFF);
 429              $gBlur = (($rgbBlur >> 8) & 0xFF);
 430              $bBlur = ($rgbBlur & 0xFF);
 431  
 432              // When the masked pixels differ less from the original
 433              // than the threshold specifies, they are set to their original value.
 434              $rNew = (abs($rOrig - $rBlur) >= $threshold) ? max(0, min(255, ($amount * ($rOrig - $rBlur)) + $rOrig)) : $rOrig;
 435              $gNew = (abs($gOrig - $gBlur) >= $threshold) ? max(0, min(255, ($amount * ($gOrig - $gBlur)) + $gOrig)) : $gOrig;
 436              $bNew = (abs($bOrig - $bBlur) >= $threshold) ? max(0, min(255, ($amount * ($bOrig - $bBlur)) + $bOrig)) : $bOrig;
 437  
 438              if (($rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew)) {
 439                  $pixCol = ImageColorAllocate($img, $rNew, $gNew, $bNew);
 440                  ImageSetPixel($img, $x, $y, $pixCol);
 441              }
 442          }
 443      }
 444      return $img;
 445  }

title

Description

title

Description

title

Description

title

title

Body