mambax7/extgallery

View on GitHub
class/pear/Image/Transform/Driver/NetPBM.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

/* vim: set expandtab tabstop=4 shiftwidth=4: */

/**
 * NetPBM implementation for Image_Transform package
 *
 * PHP versions 4 and 5
 *
 * LICENSE: This source file is subject to version 3.0 of the PHP license
 * that is available through the world-wide-web at the following URI:
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
 * the PHP License and are unable to obtain it through the web, please
 * send a note to license@php.net so we can mail you a copy immediately.
 *
 * @category   Image
 * @package    Image_Transform
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
 * @copyright  2002-2005 The PHP Group
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 * @version    CVS: $Id: NetPBM.php 236527 2007-05-28 16:36:09Z dufuz $
 * @link       http://pear.php.net/package/Image_Transform
 */

//require_once __DIR__ . '/Image/Transform.php';
//require_once __DIR__ . '/System.php';
require_once XOOPS_ROOT_PATH . '/modules/extgallery/class/pear/Image/Transform.php';
require_once XOOPS_ROOT_PATH . '/modules/extgallery/class/pear/System.php';

/**
 * NetPBM implementation for Image_Transform package
 *
 * @category   Image
 * @package    Image_Transform
 * @subpackage Image_Transform_Driver_NetPBM
 * @author     Peter Bowyer <peter@mapledesign.co.uk>
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
 * @copyright  2002-2005 The PHP Group
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 * @version    Release: @package_version@
 * @link       http://pear.php.net/package/Image_Transform
 * @link       http://netpbm.sourceforge.net/
 */
class Image_Transform_Driver_NetPBM extends Image_Transform
{
    /**
     * associative array commands to be executed
     * @var array
     */
    public $command = [];

    /**
     * Class Constructor
     */
    public function Image_Transform_Driver_NetPBM()
    {
        $this->__construct();
    }

    // End function Image_NetPBM

    /**
     * Class Constructor
     */
    public function __construct()
    {
        if (!defined('IMAGE_TRANSFORM_NETPBM_PATH')) {
            $path = \dirname(System::which('pnmscale')) . DIRECTORY_SEPARATOR;
            define('IMAGE_TRANSFORM_NETPBM_PATH', $path);
        }
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pnmscale' . (OS_WINDOWS ? '.exe' : ''))) {
            $this->isError(PEAR::raiseError('Couldn\'t find "pnmscale" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED));
        }
    }

    // End function Image_NetPBM

    /**
     * Load image
     *
     * @param mixed $image
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function load($image)
    {
        $this->image = $image;
        $result      = $this->_get_image_details($image);
        if (PEAR::isError($result)) {
            return $result;
        }

        return true;
    }

    // End load

    /**
     * Resize the image.
     *
     * @access private
     *
     * @param int   $new_x   New width
     * @param int   $new_y   New height
     * @param mixed $options Optional parameters
     *
     * @return true on success or PEAR Error object on error
     * @see    PEAR::isError()
     */
    public function _resize($new_x, $new_y, $options = null)
    {
        // there's no technical reason why resize can't be called multiple
        // times...it's just silly to do so
        $scaleMethod = $this->_getOption('scaleMethod', $options, 'smooth');
        switch ($scaleMethod) {
            case 'pixel':
                $scale_x = $new_x / $this->img_x;
                if ($scale_x == $new_y / $this->img_x
                    && $scale_x > 1
                    && floor($scale_x) == $scale_x) {
                    if (System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pnmenlarge' . (OS_WINDOWS ? '.exe' : ''))) {
                        $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmenlarge', $scale_x);
                    } else {
                        return PEAR::raiseError('Couldn\'t find "pnmenlarge" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
                    }
                } else {
                    $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmscale', '-nomix -width ' . ((int)$new_x) . ' -height ' . ((int)$new_y));
                }
                break;
            case 'smooth':
            default:
                $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmscale', '-width ' . ((int)$new_x) . ' -height ' . ((int)$new_y));
                // Smooth things if scaling by a factor more than 3
                // (see pnmscale man page)
                if ($new_x / $this->img_x > 3
                    || $new_y / $this->img_y > 3) {
                    if (System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pnmsmooth' . (OS_WINDOWS ? '.exe' : ''))) {
                        $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmsmooth');
                    } else {
                        return PEAR::raiseError('Couldn\'t find "pnmsmooth" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
                    }
                }
        } // End [SWITCH]

        $this->_set_new_x($new_x);
        $this->_set_new_y($new_y);

        return true;
    }

    // End resize

    /**
     * Rotates the image
     *
     * @param int   $angle The angle to rotate the image through
     * @param array $options
     * @return bool|PEAR_Error TRUE on success, PEAR_Error object on error
     */
    public function rotate($angle, $options = null)
    {
        if (!($angle == $this->_rotation_angle($angle))) {
            // No rotation needed
            return true;
        }

        // For pnmrotate, we want to limit rotations from -45 to +45 degrees
        // even if acceptable range is -90 to +90 (see pnmrotate man page)
        // Bring image to that range by using pamflip
        if ($angle > 45 && $angle < 315) {
            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pamflip' . (OS_WINDOWS ? '.exe' : ''))) {
                return PEAR::raiseError('Couldn\'t find "pamflip" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
            }

            $quarters        = floor(ceil($angle / 45) / 2);
            $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pamflip', '-rotate' . (360 - $quarters * 90));
            $angle           -= $quarters * 90;
        }

        if (0 != $angle) {
            if ($angle > 45) {
                $angle -= 360;
            }

            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pnmrotate' . (OS_WINDOWS ? '.exe' : ''))) {
                return PEAR::raiseError('Couldn\'t find "pnmrotate" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
            }

            $bgcolor = $this->_getColor('canvasColor', $options, [255, 255, 255]);
            $bgcolor = $this->colorarray2colorhex($bgcolor);

            $scaleMethod = $this->_getOption('scaleMethod', $options, 'smooth');
            if ('pixel' != $scaleMethod) {
                $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmrotate', '-background=' . $bgcolor . ' -' . (float)$angle);
            } else {
                $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmrotate', '-background=' . $bgcolor . ' -noantialias -' . (float)$angle);
            }
        }

        return true;
    }

    // End rotate

    /**
     * Crop an image
     *
     * @param int $width  Cropped image width
     * @param int $height Cropped image height
     * @param int $x      positive X-coordinate to crop at
     * @param int $y      positive Y-coordinate to crop at
     *
     * @return mixed TRUE or a PEAR error object on error
     * @todo keep track of the new cropped size
     **/
    public function crop($width, $height, $x = 0, $y = 0)
    {
        // Sanity check
        if (!$this->intersects($width, $height, $x, $y)) {
            return PEAR::raiseError('Nothing to crop', IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
        }
        if (0 != $x || 0 != $y
            || $width != $this->img_x
            || $height != $this->img_y) {
            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pnmcut' . (OS_WINDOWS ? '.exe' : ''))) {
                return PEAR::raiseError('Couldn\'t find "pnmcut" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
            }

            $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmcut', '-left ' . ((int)$x) . ' -top ' . ((int)$y) . ' -width ' . ((int)$width) . ' -height ' . ((int)$height));
        }

        return true;
    }

    // End crop

    /**
     * Adjust the image gamma
     *
     * @param float $outputgamma
     *
     * @return mixed TRUE or a PEAR error object on error
     */
    public function gamma($outputgamma = 1.0)
    {
        if (1.0 != $outputgamme) {
            if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pnmgamma' . (OS_WINDOWS ? '.exe' : ''))) {
                return PEAR::raiseError('Couldn\'t find "pnmgamma" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
            }
            $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pnmgamma', (float)$outputgamma);
        }

        return true;
    }

    /**
     * Vertical mirroring
     *
     * @return true or PEAR Error object on error
     **@see mirror()
     */
    public function flip()
    {
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pamflip' . (OS_WINDOWS ? '.exe' : ''))) {
            return PEAR::raiseError('Couldn\'t find "pamflip" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
        }
        $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pamflip', '-topbottom');

        return true;
    }

    /**
     * Horizontal mirroring
     *
     * @return true or PEAR Error object on error
     **@see flip()
     */
    public function mirror()
    {
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'pamflip' . (OS_WINDOWS ? '.exe' : ''))) {
            return PEAR::raiseError('Couldn\'t find "pamflip" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
        }
        $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'pamflip', '-leftright');

        return true;
    }

    /**
     * Converts an image into greyscale colors
     *
     * @access public
     * @return mixed TRUE or a PEAR error object on error
     **/
    public function greyscale()
    {
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'ppmtopgm' . (OS_WINDOWS ? '.exe' : ''))) {
            return PEAR::raiseError('Couldn\'t find "ppmtopgm" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
        }
        $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'ppmtopgm');

        return true;
    }

    /**
     * adds text to an image
     *
     * @param mixed $params
     *
     * @return object
     */
    public function addText($params)
    {
        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'ppmlabel' . (OS_WINDOWS ? '.exe' : ''))) {
            return PEAR::raiseError('Couldn\'t find "ppmlabel" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
        }

        // we ignore 'resize_first' since the more logical approach would be
        // for the user to just call $this->_resize() _first_ ;)
        extract(array_merge($this->_get_default_text_params(), $params));

        $options = ['colorFont' => $color];
        $color   = $this->_getColor('colorFont', $options, [0, 0, 0]);
        $color   = $this->colorarray2colorhex($color);

        $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'ppmlabel', '-angle ' . ((int)$angle) . ' -colour ' . escapeshellarg($color) . ' -size ' . ((float)$size) . ' -x ' . ((int)$x) . ' -y ' . $y + $size . ' -text ' . escapeshellarg($text));
    }

    // End addText

    /**
     * Image_Transform_Driver_NetPBM::_postProcess()
     *
     * @param $type
     * @param $quality
     * @return string A chain of shell command
     * @link http://netpbm.sourceforge.net/doc/directory.html
     */
    public function _postProcess($type, $quality)
    {
        array_unshift($this->command, $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, mb_strtolower($this->type) . 'topnm', escapeshellarg($this->image)));
        $arg     = '';
        $type    = mb_strtolower($type);
        $program = '';
        switch ($type) {
            // ppmto* converters
            case 'gif':
                if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . 'ppmquant' . (OS_WINDOWS ? '.exe' : ''))) {
                    return PEAR::raiseError('Couldn\'t find "ppmquant" binary', IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
                }
                $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, 'ppmquant', 256);
            // no break
            case 'acad':
            case 'bmp':
            case 'eyuv':
            case 'ilbm':
            case 'leaf':
            case 'lj':
            case 'mitsu':
            case 'mpeg':
            case 'neo':
            case 'pcx':
            case 'pi1':
            case 'pict':
            case 'pj':
            case 'pjxl':
            case 'puzz':
            case 'sixel':
            case 'tga':
            case 'uil':
            case 'xpm':
            case 'yuv':
                $program = 'ppmto' . $type;
                break;
            // Windows icon
            case 'winicon':
            case 'ico':
                $type    = 'winicon';
                $program = 'ppmto' . $type;
                break;
            // pbmto* converters
            case 'ascii':
            case 'text':
            case 'txt':
                $type = 'ascii';
            // no break
            case 'atk':
            case 'bbubg':
            case 'epsi':
            case 'epson':
            case 'escp2':
            case 'icon':    // Sun icon
            case 'gem':
            case 'go':
            case 'lj':
            case 'ln03':
            case 'lps':
            case 'macp':
            case 'mda':
            case 'mgr':
            case 'pi3':
            case 'pk':
            case 'plot':
            case 'ptx':
            case 'wbp':
            case 'xbm':
            case 'x10bm':
            case 'ybm':
            case 'zinc':
            case '10x':
                $program = 'pbmto' . $type;
                break;
            // pamto* converters
            case 'jpc':
                $type = 'jpeg2k';
            // no break
            case 'html':
            case 'pfm':
            case 'tga':
                $program = 'pamto' . $type;
                break;
            // pnmto* converters
            case 'jpc':
                $type = 'jpeg2k';
                break;
            case 'wfa':
                $type = 'fiasco';
                break;
            case 'jpg':
                $type = 'jpeg';
            // no break
            case 'jpeg':
                $arg = '--quality=' . $quality;
            // no break
            case 'jbig':
            case 'fits':
            case 'palm':
            case 'pclxl':
            case 'png':
            case 'ps':
            case 'rast':
            case 'rle':
            case 'sgi':
            case 'sir':
            case 'tiff':
            case 'xwd':
                $program = 'pnmto' . $type;
                break;
        } // switch

        if ('' == $program) {
            $program = 'pnmto' . $type;
        }

        if (!System::which(IMAGE_TRANSFORM_NETPBM_PATH . $program . (OS_WINDOWS ? '.exe' : ''))) {
            return PEAR::raiseError("Couldn't find \"$program\" binary", IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
        }
        $this->command[] = $this->_prepare_cmd(IMAGE_TRANSFORM_NETPBM_PATH, $program);

        return implode('|', $this->command);
    }

    /**
     * Save the image file
     *
     * @param string $filename the name of the file to write to
     * @param string $type     (jpeg,png...);
     * @param int    $quality  75
     * @return true or PEAR Error object on error
     */
    public function save($filename, $type = null, $quality = 75)
    {
        $type    = $type ?? $this->type;
        $options = [];
        if (null !== $quality) {
            $options['quality'] = $quality;
        }
        $quality = $this->_getOption('quality', $options, $quality);

        $nullDevice = OS_WINDOWS ? 'nul' : '/dev/null';

        $cmd = $this->_postProcess($type, $quality) . '> "' . $filename . '"';
        exec($cmd . ' 2>  ' . $nullDevice, $res, $exit);
        if (!$this->keep_settings_on_save) {
            $this->free();
        }

        return (0 == $exit) ? true : PEAR::raiseError(implode('. ', $res), IMAGE_TRANSFORM_ERROR_IO);
    }

    // End save

    /**
     * Display image without saving and lose changes
     *
     * @param string $type    (jpeg,png...);
     * @param int    $quality 75
     * @return true or PEAR Error object on error
     */
    public function display($type = null, $quality = null)
    {
        $type    = $type ?? $this->type;
        $options = [];
        if (null !== $quality) {
            $options['quality'] = $quality;
        }
        $quality = $this->_getOption('quality', $options, 75);

        header('Content-type: ' . $this->getMimeType($type));
        $cmd = $this->_postProcess($type, $quality);
        passthru($cmd . ' 2>&1');
        if (!$this->keep_settings_on_save) {
            $this->free();
        }

        return true;
    }

    /**
     * Destroy image handle
     */
    public function free()
    {
        $this->command = [];
    }
} // End class ImageIM