1<?php
2// +----------------------------------------------------------------------+
3// | PHP Version 4                                                        |
4// +----------------------------------------------------------------------+
5// | Copyright (c) 1997-2003 The PHP Group                                |
6// +----------------------------------------------------------------------+
7// | This source file is subject to version 2.02 of the PHP license,      |
8// | that is bundled with this package in the file LICENSE, and is        |
9// | available at through the world-wide-web at                           |
10// | http://www.php.net/license/2_02.txt.                                 |
11// | If you did not receive a copy of the PHP license and are unable to   |
12// | obtain it through the world-wide-web, please send a note to          |
13// | license@php.net so we can mail you a copy immediately.               |
14// +----------------------------------------------------------------------+
15// | Authors: Jason Rust <jrust@rustyparts.com>                           |
16// +----------------------------------------------------------------------+
17// $Id: Imlib.php 258825 2008-04-30 23:00:13Z cweiske $
18// {{{ requires
19
20require_once 'Image/Transform.php';
21
22// }}}
23// {{{ example usage
24
25//    $img    = new Image_Transform::factory('Imlib');
26//    $angle  = -90;
27//    $img->load('test.png');
28//    $img->rotate($angle);
29//    $img->addText(array('text'=>"Rotation $angle",'x'=>0,'y'=>100,'font'=>'arial.ttf','color'=>'#ffffff'));
30//    $img->display();
31
32// }}}
33// {{{ class Image_Transform_Driver_Imlib
34
35/**
36 * Performs image manipulation with the imlib library.
37 *
38 * @see http://mmcc.cx/php_imlib/index.php
39 * @version Revision: 1.0
40 * @author  Jason Rust <jrust@rustyparts.com>
41 * @package Image_Transform
42 */
43
44// }}}
45class Image_Transform_Driver_Imlib extends Image_Transform {
46    // {{{ properties
47
48    /**
49     * Holds the image file for manipulation
50     */
51    var $imageHandle = '';
52
53    /**
54     * Holds the original image file
55     */
56    var $oldHandle = '';
57
58    // }}}
59    // {{{ constructor
60
61    /**
62     * Check settings
63     *
64     * @see __construct()
65     */
66    function Image_Transform_Imlib()
67    {
68        $this->__construct();
69    }
70
71    /**
72     * Check settings
73     *
74     * @return mixed true or  or a PEAR error object on error
75     *
76     * @see PEAR::isError()
77     */
78    function __construct()
79    {
80        if (!PEAR::loadExtension('imlib')) {
81            $this->isError(
82                PEAR::raiseError(
83                    'Couldn\'t find the imlib extension.',
84                    IMAGE_TRANSFORM_ERROR_UNSUPPORTED
85                )
86            );
87        }
88    }
89
90    // }}}
91    // {{{ load()
92
93    /**
94     * Load image
95     *
96     * @param string filename
97     *
98     * @return mixed TRUE or a PEAR error object on error
99     * @see PEAR::isError()
100     */
101    function load($image)
102    {
103        $this->image = $image;
104        $this->imageHandle = imlib_load_image($this->image);
105        $result =& $this->_get_image_details($image);
106        if (PEAR::isError($result)) {
107            return $result;
108        }
109
110        return true;
111    }
112
113    // }}}
114    // {{{ addText()
115
116    /**
117     * Adds text to the image.  Note that the angle should be one of the following
118     * constants:  IMLIB_TEXT_TO_RIGHT, IMLIB_TEXT_TO_LEFT, IMLIB_TEXT_TO_DOWN,
119     * IMLIB_TEXT_TO_UP, IMLIB_TEXT_TO_ANGLE
120     *
121     * @param   array   options     Array contains options
122     *                              array(
123     *                                  'text'  The string to draw
124     *                                  'x'     Horizontal position
125     *                                  'y'     Vertical Position
126     *                                  'color' Font color
127     *                                  'font'  Font to be used
128     *                                  'size'  Size of the fonts in pixel
129     *                                  'angle' A imlib direction constant
130     *                              )
131     *
132     * @return TRUE or PEAR Error object on error
133     * @see PEAR::isError()
134     */
135    function addText($params)
136    {
137        $default_params = array(
138                                'text' => 'This is Text',
139                                'x' => 10,
140                                'y' => 20,
141                                'color' => array(255,0,0),
142                                'font' => 'Arial.ttf',
143                                'size' => '12',
144                                'angle' => IMLIB_TEXT_TO_RIGHT,
145                                );
146        $params = array_merge($default_params, $params);
147        extract($params);
148
149        if (!is_array($color)){
150            if ($color[0] == '#'){
151                $color = $this->colorhex2colorarray($color);
152            } else {
153                include_once 'Image/Transform/Driver/ColorsDefs.php';
154                $color = isset($colornames[$color]) ? $colornames[$color] : false;
155            }
156        }
157
158        $fontResource = imlib_load_font($font . '/' . $size);
159        imlib_text_draw($this->imageHandle, $fontResource, $x, $y, $text, $angle, $color[0], $color[1], $color[2], 255);
160        return true;
161    }
162
163    // }}}
164    // {{{ rotate()
165
166    /**
167     * Rotate image by the given angle
168     *
169     * @param int       $angle      Rotation angle
170     *
171     * @return TRUE or PEAR Error object on error
172     */
173    function rotate($angle)
174    {
175        $this->oldHandle = $this->imageHandle;
176        $this->imageHandle = imlib_create_rotated_image($this->imageHandle, $angle);
177        $new_x = imlib_image_get_width($this->imageHandle);
178        $new_y = imlib_image_get_height($this->imageHandle);
179        // when rotating it creates a bigger picture than before so that it can rotate at any angle
180        // so for right angles we crop it back to the original size
181        if ($angle % 90 == 0) {
182            if (abs($angle) == 90 || $angle == 270) {
183                $y_pos = ($new_x - $this->img_x) / 2;
184                $x_pos = ($new_y - $this->img_y) / 2;
185                $y_pos++;
186                $x_pos++;
187                $this->crop($this->img_y, $this->img_x, $x_pos, $y_pos);
188            } else {
189                $x_pos = ($new_x - $this->img_x) / 2;
190                $y_pos = ($new_y - $this->img_y) / 2;
191                $this->crop($this->img_x, $this->img_y, $x_pos, $y_pos);
192            }
193        } else {
194            $this->img_x = $new_x;
195            $this->img_y = $new_y;
196        }
197
198        return true;
199    }
200
201    // }}}
202    // {{{ crop()
203
204    /**
205     * Crops the current image to a specified height and width
206     *
207     * @param int $in_cropWidth The width of the new image
208     * @param int $in_cropHeight The height of the new image
209     * @param int $in_cropX The X coordinate on the image to start the crop
210     * @param int $in_cropY The Y coordinate on the image to start the crop
211     *
212     * @access public
213     * @return TRUE or PEAR Error object on error
214     */
215    function crop($in_cropWidth, $in_cropHeight, $in_cropX, $in_cropY)
216    {
217        // Sanity check
218        if (!$this->_intersects($in_cropWidth, $in_cropHeight, $in_cropX, $in_cropY)) {
219            return PEAR::raiseError('Nothing to crop', IMAGE_TRANSFORM_ERROR_OUTOFBOUND);
220        }
221        $this->oldHandle = $this->imageHandle;
222        $this->imageHandle = imlib_create_cropped_image($this->imageHandle, $in_cropX, $in_cropY, $in_cropWidth, $in_cropHeight);
223        $this->img_x = $in_cropWidth;
224        $this->img_y = $in_cropHeight;
225        return true;
226    }
227
228    // }}}
229    // {{{ save()
230
231    /**
232     * Save the image file.  Determines what type of image to save based on extension.
233     *
234     * @param $filename string  the name of the file to write to
235     * @param $type     string  (optional) define the output format, default
236     *                          is the current used format
237     * @param $quality  int     (optional) output DPI, default is 75
238     *
239     * @return TRUE on success or PEAR Error object on error
240     */
241    function save($filename, $type = '', $quality = 75)
242    {
243        if (!is_resource($this->imageHandle)) {
244            return PEAR::raiseError('Invalid image', true);
245        }
246
247        $err = 0;
248        $type    = ($type == '') ? $this->type : $type;
249        $quality = (is_null($quality)) ? $this->_options['quality'] : $quality;
250        imlib_image_set_format($this->imageHandle, $type);
251        $return = imlib_save_image($this->imageHandle, $filename, $err, $quality);
252        $this->imageHandle = $this->oldHandle;
253        $this->resized = false;
254        if (!$return) {
255            return PEAR::raiseError('Couldn\'t save image. Reason: ' . $err, true);
256        }
257        return true;
258    }
259
260    // }}}
261    // {{{ display()
262
263    /**
264     * Display image without saving and lose changes
265     *
266     * This method adds the Content-type HTTP header
267     *
268     * @param string $type (optional) (JPG,PNG...);
269     * @param int $quality (optional) 75
270     *
271     * @return TRUE on success or PEAR Error object on error
272     */
273    function display($type = '', $quality = null)
274    {
275        if (!is_resource($this->imageHandle)) {
276            return PEAR::raiseError('Invalid image', true);
277        }
278
279        $type    = ($type == '') ? $this->type : $type;
280        $quality = (is_null($quality)) ? $this->_options['quality'] : $quality;
281        imlib_image_set_format($this->imageHandle, $type);
282        $err = 0;
283        header('Content-type: ' . $this->getMimeType($type));
284        $return = imlib_dump_image($this->imageHandle, $err, $quality);
285        $this->imageHandle = $this->oldHandle;
286        $this->resized = false;
287        imlib_free_image($this->oldHandle);
288        if (!$return) {
289            return PEAR::raiseError('Couldn\'t output image. Reason: ' . $err, true);
290        }
291        return true;
292    }
293
294    // }}}
295    // {{{ free()
296
297    /**
298     * Destroy image handle
299     *
300     * @return void
301     */
302    function free()
303    {
304        if (is_resource($this->imageHandle)) {
305            imlib_free_image($this->imageHandle);
306        }
307    }
308
309    // }}}
310    // {{{ _resize()
311
312    /**
313     * Resize the image.
314     *
315     * @access private
316     *
317     * @param int   $new_x   New width
318     * @param int   $new_y   New height
319     * @param mixed $options Optional parameters
320     *
321     * @return TRUE on success or PEAR Error object on error
322     * @see PEAR::isError()
323     */
324    function _resize($new_x, $new_y, $options = null)
325    {
326        if ($this->resized === true) {
327            return PEAR::raiseError('You have already resized the image without saving it.  Your previous resizing will be overwritten', null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);
328        }
329
330        $this->oldHandle = $this->imageHandle;
331        $this->imageHandle = imlib_create_scaled_image($this->imageHandle, $new_x, $new_y);
332        $this->img_x = $new_x;
333        $this->img_y = $new_y;
334        $this->resized = true;
335        return true;
336    }
337
338    // }}}
339    // {{{ _get_image_details()
340
341    /**
342     * Gets the image details
343     *
344     * @access private
345     * @return TRUE on success or PEAR Error object on error
346     */
347    function _get_image_details()
348    {
349        $this->img_x = imlib_image_get_width($this->imageHandle);
350        $this->img_y = imlib_image_get_height($this->imageHandle);
351        $this->type = imlib_image_format($this->imageHandle);
352        $this->type = ($this->type == '') ? 'png' : $this->type;
353        return true;
354    }
355
356    // }}}
357
358    /**
359     * Horizontal mirroring
360     *
361     * @return TRUE on success, PEAR Error object on error
362     */
363    function mirror()
364    {
365        imlib_image_flip_horizontal($this->imageHandle);
366        return true;
367    }
368
369    /**
370     * Vertical mirroring
371     *
372     * @return TRUE on success, PEAR Error object on error
373     */
374    function flip()
375    {
376        imlib_image_flip_vertical($this->imageHandle);
377        return true;
378    }
379}