Edited at

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

More than 1 year has 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();
}
}