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
 * NetPBM 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
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
19
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
20
 * @copyright  2002-2005 The PHP Group
21
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
22
 * @version    CVS: $Id: NetPBM.php,v 1.21 2007/04/19 16:36:09 dufuz Exp $
23
 * @link       http://pear.php.net/package/Image_Transform
24
 */
25
 
26
require_once 'Image/Transform.php';
27
require_once 'System.php';
28
 
29
/**
30
 * NetPBM implementation for Image_Transform package
31
 *
32
 * @category   Image
33
 * @package    Image_Transform
34
 * @subpackage Image_Transform_Driver_NetPBM
35
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
36
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
37
 * @copyright  2002-2005 The PHP Group
38
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
39
 * @version    Release: @package_version@
40
 * @link       http://pear.php.net/package/Image_Transform
41
 * @link       http://netpbm.sourceforge.net/
42
 */
43
class Image_Transform_Driver_NetPBM extends Image_Transform
44
{
45
    /**
46
     * associative array commands to be executed
47
     * @var array
48
     */
49
    var $command = array();
50
 
51
    /**
52
     * Class Constructor
53
     */
54
    function Image_Transform_Driver_NetPBM()
55
    {
56
        $this->__construct();
57
 
58
    } // End function Image_NetPBM
59
 
60
    /**
61
     * Class Constructor
62
     */
63
    function __construct()
64
    {
65
        if (!defined('IMAGE_TRANSFORM_NETPBM_PATH')) {
66
            $path = dirname(System::which('pnmscale'))
67
                    . DIRECTORY_SEPARATOR;
68
            define('IMAGE_TRANSFORM_NETPBM_PATH', $path);
69
        }
70
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pnmscale'
71
                             . ((OS_WINDOWS) ? '.exe' : ''))) {
72
            $this->isError(PEAR::raiseError('Couldn\'t find "pnmscale" binary',
73
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED));
74
        }
75
    } // End function Image_NetPBM
76
 
77
    /**
78
     * Load image
79
     *
80
     * @param string filename
81
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
82
     * @access public
83
     */
84
    function load($image)
85
    {
86
        $this->image = $image;
87
        $result = $this->_get_image_details($image);
88
        if (PEAR::isError($result)) {
89
            return $result;
90
        }
91
        return true;
92
 
93
    } // End load
94
 
95
    /**
96
     * Resize the image.
97
     *
98
     * @access private
99
     *
100
     * @param int   $new_x   New width
101
     * @param int   $new_y   New height
102
     * @param mixed $options Optional parameters
103
     *
104
     * @return true on success or PEAR Error object on error
105
     * @see PEAR::isError()
106
     */
107
    function _resize($new_x, $new_y, $options = null)
108
    {
109
        // there's no technical reason why resize can't be called multiple
110
        // times...it's just silly to do so
111
        $scaleMethod = $this->_getOption('scaleMethod', $options, 'smooth');
112
        switch ($scaleMethod) {
113
            case 'pixel':
114
                $scale_x = $new_x / $this->img_x;
115
                if ($scale_x == $new_y / $this->img_x
116
                    && $scale_x > 1
117
                    && floor($scale_x) == $scale_x) {
118
                    if (System::which(IMAGE_TRANSFORM_NETPBM_PATH .
119
                                           'pnmenlarge'
120
                                           . ((OS_WINDOWS) ? '.exe' : ''))) {
121
                        $this->command[] = $this->_prepare_cmd(
122
                            IMAGE_TRANSFORM_NETPBM_PATH,
123
                            'pnmenlarge',
124
                            $scale_x);
125
                    } else {
126
                        return PEAR::raiseError('Couldn\'t find "pnmenlarge" binary',
127
                            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
128
                    }
129
                } else {
130
                    $this->command[] = $this->_prepare_cmd(
131
                        IMAGE_TRANSFORM_NETPBM_PATH,
132
                        'pnmscale',
133
                        '-nomix -width ' . ((int) $new_x)
134
                            . ' -height ' . ((int) $new_y));
135
                }
136
                break;
137
 
138
            case 'smooth':
139
            default:
140
                $this->command[] = $this->_prepare_cmd(
141
                    IMAGE_TRANSFORM_NETPBM_PATH,
142
                    'pnmscale',
143
                    '-width ' . ((int) $new_x) . ' -height '
144
                        . ((int) $new_y));
145
                // Smooth things if scaling by a factor more than 3
146
                // (see pnmscale man page)
147
                if ($new_x / $this->img_x > 3
148
                    || $new_y / $this->img_y > 3) {
149
                    if (System::which(IMAGE_TRANSFORM_NETPBM_PATH .
150
                                           'pnmsmooth' . ((OS_WINDOWS) ? '.exe' : ''))) {
151
                        $this->command[] = $this->_prepare_cmd(
152
                            IMAGE_TRANSFORM_NETPBM_PATH,
153
                            'pnmsmooth');
154
                    } else {
155
                        return PEAR::raiseError('Couldn\'t find "pnmsmooth" binary',
156
                            IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
157
                    }
158
                }
159
        } // End [SWITCH]
160
 
161
        $this->_set_new_x($new_x);
162
        $this->_set_new_y($new_y);
163
        return true;
164
 
165
    } // End resize
166
 
167
    /**
168
     * Rotates the image
169
     *
170
     * @param int $angle The angle to rotate the image through
171
     * @param array $options
172
     * @return bool|PEAR_Error TRUE on success, PEAR_Error object on error
173
     */
174
    function rotate($angle, $options = null)
175
    {
176
        if (!($angle == $this->_rotation_angle($angle))) {
177
            // No rotation needed
178
            return true;
179
        }
180
 
181
        // For pnmrotate, we want to limit rotations from -45 to +45 degrees
182
        // even if acceptable range is -90 to +90 (see pnmrotate man page)
183
        // Bring image to that range by using pamflip
184
        if ($angle > 45 && $angle < 315) {
185
            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
186
                                   'pamflip' . ((OS_WINDOWS) ? '.exe' : ''))) {
187
                return PEAR::raiseError('Couldn\'t find "pamflip" binary',
188
                    IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
189
            }
190
 
191
            $quarters = floor(ceil($angle / 45) / 2);
192
            $this->command[] = $this->_prepare_cmd(
193
                IMAGE_TRANSFORM_NETPBM_PATH,
194
                'pamflip',
195
                '-rotate' . (360 - $quarters * 90));
196
            $angle -= $quarters * 90;
197
        }
198
 
199
        if ($angle != 0) {
200
            if ($angle > 45) {
201
                $angle -= 360;
202
            }
203
 
204
            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
205
                                   'pnmrotate' . ((OS_WINDOWS) ? '.exe' : ''))) {
206
                return PEAR::raiseError('Couldn\'t find "pnmrotate" binary',
207
                    IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
208
            }
209
 
210
            $bgcolor = $this->_getColor('canvasColor', $options,
211
                                            array(255, 255, 255));
212
            $bgcolor = $this->colorarray2colorhex($bgcolor);
213
 
214
            $scaleMethod = $this->_getOption('scaleMethod', $options, 'smooth');
215
            if ($scaleMethod != 'pixel') {
216
                $this->command[] = $this->_prepare_cmd(
217
                    IMAGE_TRANSFORM_NETPBM_PATH,
218
                    'pnmrotate',
219
                    '-background=' . $bgcolor . ' -' . (float) $angle);
220
            } else {
221
                $this->command[] = $this->_prepare_cmd(
222
                    IMAGE_TRANSFORM_NETPBM_PATH,
223
                    'pnmrotate',
224
                    '-background=' . $bgcolor . ' -noantialias -' . (float) $angle);
225
            }
226
        }
227
        return true;
228
    } // End rotate
229
 
230
    /**
231
     * Crop an image
232
     *
233
     * @param int $width Cropped image width
234
     * @param int $height Cropped image height
235
     * @param int $x positive X-coordinate to crop at
236
     * @param int $y positive Y-coordinate to crop at
237
     *
238
     * @return mixed TRUE or a PEAR error object on error
239
     * @todo keep track of the new cropped size
240
     **/
241
    function crop($width, $height, $x = 0, $y = 0)
242
    {
243
        // Sanity check
244
        if (!$this->intersects($width, $height, $x, $y)) {
245
            return PEAR::raiseError('Nothing to crop', IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
246
        }
247
        if ($x != 0 || $y != 0
248
            || $width != $this->img_x
249
            || $height != $this->img_y) {
250
            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
251
                                   'pnmcut' . ((OS_WINDOWS) ? '.exe' : ''))) {
252
                return PEAR::raiseError('Couldn\'t find "pnmcut" binary',
253
                    IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
254
            }
255
 
256
            $this->command[] = $this->_prepare_cmd(
257
                IMAGE_TRANSFORM_NETPBM_PATH,
258
                'pnmcut',
259
                '-left ' . ((int) $x)
260
                    . ' -top ' . ((int) $y)
261
                    . ' -width ' . ((int) $width)
262
                    . ' -height ' . ((int) $height));
263
        }
264
        return true;
265
    } // End crop
266
 
267
    /**
268
     * Adjust the image gamma
269
     *
270
     * @param float $outputgamma
271
     *
272
     * @return mixed TRUE or a PEAR error object on error
273
     */
274
    function gamma($outputgamma = 1.0) {
275
        if ($outputgamme != 1.0) {
276
            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
277
                                   'pnmgamma' . ((OS_WINDOWS) ? '.exe' : ''))) {
278
                return PEAR::raiseError('Couldn\'t find "pnmgamma" binary',
279
                    IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
280
            }
281
            $this->command[] = $this->_prepare_cmd(
282
                IMAGE_TRANSFORM_NETPBM_PATH,
283
                'pnmgamma',
284
                (float) $outputgamma);
285
        }
286
        return true;
287
    }
288
 
289
    /**
290
     * Vertical mirroring
291
     *
292
     * @see mirror()
293
     * @return TRUE or PEAR Error object on error
294
     **/
295
    function flip()
296
    {
297
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
298
                               'pamflip' . ((OS_WINDOWS) ? '.exe' : ''))) {
299
            return PEAR::raiseError('Couldn\'t find "pamflip" binary',
300
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
301
        }
302
        $this->command[] = $this->_prepare_cmd(
303
            IMAGE_TRANSFORM_NETPBM_PATH,
304
            'pamflip',
305
            '-topbottom');
306
        return true;
307
    }
308
 
309
    /**
310
     * Horizontal mirroring
311
     *
312
     * @see flip()
313
     * @return TRUE or PEAR Error object on error
314
     **/
315
    function mirror()
316
    {
317
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
318
                               'pamflip' . ((OS_WINDOWS) ? '.exe' : ''))) {
319
            return PEAR::raiseError('Couldn\'t find "pamflip" binary',
320
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
321
        }
322
        $this->command[] = $this->_prepare_cmd(
323
            IMAGE_TRANSFORM_NETPBM_PATH,
324
            'pamflip',
325
            '-leftright');
326
        return true;
327
    }
328
 
329
    /**
330
     * Converts an image into greyscale colors
331
     *
332
     * @access public
333
     * @return mixed TRUE or a PEAR error object on error
334
     **/
335
    function greyscale()
336
    {
337
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
338
                               'ppmtopgm' . ((OS_WINDOWS) ? '.exe' : ''))) {
339
            return PEAR::raiseError('Couldn\'t find "ppmtopgm" binary',
340
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
341
        }
342
        $this->command[] = $this->_prepare_cmd(
343
            IMAGE_TRANSFORM_NETPBM_PATH,
344
            'ppmtopgm');
345
        return true;
346
    }
347
 
348
    /**
349
     * adds text to an image
350
     *
351
     * @param   array   options     Array contains options
352
     *             array(
353
     *                  'text'          // The string to draw
354
     *                  'x'             // Horizontal position
355
     *                  'y'             // Vertical Position
356
     *                  'color'         // Font color
357
     *                  'font'          // Font to be used
358
     *                  'size'          // Size of the fonts in pixel
359
     *                  'resize_first'  // Tell if the image has to be resized
360
     *                                  // before drawing the text
361
     *                   )
362
     *
363
     * @return void
364
     */
365
    function addText($params)
366
    {
367
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH .
368
                               'ppmlabel' . ((OS_WINDOWS) ? '.exe' : ''))) {
369
            return PEAR::raiseError('Couldn\'t find "ppmlabel" binary',
370
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
371
        }
372
 
373
        // we ignore 'resize_first' since the more logical approach would be
374
        // for the user to just call $this->_resize() _first_ ;)
375
        extract(array_merge($this->_get_default_text_params(), $params));
376
 
377
        $options = array('colorFont' => $color);
378
        $color = $this->_getColor('colorFont', $options, array(0, 0, 0));
379
        $color = $this->colorarray2colorhex($color);
380
 
381
        $this->command[] = $this->_prepare_cmd(
382
            IMAGE_TRANSFORM_NETPBM_PATH,
383
            'ppmlabel',
384
            '-angle ' . ((int) $angle)
385
                . ' -colour ' . escapeshellarg($color)
386
                . ' -size ' . ((float) $size)
387
                . ' -x ' . ((int) $x)
388
                . ' -y ' . ((int) ($y + $size))
389
                . ' -text ' . escapeshellarg($text));
390
 
391
    } // End addText
392
 
393
    /**
394
     * Image_Transform_Driver_NetPBM::_postProcess()
395
     *
396
     * @param $type
397
     * @param $quality
398
     * @return string A chain of shell command
399
     * @link http://netpbm.sourceforge.net/doc/directory.html
400
     */
401
    function _postProcess($type, $quality)
402
    {
403
        array_unshift($this->command, $this->_prepare_cmd(
404
            IMAGE_TRANSFORM_NETPBM_PATH,
405
            strtolower($this->type) . 'topnm',
406
            escapeshellarg($this->image)));
407
        $arg = '';
408
        $type = strtolower($type);
409
        $program = '';
410
        switch ($type) {
411
            // ppmto* converters
412
            case 'gif':
413
                if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'ppmquant'
414
                                    . ((OS_WINDOWS) ? '.exe' : ''))) {
415
                    return PEAR::raiseError('Couldn\'t find "ppmquant" binary',
416
                        IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
417
                }
418
                $this->command[] = $this->_prepare_cmd(
419
                    IMAGE_TRANSFORM_NETPBM_PATH,
420
                    'ppmquant',
421
                    256);
422
            case 'acad':
423
            case 'bmp':
424
            case 'eyuv':
425
            case 'ilbm':
426
            case 'leaf':
427
            case 'lj':
428
            case 'mitsu':
429
            case 'mpeg':
430
            case 'neo':
431
            case 'pcx':
432
            case 'pi1':
433
            case 'pict':
434
            case 'pj':
435
            case 'pjxl':
436
            case 'puzz':
437
            case 'sixel':
438
            case 'tga':
439
            case 'uil':
440
            case 'xpm':
441
            case 'yuv':
442
                $program = 'ppmto' . $type;
443
                break;
444
 
445
            // Windows icon
446
            case 'winicon':
447
            case 'ico':
448
                $type = 'winicon';
449
                $program = 'ppmto' . $type;
450
                break;
451
 
452
            // pbmto* converters
453
            case 'ascii':
454
            case 'text':
455
            case 'txt':
456
                $type = 'ascii';
457
            case 'atk':
458
            case 'bbubg':
459
            case 'epsi':
460
            case 'epson':
461
            case 'escp2':
462
            case 'icon':    // Sun icon
463
            case 'gem':
464
            case 'go':
465
            case 'lj':
466
            case 'ln03':
467
            case 'lps':
468
            case 'macp':
469
            case 'mda':
470
            case 'mgr':
471
            case 'pi3':
472
            case 'pk':
473
            case 'plot':
474
            case 'ptx':
475
            case 'wbp':
476
            case 'xbm':
477
            case 'x10bm':
478
            case 'ybm':
479
            case 'zinc':
480
            case '10x':
481
                $program = 'pbmto' . $type;
482
                break;
483
 
484
            // pamto* converters
485
            case 'jpc':
486
                $type = 'jpeg2k';
487
            case 'html':
488
            case 'pfm':
489
            case 'tga':
490
                $program = 'pamto' . $type;
491
                break;
492
 
493
            // pnmto* converters
494
            case 'jpc':
495
                $type = 'jpeg2k';
496
                break;
497
            case 'wfa':
498
                $type = 'fiasco';
499
                break;
500
            case 'jpg':
501
                $type = 'jpeg';
502
            case 'jpeg':
503
                $arg = '--quality=' . $quality;
504
            case 'jbig':
505
            case 'fits':
506
            case 'palm':
507
            case 'pclxl':
508
            case 'png':
509
            case 'ps':
510
            case 'rast':
511
            case 'rle':
512
            case 'sgi':
513
            case 'sir':
514
            case 'tiff':
515
            case 'xwd':
516
                $program = 'pnmto' . $type;
517
                break;
518
 
519
        } // switch
520
 
521
        if ($program == '') {
522
            $program = 'pnmto' . $type;
523
        }
524
 
525
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . $program
526
                            . ((OS_WINDOWS) ? '.exe' : ''))) {
527
            return PEAR::raiseError("Couldn't find \"$program\" binary",
528
                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
529
        }
530
        $this->command[] = $this->_prepare_cmd(
531
            IMAGE_TRANSFORM_NETPBM_PATH,
532
            $program);
533
        return implode('|', $this->command);
534
    }
535
 
536
    /**
537
     * Save the image file
538
     *
539
     * @param $filename string the name of the file to write to
540
     * @param string $type (jpeg,png...);
541
     * @param int $quality 75
542
     * @return TRUE or PEAR Error object on error
543
     */
544
    function save($filename, $type = null, $quality = 75)
545
    {
546
        $type    = (is_null($type)) ? $this->type : $type;
547
        $options = array();
548
        if (!is_null($quality)) {
549
            $options['quality'] = $quality;
550
        }
551
        $quality = $this->_getOption('quality', $options, $quality);
552
 
553
        $nullDevice = (OS_WINDOWS) ? 'nul' : '/dev/null';
554
 
555
        $cmd = $this->_postProcess($type, $quality) . '> "' . $filename . '"';
556
        exec($cmd . '2> ' . $nullDevice, $res, $exit);
557
        if (!$this->keep_settings_on_save) {
558
            $this->free();
559
        }
560
 
561
        return ($exit == 0) ? true : PEAR::raiseError(implode('. ', $res),
562
            IMAGE_TRANSFORM_ERROR_IO);
563
    } // End save
564
 
565
    /**
566
     * Display image without saving and lose changes
567
     *
568
     * @param string $type (jpeg,png...);
569
     * @param int $quality 75
570
     * @return TRUE or PEAR Error object on error
571
     */
572
    function display($type = null, $quality = null)
573
    {
574
        $type    = (is_null($type)) ? $this->type : $type;
575
        $options = array();
576
        if (!is_null($quality)) {
577
            $options['quality'] = $quality;
578
        }
579
        $quality = $this->_getOption('quality', $options, 75);
580
 
581
        header('Content-type: ' . $this->getMimeType($type));
582
        $cmd = $this->_postProcess($type, $quality);
583
        passthru($cmd . ' 2>&1');
584
        if (!$this->keep_settings_on_save) {
585
            $this->free();
586
        }
587
 
588
        return true;
589
    }
590
 
591
    /**
592
     * Destroy image handle
593
     *
594
     * @return void
595
     */
596
    function free()
597
    {
598
        $this->command = array();
599
    }
600
 
601
 
602
} // End class ImageIM