Initial Kohana install
[speedfreak] / Server / system / libraries / drivers / Image / GraphicsMagick.php
1 <?php defined('SYSPATH') OR die('No direct access allowed.');
2 /**
3  * GraphicsMagick Image Driver.
4  *
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 {
11
12         // Directory that GM is installed in
13         protected $dir = '';
14
15         // Command extension (exe for windows)
16         protected $ext = '';
17
18         // Temporary image filename
19         protected $tmp_image;
20
21         /**
22          * Attempts to detect the GraphicsMagick installation directory.
23          *
24          * @throws  Kohana_Exception
25          * @param   array   configuration
26          * @return  void
27          */
28         public function __construct($config)
29         {
30                 if (empty($config['directory']))
31                 {
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');
35
36                         $config['directory'] = dirname($path);
37                 }
38
39                 // Set the command extension
40                 $this->ext = (PHP_SHLIB_SUFFIX === 'dll') ? '.exe' : '';
41
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);
45
46
47                 // Set the installation directory
48                 $this->dir = str_replace('\\', '/', realpath($config['directory'])).'/';
49         }
50
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.
54          */
55         public function process($image, $actions, $dir, $file, $render = FALSE)
56         {
57                 // We only need the filename
58                 $image = $image['file'];
59
60                 // Unique temporary filename
61                 $this->tmp_image = $dir.'k2img--'.sha1(time().$dir.$file).substr($file, strrpos($file, '.'));
62
63                 // Copy the image to the temporary file
64                 copy($image, $this->tmp_image);
65
66                 // Quality change is done last
67                 $quality = (int) arr::remove('quality', $actions);
68
69                 // Use 95 for the default quality
70                 empty($quality) and $quality = 95;
71
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);
75
76                 if ($status = $this->execute($actions))
77                 {
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))
82                         {
83                                 $this->errors[] = $error;
84                         }
85                         else
86                         {
87                                 // Output the image directly to the browser
88                                 if ($render !== FALSE)
89                                 {
90                                         $contents = file_get_contents($this->tmp_image);
91                                         switch (substr($file, strrpos($file, '.') + 1))
92                                         {
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;
103                                         }
104                                         echo $contents;
105                                 }
106                         }
107                 }
108
109                 // Remove the temporary image
110                 unlink($this->tmp_image);
111                 $this->tmp_image = '';
112
113                 return $status;
114         }
115
116         public function crop($prop)
117         {
118                 // Sanitize and normalize the properties into geometry
119                 $this->sanitize_geometry($prop);
120
121                 // Set the IM geometry based on the properties
122                 $geometry = escapeshellarg($prop['width'].'x'.$prop['height'].'+'.$prop['left'].'+'.$prop['top']);
123
124                 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -crop '.$geometry.' '.$this->cmd_image.' '.$this->cmd_image))
125                 {
126                         $this->errors[] = $error;
127                         return FALSE;
128                 }
129
130                 return TRUE;
131         }
132
133         public function flip($dir)
134         {
135                 // Convert the direction into a GM command
136                 $dir = ($dir === Image::HORIZONTAL) ? '-flop' : '-flip';
137
138                 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' '.$dir.' '.$this->cmd_image.' '.$this->cmd_image))
139                 {
140                         $this->errors[] = $error;
141                         return FALSE;
142                 }
143
144                 return TRUE;
145         }
146
147         public function resize($prop)
148         {
149                 switch ($prop['master'])
150                 {
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;
163                 }
164
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))
167                 {
168                         $this->errors[] = $error;
169                         return FALSE;
170                 }
171
172                 return TRUE;
173         }
174
175         public function rotate($amt)
176         {
177                 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -rotate '.escapeshellarg($amt).' -background transparent '.$this->cmd_image.' '.$this->cmd_image))
178                 {
179                         $this->errors[] = $error;
180                         return FALSE;
181                 }
182
183                 return TRUE;
184         }
185
186         public function sharpen($amount)
187         {
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);
193
194                 // Convert the amount to an GM command
195                 $sharpen = escapeshellarg($radius.'x'.$sigma.'+'.$amount.'+0');
196
197                 if ($error = exec(escapeshellcmd($this->dir.'gm'.$this->ext.' convert').' -unsharp '.$sharpen.' '.$this->cmd_image.' '.$this->cmd_image))
198                 {
199                         $this->errors[] = $error;
200                         return FALSE;
201                 }
202
203                 return TRUE;
204         }
205
206         protected function properties()
207         {
208                 return array_slice(getimagesize($this->tmp_image), 0, 2, FALSE);
209         }
210
211 } // End Image GraphicsMagick Driver