Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
/* vim: set expandtab tabstop=4 shiftwidth=4: */
4
 
5
/**
6
 * GD implementation for Image_Transform package
7
 *
8
 * PHP versions 4 and 5
9
 *
10
 * LICENSE: This source file is subject to version 3.0 of the PHP license
11
 * that is available through the world-wide-web at the following URI:
12
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
13
 * the PHP License and are unable to obtain it through the web, please
14
 * send a note to license@php.net so we can mail you a copy immediately.
15
 *
16
 * @category   Image
17
 * @package    Image_Transform
18
 * @subpackage Image_Transform_Driver_GD
19
 * @author     Alan Knowles <alan@akbkhome.com>
20
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
21
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
22
 * @copyright  2002-2005 The PHP Group
23
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
24
 * @version    CVS: $Id: GD.php,v 1.32 2007/04/19 16:36:09 dufuz Exp $
25
 * @link       http://pear.php.net/package/Image_Transform
26
 */
27
 
28
require_once 'Image/Transform.php';
29
 
30
/**
31
 * GD implementation for Image_Transform package
32
 *
33
 * Usage :
34
 *    $img    =& Image_Transform::factory('GD');
35
 *    $angle  = -78;
36
 *    $img->load('magick.png');
37
 *
38
 *    if ($img->rotate($angle, array(
39
 *               'autoresize' => true,
40
 *               'color_mask' => array(255, 0, 0)))) {
41
 *        $img->addText(array(
42
 *               'text' => 'Rotation ' . $angle,
43
 *               'x' => 0,
44
 *               'y' => 100,
45
 *               'font' => '/usr/share/fonts/default/TrueType/cogb____.ttf'));
46
 *        $img->display();
47
 *    } else {
48
 *        echo "Error";
49
 *    }
50
 *    $img->free();
51
 *
52
 * @category   Image
53
 * @package    Image_Transform
54
 * @subpackage Image_Transform_Driver_GD
55
 * @author     Alan Knowles <alan@akbkhome.com>
56
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
57
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
58
 * @copyright  2002-2005 The PHP Group
59
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
60
 * @version    Release: @package_version@
61
 * @link       http://pear.php.net/package/Image_Transform
62
 * @since      PHP 4.0
63
 */
64
class Image_Transform_Driver_GD extends Image_Transform
65
{
66
    /**
67
     * Holds the image resource for manipulation
68
     *
69
     * @var resource $imageHandle
70
     * @access protected
71
     */
72
    var $imageHandle = null;
73
 
74
    /**
75
     * Holds the original image file
76
     *
77
     * @var resource $imageHandle
78
     * @access protected
79
     */
80
    var $old_image = null;
81
 
82
    /**
83
     * Check settings
84
     */
85
    function Image_Transform_Driver_GD()
86
    {
87
        $this->__construct();
88
    } // End function Image
89
 
90
    /**
91
     * Check settings
92
     *
93
     * @since PHP 5
94
     */
95
    function __construct()
96
    {
97
        if (!PEAR::loadExtension('gd')) {
98
            $this->isError(PEAR::raiseError("GD library is not available.",
99
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED));
100
        } else {
101
            $types = ImageTypes();
102
            if ($types & IMG_PNG) {
103
                $this->_supported_image_types['png'] = 'rw';
104
            }
105
            if (($types & IMG_GIF)
106
                || function_exists('imagegif')) {
107
                $this->_supported_image_types['gif'] = 'rw';
108
            } elseif (function_exists('imagecreatefromgif')) {
109
                $this->_supported_image_types['gif'] = 'r';
110
            }
111
            if ($types & IMG_JPG) {
112
                $this->_supported_image_types['jpeg'] = 'rw';
113
            }
114
            if ($types & IMG_WBMP) {
115
                $this->_supported_image_types['wbmp'] = 'rw';
116
            }
117
            if (!$this->_supported_image_types) {
118
                $this->isError(PEAR::raiseError("No supported image types available", IMAGE_TRANSFORM_ERROR_UNSUPPORTED));
119
            }
120
        }
121
 
122
    } // End function Image
123
 
124
    /**
125
     * Loads an image from file
126
     *
127
     * @param string $image filename
128
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
129
     * @access public
130
     */
131
    function load($image)
132
    {
133
        $this->free();
134
 
135
        $this->image = $image;
136
        $result = $this->_get_image_details($image);
137
        if (PEAR::isError($result)) {
138
            return $result;
139
        }
140
        if (!$this->supportsType($this->type, 'r')) {
141
            return PEAR::raiseError('Image type not supported for input',
142
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
143
        }
144
 
145
        $functionName = 'ImageCreateFrom' . $this->type;
146
        $this->imageHandle = $functionName($this->image);
147
        if (!$this->imageHandle) {
148
            $this->imageHandle = null;
149
            return PEAR::raiseError('Error while loading image file.',
150
                IMAGE_TRANSFORM_ERROR_IO);
151
        }
152
        return true;
153
 
154
    } // End load
155
 
156
    /**
157
     * Adds a border of constant width around an image
158
     *
159
     * @param int $border_width Width of border to add
160
     * @author Peter Bowyer
161
     * @return bool TRUE
162
     * @access public
163
     */
164
    function addBorder($border_width, $color = '')
165
    {
166
        $this->new_x = $this->img_x + 2 * $border_width;
167
        $this->new_y = $this->img_y + 2 * $border_width;
168
 
169
        $new_img = $this->_createImage($new_x, $new_y, $this->true_color);
170
 
171
        $options = array('pencilColor', $color);
172
        $color = $this->_getColor('pencilColor', $options, array(0, 0, 0));
173
        if ($color) {
174
            if ($this->true_color) {
175
                $c = imagecolorresolve($this->imageHandle, $color[0], $color[1], $color[2]);
176
                imagefill($new_img, 0, 0, $c);
177
            } else {
178
                imagecolorset($new_img, imagecolorat($new_img, 0, 0), $color[0], $color[1], $color[2]);
179
            }
180
        }
181
        ImageCopy($new_img, $this->imageHandle, $border_width, $border_width, 0, 0, $this->img_x, $this->img_y);
182
        $this->imageHandle = $new_img;
183
        $this->resized = true;
184
 
185
        return true;
186
    }
187
 
188
    /**
189
     * addText
190
     *
191
     * @param   array   $params     Array contains options
192
     *                              array(
193
     *                                  'text'  The string to draw
194
     *                                  'x'     Horizontal position
195
     *                                  'y'     Vertical Position
196
     *                                  'color' Font color
197
     *                                  'font'  Font to be used
198
     *                                  'size'  Size of the fonts in pixel
199
     *                                  'resize_first'  Tell if the image has to be resized
200
     *                                                  before drawing the text
201
     *                              )
202
     *
203
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
204
     */
205
    function addText($params)
206
    {
207
        $params = array_merge($this->_get_default_text_params(), $params);
208
        extract($params);
209
 
210
        $options = array('fontColor' => $color);
211
        $color = $this->_getColor('fontColor', $options, array(0, 0, 0));
212
 
213
        $c = imagecolorresolve ($this->imageHandle, $color[0], $color[1], $color[2]);
214
 
215
        if ('ttf' == substr($font, -3)) {
216
            ImageTTFText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text);
217
        } else {
218
            ImagePSText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text);
219
        }
220
        return true;
221
    } // End addText
222
 
223
    /**
224
     * Rotates image by the given angle
225
     *
226
     * Uses a fast rotation algorythm for custom angles
227
     * or lines copy for multiple of 90 degrees
228
     *
229
     * @param int   $angle   Rotation angle
230
     * @param array $options array(
231
     *                             'canvasColor' => array(r ,g, b), named color or #rrggbb
232
     *                            )
233
     * @author Pierre-Alain Joye
234
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
235
     * @access public
236
     */
237
    function rotate($angle, $options = null)
238
    {
239
        if (($angle % 360) == 0) {
240
            return true;
241
        }
242
 
243
        $color_mask = $this->_getColor('canvasColor', $options,
244
                                        array(255, 255, 255));
245
 
246
        $mask   = imagecolorresolve($this->imageHandle, $color_mask[0], $color_mask[1], $color_mask[2]);
247
 
248
        $this->old_image   = $this->imageHandle;
249
 
250
        // Multiply by -1 to change the sign, so the image is rotated clockwise
251
        $this->imageHandle = ImageRotate($this->imageHandle, $angle * -1, $mask);
252
        return true;
253
    }
254
 
255
    /**
256
     * Horizontal mirroring
257
     *
258
     * @return mixed TRUE or PEAR_Error object on error
259
     * @access public
260
     * @see flip()
261
     **/
262
    function mirror()
263
    {
264
        $new_img = $this->_createImage();
265
        for ($x = 0; $x < $this->new_x; ++$x) {
266
            imagecopy($new_img, $this->imageHandle, $x, 0,
267
                $this->new_x - $x - 1, 0, 1, $this->new_y);
268
        }
269
        imagedestroy($this->imageHandle);
270
        $this->imageHandle = $new_img;
271
        return true;
272
    }
273
 
274
    /**
275
     * Vertical mirroring
276
     *
277
     * @return TRUE or PEAR Error object on error
278
     * @access public
279
     * @see mirror()
280
     **/
281
    function flip()
282
    {
283
        $new_img = $this->_createImage();
284
        for ($y = 0; $y < $this->new_y; ++$y) {
285
            imagecopy($new_img, $this->imageHandle, 0, $y,
286
                0, $this->new_y - $y - 1, $this->new_x, 1);
287
        }
288
        imagedestroy($this->imageHandle);
289
        $this->imageHandle = $new_img;
290
 
291
        /* for very large images we may want to use the following
292
           Needs to find out what is the threshhold
293
        for ($x = 0; $x < $this->new_x; ++$x) {
294
            for ($y1 = 0; $y1 < $this->new_y / 2; ++$y1) {
295
                $y2 = $this->new_y - 1 - $y1;
296
                $color1 = imagecolorat($this->imageHandle, $x, $y1);
297
                $color2 = imagecolorat($this->imageHandle, $x, $y2);
298
                imagesetpixel($this->imageHandle, $x, $y1, $color2);
299
                imagesetpixel($this->imageHandle, $x, $y2, $color1);
300
            }
301
        } */
302
        return true;
303
    }
304
 
305
    /**
306
     * Crops image by size and start coordinates
307
     *
308
     * @param int width Cropped image width
309
     * @param int height Cropped image height
310
     * @param int x X-coordinate to crop at
311
     * @param int y Y-coordinate to crop at
312
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
313
     * @access public
314
     */
315
    function crop($width, $height, $x = 0, $y = 0)
316
    {
317
        // Sanity check
318
        if (!$this->intersects($width, $height, $x, $y)) {
319
            return PEAR::raiseError('Nothing to crop', IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
320
        }
321
        $x = min($this->new_x, max(0, $x));
322
        $y = min($this->new_y, max(0, $y));
323
        $width   = min($width,  $this->new_x - $x);
324
        $height  = min($height, $this->new_y - $y);
325
        $new_img = $this->_createImage($width, $height);
326
 
327
        if (!imagecopy($new_img, $this->imageHandle, 0, 0, $x, $y, $width, $height)) {
328
            imagedestroy($new_img);
329
            return PEAR::raiseError('Failed transformation: crop()',
330
                IMAGE_TRANSFORM_ERROR_FAILED);
331
        }
332
 
333
        $this->old_image = $this->imageHandle;
334
        $this->imageHandle = $new_img;
335
        $this->resized = true;
336
 
337
        $this->new_x = $width;
338
        $this->new_y = $height;
339
        return true;
340
    }
341
 
342
    /**
343
     * Converts the image to greyscale
344
     *
345
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
346
     * @access public
347
     */
348
    function greyscale() {
349
        imagecopymergegray($this->imageHandle, $this->imageHandle, 0, 0, 0, 0, $this->new_x, $this->new_y, 0);
350
        return true;
351
    }
352
 
353
   /**
354
    * Resize Action
355
    *
356
    * For GD 2.01+ the new copyresampled function is used
357
    * It uses a bicubic interpolation algorithm to get far
358
    * better result.
359
    *
360
    * Options:
361
    *  - scaleMethod: "pixel" or "smooth"
362
    *
363
    * @param int   $new_x   New width
364
    * @param int   $new_y   New height
365
    * @param mixed $options Optional parameters
366
    *
367
    * @return bool|PEAR_Error TRUE on success or PEAR_Error object on error
368
    * @access protected
369
    */
370
    function _resize($new_x, $new_y, $options = null)
371
    {
372
        if ($this->resized === true) {
373
            return PEAR::raiseError('You have already resized the image without saving it.  Your previous resizing will be overwritten', null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);
374
        }
375
 
376
        if ($this->new_x == $new_x && $this->new_y == $new_y) {
377
            return true;
378
        }
379
 
380
        $scaleMethod = $this->_getOption('scaleMethod', $options, 'smooth');
381
 
382
        // Make sure to get a true color image if doing resampled resizing
383
        // otherwise get the same type of image
384
        $trueColor = ($scaleMethod == 'pixel') ? null : true;
385
        $new_img = $this->_createImage($new_x, $new_y, $trueColor);
386
 
387
        $icr_res = null;
388
        if ($scaleMethod != 'pixel' && function_exists('ImageCopyResampled')) {
389
            $icr_res = ImageCopyResampled($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y);
390
        }
391
        if (!$icr_res) {
392
            ImageCopyResized($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y);
393
        }
394
        $this->old_image = $this->imageHandle;
395
        $this->imageHandle = $new_img;
396
        $this->resized = true;
397
 
398
        $this->new_x = $new_x;
399
        $this->new_y = $new_y;
400
        return true;
401
    }
402
 
403
    /**
404
     * Adjusts the image gamma
405
     *
406
     * @param float $outputgamma
407
     *
408
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
409
     * @access public
410
     */
411
    function gamma($outputgamma = 1.0)
412
    {
413
        if ($outputgamma != 1.0) {
414
            ImageGammaCorrect($this->imageHandle, 1.0, $outputgamma);
415
        }
416
        return true;
417
    }
418
 
419
    /**
420
     * Helper method to save to a file or output the image
421
     *
422
     * @param string $filename the name of the file to write to (blank to output)
423
     * @param string $types    define the output format, default
424
     *                          is the current used format
425
     * @param int    $quality  output DPI, default is 75
426
     *
427
     * @return bool|PEAR_Error TRUE on success or PEAR_Error object on error
428
     * @access protected
429
     */
430
    function _generate($filename, $type = '', $quality = null)
431
    {
432
        $type = strtolower(($type == '') ? $this->type : $type);
433
        $options = (is_array($quality)) ? $quality : array();
434
        switch ($type) {
435
            case 'jpg':
436
                $type = 'jpeg';
437
            case 'jpeg':
438
                if (is_numeric($quality)) {
439
                    $options['quality'] = $quality;
440
                }
441
                $quality = $this->_getOption('quality', $options, 75);
442
                break;
443
        }
444
        if (!$this->supportsType($type, 'w')) {
445
            return PEAR::raiseError('Image type not supported for output',
446
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
447
        }
448
 
449
        if ($filename == '') {
450
            header('Content-type: ' . $this->getMimeType($type));
451
            $action = 'output image';
452
        } else {
453
            $action = 'save image to file';
454
        }
455
 
456
        $functionName = 'image' . $type;
457
        switch ($type) {
458
            case 'jpeg':
459
                $result = $functionName($this->imageHandle, $filename, $quality);
460
                break;
461
            default:
462
                if ($filename == '') {
463
                    $result = $functionName($this->imageHandle);
464
                } else {
465
                    $result = $functionName($this->imageHandle, $filename);
466
                }
467
        }
468
        if (!$result) {
469
            return PEAR::raiseError('Couldn\'t ' . $action,
470
                IMAGE_TRANSFORM_ERROR_IO);
471
        }
472
        $this->imageHandle = $this->old_image;
473
        if (!$this->keep_settings_on_save) {
474
            $this->free();
475
        }
476
        return true;
477
 
478
    } // End save
479
 
480
    /**
481
     * Displays image without saving and lose changes.
482
     *
483
     * This method adds the Content-type HTTP header
484
     *
485
     * @param string $type (JPEG, PNG...);
486
     * @param int    $quality 75
487
     *
488
     * @return bool|PEAR_Error TRUE or PEAR_Error object on error
489
     * @access public
490
     */
491
    function display($type = '', $quality = null)
492
    {
493
        return $this->_generate('', $type, $quality);;
494
    }
495
 
496
    /**
497
     * Saves the image to a file
498
     *
499
     * @param string $filename the name of the file to write to
500
     * @param string $type     the output format, default
501
     *                          is the current used format
502
     * @param int    $quality  default is 75
503
     *
504
     * @return bool|PEAR_Error TRUE on success or PEAR_Error object on error
505
     * @access public
506
     */
507
    function save($filename, $type = '', $quality = null)
508
    {
509
        if (!trim($filename)) {
510
            return PEAR::raiseError('Filename missing',
511
                IMAGE_TRANSFORM_ERROR_ARGUMENT);
512
        }
513
        return $this->_generate($filename, $type, $quality);
514
    }
515
 
516
    /**
517
     * Destroys image handle
518
     *
519
     * @access public
520
     */
521
    function free()
522
    {
523
        $this->resized = false;
524
        if (is_resource($this->imageHandle)) {
525
            ImageDestroy($this->imageHandle);
526
        }
527
        $this->imageHandle = null;
528
        if (is_resource($this->old_image)){
529
            ImageDestroy($this->old_image);
530
        }
531
        $this->old_image = null;
532
    }
533
 
534
    /**
535
     * Returns a new image for temporary processing
536
     *
537
     * @param int $width width of the new image
538
     * @param int $height height of the new image
539
     * @param bool $trueColor force which type of image to create
540
     * @return resource a GD image resource
541
     * @access protected
542
     */
543
    function _createImage($width = -1, $height = -1, $trueColor = null)
544
    {
545
        if ($width == -1) {
546
            $width = $this->new_x;
547
        }
548
        if ($height == -1) {
549
            $height = $this->new_y;
550
        }
551
 
552
        $new_img = null;
553
        if (is_null($trueColor)) {
554
            if (function_exists('imageistruecolor')) {
555
                $createtruecolor = imageistruecolor($this->imageHandle);
556
            } else {
557
                $createtruecolor = true;
558
            }
559
        } else {
560
            $createtruecolor = $trueColor;
561
        }
562
        if ($createtruecolor
563
            && function_exists('ImageCreateTrueColor')) {
564
            $new_img = @ImageCreateTrueColor($width, $height);
565
        }
566
        if (!$new_img) {
567
            $new_img = ImageCreate($width, $height);
568
            imagepalettecopy($new_img, $this->imageHandle);
569
            $color = imagecolortransparent($this->imageHandle);
570
            if ($color != -1) {
571
                imagecolortransparent($new_img, $color);
572
                imagefill($new_img, 0, 0, $color);
573
            }
574
        }
575
        return $new_img;
576
    }
577
}