ImageManager
[ class tree: ImageManager ] [ index: ImageManager ] [ all elements ]

Source for file ImageEditor.php

Documentation is available at ImageEditor.php

  1. <?php
  2. /**
  3.  * Image Editor. Editing tools, crop, rotate, scale and save.
  4.  * @author $Author: Wei Zhuo $
  5.  * @author $Author: Paul Moers <mail@saulmade.nl> $ - watermarking and replace code + several small enhancements <http://fckplugins.saulmade.nl>
  6.  * @version $Id: ImageEditor.php 27 2004-04-01 08:31:57Z Wei Zhuo $
  7.  * @package ImageManager
  8.  */
  9.  
  10. require_once('Transform.php');
  11.  
  12. /**
  13.  * Handles the basic image editing capbabilities.
  14.  * @author $Author: Wei Zhuo $
  15.  * @version $Id: ImageEditor.php 27 2004-04-01 08:31:57Z Wei Zhuo $
  16.  * @package ImageManager
  17.  * @subpackage Editor
  18.  */
  19. class ImageEditor 
  20. {
  21.     /**
  22.      * ImageManager instance.
  23.      */
  24.     var $manager;
  25.  
  26.     /**
  27.      * user based on IP address
  28.      */
  29.     var $_uid;
  30.  
  31.     /**
  32.      * tmp file storage time.
  33.      */
  34.     var $lapse_time =900//15 mins
  35.  
  36.     var $filesaved = 0;
  37.  
  38.     /**
  39.      * Create a new ImageEditor instance. Editing requires a
  40.      * tmp file, which is saved in the current directory where the
  41.      * image is edited. The tmp file is assigned by md5 hash of the
  42.      * user IP address. This hashed is used as an ID for cleaning up
  43.      * the tmp files. In addition, any tmp files older than the
  44.      * the specified period will be deleted.
  45.      * @param ImageManager $manager the image manager, we need this
  46.      *  for some file and path handling functions.
  47.      */
  48.     function ImageEditor($manager
  49.     {
  50.         $this->manager = $manager;
  51.         $this->_uid = md5($_SERVER['REMOTE_ADDR']);
  52.     }
  53.     
  54.     /**
  55.      * Did we save a file?
  56.      * @return int 1 if the file was saved sucessfully,
  57.      *  0 no save operation, -1 file save error.
  58.      */
  59.     function isFileSaved(
  60.     {
  61.         Return $this->filesaved;
  62.     }
  63.  
  64.     /**
  65.      * Process the image, if not action, just display the image.
  66.      * @return array with image information, empty array if not an image.
  67.      *  <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
  68.      *  'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
  69.      */
  70.     function processImage($uploadedRelative)
  71.     {
  72.         if (isset($uploadedRelative&& $uploadedRelative != "")
  73.         {
  74.             $relative $uploadedRelative;
  75.         }
  76.         elseif(isset($_GET['img']))
  77.         {
  78.             $relative rawurldecode($_GET['img']);
  79.         }
  80.         else
  81.         {
  82.             Return array();
  83.         }
  84.  
  85.         $imgURL $this->manager->getFileURL($relative);
  86.         $fullpath $this->manager->getFullPath($relative);
  87.         
  88.         $imgInfo @getImageSize($fullpath);
  89.         if(!is_array($imgInfo))
  90.             Return array();
  91.  
  92.         $action $this->getAction();
  93.  
  94.         if(!is_null($action))
  95.         {
  96.             $image $this->processAction($action$relative$fullpath);
  97.         }
  98.         else
  99.         {
  100.             $image['src'$imgURL;
  101.             $image['dimensions'$imgInfo[3];
  102.             $image['width'$imgInfo[0];
  103.             $image['height'$imgInfo[1];
  104.             $image['file'$relative;
  105.             $image['fullpath'$fullpath;
  106.         }
  107.  
  108.         Return $image;
  109.     }
  110.  
  111.  
  112.     /**
  113.      * Process the actions, crop, scale(resize), rotate, flip, and save.
  114.      * When ever an action is performed, the result is save into a
  115.      * temporary image file, see createUnique on the filename specs.
  116.      * It does not return the saved file, alway returning the tmp file.
  117.      * @param string $action, should be 'crop', 'scale', 'rotate','flip', or 'save'
  118.      * @param string $relative the relative image filename
  119.      * @param string $fullpath the fullpath to the image file
  120.      * @return array with image information
  121.      *  <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
  122.      *  'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
  123.      */
  124.     function processAction($action$relative$fullpath
  125.     {
  126.         $params '';
  127.  
  128.         if(isset($_GET['params']))
  129.             $params $_GET['params'];
  130.  
  131.         $values =  explode(',',$params,4);
  132.         $saveFile $this->getSaveFileName($values[0]);
  133.  
  134.         $img Image_Transform::factory(IMAGE_CLASS);
  135.         $img->load($fullpath);
  136.  
  137.         switch ($action
  138.         {
  139.             case 'replace':
  140.  
  141.                 // 'ImageManager.php' handled the uploaded file, it's now on the server.
  142.                 // If maximum size is specified, constrain image to it.
  143.                 if ($this->manager->config['maxWidth'&& $this->manager->config['maxHeight'&& ($img->img_x $this->manager->config['maxWidth'|| $img->img_y $this->manager->config['maxHeight']))
  144.                 {
  145.                     $percentage min($this->manager->config['maxWidth']/$img->img_x$this->manager->config['maxHeight']/$img->img_y);
  146.                     $img->scale($percentage);
  147.                 }
  148.  
  149.                 break;
  150.  
  151.             case 'watermark':
  152.  
  153.                     // loading target image
  154.                     $functionName 'ImageCreateFrom' $img->type;
  155.                     if(function_exists($functionName))
  156.                     {
  157.                         $imageResource $functionName($fullpath);
  158.                     }
  159.                     else
  160.                     {
  161.                         echo "<script>alert(\"Error when loading '" basename($fullpath"' - Loading '" $img->type "' files not supported\");</script>";
  162.                         return false;
  163.                     }
  164.  
  165.                     // loading watermark
  166.                     $watermarkFullPath $_GET['watermarkFullPath'];
  167.                     $watermarkImageType strtolower(substr($watermarkFullPathstrrpos($watermarkFullPath"."1));
  168.                     if ($watermarkImageType == "jpg"$watermarkImageType "jpeg"}
  169.                     if ($watermarkImageType == "tif"$watermarkImageType "tiff"}
  170.                     $functionName 'ImageCreateFrom' $watermarkImageType;
  171.                     if(function_exists($functionName))
  172.                     {
  173.                         $watermarkResource $functionName($watermarkFullPath);
  174.                     }
  175.                     else
  176.                     {
  177.                         echo "<script>alert(\"Error when loading '" basename($watermarkFullPath"' - Loading '" $img->type "' files not supported\");</script>";
  178.                         return false;
  179.                     }
  180.  
  181.                     $numberOfColors imagecolorstotal($watermarkResource);
  182.  
  183.                     $watermarkX = isset($_GET['watermarkX']$_GET['watermarkX': -1;
  184.                     $watermarkY = isset($_GET['watermarkY']$_GET['watermarkY': -1;
  185.                     $opacity $_GET['opacity'];
  186.  
  187.                     // PNG24 watermark on GIF target needs special handling
  188.                     // PNG24 watermark with alpha transparency on other targets need also this handling
  189.                     if ($watermarkImageType == "png" && $numberOfColors == && ($img->type == "gif" || $opacity 100))
  190.                     {
  191.                         require_once('Classes/api.watermark.php');
  192.  
  193.                         $watermarkAPI new watermark();
  194.                         $imageResource $watermarkAPI->create_watermark($imageResource$watermarkResource$opacity$watermarkX$watermarkY);
  195.                     }
  196.                     // PNG24 watermark without alpha transparency on other targets than GIF can use 'imagecopy'
  197.                     elseif ($watermarkImageType == "png" && $numberOfColors == && $opacity == 100)
  198.                     {
  199.                         $watermark_width imagesx($watermarkResource);
  200.                         $watermark_height imagesy($watermarkResource);
  201.  
  202.                         imagecopy($imageResource$watermarkResource$watermarkX$watermarkY00$watermark_width$watermark_height);
  203.                     }
  204.                     // Other watermarks can be appllied no swet on all targets
  205.                     else
  206.                     {
  207.                         $watermark_width imagesx($watermarkResource);
  208.                         $watermark_height imagesy($watermarkResource);
  209.  
  210.                         imagecopymerge($imageResource$watermarkResource$watermarkX$watermarkY00$watermark_width$watermark_height$opacity);
  211.                     }
  212.  
  213.                 break;
  214.  
  215.             case 'crop':
  216.                 $img->crop(intval($values[0]),intval($values[1]),
  217.                             intval($values[2]),intval($values[3]));
  218.                 break;
  219.             case 'scale':
  220.                 $img->resize(intval($values[0]),intval($values[1]));
  221.                 break;
  222.             case 'rotate':
  223.                 $img->rotate(floatval($values[0]));
  224.                 break;
  225.             case 'flip':
  226.                 if ($values[0== 'hoz')
  227.                     $img->flip(true);
  228.                 else if($values[0== 'ver'
  229.                     $img->flip(false);
  230.                 break;
  231.             case 'save':
  232.                 if(!is_null($saveFile))
  233.                 {
  234.                     $quality intval($values[1]);
  235.                     if($quality <0$quality 85;
  236.                     $newSaveFile $this->makeRelative($relative$saveFile);
  237.                     $oldSaveFile $newSaveFile;
  238.  
  239.                     if ($this->manager->config['allow_newFileName'&& $this->manager->config['allow_overwrite'== false)
  240.                     {
  241.                         // check whether a file already exist and if there is, create a variant of the filename
  242.                         $newName $this->getUniqueFilename($newSaveFile);
  243.                         //get unique filename just returns the filename, so
  244.                         //we need to make the relative path again.
  245.                         $newSaveFile $this->makeRelative($relative$newName);
  246.  
  247.                         // forced new name?
  248.                         if ($oldSaveFile != $newSaveFile)
  249.                         {
  250.                             $this->forcedNewName $newName;
  251.                         }
  252.                         else
  253.                         {
  254.                             $this->forcedNewName false;
  255.                         }
  256.                     }
  257.  
  258.                     $newSaveFullpath $this->manager->getFullPath($newSaveFile);
  259.                     $img->save($newSaveFullpath$values[0]$quality);
  260.                     if(is_file($newSaveFullpath))
  261.                         $this->filesaved = 1;
  262.                     else
  263.                         $this->filesaved = -1;
  264.                 }
  265.                 break;
  266.         }
  267.         
  268.         //create the tmp image file
  269.         $filename $this->createUnique($fullpath);
  270.         $newRelative $this->makeRelative($relative$filename);
  271.         $newFullpath $this->manager->getFullPath($newRelative);
  272.         $newURL $this->manager->getFileURL($newRelative);
  273.  
  274.         // when uploaded and not resized, rename and don't save
  275.         if ($action == "replace" && $percentage <= 0)
  276.         {
  277.             rename($fullpath$newFullpath);
  278.         }
  279.         // when watermarked, save to new filename
  280.         elseif ($action == "watermark")
  281.         {
  282.             // save image
  283.             $functionName   'image' $img->type;
  284.             if(function_exists($functionName))
  285.             {
  286.                 if($type=='jpeg')
  287.                     $functionName($imageResource$newFullpath100);
  288.                 else
  289.                     $functionName($imageResource$newFullpath);
  290.             }
  291.             else
  292.             {
  293.                 echo "<script>alert(\"Error when saving '" basename($newFullpath"' - Saving '" $img->type "' files not supported\");</script>";
  294.                 return false;
  295.             }
  296.         }
  297.         else
  298.         {
  299.             //save the file.
  300.             $img->save($newFullpath);
  301.             $img->free();
  302.         }
  303.  
  304.         // when uploaded was resized and saved, remove original
  305.         if ($action == "replace" && $percentage 0)
  306.         {
  307.             unlink($fullpath);
  308.         }
  309.  
  310.         //get the image information
  311.         $imgInfo @getimagesize($newFullpath);
  312.  
  313.         $image['src'$newURL;
  314.         $image['dimensions'$imgInfo[3];
  315.         $image['width'$imgInfo[0];
  316.         $image['height'$imgInfo[1];
  317.         $image['file'$newRelative;
  318.         $image['fullpath'$newFullpath;
  319.  
  320.  
  321.         Return $image;
  322.     
  323.     }
  324.  
  325.  
  326.  
  327.     /**
  328.      * Get the file name base on the save name
  329.      * and the save type.
  330.      * @param string $type image type, 'jpeg', 'png', or 'gif'
  331.      * @return string the filename according to save type
  332.      */
  333.     function getSaveFileName($type
  334.     {
  335.         if(!isset($_GET['file']))
  336.             Return null;
  337.  
  338.         $filename Files::escape(rawurldecode($_GET['file']));
  339.         $index strrpos($filename,'.');
  340.         $base substr($filename,0,$index);
  341.         $ext strtolower(substr($filename,$index+1,strlen($filename)));
  342.  
  343.         if($type == 'jpeg' && !($ext=='jpeg' || $ext=='jpg'))
  344.         {
  345.             Return $base.'.jpeg';
  346.         }
  347.         if($type=='png' && $ext != 'png')
  348.             Return $base.'.png';
  349.         if($type=='gif' && $ext != 'gif')
  350.             Return $base.'.gif';
  351.  
  352.         Return $filename;
  353.     }
  354.  
  355.     /**
  356.      * Get the default save file name, used by editor.php.
  357.      * @return string a suggestive filename, this should be unique
  358.      */
  359.     function getDefaultSaveFile(
  360.     {
  361.         if(isset($_GET['img']))
  362.             $relative rawurldecode($_GET['img']);
  363.         else
  364.             Return null;
  365.  
  366.         Return $this->getUniqueFilename($relative);
  367.     }
  368.  
  369.     /**
  370.      * Get a unique filename. If the file exists, the filename
  371.      * base is appended with an increasing integer.
  372.      * @param string $relative the relative filename to the base_dir
  373.      * @return string a unique filename in the current path
  374.      */
  375.     function getUniqueFilename($relative
  376.     {
  377.         $fullpath $this->manager->getFullPath($relative);
  378.         
  379.         $pathinfo pathinfo($fullpath);
  380.  
  381.         $path Files::fixPath($pathinfo['dirname']);
  382.         $file Files::escape($pathinfo['basename']);
  383.         
  384.         $filename $file;
  385.  
  386.         $dotIndex strrpos($file'.');
  387.         $ext '';
  388.  
  389.         if(is_int($dotIndex)) 
  390.         {
  391.             $ext substr($file$dotIndex);
  392.             $base substr($file0$dotIndex);
  393.         }
  394.  
  395.         $counter 0;
  396.         while(is_file($path.$filename)) 
  397.         {
  398.             $counter++;
  399.             $filename $base.'_'.$counter.$ext;
  400.         }
  401.         
  402.         Return $filename;
  403.         
  404.     }
  405.  
  406.     /**
  407.      * Specifiy the original relative path, a new filename
  408.      * and return the new filename with relative path.
  409.      * i.e. $pathA (-filename) + $file
  410.      * @param string $pathA the relative file
  411.      * @param string $file the new filename
  412.      * @return string relative path with the new filename
  413.      */
  414.     function makeRelative($pathA$file
  415.     {
  416.         $index strrpos($pathA,'/');
  417.         if(!is_int($index))
  418.             Return $file;
  419.  
  420.         $path substr($pathA0$index);
  421.         Return Files::fixPath($path).$file;
  422.     }
  423.  
  424.     /**
  425.      * Get the action GET parameter
  426.      * @return string action parameter
  427.      */
  428.     function getAction(
  429.     {
  430.         $action null;
  431.         if(isset($_GET['action']))
  432.             $action $_GET['action'];
  433.         Return $action;
  434.     }
  435.  
  436.     /**
  437.      * Generate a unique string based on md5(microtime()).
  438.      * Well not so uniqe, as it is limited to 6 characters
  439.      * @return string unique string.
  440.      */
  441.     function uniqueStr()
  442.     {
  443.       return substr(md5(microtime()),0,6);
  444.     }
  445.  
  446.     /**
  447.      * Create unique tmp image file name.
  448.      * The filename is based on the tmp file prefix
  449.      * specified in config.inc.php plus
  450.      * the UID (basically a md5 of the remote IP)
  451.      * and some random 6 character string.
  452.      * This function also calls to clean up the tmp files.
  453.      * @param string $file the fullpath to a file
  454.      * @return string a unique filename for that path
  455.      *  NOTE: it only returns the filename, path no included.
  456.      */
  457.     function createUnique($file
  458.     {
  459.         $pathinfo pathinfo($file);
  460.         $path Files::fixPath($pathinfo['dirname']);
  461.         $imgType $this->getImageType($file);
  462.  
  463.         $unique_str $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
  464.  
  465.        //make sure the the unique temp file does not exists
  466.         while (file_exists($path.$unique_str))
  467.         {
  468.             $unique_str $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
  469.         }
  470.  
  471.         $this->cleanUp($path,$pathinfo['basename']);
  472.  
  473.         Return $unique_str;
  474.     }
  475.  
  476.     /**
  477.      * Delete any tmp image files.
  478.      * @param string $path the full path
  479.      *  where the clean should take place.
  480.      */
  481.     function cleanUp($path,$file
  482.     {
  483.         $path Files::fixPath($path);
  484.  
  485.         if(!is_dir($path))
  486.             Return false;
  487.  
  488.         $d @dir($path);
  489.         
  490.         $tmp $this->manager->getTmpPrefix();
  491.         $tmpLen strlen($tmp);
  492.  
  493.         $prefix $tmp.$this->_uid;
  494.         $len strlen($prefix);
  495.  
  496.         while (false !== ($entry $d->read())) 
  497.         {
  498.             //echo $entry."<br>";
  499.             if(is_file($path.$entry&& $this->manager->isTmpFile($entry))
  500.             {
  501.                 if(substr($entry,0,$len)==$prefix && $entry != $file)
  502.                     Files::delFile($path.$entry);
  503.                 else if(substr($entry,0,$tmpLen)==$tmp && $entry != $file)
  504.                 {
  505.                     if(filemtime($path.$entry)+$this->lapse_time < time())
  506.                         Files::delFile($path.$entry);
  507.                 }
  508.             }
  509.         }
  510.         $d->close();
  511.     }
  512.  
  513.     /**
  514.      * Get the image type base on an image file.
  515.      * @param string $file the full path to the image file.
  516.      * @return string of either 'gif', 'jpeg', 'png' or 'bmp'
  517.      *  otherwise it will return null.
  518.      */
  519.     function getImageType($file
  520.     {
  521.         $imageInfo @getImageSize($file);
  522.  
  523.         if(!is_array($imageInfo))
  524.             Return null;
  525.  
  526.         switch($imageInfo[2]
  527.         {
  528.             case 1:
  529.                 Return 'gif';
  530.             case 2:
  531.                 Return 'jpeg';
  532.             case 3:
  533.                 Return 'png';
  534.             case 6:
  535.                 Return 'bmp';
  536.         }
  537.  
  538.         Return null;
  539.     }
  540.  
  541.     /**
  542.      * Check if the specified image can be edit by GD
  543.      * mainly to check that GD can read and save GIFs
  544.      * @return int 0 if it is not a GIF file, 1 is GIF is editable, -1 if not editable.
  545.      */
  546.     function isGDEditable(
  547.     {
  548.         if(isset($_GET['img']))
  549.             $relative rawurldecode($_GET['img']);
  550.         else
  551.             Return 0;
  552.         if(IMAGE_CLASS != 'GD')
  553.             Return 0;
  554.  
  555.         $fullpath $this->manager->getFullPath($relative);
  556.  
  557.         $type $this->getImageType($fullpath);
  558.         if($type != 'gif')
  559.             Return 0;
  560.  
  561.         if(function_exists('ImageCreateFrom'+$type)
  562.             && function_exists('image'+$type))
  563.             Return 1;
  564.         else
  565.             Return -1;
  566.     }
  567.  
  568.     /**
  569.      * Check if GIF can be edit by GD.
  570.      * @return int 0 if it is not using the GD library, 1 is GIF is editable, -1 if not editable.
  571.      */
  572.     function isGDGIFAble(
  573.     {
  574.         if(IMAGE_CLASS != 'GD')
  575.             Return 0;
  576.  
  577.         if(function_exists('ImageCreateFromGif')
  578.             && function_exists('imagegif'))
  579.             Return 1;
  580.         else
  581.             Return -1;
  582.     }
  583. }
  584.  
  585. ?>

Documentation generated on Thu, 12 Jun 2008 13:46:27 -0500 by phpDocumentor 1.4.1