Help us understand the problem. What is going on with this article?

Imagickをちょっと良い感じに使いたい。

More than 3 years have passed since last update.

!実施環境を見てもらえば分かると思いますが、いろいろ古いです。

実施環境

  • OS: Ubuntu 14.04.5 LTS
  • php: 5.5.9
  • php5-imagick: 3.1.2-1build1

本題

こんな感じのclassを作る(とりあえず雰囲気が伝われば幸いです)。

ImagickHelper.php
<?php
class ImagickHelper {
  private $imagick = null;
  /**
   *
   * @param $file
   * @return
   * @throw Exception
   */
  public function begin($file) {
    if ($file === null) {
      throw new Exception('$file must not be null.');
    }
    try {
      if ($this->imagick === null) {
        $this->imagick = new Imagick();
      } else {
        $this->imagick->clear();
      }
      $this->imagick->readImage($file);
      return $this;
    } catch(ImagickException $e) {
      throw new Exception($e->getMessage().' file: '.basename(__FILE__).' line: '.__LINE__);
    }
  }
  /**
   * JPEG画像の回転補正(ExifのOrientation対応)
   * @param $file
   * @return
   * @throw Exception
   */
  public function adjustExifOrientation() {
    $this->verify();
    try {
      if (strtolower($this->imagick->getImageFormat()) != 'jpeg') {
        return $this;
      }
      $orientation = $this->imagick->getImageOrientation();
      $isRotated = true;
      switch($orientation) {
        case Imagick::ORIENTATION_BOTTOMRIGHT:
          $this->imagick->rotateimage('none', 180);
          break;
        case Imagick::ORIENTATION_RIGHTTOP:
          $this->imagick->rotateimage('none', 90);
          break;
        case Imagick::ORIENTATION_LEFTBOTTOM:
          $this->imagick->rotateimage('none', -90);
          break;
        default:
          $isRotated = false;
      }
      if ($isRotated) {
        $this->imagick->setImageOrientation(Imagick::ORIENTATION_TOPLEFT);
      }
      return $this;
    } catch(ImagickException $e) {
      throw new Exception($e->getMessage().' file: '.basename(__FILE__).' line: '.__LINE__);
    }
  }
  /**
   *
   * @param
   * @param
   * @param
   * @return
   * @throw Exception
   */
  public function reduce($width, $height, $aspectFit = true) {
    $this->verify();
    try {
      // オリジナルの画像サイズ
      $imgWidth = $this->imagick->getImageWidth();
      $imgHeight = $this->imagick->getImageHeight();
      // 画像が指定サイズより大きい場合
      if ($imgWidth > $width || $imgHeight > $height) {
        $newWidth = $width;
        $newHeight = $height;
        if ($aspectFit) {
          if (($width / $height) > ($imgWidth / $imgHeight)) {
            $newWidth = 0;
          } else {
            $newHeight = 0;
          }
        }
        $this->imagick->resizeImage($newWidth, $newHeight, imagick::FILTER_LANCZOS, 1);
      }
      return $this;
    } catch(ImagickException $e) {
      throw new Exception($e->getMessage().' file: '.basename(__FILE__).' line: '.__LINE__);
    }
  }
  /**
   *
   * @param $fn 品質を返す関数(引数に画像サイズ(byte)を取る)
   * @return
   * @throw Exception
   */
  public function compress(callable $fn = null) {
    $this->verify();
    try {
      $quality = is_callable($fn) ? call_user_func($fn, strlen($this->imagick->getImageBlob())) : 0;
      $comp = call_user_func(function($format) {
        switch($format) {
          case 'jpeg':
            return imagick::COMPRESSION_JPEG;
            break;
          default:
            return imagick::COMPRESSION_UNDEFINED;
        }
      }, strtolower($this->imagick->getImageFormat()));
      $this->imagick->setImageCompression($comp);
      if (!$this->imagick->setImageCompressionQuality($quality)) {
        throw new Exception("Failed to set image compression quality. quality: {$quality}");
      }
      return $this;
    } catch(ImagickException $e) {
      throw new Exception($e->getMessage().' file: '.basename(__FILE__).' line: '.__LINE__);
    }
  }
  /**
   *
   * @param $quality 品質
   * @return
   * @throw Exception
   */
  public function cropThumbnail($width, $height) {
    if ($width === null || $width === null) {
      throw new Exception('$width and $height must not be null.');
    }
    $this->verify();
    try {
      if (!$this->imagick->cropThumbnailImage($width, $height)) {
        throw new Exception("Failed to crop thumbnail image. wdith: {$width} height: {$height}");
      }
      return $this;
    } catch(ImagickException $e) {
      throw new Exception($e->getMessage().' file: '.basename(__FILE__).' line: '.__LINE__);
    }
  }
  /**
   *
   * @param $output 出力先(ファイル名まで)
   * @return
   * @throw Exception
   */
  public function write($output = null) {
    $this->verify();
    try {
      $this->imagick->writeImage($output);
      return $this;
    } catch(ImagickException $e) {
      throw new Exception($e->getMessage().' file: '.basename(__FILE__).' line: '.__LINE__);
    }
  }
  /**
   *
   * @return
   * @throw Exception
   */
  public function clear() {
    $this->verify();
    try {
      $this->imagick->clear();
      return $this;
    } catch(ImagickException $e) {
      throw new Exception($e->getMessage().' file: '.basename(__FILE__).' line: '.__LINE__);
    }
  }
  /**
   *
   * @return $this
   */
  public function discard() {
    $this->imagick = null;
    return $this;
  }
  /**
   *
   * @throw Exception
   */
  private function verify() {
    if ($this->imagick === null) {
      throw new Exception('To start the imagick process, call begin() at first.');
    }
  }
}

使う側はこんな感じ。

/**
 * 画像の加工処理
 */
private function imageProcessing($file) {
  $im = new ImagickHelper();
  try {
    // EXIF Orientationを調整して、縮小して、圧縮して書き出す
    $im->begin($file)->adjustExifOrientation()
    ->reduce($this->image_max_width, $this->image_max_height)
    ->compress(function($imageLength) {
      // 1MB以上だったら品質を80%に設定
      switch ($imageLength) {
        case 1000000 <= $imageLength:
          return 80;
          break;
        default:
          return 0;
      }
    })->write($file)->clear();
    return true;
  } catch(Exception $e) {
    echo "An error occurred. {$e->getMessage()}";
    return false;
  } finally {
    $im->discard();
  }
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした