Imagick seems slow, can i make it faster?

IMagick is a native PHP extension to create and modify images using the ImageMagick API. ImageMagick Studio LLC did not write nor does it maintain the IMagick extension, however, IMagick users are welcome to discuss the extension here.
Post Reply
rokdzone
Posts: 8
Joined: 2015-02-11T08:29:25-07:00
Authentication code: 6789

Imagick seems slow, can i make it faster?

Post by rokdzone »

I'm using ImageMagick 6.6.5-9 2010-11-15 Q16
with PHP module 3.1.2 (php_imagick-3.1.2-5.3-nts-vc9-x86.zip)
running on Windows 8.1 / Intel i7 with 32GB RAM

I have replaced GD-library with Imagick in my PHP project because i've needed some functions
like change perspective on an image, which works great btw.

But...Imagick seems so much slower in some regards, generating 2 different image copies (100x100 and 800x800) from
12 PNG-images with an average size of 1200x800 now takes 7-10 secs instead of near instantaneously with GD-library.

Is this normal?

Reviews i've read claims that Imagick is the faster and more optimized choice...but 'ive also read the opposite.
Don't know what to belief anymore.

Anyway, ive read that using the Q8 version speeds things up, can i use that version when working with 24-bit PNG-images?
Or is the colourspace limited to 8-bit

Anyway, here is my PHP Image class containing all (hints to get things more optimized is very much appreciated)

Code: Select all

<?php
class Image {
	private $file;
	private $image;
	private $info;

	public function __construct($file) {
		
		if (extension_loaded('imagick')) {
			
			if (file_exists($file)) {
				
				$this->file = $file;
				
				$image = new Imagick();
				$image->readImage($file); 
				$info = $image->identifyImage(true);

				$this->info = array(
					'width'  			=> $info['geometry']['width'],
					'height' 			=> $info['geometry']['height'],
					'filesize'		=> $info['fileSize'],
					'compression'	=> $info['compression'],
					'signature'		=> $info['signature'],
					'colorspace'	=> $info['colorSpace'],
					'units'				=> $info['units'],
					'type'				=> $info['type'],
					'mime'   			=> $info['mimetype']
				);
				
				if ($this->info['mime'] == 'image/png') {
					$image->setFormat('png24');
				}
				
				$this->image = $image;
				
			} else {
				exit('Error: Could not load image ' . $file . '!');
			}
		} else {
			exit('Error: The Imagick component is not installed on your server!');
		} 
	}
	
	private function create($file = false) {
		
		if ($file) {
			return new Imagick($file);
		} else {
			return new Imagick();
		}

	}
	
	public function perspective($offset = array(), $background = 'transparent') {
			
		if (count($offset) > 7) {
			
			$points = array(0,0,
								(float)$offset['transform_topleft_x'], (float)$offset['transform_topleft_y'],
								0, $this->image->getImageHeight(),
								(float)$offset['transform_bottomleft_x'], (float)$offset['transform_bottomleft_y'],
								$this->image->getImageWidth(), 0,
								(float)$offset['transform_topright_x'], (float)$offset['transform_topright_y'],
								$this->image->getImageWidth(), $this->image->getImageHeight(),
								(float)$offset['transform_bottomright_x'], (float)$offset['transform_bottomright_y']
			);
				
			$this->image->setImageMatte(true);
			$this->image->setImageMatteColor($background);
			$this->image->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
			$this->image->distortImage(Imagick::DISTORTION_PERSPECTIVE, $points, true);
			
		}
		
	}
	
	public function save($file, $quality = 90) {
		
		$info = pathinfo($file);

		$extension = strtolower($info['extension']);
		
		if (is_object($this->image)) {
			if ($extension == 'jpeg' || $extension == 'jpg') {
				$this->image->setImageFormat('jpg');
				$this->image->setImageCompression(imagick::COMPRESSION_JPEG2000);
				$this->image->setImageCompressionQuality($quality);
				$this->image->stripImage();
			} elseif ($extension == 'png') {
				$this->image->setImageFormat('png');
				$this->image->setImageCompression(0);
			} elseif ($extension == 'gif') {
				$this->image->setImageFormat('gif');
			}
			
			$this->image->writeImage($file);
			
		}
	}
	
	public function output() {
		
		return $this->image;
		
	}
	
	public function base64output($quality = 90) {
		
		if ($this->info['mime']) {
			
			$response = new Response();
			
			$response->addHeader('Content-Type: ' . $this->info['mime']);
			$response->addHeader('Content-transfer-encoding: base64');
			$response->addHeader('Expires: Sun, 01 Jan 2014 00:00:00 GMT');
			$response->addHeader('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
			$response->addHeader('Cache-Control: post-check=0, pre-check=0');
			$response->addHeader('Pragma: no-cache');
			
			if ($this->info['mime'] == 'image/jpeg') {
				$this->image->setImageFormat('jpg');
				$this->image->setImageCompression(imagick::COMPRESSION_JPEG2000);
				$this->image->setImageCompressionQuality($quality);
				$this->image->stripImage();
			} elseif ($this->info['mime'] == 'image/png') {
				$this->image->setImageFormat('png');
				$this->image->setImageCompression(0);
			} elseif ($this->info['mime'] == 'image/gif') {
				$this->image->setImageFormat('gif');
			}
			
			ob_start();
			echo $this->image;	
			return base64_encode(ob_get_clean());
			
		}
		
	}
	
	public function resize($width = 0, $height = 0, $default = '', $method = 'THUMB', $filter = Imagick::FILTER_CATROM) {
		
		if (!$this->info['width'] || !$this->info['height']) {
			return;
		}
		
		$xpos = 0;
		$ypos = 0;
		$scale = 1;
		
		$scale_w = $width / $this->info['width'];
		$scale_h = $height / $this->info['height'];
		
		if ($default == 'w') {
			$scale = $scale_w;
		} elseif ($default == 'h') {
			$scale = $scale_h;
		} else {
			$scale = min($scale_w, $scale_h);
		}

		if ($scale == 1 && $scale_h == $scale_w && $this->info['mime'] != 'image/png') {
			return;
		}
		
		$new_width = (int)($this->info['width'] * $scale);
		$new_height = (int)($this->info['height'] * $scale);
		$xpos = (int)(($width - $new_width) / 2);
		$ypos = (int)(($height - $new_height) / 2);
		
		$image = $this->image;
		
		if ($method == 'SCALE') {
			$image->scaleImage($new_width, $new_height);
		} elseif ($method == 'THUMB') {
			$image->thumbnailImage($new_width, $new_height, false);
		} elseif ($method == 'RESIZE') {
			$image->resizeImage($new_width, $new_height, $filter, 1);
		}
		
		if ($this->info['mime'] == 'image/png') {
			$background = 'none';
		} else {
			$background = 'white';
		}
		
		$canvas = $this->create();
		$canvas->newImage($width, $height, new ImagickPixel($background));
		$canvas->compositeImage($image, imagick::COMPOSITE_OVER, $xpos, $ypos);
		
		$this->info['width'] = $width;
		$this->info['height'] = $height;
		
		$this->image = $canvas;
		
		$image->clear(); 
		$image->destroy();
		
	}
	
	public function scale($width = 0, $height = 0, $method = 'THUMB', $filter = Imagick::FILTER_CATROM) {
		
		if ($method == 'SCALE') {
			$this->image->scaleImage($width, $height);
		} elseif ($method == 'THUMB') {
			$this->image->thumbnailImage($width, $height, false);
		} elseif ($method == 'RESIZE') {
			$this->image->resizeImage($width, $height, $filter, 1);
		}
		
		$this->info['width'] = $this->image->getImageWidth();
		$this->info['height'] = $this->image->getImageHeight();
		
	}
	
	public function watermark($file, $position = 'bottomright', $x = 0, $y = 0) {
		
		$watermark = $this->create($file);
	
		$watermark_width = $watermark->getImageWidth();
		$watermark_height = $watermark->getImageHeight();

		switch($position) {
			case 'topleft':
				$watermark_pos_x = 0;
				$watermark_pos_y = 0;
				break;
			case 'topright':
				$watermark_pos_x = $this->info['width'] - $watermark_width;
				$watermark_pos_y = 0;
				break;
			case 'bottomleft':
				$watermark_pos_x = 0;
				$watermark_pos_y = $this->info['height'] - $watermark_height;
				break;
			case 'bottomright':
				$watermark_pos_x = $this->info['width'] - $watermark_width;
				$watermark_pos_y = $this->info['height'] - $watermark_height;
				break;
			case 'custom':
				$watermark_pos_x = $x;
				$watermark_pos_y = $y;
				break;
		}
		
		$image = $this->image;
		$image->compositeImage($watermark, imagick::COMPOSITE_OVER, $watermark_pos_x, $watermark_pos_y);
		
		$this->image = $image;
		
	}
	
	public function opacity($opacity) {
		
		if ($opacity < 1) {
			$this->image->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity, Imagick::CHANNEL_ALPHA);
		}
		
	}
	
	public function crop($top_x, $top_y, $bottom_x, $bottom_y) {
		
		$this->image->cropImage($bottom_x, $bottom_y, $top_x, $top_y);
		
		$this->info['width'] = $this->image->getImageWidth();
		$this->info['height'] = $this->image->getImageHeight();
		
	}
	
	public function rotate($degree, $color = '#00000000') {
		
		$this->image->rotateImage(new ImagickPixel($color), $degree);

		$this->info['width'] = $this->image->getImageWidth();
		$this->info['height'] = $this->image->getImageHeight();
		
	}
	
	public function composite($watermark, $x = 0, $y = 0) {
		
		$this->image->compositeImage($watermark, imagick::COMPOSITE_OVER, $x, $y);
		
		$this->info['width'] = $this->image->getImageWidth();
		$this->info['height'] = $this->image->getImageHeight();
		
	}
	
	private function merge($file, $x = 0, $y = 0, $opacity = 1) {
		
		$merge = $this->create($file);
		
		if ($opacity < 1) {
			$merge->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity, Imagick::CHANNEL_ALPHA);
		}
		
		$this->image->compositeImage($merge, imagick::COMPOSITE_OVER, $x, $y);
		
	}
	
	public function __destruct() {
		
		$this->image->clear(); 
		$this->image->destroy();
		
	}

}
Post Reply