Aleksander Machniak
2012-06-06 d1d0564a91812e3e58569bfa0ef413d36e130d24
commit | author | age
a71a97 1 <?php
A 2
3 /*
4  +-----------------------------------------------------------------------+
5  | program/include/rcube_image.php                                       |
6  |                                                                       |
7  | This file is part of the Roundcube Webmail client                     |
8  | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
9  | Copyright (C) 2011-2012, Kolab Systems AG                             |
10  |                                                                       |
11  | Licensed under the GNU General Public License version 3 or            |
12  | any later version with exceptions for skins & plugins.                |
13  | See the README file for a full license statement.                     |
14  |                                                                       |
15  | PURPOSE:                                                              |
19cc5b 16  |   Image resizer and converter                                         |
a71a97 17  |                                                                       |
A 18  +-----------------------------------------------------------------------+
19  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
20  | Author: Aleksander Machniak <alec@alec.pl>                            |
21  +-----------------------------------------------------------------------+
22 */
23
24 class rcube_image
25 {
26     private $image_file;
19cc5b 27
AM 28     const TYPE_GIF = 1;
29     const TYPE_JPG = 2;
30     const TYPE_PNG = 3;
31     const TYPE_TIF = 4;
32
33     public static $extensions = array(
34         self::TYPE_GIF => 'gif',
35         self::TYPE_JPG => 'jpg',
36         self::TYPE_PNG => 'png',
37         self::TYPE_TIF => 'tif',
38     );
39
a71a97 40
A 41     function __construct($filename)
42     {
43         $this->image_file = $filename;
44     }
45
46     /**
47      * Get image properties.
48      *
49      * @return mixed Hash array with image props like type, width, height
50      */
51     public function props()
52     {
f5a7e1 53         // use GD extension
a71a97 54         if (function_exists('getimagesize') && ($imsize = @getimagesize($this->image_file))) {
A 55             $width   = $imsize[0];
56             $height  = $imsize[1];
57             $gd_type = $imsize['2'];
58             $type    = image_type_to_extension($imsize['2'], false);
59         }
60
f5a7e1 61         // use ImageMagick
A 62         if (!$type && ($data = $this->identify())) {
63             list($type, $width, $height) = $data;
a71a97 64         }
A 65
66         if ($type) {
67             return array(
68                 'type'    => $type,
69                 'gd_type' => $gd_type,
70                 'width'   => $width,
71                 'height'  => $height,
72             );
73         }
74     }
75
76     /**
77      * Resize image to a given size
78      *
79      * @param int    $size      Max width/height size
80      * @param string $filename  Output filename
81      *
19cc5b 82      * @return bool True on success, False on failure
a71a97 83      */
A 84     public function resize($size, $filename = null)
85     {
be98df 86         $result  = false;
A 87         $rcube   = rcube::get_instance();
b1b808 88         $convert = $rcube->config->get('im_convert_path', false);
be98df 89         $props   = $this->props();
a71a97 90
A 91         if (!$filename) {
92             $filename = $this->image_file;
93         }
94
95         // use Imagemagick
96         if ($convert) {
97             $p['out']  = $filename;
98             $p['in']   = $this->image_file;
99             $p['size'] = $size.'x'.$size;
f5a7e1 100             $type      = $props['type'];
a71a97 101
f5a7e1 102             if (!$type && ($data = $this->identify())) {
A 103                 $type = $data[0];
a71a97 104             }
A 105
106             $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
107             $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75);
108             $p['-opts'] = array('-resize' => $size.'>');
109
110             if (in_array($type, explode(',', $p['types']))) { // Valid type?
19cc5b 111                 $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p);
a71a97 112             }
A 113
19cc5b 114             if ($result === '') {
a71a97 115                 return true;
A 116             }
117         }
118
119         // use GD extension
120         $gd_types = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG);
121         if ($props['gd_type'] && in_array($props['gd_type'], $gd_types)) {
122             if ($props['gd_type'] == IMAGETYPE_JPEG) {
123                 $image = imagecreatefromjpeg($this->image_file);
124             }
125             elseif($props['gd_type'] == IMAGETYPE_GIF) {
126                 $image = imagecreatefromgif($this->image_file);
127             }
128             elseif($props['gd_type'] == IMAGETYPE_PNG) {
129                 $image = imagecreatefrompng($this->image_file);
130             }
131
132             $scale  = $size / max($props['width'], $props['height']);
133             $width  = $props['width']  * $scale;
134             $height = $props['height'] * $scale;
135
136             $new_image = imagecreatetruecolor($width, $height);
137
138             // Fix transparency of gif/png image
139             if ($props['gd_type'] != IMAGETYPE_JPEG) {
140                 imagealphablending($new_image, false);
141                 imagesavealpha($new_image, true);
142                 $transparent = imagecolorallocatealpha($new_image, 255, 255, 255, 127);
143                 imagefilledrectangle($new_image, 0, 0, $width, $height, $transparent);
144             }
145
146             imagecopyresampled($new_image, $image, 0, 0, 0, 0, $width, $height, $props['width'], $props['height']);
147             $image = $new_image;
148
149             if ($props['gd_type'] == IMAGETYPE_JPEG) {
150                 $result = imagejpeg($image, $filename, 75);
151             }
152             elseif($props['gd_type'] == IMAGETYPE_GIF) {
153                 $result = imagegif($image, $filename);
154             }
155             elseif($props['gd_type'] == IMAGETYPE_PNG) {
156                 $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
157             }
158
159             if ($result) {
160                 return true;
161             }
162         }
163
19cc5b 164         // @TODO: print error to the log?
AM 165         return false;
166     }
167
168     /**
169      * Convert image to a given type
170      *
171      * @param int    $type      Destination file type (see class constants)
172      * @param string $filename  Output filename (if empty, original file will be used
173      *                          and filename extension will be modified)
174      *
175      * @return bool True on success, False on failure
176      */
177     public function convert($type, $filename = null)
178     {
179         $rcube   = rcube::get_instance();
180         $convert = $rcube->config->get('im_convert_path', false);
181
182         if (!$filename) {
183             $filename = $this->image_file;
184
185             // modify extension
186             if ($extension = self::$extensions[$type]) {
187                 $filename = preg_replace('/\.[^.]+$/', '', $filename) . '.' . $extension;
188             }
189         }
190
191         // use ImageMagick
192         if ($convert) {
193             $p['in']   = $this->image_file;
194             $p['out']  = $filename;
195             $p['type'] = self::$extensions[$type];
196
197             $result = rcube::exec($convert . ' 2>&1 -colorspace RGB -quality 75 {in} {type}:{out}', $p);
198
199             if ($result === '') {
200                 return true;
201             }
202         }
203
204         // use GD extension (TIFF isn't supported)
205         $props    = $this->props();
206         $gd_types = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG);
207
208         if ($props['gd_type'] && in_array($props['gd_type'], $gd_types)) {
209             if ($props['gd_type'] == IMAGETYPE_JPEG) {
210                 $image = imagecreatefromjpeg($this->image_file);
211             }
212             else if ($props['gd_type'] == IMAGETYPE_GIF) {
213                 $image = imagecreatefromgif($this->image_file);
214             }
215             else if ($props['gd_type'] == IMAGETYPE_PNG) {
216                 $image = imagecreatefrompng($this->image_file);
217             }
218
219             if ($type == self::TYPE_JPG) {
220                 $result = imagejpeg($image, $filename, 75);
221             }
222             else if ($type == self::TYPE_GIF) {
223                 $result = imagegif($image, $filename);
224             }
225             else if ($type == self::TYPE_PNG) {
226                 $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
227             }
228         }
a71a97 229
A 230         // @TODO: print error to the log?
231         return false;
232     }
233
f5a7e1 234     /**
A 235      * Identify command handler.
236      */
237     private function identify()
238     {
be98df 239         $rcube = rcube::get_instance();
f5a7e1 240
be98df 241         if ($cmd = $rcube->config->get('im_identify_path')) {
f5a7e1 242             $args = array('in' => $this->image_file, 'format' => "%m %[fx:w] %[fx:h]");
be98df 243             $id   = rcube::exec($cmd. ' 2>/dev/null -format {format} {in}', $args);
f5a7e1 244
A 245             if ($id) {
246                 return explode(' ', strtolower($id));
247             }
248         }
249     }
19cc5b 250
a71a97 251 }