source: trunk/plugins/ImageManager/Classes/ImageEditor.php @ 111

Last change on this file since 111 was 111, checked in by niko, 14 years ago

#225
several ImageManager? fixes, see #225 for details

File size: 10.8 KB
Line 
1<?php
2/**
3 * Image Editor. Editing tools, crop, rotate, scale and save.
4 * @author $Author: Wei Zhuo $
5 * @version $Id: ImageEditor.php 27 2004-04-01 08:31:57Z Wei Zhuo $
6 * @package ImageManager
7 */
8
9require_once('Transform.php');
10
11/**
12 * Handles the basic image editing capbabilities.
13 * @author $Author: Wei Zhuo $
14 * @version $Id: ImageEditor.php 27 2004-04-01 08:31:57Z Wei Zhuo $
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                                        $newSaveFullpath = $this->manager->getFullPath($newSaveFile);
157                                        $img->save($newSaveFullpath, $values[0], $quality);
158                                        if(is_file($newSaveFullpath))
159                                                $this->filesaved = 1;
160                                        else
161                                                $this->filesaved = -1;
162                                }
163                                break;
164                }
165               
166                //create the tmp image file
167                $filename = $this->createUnique($fullpath);
168                $newRelative = $this->makeRelative($relative, $filename);
169                $newFullpath = $this->manager->getFullPath($newRelative);
170                $newURL = $this->manager->getFileURL($newRelative);
171               
172                //save the file.
173                $img->save($newFullpath);
174                $img->free();
175
176                //get the image information
177                $imgInfo = @getimagesize($newFullpath);
178
179                $image['src'] = $newURL;
180                $image['dimensions'] = $imgInfo[3];
181                $image['file'] = $newRelative;
182                $image['fullpath'] = $newFullpath;
183
184                Return $image;
185       
186        }
187
188        /**
189         * Get the file name base on the save name
190         * and the save type.
191         * @param string $type image type, 'jpeg', 'png', or 'gif'
192         * @return string the filename according to save type
193         */
194        function getSaveFileName($type)
195        {
196                if(!isset($_GET['file']))
197                        Return null;
198
199                $filename = Files::escape(rawurldecode($_GET['file']));
200                $index = strrpos($filename,'.');
201                $base = substr($filename,0,$index);
202                $ext = strtolower(substr($filename,$index+1,strlen($filename)));
203
204                if($type == 'jpeg' && !($ext=='jpeg' || $ext=='jpg'))
205                {
206                        Return $base.'.jpeg';
207                }
208                if($type=='png' && $ext != 'png')
209                        Return $base.'.png';
210                if($type=='gif' && $ext != 'gif')
211                        Return $base.'.gif';
212
213                Return $filename;
214        }
215
216        /**
217         * Get the default save file name, used by editor.php.
218         * @return string a suggestive filename, this should be unique
219         */
220        function getDefaultSaveFile()
221        {
222                if(isset($_GET['img']))
223                        $relative = rawurldecode($_GET['img']);
224                else
225                        Return null;
226
227                Return $this->getUniqueFilename($relative);
228        }
229
230        /**
231         * Get a unique filename. If the file exists, the filename
232         * base is appended with an increasing integer.
233         * @param string $relative the relative filename to the base_dir
234         * @return string a unique filename in the current path
235         */
236        function getUniqueFilename($relative)
237        {
238                $fullpath = $this->manager->getFullPath($relative);
239               
240                $pathinfo = pathinfo($fullpath);
241
242                $path = Files::fixPath($pathinfo['dirname']);
243                $file = Files::escape($pathinfo['basename']);
244               
245                $filename = $file;
246
247                $dotIndex = strrpos($file, '.');
248                $ext = '';
249
250                if(is_int($dotIndex))
251                {
252                        $ext = substr($file, $dotIndex);
253                        $base = substr($file, 0, $dotIndex);
254                }
255
256                $counter = 0;
257                while(is_file($path.$filename))
258                {
259                        $counter++;
260                        $filename = $base.'_'.$counter.$ext;
261                }
262               
263                Return $filename;
264               
265        }
266
267        /**
268         * Specifiy the original relative path, a new filename
269         * and return the new filename with relative path.
270         * i.e. $pathA (-filename) + $file
271         * @param string $pathA the relative file
272         * @param string $file the new filename
273         * @return string relative path with the new filename
274         */
275        function makeRelative($pathA, $file)
276        {
277                $index = strrpos($pathA,'/');
278                if(!is_int($index))
279                        Return $file;
280
281                $path = substr($pathA, 0, $index);
282                Return Files::fixPath($path).$file;
283        }
284
285        /**
286         * Get the action GET parameter
287         * @return string action parameter
288         */
289        function getAction()
290        {
291                $action = null;
292                if(isset($_GET['action']))
293                        $action = $_GET['action'];
294                Return $action;
295        }
296
297        /**
298         * Generate a unique string based on md5(microtime()).
299         * Well not so uniqe, as it is limited to 6 characters
300         * @return string unique string.
301         */
302    function uniqueStr()
303    {
304      return substr(md5(microtime()),0,6);
305    }
306
307        /**
308         * Create unique tmp image file name.
309         * The filename is based on the tmp file prefix
310         * specified in config.inc.php plus
311         * the UID (basically a md5 of the remote IP)
312         * and some random 6 character string.
313         * This function also calls to clean up the tmp files.
314         * @param string $file the fullpath to a file
315         * @return string a unique filename for that path
316         * NOTE: it only returns the filename, path no included.
317         */
318        function createUnique($file)
319        {
320                $pathinfo = pathinfo($file);
321                $path = Files::fixPath($pathinfo['dirname']);
322                $imgType = $this->getImageType($file);
323
324                $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
325
326           //make sure the the unique temp file does not exists
327        while (file_exists($path.$unique_str))
328        {
329            $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
330        }
331
332                $this->cleanUp($path,$pathinfo['basename']);
333
334                Return $unique_str;
335        }
336
337        /**
338         * Delete any tmp image files.
339         * @param string $path the full path
340         * where the clean should take place.
341         */
342        function cleanUp($path,$file)
343        {
344                $path = Files::fixPath($path);
345
346                if(!is_dir($path))
347                        Return false;
348
349                $d = @dir($path);
350               
351                $tmp = $this->manager->getTmpPrefix();
352                $tmpLen = strlen($tmp);
353
354                $prefix = $tmp.$this->_uid;
355                $len = strlen($prefix);
356
357                while (false !== ($entry = $d->read()))
358                {
359                        //echo $entry."<br>";
360                        if(is_file($path.$entry) && $this->manager->isTmpFile($entry))
361                        {
362                                if(substr($entry,0,$len)==$prefix && $entry != $file)
363                                        Files::delFile($path.$entry);
364                                else if(substr($entry,0,$tmpLen)==$tmp && $entry != $file)
365                                {
366                                        if(filemtime($path.$entry)+$this->lapse_time < time())
367                                                Files::delFile($path.$entry);
368                                }
369                        }
370                }
371                $d->close();
372        }
373
374        /**
375         * Get the image type base on an image file.
376         * @param string $file the full path to the image file.
377         * @return string of either 'gif', 'jpeg', 'png' or 'bmp'
378         * otherwise it will return null.
379         */
380        function getImageType($file)
381        {
382                $imageInfo = @getImageSize($file);
383
384                if(!is_array($imageInfo))
385                        Return null;
386
387                switch($imageInfo[2])
388                {
389                        case 1:
390                                Return 'gif';
391                        case 2:
392                                Return 'jpeg';
393                        case 3:
394                                Return 'png';
395                        case 6:
396                                Return 'bmp';
397                }
398
399                Return null;
400        }
401
402        /**
403         * Check if the specified image can be edit by GD
404         * mainly to check that GD can read and save GIFs
405         * @return int 0 if it is not a GIF file, 1 is GIF is editable, -1 if not editable.
406         */
407        function isGDEditable()
408        {
409                if(isset($_GET['img']))
410                        $relative = rawurldecode($_GET['img']);
411                else
412                        Return 0;
413                if(IMAGE_CLASS != 'GD')
414                        Return 0;
415
416                $fullpath = $this->manager->getFullPath($relative);
417
418                $type = $this->getImageType($fullpath);
419                if($type != 'gif')
420                        Return 0;
421
422                if(function_exists('ImageCreateFrom'+$type)
423                        && function_exists('image'+$type))
424                        Return 1;
425                else
426                        Return -1;
427        }
428
429        /**
430         * Check if GIF can be edit by GD.
431         * @return int 0 if it is not using the GD library, 1 is GIF is editable, -1 if not editable.
432         */
433        function isGDGIFAble()
434        {
435                if(IMAGE_CLASS != 'GD')
436                        Return 0;
437
438                if(function_exists('ImageCreateFromGif')
439                        && function_exists('imagegif'))
440                        Return 1;
441                else
442                        Return -1;
443        }
444}
445
446?>
Note: See TracBrowser for help on using the repository browser.