1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 
<?php
namespace Omeka\File\Thumbnailer;

use Imagick as ImagickPhp;
use ImagickException;
use Omeka\File\Exception;
use Omeka\File\TempFileFactory;

class Imagick extends AbstractThumbnailer
{
    /**
     * @var TempFileFactory
     */
    protected $tempFileFactory;

    /**
     * Check whether the GD entension is loaded.
     *
     * @throws Exception\InvalidThumbnailer
     */
    public function __construct(TempFileFactory $tempFileFactory)
    {
        if (!extension_loaded('imagick')) {
            throw new Exception\InvalidThumbnailerException('The imagick PHP extension must be loaded to use this thumbnailer.');
        }
        $this->tempFileFactory = $tempFileFactory;
    }

    /**
     * {@inheritDoc}
     */
    public function create($strategy, $constraint, array $options = [])
    {
        try {
            $imagick = new ImagickPhp;
            if ($this->sourceFile->getMediaType() == 'application/pdf') {
                $imagick->setResolution(150, 150);
            }
            $imagick->readImage(sprintf('%s[%s]', $this->source, $this->getOption('page', 0)));
        } catch (ImagickException $e) {
            throw new Exception\CannotCreateThumbnailException;
        }

        if ($this->getOption('autoOrient', false)) {
            $this->autoOrient($imagick);
        }

        $origWidth = $imagick->getImageWidth();
        $origHeight = $imagick->getImageHeight();

        $imagick->setBackgroundColor('white');
        $imagick->setImageBackgroundColor('white');
        $imagick->setImagePage($origWidth, $origHeight, 0, 0);
        $imagick = $imagick->mergeImageLayers(ImagickPhp::LAYERMETHOD_FLATTEN);

        switch ($strategy) {
            case 'square':
                $gravity = isset($options['gravity']) ? $options['gravity'] : 'center';
                if ($origWidth < $origHeight) {
                    $tempWidth = $constraint;
                    $tempHeight = $origHeight * ($constraint / $origWidth);
                    $origX = 0;
                    $origY = $this->getOffsetY($tempHeight, $constraint, $gravity);
                } else {
                    $tempHeight = $constraint;
                    $tempWidth = $origWidth * ($constraint / $origHeight);
                    $origY = 0;
                    $origX = $this->getOffsetX($tempWidth, $constraint, $gravity);
                }
                $imagick->thumbnailImage($tempWidth, $tempHeight);
                $imagick->cropImage($constraint, $constraint, $origX, $origY);
                $imagick->setImagePage($constraint, $constraint, 0, 0);
                break;
            case 'default':
            default:
                if ($origWidth < $constraint && $origHeight < $constraint) {
                    $imagick->thumbnailImage($origWidth, $origHeight, true);
                } else {
                    $imagick->thumbnailImage($constraint, $constraint, true);
                }
        }

        $tempFile = $this->tempFileFactory->build();
        $tempPath = sprintf('%s.%s', $tempFile->getTempPath(), 'jpg');
        $tempFile->delete();

        $imagick->writeImage($tempPath);
        $imagick->clear();

        return $tempPath;
    }

    /**
     * Detect orientation flag and rotate image accordingly.
     *
     * @param ImagickPhp $imagick
     */
    protected function autoOrient($imagick)
    {
        $orientation = $imagick->getImageOrientation();
        $white = new ImagickPixel('#fff');
        switch ($orientation) {
            case ImagickPhp::ORIENTATION_RIGHTTOP:
                $imagick->rotateImage($white, 90);
                break;
            case ImagickPhp::ORIENTATION_BOTTOMRIGHT:
                $imagick->rotateImage($white, 180);
                break;
            case ImagickPhp::ORIENTATION_LEFTBOTTOM:
                $imagick->rotateImage($white, 270);
                break;
            case ImagickPhp::ORIENTATION_TOPRIGHT:
                $imagick->flopImage();
                break;
            case ImagickPhp::ORIENTATION_RIGHTBOTTOM:
                $imagick->flopImage();
                $imagick->rotateImage($white, 90);
                break;
            case ImagickPhp::ORIENTATION_BOTTOMLEFT:
                $imagick->flopImage();
                $imagick->rotateImage($white, 180);
                break;
            case ImagickPhp::ORIENTATION_LEFTTOP:
                $imagick->flopImage();
                $imagick->rotateImage($white, 270);
                break;
            case ImagickPhp::ORIENTATION_TOPLEFT:
            default:
                break;
        }
    }
}