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

Last change on this file since 938 was 938, checked in by ray, 11 years ago

fixed an error from rev [937] and replaced linux.gif from demo_images that was somehow broken

  • Property svn:keywords set to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
File size: 12.8 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                        $image['filesize'] = @filesize($fullpath);
98                }
99
100                Return $image;
101        }
102
103        /**
104         * Process the actions, crop, scale(resize), rotate, flip, and save.
105         * When ever an action is performed, the result is save into a
106         * temporary image file, see createUnique on the filename specs.
107         * It does not return the saved file, alway returning the tmp file.
108         * @param string $action, should be 'crop', 'scale', 'rotate','flip', or 'save'
109         * @param string $relative the relative image filename
110         * @param string $fullpath the fullpath to the image file
111         * @return array with image information
112         * <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
113         * 'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
114         */
115        function processAction($action, $relative, $fullpath)
116        {
117                $params = '';
118               
119                if(isset($_GET['params']))
120                        $params = $_GET['params'];
121
122                $values =  explode(',',$params);
123                $saveFile = $this->getSaveFileName($values[0]);
124
125                $img = Image_Transform::factory(IMAGE_CLASS);
126                $img->load($fullpath);
127               
128                if ( is_callable( array($img,'paletteToTrueColorWithTransparency')) && !imageistruecolor($img->imageHandle))
129                {
130                        $img->paletteToTrueColorWithTransparency();
131                }
132                switch ($action)
133                {
134                        case 'crop':
135                                $img->crop(intval($values[0]),intval($values[1]),
136                                                        intval($values[2]),intval($values[3]));
137                        break;
138                        case 'scale':
139                                $img->resize(intval($values[0]),intval($values[1]));
140                                break;
141                        case 'rotate':
142                                $img->rotate(floatval($values[0]));
143                                break;
144                        case 'flip':
145                                if ($values[0] == 'hoz')
146                                        $img->flip(true);
147                                else if($values[0] == 'ver')
148                                        $img->flip(false);
149                                break;
150                        case 'save':
151                                if(!is_null($saveFile))
152                                {
153                                        $quality = intval($values[1]);
154                            if($quality <0) $quality = 85;
155                                        $newSaveFile = $this->makeRelative($relative, $saveFile);
156                                        $newSaveFile = $this->getUniqueFilename($newSaveFile);
157                                       
158                                        //get unique filename just returns the filename, so
159                                        //we need to make the relative path once more.
160                                        $newSaveFile = $this->makeRelative($relative, $newSaveFile);
161                                $image['saveFile'] = $newSaveFile;
162                                        $newSaveFullpath = $this->manager->getFullPath($newSaveFile);
163                                        if ( $values[0] == 'gif' && is_callable(array($img, 'preserveTransparencyForPalette')))
164                                        {
165                                                $img->preserveTransparencyForPalette();
166                                        }
167                                        $img->save($newSaveFullpath, $values[0], $quality);
168                                        if(is_file($newSaveFullpath))
169                                                $this->filesaved = 1;
170                                        else
171                                                $this->filesaved = -1;
172                                }
173                                break;
174                                case 'preview':
175                                        $quality = intval($values[1]);
176                                       
177                                       
178                                        $image['file'] = $relative;
179                                        $image['fullpath'] = $fullpath;
180                                       
181                                        //create the tmp image file
182                                        $filename = $this->createUnique($fullpath);
183                                        $newRelative = $this->makeRelative($relative, $filename);
184                                        $newFullpath = $this->manager->getFullPath($newRelative);
185                                        $newURL = $this->manager->getFileURL($newRelative);
186                                       
187                                       
188                                        if ( $values[0] == 'gif' && is_callable(array($img, 'preserveTransparencyForPalette')))
189                                        {
190                                                $img->preserveTransparencyForPalette();
191                                        }
192                                        $img->save($newFullpath, $values[0] );
193                                        $img->free();
194                       
195                                        //get the image information
196                                        $imgInfo = @getimagesize($newFullpath);
197                               
198                                        $image['src'] = $newURL;
199                                $image['width'] = $imgInfo[0];
200                                        $image['height'] = $imgInfo[1];
201                                        $image['dimensions'] = $imgInfo[3];
202                                        $image['file'] = $relative;
203                                        $image['fullpath'] = $fullpath;
204                                        $image['filesize'] = @filesize($newFullpath);
205
206                                        Return $image;
207       
208                                break;
209                }
210               
211                //create the tmp image file
212                $filename = $this->createUnique($fullpath);
213                $newRelative = $this->makeRelative($relative, $filename);
214                $newFullpath = $this->manager->getFullPath($newRelative);
215                $newURL = $this->manager->getFileURL($newRelative);
216
217                //save the file.
218                $img->save($newFullpath, 'png' );
219                $img->free();
220
221                //get the image information
222                $imgInfo = @getimagesize($newFullpath);
223
224                $image['src'] = $newURL;
225        $image['width'] = $imgInfo[0];
226                $image['height'] = $imgInfo[1];
227                $image['dimensions'] = $imgInfo[3];
228                $image['file'] = $newRelative;
229                $image['fullpath'] = $newFullpath;
230                $image['filesize'] = @filesize($newFullpath);
231                $image['type'] = image_type_to_mime_type($imgInfo[2]);
232               
233                Return $image;
234       
235        }
236
237        /**
238         * Get the file name base on the save name
239         * and the save type.
240         * @param string $type image type, 'jpeg', 'png', or 'gif'
241         * @return string the filename according to save type
242         */
243        function getSaveFileName($type)
244        {
245                if(!isset($_GET['file']))
246                        Return null;
247
248                $filename = Files::escape(rawurldecode($_GET['file']));
249                $index = strrpos($filename,'.');
250                $base = substr($filename,0,$index);
251                $ext = strtolower(substr($filename,$index+1,strlen($filename)));
252
253                if($type == 'jpeg' && !($ext=='jpeg' || $ext=='jpg'))
254                {
255                        Return $base.'.jpeg';
256                }
257                if($type=='png' && $ext != 'png')
258                        Return $base.'.png';
259                if($type=='gif' && $ext != 'gif')
260                        Return $base.'.gif';
261
262                Return $filename;
263        }
264
265        /**
266         * Get the default save file name, used by editor.php.
267         * @return string a suggestive filename, this should be unique
268         */
269        function getDefaultSaveFile()
270        {
271                if(isset($_GET['img']))
272                        $relative = rawurldecode($_GET['img']);
273                else
274                        Return null;
275
276                Return $this->getUniqueFilename($relative);
277        }
278
279        /**
280         * Get a unique filename. If the file exists, the filename
281         * base is appended with an increasing integer.
282         * @param string $relative the relative filename to the base_dir
283         * @return string a unique filename in the current path
284         */
285        function getUniqueFilename($relative)
286        {
287                $fullpath = $this->manager->getFullPath($relative);
288               
289                $pathinfo = pathinfo($fullpath);
290
291                $path = Files::fixPath($pathinfo['dirname']);
292                $file = Files::escape($pathinfo['basename']);
293               
294                $filename = $file;
295
296                $dotIndex = strrpos($file, '.');
297                $ext = '';
298
299                if(is_int($dotIndex))
300                {
301                        $ext = substr($file, $dotIndex);
302                        $base = substr($file, 0, $dotIndex);
303                }
304
305                $counter = 0;
306                while(is_file($path.$filename))
307                {
308                        $counter++;
309                        $filename = $base.'_'.$counter.$ext;
310                }
311               
312                Return $filename;
313               
314        }
315
316        /**
317         * Specifiy the original relative path, a new filename
318         * and return the new filename with relative path.
319         * i.e. $pathA (-filename) + $file
320         * @param string $pathA the relative file
321         * @param string $file the new filename
322         * @return string relative path with the new filename
323         */
324        function makeRelative($pathA, $file)
325        {
326                $index = strrpos($pathA,'/');
327                if(!is_int($index))
328                        Return $file;
329
330                $path = substr($pathA, 0, $index);
331                Return Files::fixPath($path).$file;
332        }
333
334        /**
335         * Get the action GET parameter
336         * @return string action parameter
337         */
338        function getAction()
339        {
340                $action = null;
341                if(isset($_GET['action']))
342                        $action = $_GET['action'];
343                Return $action;
344        }
345
346        /**
347         * Generate a unique string based on md5(microtime()).
348         * Well not so uniqe, as it is limited to 6 characters
349         * @return string unique string.
350         */
351    function uniqueStr()
352    {
353      return substr(md5(microtime()),0,6);
354    }
355
356        /**
357         * Create unique tmp image file name.
358         * The filename is based on the tmp file prefix
359         * specified in config.inc.php plus
360         * the UID (basically a md5 of the remote IP)
361         * and some random 6 character string.
362         * This function also calls to clean up the tmp files.
363         * @param string $file the fullpath to a file
364         * @return string a unique filename for that path
365         * NOTE: it only returns the filename, path no included.
366         */
367        function createUnique($file)
368        {
369                $pathinfo = pathinfo($file);
370                $path = Files::fixPath($pathinfo['dirname']);
371                $imgType = $this->getImageType($file);
372
373                $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
374
375           //make sure the the unique temp file does not exists
376        while (file_exists($path.$unique_str))
377        {
378            $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
379        }
380
381                $this->cleanUp($path,$pathinfo['basename']);
382
383                Return $unique_str;
384        }
385
386        /**
387         * Delete any tmp image files.
388         * @param string $path the full path
389         * where the clean should take place.
390         */
391        function cleanUp($path,$file)
392        {
393                $path = Files::fixPath($path);
394
395                if(!is_dir($path))
396                        Return false;
397
398                $d = @dir($path);
399               
400                $tmp = $this->manager->getTmpPrefix();
401                $tmpLen = strlen($tmp);
402
403                $prefix = $tmp.$this->_uid;
404                $len = strlen($prefix);
405
406                while (false !== ($entry = $d->read()))
407                {
408                        //echo $entry."<br>";
409                        if(is_file($path.$entry) && $this->manager->isTmpFile($entry))
410                        {
411                                if(substr($entry,0,$len)==$prefix && $entry != $file)
412                                        Files::delFile($path.$entry);
413                                else if(substr($entry,0,$tmpLen)==$tmp && $entry != $file)
414                                {
415                                        if(filemtime($path.$entry)+$this->lapse_time < time())
416                                                Files::delFile($path.$entry);
417                                }
418                        }
419                }
420                $d->close();
421        }
422
423        /**
424         * Get the image type base on an image file.
425         * @param string $file the full path to the image file.
426         * @return string of either 'gif', 'jpeg', 'png' or 'bmp'
427         * otherwise it will return null.
428         */
429        function getImageType($file)
430        {
431                $imageInfo = @getImageSize($file);
432
433                if(!is_array($imageInfo))
434                        Return null;
435
436                switch($imageInfo[2])
437                {
438                        case 1:
439                                Return 'gif';
440                        case 2:
441                                Return 'jpeg';
442                        case 3:
443                                Return 'png';
444                        case 6:
445                                Return 'bmp';
446                }
447
448                Return null;
449        }
450
451        /**
452         * Check if the specified image can be edit by GD
453         * mainly to check that GD can read and save GIFs
454         * @return int 0 if it is not a GIF file, 1 is GIF is editable, -1 if not editable.
455         */
456        function isGDEditable()
457        {
458                if(isset($_GET['img']))
459                        $relative = rawurldecode($_GET['img']);
460                else
461                        Return 0;
462                if(IMAGE_CLASS != 'GD')
463                        Return 0;
464
465                $fullpath = $this->manager->getFullPath($relative);
466 
467                $type = $this->getImageType($fullpath);
468                if($type != 'gif')
469                        Return 0;
470
471                if(function_exists('ImageCreateFrom'.$type)
472                        && function_exists('image'.$type))
473                        Return 1;
474                else
475                        Return -1;
476        }
477
478        /**
479         * Check if GIF can be edit by GD.
480         * @return int 0 if it is not using the GD library, 1 is GIF is editable, -1 if not editable.
481         */
482        function isGDGIFAble()
483        {
484                if(IMAGE_CLASS != 'GD')
485                        Return 0;
486
487                if(function_exists('ImageCreateFromGif')
488                        && function_exists('imagegif'))
489                        Return 1;
490                else
491                        Return -1;
492        }
493}
494
495?>
Note: See TracBrowser for help on using the repository browser.