Преоразмеряване на изображения в PHP

Прeоразмеряването и създаването на миниатюри (thumbnails) е едно от нещата, който доста често се налага да правя. Трудно ми е да се сетя сайт, по който да съм работил и за който не е било необходимо, да се обработват качените от потребителите картинки. Казано с други думи, това е задача, която спокойно можем да наречем всекидневна.
В PHP имаме на разположение, цели две библиотеки за целта – GD и Image Magick. GD e включена в изходния код на PHP, за разлика от Image Magic, която се намира в PECL (http://pecl.php.net/). Реших да тествам двете библиотеки, за да видя коя се справя по-добре с преоразмеряването. Използвах PHP 5.2.4 с версия 2 на GD и ImageMagick 6.3.7 с php-imagick 2.0.1. Тестът се състои в преоразмеряване на една картинка 1000 пъти. Ето го и кода, под него са резултатите от пет поредни изпълнения в секунди, както и крайният резултат.

Код за тестване на GD
[geshi lang=php]
$start = microtime(true);

for($i = 1; $i <= 1000; $i++) {
list($width, $height) = getimagesize('image.jpg');
$image = imagecreatefromjpeg('image.jpg');
$th_image = imagecreatetruecolor(400, 400);
// imagecopyresized($image, $th_image, 0, 0, 0, 0, 400, 400, $width, $height);
imagecopyresampled($th_image, $image, 0, 0, 0, 0, 400, 400, $width, $height); // better quality
//imagejpeg($th_image, 'th_image.jpg');
}

$end = microtime(true);
$result = $end - $start;
echo "The result is $result sec.\n";
[/geshi]

Резултати от теста GD
1) 410.775580883
2) 409.137652159
3) 408.297181129
4) 428.035866976
5) 447.850259066
415,983033339

Код за тестване на Image Magick
[geshi lang=php]
$start = microtime(true);

for($i = 1; $i <= 1000; $i++) {
$image = new Imagick('image.jpg');
$image->thumbnailImage(400, 400);
//$image->writeImage(‘th_image.jpg’);
}

$end = microtime(true);
$result = $end – $start;
echo „The result is $result sec.\n“;
[/geshi]

Резултати от теста Image Magick
1) 838.643035889
2) 876.974920988
3) 916.62350893
4) 964.90379405
5) 962.138086081
918,578838666

Ясно се вижда, че за момента преоразмеряването на картинки с GD е повече от два пъти по-бързо, в сравнение с Image Magick. Прави впечатление също, колко малко код трябва да напишем използвайки Image Magick. Необходими са само два реда и е повече от интуитивно, нещо което не мога да кажа че е така с GD.
Според мен, за момента GD остава по-добрият вариант основно заради бързодействието, но Image Magick също заслужава внимание. За финал се опитах да капсулирам логиката за преоразмеряване на изображения с GD в един клас, кода на който е по-долу, надявайки се да е от полза на някого.

[geshi lang=php]
class myLibs_Image_GD {

protected $image;
protected $image_path;
protected $image_width;
protected $image_height;

protected $image_th;

/\*\*
\* $path is the full or relative path to image for processing
\*
\* @param string $path
\* @return object
\*/
public function __construct($path) {
if (!isset($path) || !is_file($path)) {
throw new InvalidArgumentException(\_\_CLASS\_\_ . ' ' . \_\_METHOD\_\_ . ' invalid arguments passed.');
}

if (!is_readable($path)) {
throw new InvalidArgumentException(\_\_CLASS\_\_ . ' ' . \_\_METHOD\_\_ . ' cant read the file.');
}

list($width, $height, $type) = getimagesize($path);
switch ($type) {
case IMG_JPEG:
$this->image = imagecreatefromjpeg($path);
break;

case IMG_JPG:
$this->image = imagecreatefromjpeg($path);
break;

case IMG_PNG:
$this->image = imagecreatefrompng($path);
break;

case IMG_GIF:
$this->image = imagecreatefromgif($path);
break;

default:
throw new InvalidArgumentException(\_\_CLASS\_\_ . ‘ ‘ . \_\_METHOD\_\_ . ‘ invalid image type.’);
break;
}

$this->image_width = $width;
$this->image_height = $height;

$this->image_path = $path;
}

/\*\*
\* Pass true to $keep_ratio if you want to keep image ratio.
\*
\* @param integer $width
\* @param integer $height
\* @param boolean $keep_ratio
\* @return void
\*/
public function resize($width, $height, $keep_ratio = false) {
if (!isset($width) || !isset($height) || !is_numeric($width) || !is_numeric($height)) {
throw new InvalidArgumentException(\_\_CLASS\_\_ . ‘ ‘ . \_\_METHOD\_\_ . ‘ invalid arguments passed.’);
}

// calculate new $width and $height
$new_width = $new_height = null;
if ($keep_ratio) {
$ratio = $this->image_width / $this->image_height;
if ($this->image_width >= $this->image_height) {
$new_width = $width;
$new_height = $new_width / $ratio;
} else {
$new_height = $height;
$new_width = $new_height \* $ratio;
}
} else {
$new_width = $width;
$new_height = $height;
}

$this->image_th = imagecreatetruecolor($new_width, $new_height);
$result = imagecopyresampled($this->image_th, $this->image, 0, 0, 0, 0, $new_width, $new_height, $this->image_width, $this->image_height);
}

/\*\*
\* To create a new image set $path else changes will be
\* written on the current image.
\*
\* @param string $path
\* @param integer $type
\* @return void
\*/
public function write($path = false, $type = IMG_JPG) {
// get source image path on false
// and check for write permissions
if ($path == false) {
if (!is_writable($this->image_path)) {
throw new InvalidArgumentException(\_\_CLASS\_\_ . ‘ ‘ . \_\_METHOD\_\_ . ‘ cant write in specified file location.’);
}

$path = $this->image_path;
}else if (is_file($path)) {
if (!is_writable($path)) {
throw new InvalidArgumentException(\_\_CLASS\_\_ . ‘ ‘ . \_\_METHOD\_\_ . ‘ cant write in specified file location.’);
}
} else {
if (!is_writable(dirname($path))) {
throw new InvalidArgumentException(\_\_CLASS\_\_ . ‘ ‘ . \_\_METHOD\_\_ . ‘ cant write in specified file location.’);
}
}

switch ($type) {
case IMG_JPEG:
imagejpeg($this->image_th, $path);
break;

case IMG_JPG:
imagejpeg($this->image_th, $path);
break;

case IMG_PNG:
imagepng($this->image_th, $path);
break;

case IMG_GIF:
imagegif($this->image_th, $path);
break;

default:
throw new InvalidArgumentException(\_\_CLASS\_\_ . ‘ ‘ . \_\_METHOD\_\_ . ‘ invalid image type.’);
break;
}
}

}
[/geshi]

Сподели:
Edno23 Favit Svejo Twitter Facebook Google Buzz Delicious Google Bookmarks Digg
Публикувано в PHP. Постоянна връзка.

Един коментар по Преоразмеряване на изображения в PHP

  1. Simo каза:

    Интересно сравнение.
    Пробвал съм ImageMagick с Убунту и Слак за преоразмеряване на много снимки, но върви еднакво бавно, дори на око си личи. :D

Вашият коментар

Вашият email адрес няма да бъде публикуван Задължителните полета са отбелязани с *

*

Можете да използвате тези HTML тагове и атрибути: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>