source: trunk/plugins/ImageManager/Classes/GD.php @ 841

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

Ticket #928 ImageManager? fails if (another) Files.php exists in include path

  • Property svn:keywords set to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
File size: 16.8 KB
Line 
1<?php
2/***********************************************************************
3** Title.........:  GD Driver
4** Version.......:  1.0
5** Author........:  Xiang Wei ZHUO <wei@zhuo.org>
6** Filename......:  GD.php
7** Last changed..:  30 Aug 2003
8** Notes.........:  Orginal is from PEAR
9**/
10// +----------------------------------------------------------------------+
11// | PHP Version 4                                                        |
12// +----------------------------------------------------------------------+
13// | Copyright (c) 1997-2002 The PHP Group                                |
14// +----------------------------------------------------------------------+
15// | This source file is subject to version 2.02 of the PHP license,      |
16// | that is bundled with this package in the file LICENSE, and is        |
17// | available at through the world-wide-web at                           |
18// | http://www.php.net/license/2_02.txt.                                 |
19// | If you did not receive a copy of the PHP license and are unable to   |
20// | obtain it through the world-wide-web, please send a note to          |
21// | license@php.net so we can mail you a copy immediately.               |
22// +----------------------------------------------------------------------+
23// | Authors: Peter Bowyer <peter@mapledesign.co.uk>                      |
24// |          Alan Knowles <alan@akbkhome.com>                            |
25// +----------------------------------------------------------------------+
26//
27//    Usage :
28//    $img    = new Image_Transform_GD();
29//    $angle  = -78;
30//    $img->load('magick.png');
31//
32//    if($img->rotate($angle,array('autoresize'=>true,'color_mask'=>array(255,0,0)))){
33//        $img->addText(array('text'=>"Rotation $angle",'x'=>0,'y'=>100,'font'=>'/usr/share/fonts/default/TrueType/cogb____.ttf'));
34//        $img->display();
35//    } else {
36//        echo "Error";
37//    }
38//
39//
40// $Id$
41//
42// Image Transformation interface using the GD library
43//
44
45require_once "../ImageManager/Classes/Transform.php";
46
47Class Image_Transform_Driver_GD extends Image_Transform
48{
49    /**
50     * Holds the image file for manipulation
51     */
52    var $imageHandle = '';
53
54    /**
55     * Holds the original image file
56     */
57    var $old_image = '';
58
59    /**
60     * Check settings
61     *
62     * @return mixed true or  or a PEAR error object on error
63     *
64     * @see PEAR::isError()
65     */
66    function Image_Transform_GD()
67    {
68        return;
69    } // End function Image
70
71    /**
72     * Load image
73     *
74     * @param string filename
75     *
76     * @return mixed none or a PEAR error object on error
77     * @see PEAR::isError()
78     */
79    function load($image)
80    {
81        $this->uid = md5($_SERVER['REMOTE_ADDR']);
82        $this->image = $image;
83        $this->_get_image_details($image);
84        $functionName = 'ImageCreateFrom' . $this->type;
85                if(function_exists($functionName))
86                {
87                        $this->imageHandle = $functionName($this->image);
88                }
89    } // End load
90
91    /**
92     * addText
93     *
94     * @param   array   options     Array contains options
95     *                              array(
96     *                                  'text'  The string to draw
97     *                                  'x'     Horizontal position
98     *                                  'y'     Vertical Position
99     *                                  'Color' Font color
100     *                                  'font'  Font to be used
101     *                                  'size'  Size of the fonts in pixel
102     *                                  'resize_first'  Tell if the image has to be resized
103     *                                                  before drawing the text
104     *                              )
105     *
106     * @return none
107     * @see PEAR::isError()
108     */
109    function addText($params)
110    {
111        $default_params = array(
112                                'text' => 'This is Text',
113                                'x' => 10,
114                                'y' => 20,
115                                'color' => array(255,0,0),
116                                'font' => 'Arial.ttf',
117                                'size' => '12',
118                                'angle' => 0,
119                                'resize_first' => false // Carry out the scaling of the image before annotation?  Not used for GD
120                                );
121        $params = array_merge($default_params, $params);
122        extract($params);
123
124        if( !is_array($color) ){
125            if ($color[0]=='#'){
126                $this->colorhex2colorarray( $color );
127            } else {
128                include_once('Image/Transform/Driver/ColorsDefs.php');
129                $color = isset($colornames[$color])?$colornames[$color]:false;
130            }
131        }
132
133        $c = imagecolorresolve ($this->imageHandle, $color[0], $color[1], $color[2]);
134
135        if ('ttf' == substr($font, -3)) {
136            ImageTTFText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text);
137        } else {
138            ImagePSText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text);
139        }
140        return true;
141    } // End addText
142
143
144    /**
145     * Rotate image by the given angle
146     * Uses a fast rotation algorythm for custom angles
147     * or lines copy for multiple of 90 degrees
148     *
149     * @param int       $angle      Rotation angle
150     * @param array     $options    array(  'autoresize'=>true|false,
151     *                                      'color_mask'=>array(r,g,b), named color or #rrggbb
152     *                                   )
153     * @author Pierre-Alain Joye
154     * @return mixed none or a PEAR error object on error
155     * @see PEAR::isError()
156     */
157    function rotate($angle, $options=null)
158    {
159        if(function_exists('imagerotate')) {
160            $white = imagecolorallocate ($this->imageHandle, 255, 255, 255);
161                        $this->imageHandle = imagerotate($this->imageHandle, $angle, $white);
162            return true;
163        }
164
165        if ( $options==null ){
166            $autoresize = true;
167            $color_mask = array(255,255,0);
168        } else {
169            extract( $options );
170        }
171
172        while ($angle <= -45) {
173            $angle  += 360;
174        }
175        while ($angle > 270) {
176            $angle  -= 360;
177        }
178
179        $t      = deg2rad($angle);
180
181        if( !is_array($color_mask) ){
182            if ($color[0]=='#'){
183                $this->colorhex2colorarray( $color_mask );
184            } else {
185                include_once('Image/Transform/Driver/ColorDefs.php');
186                $color = isset($colornames[$color_mask])?$colornames[$color_mask]:false;
187            }
188        }
189
190        // Do not round it, too much lost of quality
191        $cosT   = cos($t);
192        $sinT   = sin($t);
193
194        $img    =& $this->imageHandle;
195
196        $width  = $max_x  = $this->img_x;
197        $height = $max_y  = $this->img_y;
198        $min_y  = 0;
199        $min_x  = 0;
200
201        $x1     = round($max_x/2,0);
202        $y1     = round($max_y/2,0);
203
204        if ( $autoresize ){
205            $t      = abs($t);
206            $a      = round($angle,0);
207            switch((int)($angle)){
208                case 0:
209                        $width2     = $width;
210                        $height2    = $height;
211                    break;
212                case 90:
213                        $width2     = $height;
214                        $height2    = $width;
215                    break;
216                case 180:
217                        $width2     = $width;
218                        $height2    = $height;
219                    break;
220                case 270:
221                        $width2     = $height;
222                        $height2    = $width;
223                    break;
224                default:
225                    $width2     = (int)(abs(sin($t) * $height + cos($t) * $width));
226                    $height2    = (int)(abs(cos($t) * $height+sin($t) * $width));
227            }
228
229            $width2     -= $width2%2;
230            $height2    -= $height2%2;
231
232            $d_width    = abs($width - $width2);
233            $d_height   = abs($height - $height2);
234            $x_offset   = $d_width/2;
235            $y_offset   = $d_height/2;
236            $min_x2     = -abs($x_offset);
237            $min_y2     = -abs($y_offset);
238            $max_x2     = $width2;
239            $max_y2     = $height2;
240        }
241
242        $img2   = @imagecreate($width2,$height2);
243
244        if ( !is_resource($img2) ){
245            return false;/*PEAR::raiseError('Cannot create buffer for the rotataion.',
246                                null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);*/
247        }
248
249        $this->img_x = $width2;
250        $this->img_y = $height2;
251
252
253        imagepalettecopy($img2,$img);
254
255        $mask   = imagecolorresolve($img2,$color_mask[0],$color_mask[1],$color_mask[2]);
256
257        // use simple lines copy for axes angles
258        switch((int)($angle)){
259            case 0:
260                imagefill ($img2, 0, 0,$mask);
261                for ($y=0; $y < $max_y; $y++) {
262                    for ($x = $min_x; $x < $max_x; $x++){
263                        $c  = @imagecolorat ( $img, $x, $y);
264                        imagesetpixel($img2,$x+$x_offset,$y+$y_offset,$c);
265                    }
266                }
267                break;
268            case 90:
269                imagefill ($img2, 0, 0,$mask);
270                for ($x = $min_x; $x < $max_x; $x++){
271                    for ($y=$min_y; $y < $max_y; $y++) {
272                        $c  = imagecolorat ( $img, $x, $y);
273                        imagesetpixel($img2,$max_y-$y-1,$x,$c);
274                    }
275                }
276                break;
277            case 180:
278                imagefill ($img2, 0, 0,$mask);
279                for ($y=0; $y < $max_y; $y++) {
280                    for ($x = $min_x; $x < $max_x; $x++){
281                        $c  = @imagecolorat ( $img, $x, $y);
282                        imagesetpixel($img2, $max_x2-$x-1, $max_y2-$y-1, $c);
283                    }
284                }
285                break;
286            case 270:
287                imagefill ($img2, 0, 0,$mask);
288                for ($y=0; $y < $max_y; $y++) {
289                    for ($x = $max_x; $x >= $min_x; $x--){
290                        $c  = @imagecolorat ( $img, $x, $y);
291                        imagesetpixel($img2,$y,$max_x-$x-1,$c);
292                    }
293                }
294                break;
295            // simple reverse rotation algo
296            default:
297                $i=0;
298                for ($y = $min_y2; $y < $max_y2; $y++){
299
300                    // Algebra :)
301                    $x2 = round((($min_x2-$x1) * $cosT) + (($y-$y1) * $sinT + $x1),0);
302                    $y2 = round((($y-$y1) * $cosT - ($min_x2-$x1) * $sinT + $y1),0);
303
304                    for ($x = $min_x2; $x < $max_x2; $x++){
305
306                        // Check if we are out of original bounces, if we are
307                        // use the default color mask
308                        if ( $x2>=0 && $x2<$max_x && $y2>=0 && $y2<$max_y ){
309                            $c  = imagecolorat ( $img, $x2, $y2);
310                        } else {
311                            $c  = $mask;
312                        }
313                        imagesetpixel($img2,$x+$x_offset,$y+$y_offset,$c);
314
315                        // round verboten!
316                        $x2  += $cosT;
317                        $y2  -= $sinT;
318                    }
319                }
320                break;
321        }
322        $this->old_image    = $this->imageHandle;
323        $this->imageHandle  =  $img2;
324        return true;
325    }
326
327
328   /**
329    * Resize Action
330    *
331    * For GD 2.01+ the new copyresampled function is used
332    * It uses a bicubic interpolation algorithm to get far
333    * better result.
334    *
335    * @param int  $new_x new width
336    * @param int  $new_y new height
337    *
338    * @return true on success or pear error
339    * @see PEAR::isError()
340    */
341    function _resize($new_x, $new_y) {
342        if ($this->resized === true) {
343            return false; /*PEAR::raiseError('You have already resized the image without saving it.  Your previous resizing will be overwritten', null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);*/
344        }
345        if(function_exists('ImageCreateTrueColor')){
346            $new_img =ImageCreateTrueColor($new_x,$new_y);
347        } else {
348            $new_img =ImageCreate($new_x,$new_y);
349        }
350        if(function_exists('ImageCopyResampled')){
351            ImageCopyResampled($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y);
352        } else {
353            ImageCopyResized($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y);
354        }
355        $this->old_image = $this->imageHandle;
356        $this->imageHandle = $new_img;
357        $this->resized = true;
358
359        $this->new_x = $new_x;
360        $this->new_y = $new_y;
361        return true;
362    }
363
364    /**
365     * Crop the image
366     *
367     * @param int $crop_x left column of the image
368     * @param int $crop_y top row of the image
369     * @param int $crop_width new cropped image width
370     * @param int $crop_height new cropped image height
371     */
372    function crop($new_x, $new_y, $new_width, $new_height)
373    {
374        if(function_exists('ImageCreateTrueColor')){
375            $new_img =ImageCreateTrueColor($new_width,$new_height);
376        } else {
377            $new_img =ImageCreate($new_width,$new_height);
378        }
379        if(function_exists('ImageCopyResampled')){
380            ImageCopyResampled($new_img, $this->imageHandle, 0, 0, $new_x, $new_y,$new_width,$new_height,$new_width,$new_height);
381        } else {
382            ImageCopyResized($new_img, $this->imageHandle, 0, 0, $new_x, $new_y, $new_width,$new_height,$new_width,$new_height);
383        }
384        $this->old_image = $this->imageHandle;
385        $this->imageHandle = $new_img;
386        $this->resized = true;
387
388        $this->new_x = $new_x;
389        $this->new_y = $new_y;
390        return true;
391    }
392   
393    /**
394     * Flip the image horizontally or vertically
395     *
396     * @param boolean $horizontal true if horizontal flip, vertical otherwise
397     */
398    function flip($horizontal)
399    {
400        if(!$horizontal) {
401            $this->rotate(180);
402        }
403
404        $width = imagesx($this->imageHandle);
405        $height = imagesy($this->imageHandle);
406
407        for ($j = 0; $j < $height; $j++) {
408                $left = 0;
409                $right = $width-1;
410
411
412                while ($left < $right) {
413                    //echo " j:".$j." l:".$left." r:".$right."\n<br>";
414                    $t = imagecolorat($this->imageHandle, $left, $j);
415                    imagesetpixel($this->imageHandle, $left, $j, imagecolorat($this->imageHandle, $right, $j));
416                    imagesetpixel($this->imageHandle, $right, $j, $t);
417                    $left++; $right--;
418                }
419           
420        }
421
422        return true;
423    }
424
425
426    /**
427     * Adjust the image gamma
428     *
429     * @param float $outputgamma
430     *
431     * @return none
432     */
433    function gamma($outputgamma=1.0) {
434        ImageGammaCorrect($this->imageHandle, 1.0, $outputgamma);
435    }
436
437    /**
438     * Save the image file
439     *
440     * @param string  $filename the name of the file to write to
441     * @param int     $quality  output DPI, default is 85
442     * @param string  $types    define the output format, default
443     *                          is the current used format
444     *
445     * @return none
446     */
447    function save($filename, $type = '', $quality = 85)
448    {
449                $type           = $type==''? $this->type : $type;
450                $functionName   = 'image' . $type;
451
452                if(function_exists($functionName))
453                {
454                        $this->old_image = $this->imageHandle;
455                        if($type=='jpeg')
456                                $functionName($this->imageHandle, $filename, $quality);
457                        else
458                                $functionName($this->imageHandle, $filename);
459                        $this->imageHandle = $this->old_image;
460                        $this->resized = false;
461                }
462    } // End save
463
464
465    /**
466     * Display image without saving and lose changes
467     *
468     * @param string type (JPG,PNG...);
469     * @param int quality 75
470     *
471     * @return none
472     */
473    function display($type = '', $quality = 75)
474    {
475        if ($type != '') {
476            $this->type = $type;
477        }
478        $functionName = 'Image' . $this->type;
479                if(function_exists($functionName))
480                {
481                        header('Content-type: image/' . strtolower($this->type));
482                        $functionName($this->imageHandle, '', $quality);
483                        $this->imageHandle = $this->old_image;
484                        $this->resized = false;
485                        ImageDestroy($this->old_image);
486                        $this->free();
487                }
488    }
489
490    /**
491     * Destroy image handle
492     *
493     * @return none
494     */
495    function free()
496    {
497        if ($this->imageHandle){
498            ImageDestroy($this->imageHandle);
499        }
500    }
501
502} // End class ImageGD
503?>
Note: See TracBrowser for help on using the repository browser.