source: branches/ray/plugins/ImageManager/Classes/ImageEditor.php @ 762

Last change on this file since 762 was 762, checked in by ray, 13 years ago

updated branch

  • Property svn:keywords set to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
File size: 11.2 KB
Line 
1<?php
2/**
3 * Image Editor. Editing tools, crop, rotate, scale and save.
4 * @author $Author$
5 * @version $Id$
6 * @package ImageManager
7 */
8
9require_once('../ImageManager/Classes/Transform.php');
10
11/**
12 * Handles the basic image editing capbabilities.
13 * @author $Author$
14 * @version $Id$
15 * @package ImageManager
16 * @subpackage Editor
17 */
18class ImageEditor
19{
20        /**
21         * ImageManager instance.
22         */
23        var $manager;
24
25        /**
26         * user based on IP address
27         */
28        var $_uid;
29
30        /**
31         * tmp file storage time.
32         */
33        var $lapse_time =900; //15 mins
34
35        var $filesaved = 0;
36
37        /**
38         * Create a new ImageEditor instance. Editing requires a
39         * tmp file, which is saved in the current directory where the
40         * image is edited. The tmp file is assigned by md5 hash of the
41         * user IP address. This hashed is used as an ID for cleaning up
42         * the tmp files. In addition, any tmp files older than the
43         * the specified period will be deleted.
44         * @param ImageManager $manager the image manager, we need this
45         * for some file and path handling functions.
46         */
47        function ImageEditor($manager)
48        {
49                $this->manager = $manager;
50                $this->_uid = md5($_SERVER['REMOTE_ADDR']);
51        }
52       
53        /**
54         * Did we save a file?
55         * @return int 1 if the file was saved sucessfully,
56         * 0 no save operation, -1 file save error.
57         */
58        function isFileSaved()
59        {
60                Return $this->filesaved;
61        }
62
63        /**
64         * Process the image, if not action, just display the image.
65         * @return array with image information, empty array if not an image.
66         * <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
67         * 'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
68         */
69        function processImage()
70        {
71                if(isset($_GET['img']))
72                        $relative = rawurldecode($_GET['img']);
73                else
74                        Return array();
75               
76                //$relative = '/Series2004NoteFront.jpg';
77
78                $imgURL = $this->manager->getFileURL($relative);
79                $fullpath = $this->manager->getFullPath($relative);
80               
81                $imgInfo = @getImageSize($fullpath);
82                if(!is_array($imgInfo))
83                        Return array();
84
85                $action = $this->getAction();
86
87                if(!is_null($action))
88                {
89                        $image = $this->processAction($action, $relative, $fullpath);
90                }
91                else
92                {
93                        $image['src'] = $imgURL;
94                        $image['dimensions'] = $imgInfo[3];
95                        $image['file'] = $relative;
96                        $image['fullpath'] = $fullpath;
97                }
98
99                Return $image;
100        }
101
102        /**
103         * Process the actions, crop, scale(resize), rotate, flip, and save.
104         * When ever an action is performed, the result is save into a
105         * temporary image file, see createUnique on the filename specs.
106         * It does not return the saved file, alway returning the tmp file.
107         * @param string $action, should be 'crop', 'scale', 'rotate','flip', or 'save'
108         * @param string $relative the relative image filename
109         * @param string $fullpath the fullpath to the image file
110         * @return array with image information
111         * <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
112         * 'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
113         */
114        function processAction($action, $relative, $fullpath)
115        {
116                $params = '';
117               
118                if(isset($_GET['params']))
119                        $params = $_GET['params'];
120
121                $values =  explode(',',$params,4);
122                $saveFile = $this->getSaveFileName($values[0]);
123
124                $img = Image_Transform::factory(IMAGE_CLASS);
125                $img->load($fullpath);
126
127                switch ($action)
128                {
129                        case 'crop':
130                                $img->crop(intval($values[0]),intval($values[1]),
131                                                        intval($values[2]),intval($values[3]));
132                        break;
133                        case 'scale':
134                                $img->resize(intval($values[0]),intval($values[1]));
135                                break;
136                        case 'rotate':
137                                $img->rotate(floatval($values[0]));
138                                break;
139                        case 'flip':
140                                if ($values[0] == 'hoz')
141                                        $img->flip(true);
142                                else if($values[0] == 'ver')
143                                        $img->flip(false);
144                                break;
145                        case 'save':
146                                if(!is_null($saveFile))
147                                {
148                                        $quality = intval($values[1]);
149                            if($quality <0) $quality = 85;
150                                        $newSaveFile = $this->makeRelative($relative, $saveFile);
151                                        $newSaveFile = $this->getUniqueFilename($newSaveFile);
152                                       
153                                        //get unique filename just returns the filename, so
154                                        //we need to make the relative path once more.
155                                        $newSaveFile = $this->makeRelative($relative, $newSaveFile);
156          $image['saveFile'] = $newSaveFile;
157                                        $newSaveFullpath = $this->manager->getFullPath($newSaveFile);
158                                        $img->save($newSaveFullpath, $values[0], $quality);
159                                        if(is_file($newSaveFullpath))
160                                                $this->filesaved = 1;
161                                        else
162                                                $this->filesaved = -1;
163                                }
164                                break;
165                }
166               
167                //create the tmp image file
168                $filename = $this->createUnique($fullpath);
169                $newRelative = $this->makeRelative($relative, $filename);
170                $newFullpath = $this->manager->getFullPath($newRelative);
171                $newURL = $this->manager->getFileURL($newRelative);
172               
173                //save the file.
174                $img->save($newFullpath);
175                $img->free();
176
177                //get the image information
178                $imgInfo = @getimagesize($newFullpath);
179
180                $image['src'] = $newURL;
181    $image['width'] = $imgInfo[0];
182    $image['height'] = $imgInfo[1];
183                $image['dimensions'] = $imgInfo[3];
184                $image['file'] = $newRelative;
185                $image['fullpath'] = $newFullpath;
186
187                Return $image;
188       
189        }
190
191        /**
192         * Get the file name base on the save name
193         * and the save type.
194         * @param string $type image type, 'jpeg', 'png', or 'gif'
195         * @return string the filename according to save type
196         */
197        function getSaveFileName($type)
198        {
199                if(!isset($_GET['file']))
200                        Return null;
201
202                $filename = Files::escape(rawurldecode($_GET['file']));
203                $index = strrpos($filename,'.');
204                $base = substr($filename,0,$index);
205                $ext = strtolower(substr($filename,$index+1,strlen($filename)));
206
207                if($type == 'jpeg' && !($ext=='jpeg' || $ext=='jpg'))
208                {
209                        Return $base.'.jpeg';
210                }
211                if($type=='png' && $ext != 'png')
212                        Return $base.'.png';
213                if($type=='gif' && $ext != 'gif')
214                        Return $base.'.gif';
215
216                Return $filename;
217        }
218
219        /**
220         * Get the default save file name, used by editor.php.
221         * @return string a suggestive filename, this should be unique
222         */
223        function getDefaultSaveFile()
224        {
225                if(isset($_GET['img']))
226                        $relative = rawurldecode($_GET['img']);
227                else
228                        Return null;
229
230                Return $this->getUniqueFilename($relative);
231        }
232
233        /**
234         * Get a unique filename. If the file exists, the filename
235         * base is appended with an increasing integer.
236         * @param string $relative the relative filename to the base_dir
237         * @return string a unique filename in the current path
238         */
239        function getUniqueFilename($relative)
240        {
241                $fullpath = $this->manager->getFullPath($relative);
242               
243                $pathinfo = pathinfo($fullpath);
244
245                $path = Files::fixPath($pathinfo['dirname']);
246                $file = Files::escape($pathinfo['basename']);
247               
248                $filename = $file;
249
250                $dotIndex = strrpos($file, '.');
251                $ext = '';
252
253                if(is_int($dotIndex))
254                {
255                        $ext = substr($file, $dotIndex);
256                        $base = substr($file, 0, $dotIndex);
257                }
258
259                $counter = 0;
260                while(is_file($path.$filename))
261                {
262                        $counter++;
263                        $filename = $base.'_'.$counter.$ext;
264                }
265               
266                Return $filename;
267               
268        }
269
270        /**
271         * Specifiy the original relative path, a new filename
272         * and return the new filename with relative path.
273         * i.e. $pathA (-filename) + $file
274         * @param string $pathA the relative file
275         * @param string $file the new filename
276         * @return string relative path with the new filename
277         */
278        function makeRelative($pathA, $file)
279        {
280                $index = strrpos($pathA,'/');
281                if(!is_int($index))
282                        Return $file;
283
284                $path = substr($pathA, 0, $index);
285                Return Files::fixPath($path).$file;
286        }
287
288        /**
289         * Get the action GET parameter
290         * @return string action parameter
291         */
292        function getAction()
293        {
294                $action = null;
295                if(isset($_GET['action']))
296                        $action = $_GET['action'];
297                Return $action;
298        }
299
300        /**
301         * Generate a unique string based on md5(microtime()).
302         * Well not so uniqe, as it is limited to 6 characters
303         * @return string unique string.
304         */
305    function uniqueStr()
306    {
307      return substr(md5(microtime()),0,6);
308    }
309
310        /**
311         * Create unique tmp image file name.
312         * The filename is based on the tmp file prefix
313         * specified in config.inc.php plus
314         * the UID (basically a md5 of the remote IP)
315         * and some random 6 character string.
316         * This function also calls to clean up the tmp files.
317         * @param string $file the fullpath to a file
318         * @return string a unique filename for that path
319         * NOTE: it only returns the filename, path no included.
320         */
321        function createUnique($file)
322        {
323                $pathinfo = pathinfo($file);
324                $path = Files::fixPath($pathinfo['dirname']);
325                $imgType = $this->getImageType($file);
326
327                $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
328
329           //make sure the the unique temp file does not exists
330        while (file_exists($path.$unique_str))
331        {
332            $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
333        }
334
335                $this->cleanUp($path,$pathinfo['basename']);
336
337                Return $unique_str;
338        }
339
340        /**
341         * Delete any tmp image files.
342         * @param string $path the full path
343         * where the clean should take place.
344         */
345        function cleanUp($path,$file)
346        {
347                $path = Files::fixPath($path);
348
349                if(!is_dir($path))
350                        Return false;
351
352                $d = @dir($path);
353               
354                $tmp = $this->manager->getTmpPrefix();
355                $tmpLen = strlen($tmp);
356
357                $prefix = $tmp.$this->_uid;
358                $len = strlen($prefix);
359
360                while (false !== ($entry = $d->read()))
361                {
362                        //echo $entry."<br>";
363                        if(is_file($path.$entry) && $this->manager->isTmpFile($entry))
364                        {
365                                if(substr($entry,0,$len)==$prefix && $entry != $file)
366                                        Files::delFile($path.$entry);
367                                else if(substr($entry,0,$tmpLen)==$tmp && $entry != $file)
368                                {
369                                        if(filemtime($path.$entry)+$this->lapse_time < time())
370                                                Files::delFile($path.$entry);
371                                }
372                        }
373                }
374                $d->close();
375        }
376
377        /**
378         * Get the image type base on an image file.
379         * @param string $file the full path to the image file.
380         * @return string of either 'gif', 'jpeg', 'png' or 'bmp'
381         * otherwise it will return null.
382         */
383        function getImageType($file)
384        {
385                $imageInfo = @getImageSize($file);
386
387                if(!is_array($imageInfo))
388                        Return null;
389
390                switch($imageInfo[2])
391                {
392                        case 1:
393                                Return 'gif';
394                        case 2:
395                                Return 'jpeg';
396                        case 3:
397                                Return 'png';
398                        case 6:
399                                Return 'bmp';
400                }
401
402                Return null;
403        }
404
405        /**
406         * Check if the specified image can be edit by GD
407         * mainly to check that GD can read and save GIFs
408         * @return int 0 if it is not a GIF file, 1 is GIF is editable, -1 if not editable.
409         */
410        function isGDEditable()
411        {
412                if(isset($_GET['img']))
413                        $relative = rawurldecode($_GET['img']);
414                else
415                        Return 0;
416                if(IMAGE_CLASS != 'GD')
417                        Return 0;
418
419                $fullpath = $this->manager->getFullPath($relative);
420
421                $type = $this->getImageType($fullpath);
422                if($type != 'gif')
423                        Return 0;
424
425                if(function_exists('ImageCreateFrom'+$type)
426                        && function_exists('image'+$type))
427                        Return 1;
428                else
429                        Return -1;
430        }
431
432        /**
433         * Check if GIF can be edit by GD.
434         * @return int 0 if it is not using the GD library, 1 is GIF is editable, -1 if not editable.
435         */
436        function isGDGIFAble()
437        {
438                if(IMAGE_CLASS != 'GD')
439                        Return 0;
440
441                if(function_exists('ImageCreateFromGif')
442                        && function_exists('imagegif'))
443                        Return 1;
444                else
445                        Return -1;
446        }
447}
448
449?>
Note: See TracBrowser for help on using the repository browser.