1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4: */
3
4/**
5 * Cairo implementation for Image_Transform package
6 *
7 * PHP versions 4 and 5
8 *
9 * @category   Image
10 * @package    Image_Transform
11 * @subpackage Image_Transform_Driver_Cairowrapper
12 * @author     Christian Weiske <cweiske@php.net>
13 * @copyright  2008 The PHP Group
14 * @license    http://www.gnu.org/copyleft/lesser.html LGPL
15 * @version    CVS: $Id: Cairowrapper.php 288112 2009-09-06 21:02:37Z cweiske $
16 * @link       http://pear.php.net/package/Image_Transform
17 */
18require_once 'Image/Transform.php';
19
20/**
21 * Cairo implementation for Image_Transform package using pecl's cairo_wrapper
22 * extension.
23 *
24 * Supports png files only.
25 *
26 * @category   Image
27 * @package    Image_Transform
28 * @subpackage Image_Transform_Driver_Cairowrapper
29 * @author     Christian Weiske <cweiske@php.net>
30 * @copyright  2008 The PHP Group
31 * @license    http://www.gnu.org/copyleft/lesser.html LGPL
32 * @version    Release: @package_version@
33 * @link       http://pear.php.net/package/Image_Transform
34 */
35class Image_Transform_Driver_Cairowrapper extends Image_Transform
36{
37    var $surface = null;
38
39    /**
40     * Supported image types
41     *
42     * @var    array
43     * @access protected
44     */
45    var $_supported_image_types = array(
46        'png' => 'rw'
47    );
48
49    /**
50     * Check settings
51     */
52    function Image_Transform_Driver_Cairowrapper()
53    {
54        $this->__construct();
55    }
56
57
58
59    /**
60     * Create object and check if cairo_wrapper is loaded
61     */
62    function __construct()
63    {
64        if (!PEAR::loadExtension('cairo_wrapper')) {
65            $this->isError(
66                PEAR::raiseError(
67                    'cairo_wrapper extension is not available.',
68                    IMAGE_TRANSFORM_ERROR_UNSUPPORTED
69                )
70            );
71        }
72    }
73
74
75
76    /**
77     * Loads an image from file
78     *
79     * @param string $image filename
80     *
81     * @return bool|PEAR_Error TRUE or a PEAR_Error object on error
82     *
83     * @access public
84     */
85    function load($image)
86    {
87        $this->free();
88
89        $this->image = $image;
90        $result = $this->_get_image_details($image);
91        if (PEAR::isError($result)) {
92            return $result;
93        }
94        if (!$this->supportsType($this->type, 'r')) {
95            return PEAR::raiseError('Image type not supported for input',
96                IMAGE_TRANSFORM_ERROR_UNSUPPORTED);
97        }
98
99        $this->surface = cairo_image_surface_create_from_png($this->image);
100        if (cairo_surface_status($this->surface) != CAIRO_STATUS_SUCCESS) {
101            $this->surface = null;
102            return PEAR::raiseError('Error while loading image file.',
103                IMAGE_TRANSFORM_ERROR_IO);
104        }
105
106        return true;
107    }//function load(..)
108
109
110
111    /**
112     * Resize the image
113     *
114     * @param int   $new_x   New width
115     * @param int   $new_y   New height
116     * @param array $options Optional parameters
117     *
118     * @return bool|PEAR_Error TRUE on success or PEAR_Error object on error
119     *
120     * @access protected
121     */
122    function _resize($new_x, $new_y, $options = null)
123    {
124        if ($this->resized === true) {
125            return PEAR::raiseError(
126                'You have already resized the image without saving it.'
127                . ' Your previous resizing will be overwritten',
128                null, PEAR_ERROR_TRIGGER, E_USER_NOTICE
129            );
130        }
131
132        if ($this->new_x == $new_x && $this->new_y == $new_y) {
133            return true;
134        }
135
136        $xFactor = $new_x / $this->img_x;
137        $yFactor = $new_y / $this->img_y;
138
139        $outputSurface = cairo_image_surface_create(
140            CAIRO_FORMAT_ARGB32, $new_x, $new_y
141        );
142        $outputContext = cairo_create($outputSurface);
143
144        cairo_scale($outputContext, $xFactor, $yFactor);
145
146        cairo_set_source_surface($outputContext, $this->surface, 0, 0);
147        cairo_paint($outputContext);
148
149        cairo_destroy($outputContext);
150
151        cairo_surface_destroy($this->surface);
152
153        $this->surface = $outputSurface;
154
155        $this->new_x = $new_x;
156        $this->new_y = $new_y;
157        return true;
158    }//function _resize(..)
159
160
161
162    /**
163     * Saves the scaled image into a file.
164     *
165     * @param string $filename The filename to save to
166     * @param mixed  $type     ignored
167     * @param mixed  $quality  ignored
168     *
169     * @return bool|PEAR_Error TRUE on success or PEAR_Error object on error
170     *
171     * @access public
172     */
173    function save($filename, $type = null, $quality = null)
174    {
175        cairo_surface_write_to_png($this->surface, $filename);
176        $this->free();
177        return true;
178    }//function save(..)
179
180
181
182    /**
183     * Returns the surface of the image so it can be modified further
184     *
185     * @return resource
186     *
187     * @access public
188     */
189    function getHandle()
190    {
191        return $this->surface;
192    }//function getHandle()
193
194
195
196    /**
197     * Frees cairo handles
198     *
199     * @return void
200     *
201     * @access public
202     */
203    function free()
204    {
205        $this->resized = false;
206        if (is_resource($this->surface)) {
207            cairo_surface_destroy($this->surface);
208        }
209        $this->surface = null;
210    }//function free()
211
212
213
214    /**
215     * Mirrors the image vertically
216     * Uses an affine transformation matrix to flip the image.
217     *
218     * @return void
219     */
220    function flip()
221    {
222        $outputSurface = cairo_image_surface_create(
223            CAIRO_FORMAT_ARGB32, $this->img_x, $this->img_y
224        );
225        $outputContext = cairo_create($outputSurface);
226        //                            xx, yx, xy, yy, x0, y0
227        $matrix = cairo_matrix_create(1,  0,  0,  -1,  0, $this->img_y);
228
229        cairo_set_matrix($outputContext, $matrix);
230        cairo_set_source_surface($outputContext, $this->surface, 0, 0);
231        cairo_paint($outputContext);
232
233        cairo_destroy($outputContext);
234        cairo_surface_destroy($this->surface);
235
236        $this->surface = $outputSurface;
237    }//function flip()
238
239
240
241    /**
242     * Mirrors the image horizontally.
243     * Uses an affine transformation matrix to mirror the image.
244     *
245     * 123 -> 321
246     *
247     * @return void
248     */
249    function mirror()
250    {
251        $outputSurface = cairo_image_surface_create(
252            CAIRO_FORMAT_ARGB32, $this->img_x, $this->img_y
253        );
254        $outputContext = cairo_create($outputSurface);
255        //                            xx, yx, xy, yy, x0, y0
256        $matrix = cairo_matrix_create(-1, 0,  0,  1, $this->img_x, 0);
257
258        cairo_set_matrix($outputContext, $matrix);
259        cairo_set_source_surface($outputContext, $this->surface, 0, 0);
260        cairo_paint($outputContext);
261
262        cairo_destroy($outputContext);
263        cairo_surface_destroy($this->surface);
264
265        $this->surface = $outputSurface;
266    }//function mirror()
267
268}//class Image_Transform_Driver_Cairowrapper extends Image_Transform
269?>