1. negibouze

    Posted

    negibouze
Changes in title
+Imagickをちょっと良い感じに使いたい。
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,234 @@
+**!実施環境を見てもらえば分かると思いますが、いろいろ古いです。**
+
+## 実施環境
+
+* OS: Ubuntu 14.04.5 LTS
+* php: 5.5.9
+* php5-imagick: 3.1.2-1build1
+
+## 本題
+
+こんな感じのclassを作る(とりあえず雰囲気が伝われば幸いです)。
+
+```php: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 $maxBytes 画像サイズの上限
+ * @param $quality 品質
+ * @return
+ * @throw Exception
+ */
+ public function compress($maxBytes = 5000000, $quality = 80) {
+ $this->verify();
+ try {
+ if (!is_numeric($maxBytes) || !is_numeric($quality)) {
+ throw new Exception('$maxBytes and $quality must be numeric.');
+ }
+ if ($this->imagick->getImageLength() <= $maxBytes) {
+ return $this;
+ }
+ $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);
+ $this->imagick->setImageCompressionQuality($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 {
+ $this->imagick->cropThumbnailImage($width, $height.'aiueo');
+ 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.');
+ }
+ }
+}
+```
+
+使う側はこんな感じ。
+
+```php
+/**
+ * 画像の加工処理
+ */
+private function imageProcessing($file) {
+ $im = new ImagickHelper();
+ try {
+ // EXIF Orientationを調整して、縮小して、圧縮して書き出す
+ $im->begin($file)->adjustExifOrientation()->reduce(1920, 1080)->compress()->write()->clear();
+ return true;
+ } catch(Exception $e) {
+ echo "An error occurred. {$e->getMessage()}";
+ return false;
+ } finally {
+ $im->discard();
+ }
+}
+```