Removed dep on API
[ninja.git] / system / libraries / drivers / Image / GraphicsMagick.php
blob8840eb807e293485e964f99afc1ccab17bb40ccb
1 <?php defined('SYSPATH') OR die('No direct access allowed.');
2 /**
3 * GraphicsMagick Image Driver.
5 * @package Image
6 * @author Kohana Team
7 * @copyright (c) 2007-2008 Kohana Team
8 * @license http://kohanaphp.com/license.html
9 */
10 class Image_GraphicsMagick_Driver extends Image_Driver {
12 // Directory that GM is installed in
13 protected $dir = '';
15 // Command extension (exe for windows)
16 protected $ext = '';
18 // Temporary image filename
19 protected $tmp_image;
21 /**
22 * Attempts to detect the GraphicsMagick installation directory.
24 * @throws Kohana_Exception
25 * @param array configuration
26 * @return void
28 public function __construct($config)
30 if (empty($config['directory']))
32 // Attempt to locate GM by using "which" (only works for *nix!)
33 if ( ! is_file($path = exec('which gm')))
34 throw new Kohana_Exception('image.graphicsmagick.not_found');
36 $config['directory'] = dirname($path);
39 // Set the command extension
40 $this->ext = (PHP_SHLIB_SUFFIX === 'dll') ? '.exe' : '';
42 // Check to make sure the provided path is correct
43 if ( ! is_file(realpath($config['directory']).'/gm'.$this->ext))
44 throw new Kohana_Exception('image.graphicsmagick.not_found', 'gm'.$this->ext);
47 // Set the installation directory
48 $this->dir = str_replace('\\', '/', realpath($config['directory'])).'/';
51 /**
52 * Creates a temporary image and executes the given actions. By creating a
53 * temporary copy of the image before manipulating it, this process is atomic.
55 public function process($image, $actions, $dir, $file, $render = FALSE)
57 // We only need the filename
58 $image = $image['file'];
60 // Unique temporary filename
61 $this->tmp_image = $dir.'k2img--'.sha1(time().$dir.$file).substr($file, strrpos($file, '.'));
63 // Copy the image to the temporary file
64 copy($image, $this->tmp_image);
66 // Quality change is done last
67 $quality = (int) arr::remove('quality', $actions);
69 // Use 95 for the default quality
70 empty($quality) and $quality = 95;
72 // All calls to these will need to be escaped, so do it now
73 $this->cmd_image = escapeshellarg($this->tmp_image);
74 $this->new_image = ($render)? $this->cmd_image : escapeshellarg($dir.$file);
76 if ($status = $this->execute($actions))
78 // Use convert to change the image into its final version. This is
79 // done to allow the file type to change correctly, and to handle
80 // the quality conversion in the most effective way possible.
81 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -quality '.$quality.'% '.$this->cmd_image.' '.$this->new_image))
83 $this->errors[] = $error;
85 else
87 // Output the image directly to the browser
88 if ($render !== FALSE)
90 $contents = file_get_contents($this->tmp_image);
91 switch (substr($file, strrpos($file, '.') + 1))
93 case 'jpg':
94 case 'jpeg':
95 header('Content-Type: image/jpeg');
96 break;
97 case 'gif':
98 header('Content-Type: image/gif');
99 break;
100 case 'png':
101 header('Content-Type: image/png');
102 break;
104 echo $contents;
109 // Remove the temporary image
110 unlink($this->tmp_image);
111 $this->tmp_image = '';
113 return $status;
116 public function crop($prop)
118 // Sanitize and normalize the properties into geometry
119 $this->sanitize_geometry($prop);
121 // Set the IM geometry based on the properties
122 $geometry = escapeshellarg($prop['width'].'x'.$prop['height'].'+'.$prop['left'].'+'.$prop['top']);
124 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -crop '.$geometry.' '.$this->cmd_image.' '.$this->cmd_image))
126 $this->errors[] = $error;
127 return FALSE;
130 return TRUE;
133 public function flip($dir)
135 // Convert the direction into a GM command
136 $dir = ($dir === Image::HORIZONTAL) ? '-flop' : '-flip';
138 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' '.$dir.' '.$this->cmd_image.' '.$this->cmd_image))
140 $this->errors[] = $error;
141 return FALSE;
144 return TRUE;
147 public function resize($prop)
149 switch ($prop['master'])
151 case Image::WIDTH: // Wx
152 $dim = escapeshellarg($prop['width'].'x');
153 break;
154 case Image::HEIGHT: // xH
155 $dim = escapeshellarg('x'.$prop['height']);
156 break;
157 case Image::AUTO: // WxH
158 $dim = escapeshellarg($prop['width'].'x'.$prop['height']);
159 break;
160 case Image::NONE: // WxH!
161 $dim = escapeshellarg($prop['width'].'x'.$prop['height'].'!');
162 break;
165 // Use "convert" to change the width and height
166 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -resize '.$dim.' '.$this->cmd_image.' '.$this->cmd_image))
168 $this->errors[] = $error;
169 return FALSE;
172 return TRUE;
175 public function rotate($amt)
177 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -rotate '.escapeshellarg($amt).' -background transparent '.$this->cmd_image.' '.$this->cmd_image))
179 $this->errors[] = $error;
180 return FALSE;
183 return TRUE;
186 public function sharpen($amount)
188 // Set the sigma, radius, and amount. The amount formula allows a nice
189 // spread between 1 and 100 without pixelizing the image badly.
190 $sigma = 0.5;
191 $radius = $sigma * 2;
192 $amount = round(($amount / 80) * 3.14, 2);
194 // Convert the amount to an GM command
195 $sharpen = escapeshellarg($radius.'x'.$sigma.'+'.$amount.'+0');
197 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -unsharp '.$sharpen.' '.$this->cmd_image.' '.$this->cmd_image))
199 $this->errors[] = $error;
200 return FALSE;
203 return TRUE;
206 protected function properties()
208 return array_slice(getimagesize($this->tmp_image), 0, 2, FALSE);
211 } // End Image GraphicsMagick Driver