Image_Transform
[ class tree: Image_Transform ] [ index: Image_Transform ] [ all elements ]

Source for file NetPBM.php

Documentation is available at NetPBM.php

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