mambax7/extgallery

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

Summary

Maintainability
A
1 hr
Test Coverage
<?php

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

/**
 * imagick PECL extension implementation for Image_Transform package
 *
 *
 * 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
 * @subpackage Image_Transform_Driver_Imagick3
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
 * @copyright  2007 The PHP Group
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 * @version    CVS: $Id: Imagick3.php 266908 2008-10-01 21:11:07Z dufuz $
 * @link       http://pear.php.net/package/Image_Transform
 */
require_once __DIR__ . '/Image/Transform.php';

/**
 * imagick PECL extension implementation for Image_Transform package
 *
 * For use of version 2+ of the extension. For version 0.9.* use Imagick2 driver
 * instead
 *
 * @category   Image
 * @package    Image_Transform
 * @subpackage Image_Transform_Driver_Imagick3
 * @author     Philippe Jausions <Philippe.Jausions@11abacus.com>
 * @copyright  2007 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
 * @since      0.9.2
 * @since      PHP 5.1.3
 * @since      PECL Imagick 2.0.0a1
 */
class Image_Transform_Driver_Imagick3 extends Image_Transform
{
    /**
     * Instance of imagick
     * @var Imagick
     */
    public $imagick = null;
    /**
     * Handler of the image resource before
     * the last transformation
     * @var array
     */
    public $oldImage;

    /**
     * @see __construct()
     */
    public function Image_Transform_Driver_Imagick3()
    {
        $this->__construct();
    }

    /**
     * @see http://www.imagemagick.org/www/formats.html
     */
    public function __construct()
    {
        if (PEAR::loadExtension('imagick')) {
            require_once __DIR__ . '/Image/Transform/Driver/Imagick/ImageTypes.php';
        } else {
            $this->isError(PEAR::raiseError('Could not find the imagick extension.', IMAGE_TRANSFORM_ERROR_UNSUPPORTED));
        }
    }

    /**
     * Loads an image
     *
     * @param string $image filename
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function load($image)
    {
        $this->free();
        $this->imagick = new Imagick();

        try {
            $this->imagick->readImage($image);
        } catch (ImagickException $e) {
            $this->free();

            return $this->raiseError('Could not load image:' . $e->getMessage(), IMAGE_TRANSFORM_ERROR_IO);
        }

        $this->image = $image;
        $result      = $this->_get_image_details($image);
        if (PEAR::isError($result)) {
            return $result;
        }

        return true;
    }

    /**
     * Resizes the image
     *
     * @param int   $new_x     New width
     * @param int   $new_y     New height
     * @param mixed $options   Optional parameters
     *                         <ul>
     *                         <li>'scaleMethod': "pixel" or "smooth"</li>
     *                         </ul>
     *
     * @return bool|PEAR_Error TRUE or PEAR_Error object on error
     * @access protected
     */
    public function _resize($new_x, $new_y, $options = null)
    {
        try {
            $scaleMethod = $this->_getOption('scaleMethod', $options, 'smooth');
            $blur        = ('pixel' == $scaleMethod) ? 0 : 1;
            $this->imagick->resizeImage($new_x, $new_y, Imagick::FILTER_UNDEFINED, $blur);
        } catch (ImagickException $e) {
            return $this->raiseError('Could not resize image.', IMAGE_TRANSFORM_ERROR_FAILED);
        }

        $this->new_x = $new_x;
        $this->new_y = $new_y;

        return true;
    }

    // End resize

    /**
     * Rotates the current image
     *
     * @param float $angle   Rotation angle in degree
     * @param array $options Supported options:
     *                       <ul>
     *                       <li>'canvasColor' : array(r ,g, b), named color or #rrggbb</li>
     *                       </ul>
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function rotate($angle, $options = null)
    {
        if (0 == ($angle % 360)) {
            return true;
        }
        $color = $this->_getColor('canvasColor', $options, [255, 255, 255]);
        if (is_array($color)) {
            $color = $this->colorarray2colorhex($color);
        }
        $pixel = new ImagickPixel($color);

        try {
            $this->imagick->rotateImage($pixel, $angle);
        } catch (ImagickException $e) {
            return $this->raiseError('Cannot create a new imagick image for the rotation: ' . $e->getMessage(), IMAGE_TRANSFORM_ERROR_FAILED);
        }
        $info        = $this->imagick->getImageGeometry();
        $this->new_x = $info['width'];
        $this->new_y = $info['height'];

        return true;
    }

    // End rotate

    /**
     * Adds text to the image
     *
     * @param array $params   Array contains options:
     *                        <ul>
     *                        <li>'text' (string) The string to draw</li>
     *                        <li>'x'    (integer) Horizontal position</li>
     *                        <li>'y'    (integer) Vertical Position</li>
     *                        <li>'Color' (mixed) Font color</li>
     *                        <li>'font' (string) Font to be used</li>
     *                        <li>'size' (integer) Size of the fonts in pixel</li>
     *                        </ul>
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function addText($params)
    {
        $this->oldImage = clone $this->imagick;
        $params         = array_merge($this->_get_default_text_params(), $params);

        if (is_array($params['color'])) {
            $params['color'] = $this->colorarray2colorhex($params['color']);
        } else {
            $params['color'] = mb_strtolower($params['color']);
        }

        static $cmds = [
            'setFillColor' => 'color',
            'setFontSize'  => 'size',
            'setFontFace'  => 'font',
        ];
        $this->imagick->beginDraw();

        foreach ($cmds as $cmd => $v) {
            if (!$this->imagick->$cmd($params[$v])) {
                return $this->raiseError("Problem with adding Text::{$v} = {$params[$v]}", IMAGE_TRANSFORM_ERROR_FAILED);
            }
        }
        if (!$this->imagick->drawAnnotation($params['x'], $params['y'], $params['text'])) {
            return $this->raiseError('Problem with adding Text', IMAGE_TRANSFORM_ERROR_FAILED);
        }

        return true;
    }

    // End addText

    /**
     * Saves the image to a file
     *
     * @param string $filename the name of the file to write to
     *
     * @param string $type
     * @param null   $quality
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function save($filename, $type = '', $quality = null)
    {
        $options = is_array($quality) ? $quality : [];
        if (is_numeric($quality)) {
            $options['quality'] = $quality;
        }
        $quality = $this->_getOption('quality', $options, 75);
        $this->imagick->setImageCompression($quality);

        if ($type && strcasecmp($type, $this->type)) {
            try {
                $this->imagick->setImageFormat($type);
            } catch (ImagickException $e) {
                return $this->raiseError('Could not save image to file (conversion failed).', IMAGE_TRANSFORM_ERROR_FAILED);
            }
        }

        try {
            $this->imagick->writeImage($filename);
        } catch (ImagickException $e) {
            return $this->raiseError('Could not save image to file: ' . $e->getMessage(), IMAGE_TRANSFORM_ERROR_IO);
        }

        if (!$this->keep_settings_on_save) {
            $this->free();
        }

        return true;
    }

    // End save

    /**
     * Displays image without saving and lose changes
     *
     * This method adds the Content-type HTTP header
     *
     * @param mixed      $type
     * @param null|mixed $quality
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function display($type = '', $quality = null)
    {
        $options = is_array($quality) ? $quality : [];
        if (is_numeric($quality)) {
            $options['quality'] = $quality;
        }
        $quality = $this->_getOption('quality', $options, 75);
        $this->imagick->setImageCompression($quality);

        if ($type && strcasecmp($type, $this->type)) {
            try {
                $this->imagick->setImageFormat($type);
            } catch (ImagickException $e) {
                return $this->raiseError('Could not save image to file (conversion failed).', IMAGE_TRANSFORM_ERROR_FAILED);
            }
        }

        try {
            $image = $this->imagick->getImageBlob();
        } catch (ImagickException $e) {
            return $this->raiseError('Could not display image.', IMAGE_TRANSFORM_ERROR_IO);
        }
        header('Content-type: ' . $this->getMimeType($type));
        echo $image;
        $this->free();

        return true;
    }

    /**
     * Adjusts the image gamma
     *
     * @param float $outputgamma
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function gamma($outputgamma = 1.0)
    {
        if (1.0 != $outputgamma) {
            $this->imagick->setImageGamma($outputgamma);
        }

        return true;
    }

    /**
     * Crops the image
     *
     * @param int $width  Cropped image width
     * @param int $height Cropped image height
     * @param int $x      X-coordinate to crop at
     * @param int $y      Y-coordinate to crop at
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    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);
        }

        try {
            $this->imagick->cropImage($width, $height, $x, $y);
        } catch (ImagickException $e) {
            return $this->raiseError('Could not crop image', IMAGE_TRANSFORM_ERROR_FAILED);
        }

        // I think that setting img_x/y is wrong, but scaleByLength() & friends
        // mess up the aspect after a crop otherwise.
        $this->new_x = $width;
        $this->new_y = $height;

        return true;
    }

    /**
     * Converts the image to greyscale
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function greyscale()
    {
        $this->imagick->setImageType(Imagick::IMGTYPE_GRAYSCALE);

        /*$this->imagick->setImageColorSpace(Imagick::COLORSPACE_GRAY);
        $this->imagick->setImageDepth(8);
        $this->imagick->separateImageChannel(Imagick::CHANNEL_GRAY);
        $this->imagick->setImageChannelDepth(Imagick::CHANNEL_GRAY, 8);*/

        return true;
    }

    /**
     * Horizontal mirroring
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function mirror()
    {
        try {
            $this->imagick->flopImage();
        } catch (ImagickException $e) {
            return $this->raiseError('Could not mirror the image.', IMAGE_TRANSFORM_ERROR_FAILED);
        }

        return true;
    }

    /**
     * Vertical mirroring
     *
     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
     * @access public
     */
    public function flip()
    {
        try {
            $this->imagick->flipImage();
        } catch (ImagickException $e) {
            return $this->raiseError('Could not flip the image.', IMAGE_TRANSFORM_ERROR_FAILED);
        }

        return true;
    }

    /**
     * Destroy image handle
     *
     * @access public
     */
    public function free()
    {
        if (isset($this->imagick)) {
            $this->imagick->destroy();
            $this->imagick = null;
        }
    }

    /**
     * RaiseError Method - shows imagick Raw errors.
     *
     * @param string $message message = prefixed message..
     * @param int    $code    error code
     * @return PEAR error object
     * @access protected
     */
    public function raiseError($message, $code = 0)
    {
        return PEAR::raiseError($message, $code);
    }
}