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
 * Simple and cross-library package to doing image transformations and
7
 * manipulations.
8
 *
9
 * PHP versions 4 and 5
10
 *
11
 * LICENSE: This source file is subject to version 3.0 of the PHP license
12
 * that is available through the world-wide-web at the following URI:
13
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
14
 * the PHP License and are unable to obtain it through the web, please
15
 * send a note to license@php.net so we can mail you a copy immediately.
16
 *
17
 * @category   Image
18
 * @package    Image_Transform
19
 * @author     Vincent Oostindie <vincent@sunlight.tmfweb.nl>
20
 * @author     Alan Knowles <alan@akbkhome.com>
21
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
22
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
23
 * @copyright  2002-2007 The PHP Group
24
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
25
 * @version    CVS: $Id: Transform.php,v 1.42 2007/04/19 16:17:57 dufuz Exp $
26
 * @link       http://pear.php.net/package/Image_Transform
27
 */
28
 
29
/**
30
 * Include for error handling
31
 */
32
require_once 'PEAR.php';
33
 
34
/**
35
 * Error code for unsupported library, image format or methods
36
 */
37
define('IMAGE_TRANSFORM_ERROR_UNSUPPORTED', 1);
38
 
39
/**
40
 * Error code for failed transformation operations
41
 */
42
define('IMAGE_TRANSFORM_ERROR_FAILED', 2);
43
 
44
/**
45
 * Error code for failed i/o (Input/Output) operations
46
 */
47
define('IMAGE_TRANSFORM_ERROR_IO', 3);
48
 
49
/**
50
 * Error code for invalid arguments
51
 */
52
define('IMAGE_TRANSFORM_ERROR_ARGUMENT', 4);
53
 
54
/**
55
 * Error code for out-of-bound related errors
56
 */
57
define('IMAGE_TRANSFORM_ERROR_OUTOFBOUND', 5);
58
 
59
 
60
 
61
/**
62
 * Base class with factory method for backend driver
63
 *
64
 * The main "Image_Transform" class is a container and base class which
65
 * provides a static method for creating an Image object as well as
66
 * some utility functions (maths) common to all parts of Image_Transform.
67
 *
68
 * @category   Image
69
 * @package    Image_Transform
70
 * @author     Alan Knowles <alan@akbkhome.com>
71
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
72
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
73
 * @copyright  2002-2007 The PHP Group
74
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
75
 * @version    Release: @package_version@
76
 * @link       http://pear.php.net/package/Image_Transform
77
 * @since      PHP 4.0
78
 */
79
class Image_Transform
80
{
81
    /**
82
     * Name of the image file
83
     * @var string
84
     */
85
    var $image = '';
86
 
87
    /**
88
     * Type of the image file (eg. jpg, gif png ...)
89
     * @var string
90
     */
91
    var $type = '';
92
 
93
    /**
94
     * Original image width in x direction
95
     * @var int
96
     */
97
    var $img_x = '';
98
 
99
    /**
100
     * Original image width in y direction
101
     * @var int
102
     */
103
    var $img_y = '';
104
 
105
    /**
106
     * New image width in x direction
107
     * @var int
108
     */
109
    var $new_x = '';
110
 
111
    /**
112
     * New image width in y direction
113
     * @var int
114
     */
115
    var $new_y = '';
116
 
117
    /**
118
     * Path to the library used
119
     * e.g. /usr/local/ImageMagick/bin/ or
120
     * /usr/local/netpbm/
121
     */
122
    var $lib_path = '';
123
 
124
    /**
125
     * Flag to warn if image has been resized more than once before displaying
126
     * or saving.
127
     */
128
    var $resized = false;
129
 
130
    /**
131
     * @var array General options
132
     * @access protected
133
     */
134
    var $_options = array(
135
        'quality'     => 75,
136
        'scaleMethod' => 'smooth',
137
        'canvasColor' => array(255, 255, 255),
138
        'pencilColor' => array(0, 0, 0),
139
        'textColor'   => array(0, 0, 0)
140
        );
141
 
142
    /**
143
     * Flag for whether settings should be discarded on saving/display of image
144
     * @var bool
145
     * @see Image_Transform::keepSettingsOnSave
146
     */
147
    var $keep_settings_on_save = false;
148
 
149
    /**
150
     * Supported image types
151
     * @var array
152
     * @access protected
153
     */
154
    var $_supported_image_types = array();
155
 
156
    /**
157
     * Initialization error tracking
158
     * @var object
159
     * @access private
160
     **/
161
    var $_error = null;
162
 
163
    /**
164
     * associative array that tracks existence of programs
165
     * (for drivers using shell interface and a tiny performance
166
     * improvement if the clearstatcache() is used)
167
     * @var array
168
     * @access protected
169
     */
170
    var $_programs = array();
171
 
172
     /**
173
      * Default parameters used in the addText methods.
174
      */
175
     var $default_text_params = array('text' => 'Default text',
176
                                      'x'     => 10,
177
                                      'y'     => 20,
178
                                      'color' => 'red',
179
                                      'font'  => 'Arial.ttf',
180
                                      'size'  => '12',
181
                                      'angle' => 0,
182
                                      'resize_first' => false);
183
 
184
    /**
185
     * Creates a new Image_Transform object
186
     *
187
     * @param string $driver name of driver class to initialize. If no driver
188
     *               is specified the factory will attempt to use 'Imagick' first
189
     *               then 'GD' second, then 'Imlib' last
190
     *
191
     * @return object an Image_Transform object, or PEAR_Error on error
192
     *
193
     * @see PEAR::isError()
194
     * @see Image_Transform::setOption()
195
     */
196
    function &factory($driver = '')
197
    {
198
        if ($driver == '') {
199
            $extensions = array(
200
                'imagick' => 'Imagick2',
201
                'gd'      => 'GD',
202
                'imlib'   => 'Imlib');
203
 
204
            foreach ($extensions as $ext => $ext_driver) {
205
                if (PEAR::loadExtension($ext)) {
206
                    $driver = $ext_driver;
207
                    break;
208
                }
209
            }
210
            if (!$driver) {
211
                return PEAR::raiseError('No image library specified and none can be found.  You must specify driver in factory() call.',
212
                    IMAGE_TRANSFORM_ERROR_ARGUMENT);
213
            }
214
        }
215
        @include_once 'Image/Transform/Driver/' . basename($driver) . '.php';
216
 
217
        $classname = "Image_Transform_Driver_{$driver}";
218
        if (!class_exists($classname)) {
219
            return PEAR::raiseError('Image library not supported... aborting.',
220
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
221
        }
222
        $obj =& new $classname;
223
 
224
        // Check startup error
225
        if ($error =& $obj->isError()) {
226
            $obj =& $error;
227
        }
228
        return $obj;
229
    }
230
 
231
    /**
232
     * Returns/sets an error when the instance couldn't initialize properly
233
     *
234
     * @param  object PEAR_Error object when setting an error
235
     * @return mixed FALSE or PEAR_Error object
236
     * @access protected
237
     */
238
    function &isError($error = null)
239
    {
240
        if (!is_null($error)) {
241
            $this->_error =& $error;
242
        }
243
        return $this->_error;
244
    }
245
 
246
    /**
247
     * Resizes the image in the X and/or Y direction(s)
248
     *
249
     * If either is 0 it will keep the original size for that dimension
250
     *
251
     * @param mixed $new_x (0, number, percentage 10% or 0.1)
252
     * @param mixed $new_y (0, number, percentage 10% or 0.1)
253
     * @param array $options Options
254
     * @return mixed TRUE or PEAR_Error object on error
255
     * @access public
256
     */
257
    function resize($new_x = 0, $new_y = 0, $options = null)
258
    {
259
        // 0 means keep original size
260
        $new_x = (0 == $new_x)
261
                 ? $this->img_x
262
                 : $this->_parse_size($new_x, $this->img_x);
263
        $new_y = (0 == $new_y)
264
                 ? $this->img_y
265
                 : $this->_parse_size($new_y, $this->img_y);
266
 
267
        // Now do the library specific resizing.
268
        return $this->_resize($new_x, $new_y, $options);
269
    } // End resize
270
 
271
 
272
    /**
273
     * Scales the image to the specified width
274
     *
275
     * This method preserves the aspect ratio
276
     *
277
     * @param int $new_x Size to scale X-dimension to
278
     * @return mixed TRUE or PEAR_Error object on error
279
     * @access public
280
     */
281
    function scaleByX($new_x)
282
    {
283
        if ($new_x <= 0) {
284
            return PEAR::raiseError('New size must be strictly positive',
285
                                        IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
286
        }
287
        $new_y = round(($new_x / $this->img_x) * $this->img_y, 0);
288
        return $this->_resize(max(1, $new_x), max(1, $new_y));
289
    } // End scaleByX
290
 
291
    /**
292
     * Alias for resize()
293
     *
294
     * @see resize()
295
     */
296
    function scaleByXY($new_x = 0, $new_y = 0, $options = null)
297
    {
298
        return $this->resize($new_x, $new_y, $options);
299
    } // End scaleByXY
300
 
301
    /**
302
     * Scales the image to the specified height.
303
     *
304
     * This method preserves the aspect ratio
305
     *
306
     * @param int $new_y Size to scale Y-dimension to
307
     * @return mixed TRUE or PEAR_Error object on error
308
     * @access public
309
     */
310
    function scaleByY($new_y)
311
    {
312
        if ($new_y <= 0) {
313
            return PEAR::raiseError('New size must be strictly positive',
314
                                        IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
315
        }
316
        $new_x = round(($new_y / $this->img_y) * $this->img_x, 0);
317
        return $this->_resize(max(1, $new_x), max(1, $new_y));
318
    } // End scaleByY
319
 
320
    /**
321
     * Scales an image by a percentage, factor or a given length
322
     *
323
     * This method preserves the aspect ratio
324
     *
325
     * @param mixed (number, percentage 10% or 0.1)
326
     * @return mixed TRUE or PEAR_Error object on error
327
     * @access public
328
     * @see scaleByPercentage, scaleByFactor, scaleByLength
329
     */
330
    function scale($size)
331
    {
332
        if ((strlen($size) > 1) && (substr($size, -1) == '%')) {
333
            return $this->scaleByPercentage(substr($size, 0, -1));
334
        } elseif ($size < 1) {
335
            return $this->scaleByFactor($size);
336
        } else {
337
            return $this->scaleByLength($size);
338
        }
339
    } // End scale
340
 
341
    /**
342
     * Scales an image to a percentage of its original size.  For example, if
343
     * my image was 640x480 and I called scaleByPercentage(10) then the image
344
     * would be resized to 64x48
345
     *
346
     * @param  int $size Percentage of original size to scale to
347
     * @return mixed TRUE or PEAR_Error object on error
348
     * @access public
349
     */
350
    function scaleByPercentage($size)
351
    {
352
        return $this->scaleByFactor($size / 100);
353
    } // End scaleByPercentage
354
 
355
    /**
356
     * Scales an image to a factor of its original size.  For example, if
357
     * my image was 640x480 and I called scaleByFactor(0.5) then the image
358
     * would be resized to 320x240.
359
     *
360
     * @param float $size Factor of original size to scale to
361
     * @return mixed TRUE or PEAR_Error object on error
362
     * @access public
363
     */
364
    function scaleByFactor($size)
365
    {
366
        if ($size <= 0) {
367
            return PEAR::raiseError('New size must be strictly positive',
368
                                        IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
369
        }
370
        $new_x = round($size * $this->img_x, 0);
371
        $new_y = round($size * $this->img_y, 0);
372
        return $this->_resize(max(1, $new_x), max(1, $new_y));
373
    } // End scaleByFactor
374
 
375
    /**
376
     * Scales an image so that the longest side has the specified dimension.
377
     *
378
     * This method preserves the aspect ratio
379
     *
380
     * @param int $size Max dimension in pixels
381
     * @return mixed TRUE or PEAR_Error object on error
382
     * @access public
383
     */
384
    function scaleMaxLength($size)
385
    {
386
        if ($size <= 0) {
387
            return PEAR::raiseError('New size must be strictly positive',
388
                                        IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
389
        }
390
        if ($this->img_x >= $this->img_y) {
391
            $new_x = $size;
392
            $new_y = round(($new_x / $this->img_x) * $this->img_y, 0);
393
        } else {
394
            $new_y = $size;
395
            $new_x = round(($new_y / $this->img_y) * $this->img_x, 0);
396
        }
397
        return $this->_resize(max(1, $new_x), max(1, $new_y));
398
    } // End scaleMaxLength
399
 
400
    /**
401
     * Alias for scaleMaxLength
402
     *
403
     * @return mixed TRUE or PEAR_Error object on error
404
     * @access public
405
     * @see scaleMaxLength()
406
     */
407
    function scaleByLength($size)
408
    {
409
        return $this->scaleMaxLength($size);
410
    }
411
 
412
    /**
413
     * Fits the image in the specified box size
414
     *
415
     * If the image is bigger than the box specified by $width and $height,
416
     * it will be scaled down to fit inside of it.
417
     * If the image is smaller, nothing is done.
418
     *
419
     * @param  integer $width
420
     * @param  integer $height
421
     * @return bool|PEAR_Error TRUE or PEAR_Error object on error
422
     * @access public
423
     */
424
    function fit($width, $height)
425
    {
426
        if ($width <= 0 || $height <= 0) {
427
            return PEAR::raiseError("Invalid arguments.",
428
                IMAGE_TRANSFORM_ERROR_ARGUMENT);
429
        }
430
        $x = $this->img_x / $width;
431
        $y = $this->img_y / $height;
432
        if ($x <= 1 && $y <= 1) {
433
            return true;
434
        } elseif ($x > $y) {
435
            return $this->scaleByX($width);
436
        } else {
437
            return $this->scaleByY($height);
438
        }
439
    }
440
 
441
    /**
442
     * Fits the image in the specified width
443
     *
444
     * If the image is wider than the width specified by $width,
445
     * it will be scaled down to fit inside of it.
446
     * If the image is smaller, nothing is done.
447
     *
448
     * @param integer $width
449
     * @return bool|PEAR_Error TRUE or PEAR_Error object on error
450
     * @access public
451
     */
452
    function fitX($width)
453
    {
454
        return ($this->img_x <= $width) ? true : $this->scaleByX($width);
455
    }
456
 
457
    /**
458
     * Fits the image in the specified height
459
     *
460
     * If the image is taller than the height specified by $height,
461
     * it will be scaled down to fit inside of it.
462
     * If the image is smaller, nothing is done.
463
     *
464
     * @param integer $height
465
     * @return bool|PEAR_Error TRUE or PEAR_Error object on error
466
     * @access public
467
     */
468
    function fitY($height)
469
    {
470
        return ($this->img_y <= $height) ? true : $this->scaleByY($height);
471
    }
472
 
473
    /**
474
     * Sets one options
475
     *
476
     * @param  string Name of option
477
     * @param  mixed  Value of option
478
     * @access public
479
     * @see setOptions()
480
     */
481
    function setOption($name, $value)
482
    {
483
        $this->_options[$name] = $value;
484
    }
485
 
486
    /**
487
     * Sets multiple options at once
488
     *
489
     * Associative array of options:
490
     *  - quality     (Integer: 0: poor - 100: best)
491
     *  - scaleMethod ('smooth', 'pixel')
492
     *
493
     * @param  array $options Array of options
494
     * @access public
495
     */
496
    function setOptions($options)
497
    {
498
        $this->_options = array_merge($this->_options, $options);
499
    }
500
 
501
    /**
502
     * Sets the image type (in lowercase letters), the image height and width.
503
     *
504
     * @return mixed TRUE or PEAR_error
505
     * @access protected
506
     * @see PHP_Compat::image_type_to_mime_type()
507
     * @link http://php.net/getimagesize
508
     */
509
    function _get_image_details($image)
510
    {
511
        $data = @getimagesize($image);
512
        //  1 = GIF,   2 = JPG,  3 = PNG,  4 = SWF,  5 = PSD,  6 = BMP,
513
        //  7 = TIFF (intel byte order),   8 = TIFF (motorola byte order),
514
        //  9 = JPC,  10 = JP2, 11 = JPX, 12 = JB2, 13 = SWC, 14 = IFF,
515
        // 15 = WBMP, 16 = XBM
516
        if (!is_array($data)) {
517
            return PEAR::raiseError("Cannot fetch image or images details.", true);
518
        }
519
 
520
        switch ($data[2]) {
521
            case IMAGETYPE_GIF:
522
                $type = 'gif';
523
                break;
524
            case IMAGETYPE_JPEG:
525
                $type = 'jpeg';
526
                break;
527
            case IMAGETYPE_PNG:
528
                $type = 'png';
529
                break;
530
            case IMAGETYPE_SWF:
531
                $type = 'swf';
532
                break;
533
            case IMAGETYPE_PSD:
534
                $type = 'psd';
535
                break;
536
            case IMAGETYPE_BMP:
537
                $type = 'bmp';
538
                break;
539
            case IMAGETYPE_TIFF_II:
540
            case IMAGETYPE_TIFF_MM:
541
                $type = 'tiff';
542
                break;
543
            case IMAGETYPE_JPC:
544
                $type = 'jpc';
545
                break;
546
            case IMAGETYPE_JP2:
547
                $type = 'jp2';
548
                break;
549
            case IMAGETYPE_JPX:
550
                $type = 'jpx';
551
                break;
552
            case IMAGETYPE_JB2:
553
                $type = 'jb2';
554
                break;
555
            case IMAGETYPE_SWC:
556
                $type = 'swc';
557
                break;
558
            case IMAGETYPE_IFF:
559
                $type = 'iff';
560
                break;
561
            case IMAGETYPE_WBMP:
562
                $type = 'wbmp';
563
                break;
564
            case IMAGETYPE_XBM:
565
                $type = 'xbm';
566
                break;
567
            default:
568
                return PEAR::raiseError("Cannot recognize image format",
569
                    IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
570
        }
571
        $this->img_x = $this->new_x = $data[0];
572
        $this->img_y = $this->new_y = $data[1];
573
        $this->type  = $type;
574
 
575
        return true;
576
    }
577
 
578
 
579
    /**
580
     * Returns the matching IMAGETYPE_* constant for a given image type
581
     *
582
     * @param  mixed $type String (GIF, JPG,...)
583
     * @return mixed string or integer or input on error
584
     * @access protected
585
     * @see PHP_Compat::image_type_to_mime_type()
586
     **/
587
    function _convert_image_type($type)
588
    {
589
        switch (strtolower($type)) {
590
            case 'gif':
591
                return IMAGETYPE_GIF;
592
            case 'jpeg':
593
            case 'jpg':
594
                return IMAGETYPE_JPEG;
595
            case 'png':
596
                return IMAGETYPE_PNG;
597
            case 'swf':
598
                return IMAGETYPE_SWF;
599
            case 'psd':
600
                return IMAGETYPE_PSD;
601
            case 'bmp':
602
                return IMAGETYPE_BMP;
603
            case 'tiff':
604
                return IMAGETYPE_TIFF_II;
605
                //IMAGETYPE_TIFF_MM;
606
            case 'jpc':
607
                return IMAGETYPE_JPC;
608
            case 'jp2':
609
                return IMAGETYPE_JP2;
610
            case 'jpx':
611
                return IMAGETYPE_JPX;
612
            case 'jb2':
613
                return IMAGETYPE_JB2;
614
            case 'swc':
615
                return IMAGETYPE_SWC;
616
            case 'iff':
617
                return IMAGETYPE_IFF;
618
            case 'wbmp':
619
                return IMAGETYPE_WBMP;
620
            case 'xbm':
621
                return IMAGETYPE_XBM;
622
            default:
623
                return $type;
624
        }
625
 
626
        return (isset($types[$t = strtolower($type)])) ? $types[$t] : $type;
627
    }
628
 
629
 
630
    /**
631
     * Parses input for number format and convert
632
     *
633
     * If either parameter is 0 it will be scaled proportionally
634
     *
635
     * @param mixed $new_size (0, number, percentage 10% or 0.1)
636
     * @param int $old_size
637
     * @return mixed Integer or PEAR_error
638
     * @access protected
639
     */
640
    function _parse_size($new_size, $old_size)
641
    {
642
        if (substr($new_size, -1) == '%') {
643
            $new_size = substr($new_size, 0, -1);
644
            $new_size = $new_size / 100;
645
        }
646
        if ($new_size > 1) {
647
            return (int) $new_size;
648
        } elseif ($new_size == 0) {
649
            return (int) $old_size;
650
        } else {
651
            return (int) round($new_size * $old_size, 0);
652
        }
653
    }
654
 
655
    /**
656
     * Returns an angle between 0 and 360 from any angle value
657
     *
658
     * @param  float $angle The angle to normalize
659
     * @return float the angle
660
     * @access protected
661
     */
662
    function _rotation_angle($angle)
663
    {
664
        $angle %= 360;
665
        return ($angle < 0) ? $angle + 360 : $angle;
666
    }
667
 
668
    /**
669
     * Returns the current value of $this->default_text_params.
670
     *
671
     * @return array $this->default_text_params The current text parameters
672
     * @access protected
673
     */
674
    function _get_default_text_params()
675
    {
676
        return $this->default_text_params;
677
    }
678
 
679
    /**
680
     * Sets the image width
681
     *
682
     * @param int $size dimension to set
683
     * @access protected
684
     * @since 29/05/02 13:36:31
685
     */
686
    function _set_img_x($size)
687
    {
688
        $this->img_x = $size;
689
    }
690
 
691
    /**
692
     * Sets the image height
693
     *
694
     * @param int $size dimension to set
695
     * @access protected
696
     * @since 29/05/02 13:36:31
697
     */
698
    function _set_img_y($size)
699
    {
700
        $this->img_y = $size;
701
    }
702
 
703
    /**
704
     * Sets the new image width
705
     *
706
     * @param int $size dimension to set
707
     * @access protected
708
     * @since 29/05/02 13:36:31
709
     */
710
    function _set_new_x($size)
711
    {
712
        $this->new_x = $size;
713
    }
714
 
715
    /**
716
     * Sets the new image height
717
     *
718
     * @param int $size dimension to set
719
     * @since 29/05/02 13:36:31
720
     * @access protected
721
     */
722
    function _set_new_y($size)
723
    {
724
        $this->new_y = $size;
725
    }
726
 
727
    /**
728
     * Returns the type of the image being manipulated
729
     *
730
     * @return string the image type
731
     * @access public
732
     */
733
    function getImageType()
734
    {
735
        return $this->type;
736
    }
737
 
738
    /**
739
     * Returns the MIME type of the image being manipulated
740
     *
741
     * @param  string $type Image type to get MIME type for
742
     * @return string The MIME type if available, or an empty string
743
     * @access public
744
     * @see PHP_Compat::image_type_to_mime_type()
745
     * @link http://php.net/image_type_to_mime_type
746
     */
747
    function getMimeType($type = null)
748
    {
749
        return image_type_to_mime_type($this->_convert_image_type(($type) ? $type : $this->type));
750
    }
751
 
752
    /**
753
     * Returns the image width
754
     *
755
     * @return int the width of the image
756
     * @access public
757
     */
758
    function getImageWidth()
759
    {
760
        return $this->img_x;
761
    }
762
 
763
    /**
764
      * Returns the image height
765
      *
766
      * @return int the width of the image
767
      * @access public
768
      */
769
    function getImageHeight()
770
    {
771
        return $this->img_y;
772
    }
773
 
774
    /**
775
     * Returns the image size and extra format information
776
     *
777
     * @return array The width and height of the image
778
     * @access public
779
     * @see PHP::getimagesize()
780
     */
781
    function getImageSize()
782
    {
783
        return array(
784
            $this->img_x,
785
            $this->img_y,
786
            $this->_convert_image_type($this->type),
787
            'height="' . $this->img_y . '" width="' . $this->img_x . '"',
788
            'mime' => $this->getMimeType());
789
    }
790
 
791
    /**
792
     * This looks at the current image type and attempts to determine which
793
     * web-safe format will be most suited.  It does not work brilliantly with
794
     * *.png images, because it is very difficult to know whether they are
795
     * 8-bit or greater.  Guess I need to have fatter code here :-)
796
     *
797
     * @return string web-safe image type
798
     * @access public
799
     */
800
    function getWebSafeFormat()
801
    {
802
        switch ($this->type){
803
            case 'gif':
804
            case 'png':
805
                return 'png';
806
                break;
807
            default:
808
                return 'jpeg';
809
        } // switch
810
    }
811
 
812
    /**
813
     * Handles space in path and Windows/UNIX difference
814
     *
815
     * @param  string $path Base dir
816
     * @param  string $command Command to execute
817
     * @param  string $args Arguments to pass to the command
818
     * @return string A prepared string suitable for exec()
819
     * @access protected
820
     */
821
    function _prepare_cmd($path, $command, $args = '')
822
    {
823
        if (!OS_WINDOWS
824
            || !preg_match('/\s/', $path)) {
825
            return $path . $command . ' ' . $args;
826
        }
827
        return 'start /D "' . $path . '" /B ' . $command . ' ' . $args;
828
    }
829
 
830
    /**
831
     * Place holder for the real resize method
832
     * used by extended methods to do the resizing
833
     *
834
     * @return PEAR_error
835
     * @access protected
836
     */
837
    function _resize()
838
    {
839
        return PEAR::raiseError('Resize method not supported by driver',
840
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
841
    }
842
 
843
    /**
844
     * Loads an image file to work with
845
     *
846
     * Place holder for the real load method
847
     * used by extended methods to do the resizing
848
     *
849
     * @return PEAR_error
850
     * @access public
851
     */
852
    function load($filename) {
853
        return PEAR::raiseError('load() method not supported by driver',
854
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
855
    }
856
 
857
    /**
858
     * Outputs the image to standard output
859
     *
860
     * Place holder for the real display method
861
     * used by extended methods to do the resizing
862
     *
863
     * @param string $type Format of image to save as
864
     * @param mixed  $quality Format-dependent
865
     * @return PEAR_error
866
     * @access public
867
     */
868
    function display($type, $quality = null) {
869
        return PEAR::raiseError('display() method not supported by driver',
870
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
871
    }
872
 
873
    /**
874
     * Returns if the driver supports a given image type
875
     *
876
     * @param  string $type Image type (GIF, PNG, JPEG...)
877
     * @param  string $mode 'r' for read, 'w' for write, 'rw' for both
878
     * @return TRUE if type (and mode) is supported FALSE otherwise
879
     * @access public
880
     */
881
    function supportsType($type, $mode = 'rw') {
882
        return (strpos(@$this->_supported_image_types[strtolower($type)], $mode) === false) ? false : true;
883
    }
884
 
885
    /**
886
     * Saves image to file
887
     *
888
     * Place holder for the real save method
889
     * used by extended methods to do the resizing
890
     *
891
     * @param string $filename Filename to save image to
892
     * @param string $type Format of image to save as
893
     * @param mixed  $quality Format-dependent
894
     * @return PEAR_error
895
     * @access public
896
     */
897
    function save($filename, $type, $quality = null) {
898
        return PEAR::raiseError('save() method not supported by driver',
899
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
900
    }
901
 
902
    /**
903
     * Releases resource
904
     *
905
     * Place holder for the real free method
906
     * used by extended methods to do the resizing
907
     *
908
     * @return PEAR_error
909
     * @access public
910
     */
911
    function free() {
912
        return PEAR::raiseError('free() method not supported by driver',
913
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
914
    }
915
 
916
    /**
917
     * Converts a color string into an array of RGB values
918
     *
919
     * @param  string $colorhex A color following the #FFFFFF format
920
     * @return array 3-element array with 0-255 values
921
     * @access public
922
     *
923
     * @see rgb2colorname
924
     * @see colorarray2colorhex
925
     */
926
    function colorhex2colorarray($colorhex) {
927
        $r = hexdec(substr($colorhex, 1, 2));
928
        $g = hexdec(substr($colorhex, 3, 2));
929
        $b = hexdec(substr($colorhex, 5, 2));
930
        return array($r, $g, $b, 'type' => 'RGB');
931
    }
932
 
933
    function _send_display_headers($type)
934
    {
935
        // Find the filename of the original image:
936
        $filename = explode('.', basename($this->image));
937
        $filename = $filename[0];
938
        header('Content-type: ' . $this->getMimeType($type));
939
        header ('Content-Disposition: inline; filename=' . $filename . '.' . $type );
940
    }
941
 
942
    /**
943
     * Converts an array of RGB value into a #FFFFFF format color.
944
     *
945
     * @param  array  $color 3-element array with 0-255 values
946
     * @return mixed A color following the #FFFFFF format or FALSE
947
     *               if the array couldn't be converted
948
     * @access public
949
     *
950
     * @see rgb2colorname
951
     * @see colorhex2colorarray
952
     */
953
    function colorarray2colorhex($color) {
954
        if (!is_array($color)) {
955
            return false;
956
        }
957
        $color = sprintf('#%02X%02X%02X', @$color[0], @$color[1], @$color[2]);
958
        return (strlen($color) != 7) ? false : $color;
959
    }
960
 
961
    /*** These snitched from the File package.  Saves including another class! ***/
962
    /**
963
     * Returns the temp directory according to either the TMP, TMPDIR, or TEMP env
964
     * variables. If these are not set it will also check for the existence of
965
     * /tmp, %WINDIR%\temp
966
     *
967
     * @access public
968
     * @return string The system tmp directory
969
     */
970
    function getTempDir()
971
    {
972
        include_once 'System.php';
973
        return System::tmpdir();
974
    }
975
 
976
    /**
977
     * Returns a temporary filename using tempnam() and the above getTmpDir() function.
978
     *
979
     * @access public
980
     * @param  string $dirname Optional directory name for the tmp file
981
     * @return string          Filename and path of the tmp file
982
     */
983
    function getTempFile($dirname = NULL)
984
    {
985
        return tempnam((is_null($dirname)) ? System::tmpdir() : $dirname, 'temp.');
986
    }
987
 
988
    function keepSettingsOnSave($bool)
989
    {
990
        $this->keep_settings_on_save = $bool;
991
    }
992
 
993
    /* Methods to add to the driver classes in the future */
994
    function addText()
995
    {
996
        return PEAR::raiseError('addText() method not supported by driver',
997
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
998
    }
999
 
1000
    function addDropShadow()
1001
    {
1002
        return PEAR::raiseError('addDropShadow() method not supported by driver',
1003
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1004
    }
1005
 
1006
    function addBorder()
1007
    {
1008
        return PEAR::raiseError('addBorder() method not supported by driver',
1009
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1010
    }
1011
 
1012
    /**
1013
     * Crops an image
1014
     *
1015
     * @param int width Cropped image width
1016
     * @param int height Cropped image height
1017
     * @param int x X-coordinate to crop at
1018
     * @param int y Y-coordinate to crop at
1019
     *
1020
     * @return mixed TRUE or a PEAR_Error object on error
1021
     * @access public
1022
     **/
1023
    function crop($width, $height, $x = 0, $y = 0)
1024
    {
1025
        return PEAR::raiseError('crop() method not supported by driver',
1026
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1027
    }
1028
 
1029
    function canvasResize()
1030
    {
1031
        return PEAR::raiseError('canvasResize() method not supported by driver',
1032
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1033
    }
1034
 
1035
    /**
1036
     * Corrects the gamma of an image
1037
     *
1038
     * @param float $outputgamma Gamma correction factor
1039
     * @return mixed TRUE or a PEAR_error object on error
1040
     * @access public
1041
     **/
1042
    function gamma($outputgamma = 1.0)
1043
    {
1044
        return PEAR::raiseError('gamma() method not supported by driver',
1045
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1046
    }
1047
 
1048
    /**
1049
     * Rotates the image clockwise
1050
     *
1051
     * @param float $angle angle of rotation in degres
1052
     * @param mixed $options
1053
     * @return bool|PEAR_Error TRUE on success, PEAR_Error object on error
1054
     * @access public
1055
     */
1056
    function rotate($angle, $options = null)
1057
    {
1058
        return PEAR::raiseError('rotate() method not supported by driver',
1059
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1060
    }
1061
 
1062
    /**
1063
     * Horizontal mirroring
1064
     *
1065
     * @return mixed TRUE or PEAR_Error object on error
1066
     * @access public
1067
     * @see flip()
1068
     **/
1069
    function mirror()
1070
    {
1071
        return PEAR::raiseError('mirror() method not supported by driver',
1072
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1073
    }
1074
 
1075
    /**
1076
     * Vertical mirroring
1077
     *
1078
     * @return TRUE or PEAR Error object on error
1079
     * @access public
1080
     * @see mirror()
1081
     **/
1082
    function flip()
1083
    {
1084
        return PEAR::raiseError('flip() method not supported by driver',
1085
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1086
    }
1087
 
1088
    /**
1089
     * Converts an image into greyscale colors
1090
     *
1091
     * @return mixed TRUE or a PEAR error object on error
1092
     * @access public
1093
     **/
1094
    function greyscale()
1095
    {
1096
        return PEAR::raiseError('greyscale() method not supported by driver',
1097
            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
1098
    }
1099
 
1100
    /**
1101
     * @see greyscale()
1102
     **/
1103
    function grayscale()
1104
    {
1105
        return $this->greyscale();
1106
    }
1107
 
1108
    /**
1109
     * Returns a color option
1110
     *
1111
     * @param string $colorOf one of 'canvasColor', 'pencilColor', 'fontColor'
1112
     * @param array  $options
1113
     * @param array  $default default value to return if color not found
1114
     * @return array an RGB color array
1115
     * @access protected
1116
     */
1117
    function _getColor($colorOf, $options = array(), $default = array(0, 0, 0))
1118
    {
1119
        $opt = array_merge($this->_options, (array) $options);
1120
        if (isset($opt[$colorOf])) {
1121
            $color = $opt[$colorOf];
1122
            if (is_array($color)) {
1123
                return $color;
1124
            }
1125
            if ($color{0} == '#') {
1126
                return $this->colorhex2colorarray($color);
1127
            }
1128
            static $colornames = array();
1129
            include_once 'Image/Transform/Driver/ColorsDefs.php';
1130
            return (isset($colornames[$color])) ? $colornames[$color] : $default;
1131
        }
1132
        return $default;
1133
    }
1134
 
1135
    /**
1136
     * Returns an option
1137
     *
1138
     * @param string $name name of option
1139
     * @param array  $options local override option array
1140
     * @param mixed  $default default value to return if option is not found
1141
     * @return mixed the option
1142
     * @access protected
1143
     */
1144
    function _getOption($name, $options = array(), $default = null)
1145
    {
1146
        $opt = array_merge($this->_options, (array) $options);
1147
        return (isset($opt[$name])) ? $opt[$name] : $default;
1148
    }
1149
 
1150
    /**
1151
     * Checks if the rectangle passed intersects with the current image
1152
     *
1153
     * @param int $width
1154
     * @param int $height
1155
     * @param int $x X-coordinate
1156
     * @param int $y Y-coordinate
1157
     * @return bool|PEAR_Error TRUE if intersects, FALSE if not, and PEAR_Error on error
1158
     * @access public
1159
     */
1160
    function intersects($width, $height, $x, $y)
1161
    {
1162
        $left  = $x;
1163
        $right = $x + $width;
1164
        if ($right < $left) {
1165
            $left  = $right;
1166
            $right = $x;
1167
        }
1168
        $top    = $y;
1169
        $bottom = $y + $height;
1170
        if ($bottom < $top) {
1171
            $top    = $bottom;
1172
            $bottom = $y;
1173
        }
1174
        return (bool) ($left < $this->new_x
1175
                       && $right >= 0
1176
                       && $top < $this->new_y
1177
                       && $bottom >= 0);
1178
    }
1179
}