blob: 9826eabdd03177a0a3fdeb715fe600af75720928 [file] [log] [blame]
Andrey Andreeva92b9032011-12-24 19:05:58 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Greg Aker741de1c2010-11-10 14:52:57 -06005 * An open source application development framework for PHP 5.1.6 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Eric Barnesb1673362011-12-05 22:05:38 -05008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Eric Barnesb1673362011-12-05 22:05:38 -050010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
Andrey Andreeva3d19c42012-01-24 15:29:29 +020012 * bundled with this package in the files license.txt / license.rst. It is
Derek Jonesf4a4bd82011-10-20 12:18:42 -050013 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Greg Aker0defe5d2012-01-01 18:46:41 -060021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
Derek Allard2067d1a2008-11-13 22:59:24 +000028/**
29 * Image Manipulation class
30 *
31 * @package CodeIgniter
32 * @subpackage Libraries
33 * @category Image_lib
Derek Jonesf4a4bd82011-10-20 12:18:42 -050034 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000035 * @link http://codeigniter.com/user_guide/libraries/image_lib.html
36 */
37class CI_Image_lib {
38
Andrey Andreev3a459572011-12-21 11:23:11 +020039 public $image_library = 'gd2'; // Can be: imagemagick, netpbm, gd, gd2
40 public $library_path = '';
41 public $dynamic_output = FALSE; // Whether to send to browser or write to disk
42 public $source_image = '';
43 public $new_image = '';
44 public $width = '';
45 public $height = '';
46 public $quality = '90';
47 public $create_thumb = FALSE;
48 public $thumb_marker = '_thumb';
49 public $maintain_ratio = TRUE; // Whether to maintain aspect ratio when resizing or use hard values
50 public $master_dim = 'auto'; // auto, height, or width. Determines what to use as the master dimension
51 public $rotation_angle = '';
52 public $x_axis = '';
53 public $y_axis = '';
Derek Allard2067d1a2008-11-13 22:59:24 +000054
55 // Watermark Vars
Andrey Andreev3a459572011-12-21 11:23:11 +020056 public $wm_text = ''; // Watermark text if graphic is not used
57 public $wm_type = 'text'; // Type of watermarking. Options: text/overlay
58 public $wm_x_transp = 4;
59 public $wm_y_transp = 4;
60 public $wm_overlay_path = ''; // Watermark image path
61 public $wm_font_path = ''; // TT font
62 public $wm_font_size = 17; // Font size (different versions of GD will either use points or pixels)
63 public $wm_vrt_alignment = 'B'; // Vertical alignment: T M B
64 public $wm_hor_alignment = 'C'; // Horizontal alignment: L R C
65 public $wm_padding = 0; // Padding around text
66 public $wm_hor_offset = 0; // Lets you push text to the right
67 public $wm_vrt_offset = 0; // Lets you push text down
Andrey Andreev64dbdfb2011-12-30 14:14:07 +020068 protected $wm_font_color = '#ffffff'; // Text color
69 protected $wm_shadow_color = ''; // Dropshadow color
Andrey Andreev3a459572011-12-21 11:23:11 +020070 public $wm_shadow_distance = 2; // Dropshadow distance
71 public $wm_opacity = 50; // Image opacity: 1 - 100 Only works with image
Derek Allard2067d1a2008-11-13 22:59:24 +000072
73 // Private Vars
Andrey Andreev3a459572011-12-21 11:23:11 +020074 public $source_folder = '';
75 public $dest_folder = '';
76 public $mime_type = '';
77 public $orig_width = '';
78 public $orig_height = '';
79 public $image_type = '';
80 public $size_str = '';
81 public $full_src_path = '';
82 public $full_dst_path = '';
83 public $create_fnc = 'imagecreatetruecolor';
84 public $copy_fnc = 'imagecopyresampled';
85 public $error_msg = array();
Andrey Andreev64dbdfb2011-12-30 14:14:07 +020086 protected $wm_use_drop_shadow = FALSE;
Andrey Andreev3a459572011-12-21 11:23:11 +020087 public $wm_use_truetype = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +000088
Greg Akera9263282010-11-10 15:26:43 -060089 public function __construct($props = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000090 {
91 if (count($props) > 0)
92 {
93 $this->initialize($props);
94 }
95
Andrey Andreev8e70b792012-01-12 20:19:24 +020096 log_message('debug', 'Image Lib Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +000097 }
98
99 // --------------------------------------------------------------------
100
101 /**
102 * Initialize image properties
103 *
104 * Resets values in case this class is used in a loop
105 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000106 * @return void
107 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200108 public function clear()
Derek Allard2067d1a2008-11-13 22:59:24 +0000109 {
Michael Denniscb07a322011-08-20 23:40:59 -0700110 $props = array('library_path', 'source_image', 'new_image', 'width', 'height', 'rotation_angle', 'x_axis', 'y_axis', 'wm_text', 'wm_overlay_path', 'wm_font_path', 'wm_shadow_color', 'source_folder', 'dest_folder', 'mime_type', 'orig_width', 'orig_height', 'image_type', 'size_str', 'full_src_path', 'full_dst_path');
Derek Allard2067d1a2008-11-13 22:59:24 +0000111
112 foreach ($props as $val)
113 {
114 $this->$val = '';
115 }
116
Michael Denniscb07a322011-08-20 23:40:59 -0700117 $this->image_library = 'gd2';
118 $this->dynamic_output = FALSE;
119 $this->quality = '90';
120 $this->create_thumb = FALSE;
121 $this->thumb_marker = '_thumb';
122 $this->maintain_ratio = TRUE;
123 $this->master_dim = 'auto';
124 $this->wm_type = 'text';
125 $this->wm_x_transp = 4;
126 $this->wm_y_transp = 4;
127 $this->wm_font_size = 17;
128 $this->wm_vrt_alignment = 'B';
129 $this->wm_hor_alignment = 'C';
130 $this->wm_padding = 0;
131 $this->wm_hor_offset = 0;
132 $this->wm_vrt_offset = 0;
133 $this->wm_font_color = '#ffffff';
134 $this->wm_shadow_distance = 2;
135 $this->wm_opacity = 50;
136 $this->create_fnc = 'imagecreatetruecolor';
137 $this->copy_fnc = 'imagecopyresampled';
138 $this->error_msg = array();
139 $this->wm_use_drop_shadow = FALSE;
140 $this->wm_use_truetype = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000141 }
142
143 // --------------------------------------------------------------------
144
145 /**
146 * initialize image preferences
147 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000148 * @param array
149 * @return bool
150 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200151 public function initialize($props = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000152 {
Andrey Andreev8e70b792012-01-12 20:19:24 +0200153 // Convert array elements into class variables
Derek Allard2067d1a2008-11-13 22:59:24 +0000154 if (count($props) > 0)
155 {
156 foreach ($props as $key => $val)
157 {
Andrey Andreev64dbdfb2011-12-30 14:14:07 +0200158 if (property_exists($this, $key))
159 {
160 if (in_array($key, array('wm_font_color', 'wm_shadow_color')))
161 {
Andrey Andreev8323ae62011-12-31 18:39:10 +0200162 if (preg_match('/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i', $val, $matches))
Andrey Andreev64dbdfb2011-12-30 14:14:07 +0200163 {
Andrey Andreevcf2ba9e2012-01-01 21:57:13 +0200164 /* $matches[1] contains our hex color value, but it might be
Andrey Andreev8323ae62011-12-31 18:39:10 +0200165 * both in the full 6-length format or the shortened 3-length
166 * value.
Andrey Andreevbb96c8b2011-12-31 18:48:39 +0200167 * We'll later need the full version, so we keep it if it's
Andrey Andreev8323ae62011-12-31 18:39:10 +0200168 * already there and if not - we'll convert to it. We can
169 * access string characters by their index as in an array,
170 * so we'll do that and use concatenation to form the final
171 * value:
172 */
Andrey Andreev665af0c2011-12-30 14:39:29 +0200173 $val = (strlen($matches[1]) === 6)
174 ? '#'.$matches[1]
175 : '#'.$matches[1][0].$matches[1][0].$matches[1][1].$matches[1][1].$matches[1][2].$matches[1][2];
Andrey Andreev64dbdfb2011-12-30 14:14:07 +0200176 }
177 else
178 {
179 continue;
180 }
181 }
182
183 $this->$key = $val;
184 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000185 }
186 }
187
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200188 // Is there a source image? If not, there's no reason to continue
Derek Allard2067d1a2008-11-13 22:59:24 +0000189 if ($this->source_image == '')
190 {
191 $this->set_error('imglib_source_image_required');
Eric Barnesb1673362011-12-05 22:05:38 -0500192 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000193 }
194
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200195 /* Is getimagesize() available?
Derek Allard2067d1a2008-11-13 22:59:24 +0000196 *
197 * We use it to determine the image properties (width/height).
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200198 * Note: We need to figure out how to determine image
Derek Allard2067d1a2008-11-13 22:59:24 +0000199 * properties using ImageMagick and NetPBM
Derek Allard2067d1a2008-11-13 22:59:24 +0000200 */
201 if ( ! function_exists('getimagesize'))
202 {
203 $this->set_error('imglib_gd_required_for_props');
204 return FALSE;
205 }
206
207 $this->image_library = strtolower($this->image_library);
208
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200209 /* Set the full server path
Derek Allard2067d1a2008-11-13 22:59:24 +0000210 *
211 * The source image may or may not contain a path.
212 * Either way, we'll try use realpath to generate the
213 * full server path in order to more reliably read it.
Derek Allard2067d1a2008-11-13 22:59:24 +0000214 */
Andrey Andreev8e70b792012-01-12 20:19:24 +0200215 if (function_exists('realpath') && @realpath($this->source_image) !== FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000216 {
Andrey Andreev8e70b792012-01-12 20:19:24 +0200217 $full_source_path = str_replace('\\', '/', realpath($this->source_image));
Derek Allard2067d1a2008-11-13 22:59:24 +0000218 }
219 else
220 {
221 $full_source_path = $this->source_image;
222 }
223
224 $x = explode('/', $full_source_path);
225 $this->source_image = end($x);
226 $this->source_folder = str_replace($this->source_image, '', $full_source_path);
227
228 // Set the Image Properties
229 if ( ! $this->get_image_properties($this->source_folder.$this->source_image))
230 {
Eric Barnesb1673362011-12-05 22:05:38 -0500231 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000232 }
233
234 /*
235 * Assign the "new" image name/path
236 *
237 * If the user has set a "new_image" name it means
238 * we are making a copy of the source image. If not
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200239 * it means we are altering the original. We'll
Derek Allard2067d1a2008-11-13 22:59:24 +0000240 * set the destination filename and path accordingly.
Derek Allard2067d1a2008-11-13 22:59:24 +0000241 */
242 if ($this->new_image == '')
243 {
244 $this->dest_image = $this->source_image;
245 $this->dest_folder = $this->source_folder;
246 }
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200247 elseif (strpos($this->new_image, '/') === FALSE)
248 {
249 $this->dest_folder = $this->source_folder;
250 $this->dest_image = $this->new_image;
251 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000252 else
253 {
Andrew Mackrodt750ffb92011-12-10 23:42:07 +0000254 if (strpos($this->new_image, '/') === FALSE AND strpos($this->new_image, '\\') === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000255 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200256 $full_dest_path = str_replace('\\', '/', realpath($this->new_image));
Derek Allard2067d1a2008-11-13 22:59:24 +0000257 }
258 else
259 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200260 $full_dest_path = $this->new_image;
261 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000262
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200263 // Is there a file name?
264 if ( ! preg_match('#\.(jpg|jpeg|gif|png)$#i', $full_dest_path))
265 {
266 $this->dest_folder = $full_dest_path.'/';
267 $this->dest_image = $this->source_image;
268 }
269 else
270 {
271 $x = explode('/', $full_dest_path);
272 $this->dest_image = end($x);
273 $this->dest_folder = str_replace($this->dest_image, '', $full_dest_path);
Derek Allard2067d1a2008-11-13 22:59:24 +0000274 }
275 }
276
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200277 /* Compile the finalized filenames/paths
Derek Allard2067d1a2008-11-13 22:59:24 +0000278 *
279 * We'll create two master strings containing the
280 * full server path to the source image and the
281 * full server path to the destination image.
282 * We'll also split the destination image name
283 * so we can insert the thumbnail marker if needed.
Derek Allard2067d1a2008-11-13 22:59:24 +0000284 */
285 if ($this->create_thumb === FALSE OR $this->thumb_marker == '')
286 {
287 $this->thumb_marker = '';
288 }
289
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200290 $xp = $this->explode_name($this->dest_image);
Derek Allard2067d1a2008-11-13 22:59:24 +0000291
292 $filename = $xp['name'];
293 $file_ext = $xp['ext'];
294
295 $this->full_src_path = $this->source_folder.$this->source_image;
296 $this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext;
297
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200298 /* Should we maintain image proportions?
Derek Allard2067d1a2008-11-13 22:59:24 +0000299 *
300 * When creating thumbs or copies, the target width/height
301 * might not be in correct proportion with the source
Andrey Andreev8e70b792012-01-12 20:19:24 +0200302 * image's width/height. We'll recalculate it here.
Derek Allard2067d1a2008-11-13 22:59:24 +0000303 */
Andrey Andreev8e70b792012-01-12 20:19:24 +0200304 if ($this->maintain_ratio === TRUE && ($this->width != 0 OR $this->height != 0))
Derek Allard2067d1a2008-11-13 22:59:24 +0000305 {
306 $this->image_reproportion();
307 }
308
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200309 /* Was a width and height specified?
Derek Allard2067d1a2008-11-13 22:59:24 +0000310 *
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200311 * If the destination width/height was not submitted we
312 * will use the values from the actual file
Derek Allard2067d1a2008-11-13 22:59:24 +0000313 */
314 if ($this->width == '')
Andrey Andreev8e70b792012-01-12 20:19:24 +0200315 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000316 $this->width = $this->orig_width;
Andrey Andreev8e70b792012-01-12 20:19:24 +0200317 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000318
319 if ($this->height == '')
Andrey Andreev8e70b792012-01-12 20:19:24 +0200320 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000321 $this->height = $this->orig_height;
Andrey Andreev8e70b792012-01-12 20:19:24 +0200322 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000323
324 // Set the quality
Andrey Andreev8e70b792012-01-12 20:19:24 +0200325 $this->quality = trim(str_replace('%', '', $this->quality));
Derek Allard2067d1a2008-11-13 22:59:24 +0000326
Andrey Andreev8e70b792012-01-12 20:19:24 +0200327 if ($this->quality == '' OR $this->quality == 0 OR ! preg_match('/^[0-9]+$/', $this->quality))
328 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000329 $this->quality = 90;
Andrey Andreev8e70b792012-01-12 20:19:24 +0200330 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000331
332 // Set the x/y coordinates
Andrey Andreev8e70b792012-01-12 20:19:24 +0200333 $this->x_axis = ($this->x_axis == '' OR ! preg_match('/^[0-9]+$/', $this->x_axis)) ? 0 : $this->x_axis;
334 $this->y_axis = ($this->y_axis == '' OR ! preg_match('/^[0-9]+$/', $this->y_axis)) ? 0 : $this->y_axis;
Derek Allard2067d1a2008-11-13 22:59:24 +0000335
336 // Watermark-related Stuff...
Derek Allard2067d1a2008-11-13 22:59:24 +0000337 if ($this->wm_overlay_path != '')
338 {
Andrey Andreev8e70b792012-01-12 20:19:24 +0200339 $this->wm_overlay_path = str_replace('\\', '/', realpath($this->wm_overlay_path));
Derek Allard2067d1a2008-11-13 22:59:24 +0000340 }
341
342 if ($this->wm_shadow_color != '')
343 {
344 $this->wm_use_drop_shadow = TRUE;
345 }
Andrey Andreev8e70b792012-01-12 20:19:24 +0200346 elseif ($this->wm_use_drop_shadow == TRUE && $this->wm_shadow_color == '')
Andrey Andreev64dbdfb2011-12-30 14:14:07 +0200347 {
348 $this->wm_use_drop_shadow = FALSE;
349 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000350
351 if ($this->wm_font_path != '')
352 {
353 $this->wm_use_truetype = TRUE;
354 }
355
356 return TRUE;
357 }
358
359 // --------------------------------------------------------------------
360
361 /**
362 * Image Resize
363 *
364 * This is a wrapper function that chooses the proper
365 * resize function based on the protocol specified
366 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000367 * @return bool
368 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200369 public function resize()
Derek Allard2067d1a2008-11-13 22:59:24 +0000370 {
Andrey Andreev1a9f52c2012-01-07 01:06:34 +0200371 $protocol = ($this->image_library === 'gd2') ? 'image_process_gd' : 'image_process_'.$this->image_library;
Derek Allard2067d1a2008-11-13 22:59:24 +0000372 return $this->$protocol('resize');
373 }
374
375 // --------------------------------------------------------------------
376
377 /**
378 * Image Crop
379 *
380 * This is a wrapper function that chooses the proper
381 * cropping function based on the protocol specified
382 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000383 * @return bool
384 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200385 public function crop()
Derek Allard2067d1a2008-11-13 22:59:24 +0000386 {
Andrey Andreev5a67e3d2012-01-07 01:21:09 +0200387 $protocol = ($this->image_library === 'gd2') ? 'image_process_gd' : 'image_process_'.$this->image_library;
Derek Allard2067d1a2008-11-13 22:59:24 +0000388 return $this->$protocol('crop');
389 }
390
391 // --------------------------------------------------------------------
392
393 /**
394 * Image Rotate
395 *
396 * This is a wrapper function that chooses the proper
397 * rotation function based on the protocol specified
398 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000399 * @return bool
400 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200401 public function rotate()
Derek Allard2067d1a2008-11-13 22:59:24 +0000402 {
403 // Allowed rotation values
404 $degs = array(90, 180, 270, 'vrt', 'hor');
405
Derek Allardd9c7f032008-12-01 20:18:00 +0000406 if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs))
Derek Allard2067d1a2008-11-13 22:59:24 +0000407 {
408 $this->set_error('imglib_rotation_angle_required');
Eric Barnesb1673362011-12-05 22:05:38 -0500409 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000410 }
411
412 // Reassign the width and height
413 if ($this->rotation_angle == 90 OR $this->rotation_angle == 270)
414 {
415 $this->width = $this->orig_height;
416 $this->height = $this->orig_width;
417 }
418 else
419 {
420 $this->width = $this->orig_width;
421 $this->height = $this->orig_height;
422 }
423
Derek Allard2067d1a2008-11-13 22:59:24 +0000424 // Choose resizing function
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200425 if ($this->image_library === 'imagemagick' OR $this->image_library === 'netpbm')
Derek Allard2067d1a2008-11-13 22:59:24 +0000426 {
427 $protocol = 'image_process_'.$this->image_library;
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 return $this->$protocol('rotate');
429 }
430
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200431 return ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
432 ? $this->image_mirror_gd()
433 : $this->image_rotate_gd();
Derek Allard2067d1a2008-11-13 22:59:24 +0000434 }
435
436 // --------------------------------------------------------------------
437
438 /**
439 * Image Process Using GD/GD2
440 *
441 * This function will resize or crop
442 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000443 * @param string
444 * @return bool
445 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200446 public function image_process_gd($action = 'resize')
Derek Allard2067d1a2008-11-13 22:59:24 +0000447 {
448 $v2_override = FALSE;
449
450 // If the target width/height match the source, AND if the new file name is not equal to the old file name
451 // we'll simply make a copy of the original with the new name... assuming dynamic rendering is off.
Andrey Andreev8e70b792012-01-12 20:19:24 +0200452 if ($this->dynamic_output === FALSE && $this->orig_width == $this->width && $this->orig_height == $this->height)
Derek Allard2067d1a2008-11-13 22:59:24 +0000453 {
Andrey Andreev8e70b792012-01-12 20:19:24 +0200454 if ($this->source_image != $this->new_image && @copy($this->full_src_path, $this->full_dst_path))
Derek Allard2067d1a2008-11-13 22:59:24 +0000455 {
Andrey Andreeva92b9032011-12-24 19:05:58 +0200456 @chmod($this->full_dst_path, FILE_WRITE_MODE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000457 }
Andrey Andreeva92b9032011-12-24 19:05:58 +0200458
459 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000460 }
461
462 // Let's set up our values based on the action
463 if ($action == 'crop')
464 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200465 // Reassign the source width/height if cropping
Derek Jones4b9c6292011-07-01 17:40:48 -0500466 $this->orig_width = $this->width;
Derek Allard2067d1a2008-11-13 22:59:24 +0000467 $this->orig_height = $this->height;
468
469 // GD 2.0 has a cropping bug so we'll test for it
470 if ($this->gd_version() !== FALSE)
471 {
472 $gd_version = str_replace('0', '', $this->gd_version());
473 $v2_override = ($gd_version == 2) ? TRUE : FALSE;
474 }
475 }
476 else
477 {
478 // If resizing the x/y axis must be zero
479 $this->x_axis = 0;
480 $this->y_axis = 0;
481 }
482
Derek Jones4b9c6292011-07-01 17:40:48 -0500483 // Create the image handle
Derek Allard2067d1a2008-11-13 22:59:24 +0000484 if ( ! ($src_img = $this->image_create_gd()))
485 {
486 return FALSE;
487 }
488
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200489 /* Create the image
490 *
491 * Old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater"
492 * it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment
493 * below should that ever prove inaccurate.
494 *
495 * if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor') && $v2_override == FALSE)
496 */
Andrey Andreev8e70b792012-01-12 20:19:24 +0200497 if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor'))
Derek Allard2067d1a2008-11-13 22:59:24 +0000498 {
499 $create = 'imagecreatetruecolor';
500 $copy = 'imagecopyresampled';
501 }
502 else
503 {
504 $create = 'imagecreate';
505 $copy = 'imagecopyresized';
506 }
507
508 $dst_img = $create($this->width, $this->height);
Derek Jones595bfd12010-08-20 10:28:22 -0500509
510 if ($this->image_type == 3) // png we can actually preserve transparency
511 {
512 imagealphablending($dst_img, FALSE);
513 imagesavealpha($dst_img, TRUE);
514 }
Barry Mienydd671972010-10-04 16:33:58 +0200515
Derek Allard2067d1a2008-11-13 22:59:24 +0000516 $copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height);
517
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200518 // Show the image
Derek Allard2067d1a2008-11-13 22:59:24 +0000519 if ($this->dynamic_output == TRUE)
520 {
521 $this->image_display_gd($dst_img);
522 }
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200523 elseif ( ! $this->image_save_gd($dst_img)) // Or save it
Derek Allard2067d1a2008-11-13 22:59:24 +0000524 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200525 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000526 }
527
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200528 // Kill the file handles
Derek Allard2067d1a2008-11-13 22:59:24 +0000529 imagedestroy($dst_img);
530 imagedestroy($src_img);
531
532 // Set the file to 777
Derek Jones172e1612009-10-13 14:32:48 +0000533 @chmod($this->full_dst_path, FILE_WRITE_MODE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000534
535 return TRUE;
536 }
537
538 // --------------------------------------------------------------------
539
540 /**
541 * Image Process Using ImageMagick
542 *
543 * This function will resize, crop or rotate
544 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000545 * @param string
546 * @return bool
547 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200548 public function image_process_imagemagick($action = 'resize')
Derek Allard2067d1a2008-11-13 22:59:24 +0000549 {
Derek Jones4b9c6292011-07-01 17:40:48 -0500550 // Do we have a vaild library path?
Derek Allard2067d1a2008-11-13 22:59:24 +0000551 if ($this->library_path == '')
552 {
553 $this->set_error('imglib_libpath_invalid');
554 return FALSE;
555 }
556
Andrey Andreev8e70b792012-01-12 20:19:24 +0200557 if ( ! preg_match('/convert$/i', $this->library_path))
Derek Allard2067d1a2008-11-13 22:59:24 +0000558 {
Andrey Andreeva92b9032011-12-24 19:05:58 +0200559 $this->library_path = rtrim($this->library_path, '/').'/convert';
Derek Allard2067d1a2008-11-13 22:59:24 +0000560 }
561
562 // Execute the command
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200563 $cmd = $this->library_path.' -quality '.$this->quality;
Derek Allard2067d1a2008-11-13 22:59:24 +0000564
565 if ($action == 'crop')
566 {
Andrey Andreev8e70b792012-01-12 20:19:24 +0200567 $cmd .= ' -crop '.$this->width.'x'.$this->height.'+'.$this->x_axis.'+'.$this->y_axis.' "'.$this->full_src_path.'" "'.$this->full_dst_path .'" 2>&1';
Derek Allard2067d1a2008-11-13 22:59:24 +0000568 }
569 elseif ($action == 'rotate')
570 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200571 $angle = ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
572 ? '-flop' : '-rotate '.$this->rotation_angle;
Derek Allard2067d1a2008-11-13 22:59:24 +0000573
Andrey Andreev8e70b792012-01-12 20:19:24 +0200574 $cmd .= ' '.$angle.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
Derek Allard2067d1a2008-11-13 22:59:24 +0000575 }
Andrey Andreev8e70b792012-01-12 20:19:24 +0200576 else // Resize
Derek Allard2067d1a2008-11-13 22:59:24 +0000577 {
Andrey Andreeve4636302012-01-12 20:23:27 +0200578 $cmd .= ' -resize '.$this->width.'x'.$this->height.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
Derek Allard2067d1a2008-11-13 22:59:24 +0000579 }
580
581 $retval = 1;
Derek Allard2067d1a2008-11-13 22:59:24 +0000582 @exec($cmd, $output, $retval);
583
Andrey Andreev8e70b792012-01-12 20:19:24 +0200584 // Did it work?
Derek Allard2067d1a2008-11-13 22:59:24 +0000585 if ($retval > 0)
586 {
587 $this->set_error('imglib_image_process_failed');
588 return FALSE;
589 }
590
591 // Set the file to 777
Derek Jones172e1612009-10-13 14:32:48 +0000592 @chmod($this->full_dst_path, FILE_WRITE_MODE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000593
594 return TRUE;
595 }
596
597 // --------------------------------------------------------------------
598
599 /**
600 * Image Process Using NetPBM
601 *
602 * This function will resize, crop or rotate
603 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000604 * @param string
605 * @return bool
606 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200607 public function image_process_netpbm($action = 'resize')
Derek Allard2067d1a2008-11-13 22:59:24 +0000608 {
609 if ($this->library_path == '')
610 {
611 $this->set_error('imglib_libpath_invalid');
612 return FALSE;
613 }
614
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200615 // Build the resizing command
Derek Allard2067d1a2008-11-13 22:59:24 +0000616 switch ($this->image_type)
617 {
618 case 1 :
619 $cmd_in = 'giftopnm';
620 $cmd_out = 'ppmtogif';
621 break;
622 case 2 :
623 $cmd_in = 'jpegtopnm';
624 $cmd_out = 'ppmtojpeg';
625 break;
626 case 3 :
627 $cmd_in = 'pngtopnm';
628 $cmd_out = 'ppmtopng';
629 break;
630 }
631
632 if ($action == 'crop')
633 {
634 $cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height;
635 }
636 elseif ($action == 'rotate')
637 {
638 switch ($this->rotation_angle)
639 {
640 case 90 : $angle = 'r270';
641 break;
642 case 180 : $angle = 'r180';
643 break;
Barry Mienydd671972010-10-04 16:33:58 +0200644 case 270 : $angle = 'r90';
Derek Allard2067d1a2008-11-13 22:59:24 +0000645 break;
646 case 'vrt' : $angle = 'tb';
647 break;
648 case 'hor' : $angle = 'lr';
649 break;
650 }
651
652 $cmd_inner = 'pnmflip -'.$angle.' ';
653 }
654 else // Resize
655 {
656 $cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height;
657 }
658
659 $cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp';
660
661 $retval = 1;
Derek Allard2067d1a2008-11-13 22:59:24 +0000662 @exec($cmd, $output, $retval);
663
Andrey Andreev8e70b792012-01-12 20:19:24 +0200664 // Did it work?
Derek Allard2067d1a2008-11-13 22:59:24 +0000665 if ($retval > 0)
666 {
667 $this->set_error('imglib_image_process_failed');
668 return FALSE;
669 }
670
671 // With NetPBM we have to create a temporary image.
672 // If you try manipulating the original it fails so
673 // we have to rename the temp file.
674 copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path);
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200675 unlink($this->dest_folder.'netpbm.tmp');
Derek Jones172e1612009-10-13 14:32:48 +0000676 @chmod($this->full_dst_path, FILE_WRITE_MODE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000677
678 return TRUE;
679 }
680
681 // --------------------------------------------------------------------
682
683 /**
684 * Image Rotate Using GD
685 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000686 * @return bool
687 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200688 public function image_rotate_gd()
Derek Allard2067d1a2008-11-13 22:59:24 +0000689 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200690 // Create the image handle
Derek Allard2067d1a2008-11-13 22:59:24 +0000691 if ( ! ($src_img = $this->image_create_gd()))
692 {
693 return FALSE;
694 }
695
696 // Set the background color
697 // This won't work with transparent PNG files so we are
698 // going to have to figure out how to determine the color
699 // of the alpha channel in a future release.
700
701 $white = imagecolorallocate($src_img, 255, 255, 255);
702
Andrey Andreev8e70b792012-01-12 20:19:24 +0200703 // Rotate it!
Derek Allard2067d1a2008-11-13 22:59:24 +0000704 $dst_img = imagerotate($src_img, $this->rotation_angle, $white);
705
Andrey Andreev8e70b792012-01-12 20:19:24 +0200706 // Show the image
Derek Allard2067d1a2008-11-13 22:59:24 +0000707 if ($this->dynamic_output == TRUE)
708 {
709 $this->image_display_gd($dst_img);
710 }
Andrey Andreev8e70b792012-01-12 20:19:24 +0200711 elseif ( ! $this->image_save_gd($dst_img)) // ... or save it
Derek Allard2067d1a2008-11-13 22:59:24 +0000712 {
Andrey Andreev8e70b792012-01-12 20:19:24 +0200713 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000714 }
715
Andrey Andreev8e70b792012-01-12 20:19:24 +0200716 // Kill the file handles
Derek Allard2067d1a2008-11-13 22:59:24 +0000717 imagedestroy($dst_img);
718 imagedestroy($src_img);
719
720 // Set the file to 777
Derek Jones172e1612009-10-13 14:32:48 +0000721 @chmod($this->full_dst_path, FILE_WRITE_MODE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000722
Pascal Kriete8761ef52011-02-14 13:13:52 -0500723 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000724 }
725
726 // --------------------------------------------------------------------
727
728 /**
729 * Create Mirror Image using GD
730 *
731 * This function will flip horizontal or vertical
732 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000733 * @return bool
734 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200735 public function image_mirror_gd()
Derek Allard2067d1a2008-11-13 22:59:24 +0000736 {
737 if ( ! $src_img = $this->image_create_gd())
738 {
739 return FALSE;
740 }
741
Derek Jones4b9c6292011-07-01 17:40:48 -0500742 $width = $this->orig_width;
Derek Allard2067d1a2008-11-13 22:59:24 +0000743 $height = $this->orig_height;
744
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200745 if ($this->rotation_angle === 'hor')
Derek Allard2067d1a2008-11-13 22:59:24 +0000746 {
Andrey Andreeva92b9032011-12-24 19:05:58 +0200747 for ($i = 0; $i < $height; $i++, $left = 0, $right = $width-1)
Derek Allard2067d1a2008-11-13 22:59:24 +0000748 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000749 while ($left < $right)
750 {
751 $cl = imagecolorat($src_img, $left, $i);
752 $cr = imagecolorat($src_img, $right, $i);
753
754 imagesetpixel($src_img, $left, $i, $cr);
755 imagesetpixel($src_img, $right, $i, $cl);
756
757 $left++;
758 $right--;
759 }
760 }
761 }
762 else
763 {
Andrey Andreeva92b9032011-12-24 19:05:58 +0200764 for ($i = 0; $i < $width; $i++, $top = 0, $bot = $height-1)
Derek Allard2067d1a2008-11-13 22:59:24 +0000765 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000766 while ($top < $bot)
767 {
768 $ct = imagecolorat($src_img, $i, $top);
769 $cb = imagecolorat($src_img, $i, $bot);
770
771 imagesetpixel($src_img, $i, $top, $cb);
772 imagesetpixel($src_img, $i, $bot, $ct);
773
774 $top++;
775 $bot--;
776 }
777 }
778 }
779
Andrey Andreev8e70b792012-01-12 20:19:24 +0200780 // Show the image
Derek Allard2067d1a2008-11-13 22:59:24 +0000781 if ($this->dynamic_output == TRUE)
782 {
783 $this->image_display_gd($src_img);
784 }
Andrey Andreev8e70b792012-01-12 20:19:24 +0200785 elseif ( ! $this->image_save_gd($src_img)) // ... or save it
Derek Allard2067d1a2008-11-13 22:59:24 +0000786 {
Andrey Andreev8e70b792012-01-12 20:19:24 +0200787 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000788 }
789
Andrey Andreev8e70b792012-01-12 20:19:24 +0200790 // Kill the file handles
Derek Allard2067d1a2008-11-13 22:59:24 +0000791 imagedestroy($src_img);
792
793 // Set the file to 777
Derek Jones172e1612009-10-13 14:32:48 +0000794 @chmod($this->full_dst_path, FILE_WRITE_MODE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000795
796 return TRUE;
797 }
798
799 // --------------------------------------------------------------------
800
801 /**
802 * Image Watermark
803 *
804 * This is a wrapper function that chooses the type
805 * of watermarking based on the specified preference.
806 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000807 * @param string
808 * @return bool
809 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200810 public function watermark()
Derek Allard2067d1a2008-11-13 22:59:24 +0000811 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200812 return ($this->wm_type === 'overlay') ? $this->overlay_watermark() : $this->text_watermark();
Derek Allard2067d1a2008-11-13 22:59:24 +0000813 }
814
815 // --------------------------------------------------------------------
816
817 /**
818 * Watermark - Graphic Version
819 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000820 * @return bool
821 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200822 public function overlay_watermark()
Derek Allard2067d1a2008-11-13 22:59:24 +0000823 {
824 if ( ! function_exists('imagecolortransparent'))
825 {
826 $this->set_error('imglib_gd_required');
827 return FALSE;
828 }
829
Andrey Andreev8e70b792012-01-12 20:19:24 +0200830 // Fetch source image properties
Derek Allard2067d1a2008-11-13 22:59:24 +0000831 $this->get_image_properties();
832
Andrey Andreev8e70b792012-01-12 20:19:24 +0200833 // Fetch watermark image properties
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200834 $props = $this->get_image_properties($this->wm_overlay_path, TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000835 $wm_img_type = $props['image_type'];
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200836 $wm_width = $props['width'];
837 $wm_height = $props['height'];
Derek Allard2067d1a2008-11-13 22:59:24 +0000838
Andrey Andreev8e70b792012-01-12 20:19:24 +0200839 // Create two image resources
Derek Jones4b9c6292011-07-01 17:40:48 -0500840 $wm_img = $this->image_create_gd($this->wm_overlay_path, $wm_img_type);
Derek Allard2067d1a2008-11-13 22:59:24 +0000841 $src_img = $this->image_create_gd($this->full_src_path);
842
843 // Reverse the offset if necessary
844 // When the image is positioned at the bottom
845 // we don't want the vertical offset to push it
Andrey Andreev8e70b792012-01-12 20:19:24 +0200846 // further down. We want the reverse, so we'll
847 // invert the offset. Same with the horizontal
Derek Allard2067d1a2008-11-13 22:59:24 +0000848 // offset when the image is at the right
849
Andrey Andreev8e70b792012-01-12 20:19:24 +0200850 $this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]);
851 $this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000852
853 if ($this->wm_vrt_alignment == 'B')
854 $this->wm_vrt_offset = $this->wm_vrt_offset * -1;
855
856 if ($this->wm_hor_alignment == 'R')
857 $this->wm_hor_offset = $this->wm_hor_offset * -1;
858
Andrey Andreev8e70b792012-01-12 20:19:24 +0200859 // Set the base x and y axis values
Derek Allard2067d1a2008-11-13 22:59:24 +0000860 $x_axis = $this->wm_hor_offset + $this->wm_padding;
861 $y_axis = $this->wm_vrt_offset + $this->wm_padding;
862
Andrey Andreev8e70b792012-01-12 20:19:24 +0200863 // Set the vertical position
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200864 if ($this->wm_vrt_alignment === 'M')
Derek Allard2067d1a2008-11-13 22:59:24 +0000865 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200866 $y_axis += ($this->orig_height / 2) - ($wm_height / 2);
867 }
868 elseif ($this->wm_vrt_alignment === 'B')
869 {
870 $y_axis += $this->orig_height - $wm_height;
Derek Allard2067d1a2008-11-13 22:59:24 +0000871 }
872
Andrey Andreev8e70b792012-01-12 20:19:24 +0200873 // Set the horizontal position
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200874 if ($this->wm_hor_alignment === 'C')
Derek Allard2067d1a2008-11-13 22:59:24 +0000875 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200876 $x_axis += ($this->orig_width / 2) - ($wm_width / 2);
877 }
878 elseif ($this->wm_hor_alignment === 'R')
879 {
880 $x_axis += $this->orig_width - $wm_width;
Derek Allard2067d1a2008-11-13 22:59:24 +0000881 }
882
Derek Jones4b9c6292011-07-01 17:40:48 -0500883 // Build the finalized image
Andrey Andreev8e70b792012-01-12 20:19:24 +0200884 if ($wm_img_type == 3 && function_exists('imagealphablending'))
Derek Allard2067d1a2008-11-13 22:59:24 +0000885 {
886 @imagealphablending($src_img, TRUE);
Barry Mienydd671972010-10-04 16:33:58 +0200887 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000888
889 // Set RGB values for text and shadow
890 $rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp);
891 $alpha = ($rgba & 0x7F000000) >> 24;
892
893 // make a best guess as to whether we're dealing with an image with alpha transparency or no/binary transparency
894 if ($alpha > 0)
895 {
896 // copy the image directly, the image's alpha transparency being the sole determinant of blending
897 imagecopy($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height);
898 }
899 else
900 {
901 // set our RGB value from above to be transparent and merge the images with the specified opacity
902 imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp));
903 imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity);
904 }
905
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200906 // Output the image
Derek Allard2067d1a2008-11-13 22:59:24 +0000907 if ($this->dynamic_output == TRUE)
908 {
909 $this->image_display_gd($src_img);
910 }
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200911 elseif ( ! $this->image_save_gd($src_img)) // ... or save it
Derek Allard2067d1a2008-11-13 22:59:24 +0000912 {
Andrey Andreeva92b9032011-12-24 19:05:58 +0200913 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000914 }
915
916 imagedestroy($src_img);
917 imagedestroy($wm_img);
918
919 return TRUE;
920 }
921
922 // --------------------------------------------------------------------
923
924 /**
925 * Watermark - Text Version
926 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000927 * @return bool
928 */
Andrey Andreev4eea9892011-12-19 12:05:41 +0200929 public function text_watermark()
Derek Allard2067d1a2008-11-13 22:59:24 +0000930 {
931 if ( ! ($src_img = $this->image_create_gd()))
932 {
933 return FALSE;
934 }
935
Andrey Andreev8e70b792012-01-12 20:19:24 +0200936 if ($this->wm_use_truetype == TRUE && ! file_exists($this->wm_font_path))
Derek Allard2067d1a2008-11-13 22:59:24 +0000937 {
938 $this->set_error('imglib_missing_font');
939 return FALSE;
940 }
941
Andrey Andreev8e70b792012-01-12 20:19:24 +0200942 // Fetch source image properties
Derek Allard2067d1a2008-11-13 22:59:24 +0000943 $this->get_image_properties();
944
Derek Allard2067d1a2008-11-13 22:59:24 +0000945 // Reverse the vertical offset
946 // When the image is positioned at the bottom
947 // we don't want the vertical offset to push it
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200948 // further down. We want the reverse, so we'll
Andrey Andreev8e70b792012-01-12 20:19:24 +0200949 // invert the offset. Note: The horizontal
Derek Allard2067d1a2008-11-13 22:59:24 +0000950 // offset flips itself automatically
951
952 if ($this->wm_vrt_alignment == 'B')
953 $this->wm_vrt_offset = $this->wm_vrt_offset * -1;
954
955 if ($this->wm_hor_alignment == 'R')
956 $this->wm_hor_offset = $this->wm_hor_offset * -1;
957
958 // Set font width and height
959 // These are calculated differently depending on
960 // whether we are using the true type font or not
961 if ($this->wm_use_truetype == TRUE)
962 {
963 if ($this->wm_font_size == '')
Andrey Andreeva92b9032011-12-24 19:05:58 +0200964 {
965 $this->wm_font_size = 17;
966 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000967
Derek Jones4b9c6292011-07-01 17:40:48 -0500968 $fontwidth = $this->wm_font_size-($this->wm_font_size/4);
Derek Allard2067d1a2008-11-13 22:59:24 +0000969 $fontheight = $this->wm_font_size;
970 $this->wm_vrt_offset += $this->wm_font_size;
971 }
972 else
973 {
Derek Jones4b9c6292011-07-01 17:40:48 -0500974 $fontwidth = imagefontwidth($this->wm_font_size);
Derek Allard2067d1a2008-11-13 22:59:24 +0000975 $fontheight = imagefontheight($this->wm_font_size);
976 }
977
978 // Set base X and Y axis values
979 $x_axis = $this->wm_hor_offset + $this->wm_padding;
980 $y_axis = $this->wm_vrt_offset + $this->wm_padding;
981
Derek Allard2067d1a2008-11-13 22:59:24 +0000982 if ($this->wm_use_drop_shadow == FALSE)
983 $this->wm_shadow_distance = 0;
984
985 $this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1));
986 $this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1));
987
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200988 // Set verticle alignment
989 if ($this->wm_vrt_alignment === 'M')
Derek Allard2067d1a2008-11-13 22:59:24 +0000990 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +0200991 $y_axis += ($this->orig_height / 2) + ($fontheight / 2);
992 }
993 elseif ($this->wm_vrt_alignment === 'B')
994 {
995 $y_axis += $this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight / 2);
Derek Allard2067d1a2008-11-13 22:59:24 +0000996 }
997
998 $x_shad = $x_axis + $this->wm_shadow_distance;
999 $y_shad = $y_axis + $this->wm_shadow_distance;
1000
Andrey Andreev64dbdfb2011-12-30 14:14:07 +02001001 if ($this->wm_use_drop_shadow)
Derek Allard2067d1a2008-11-13 22:59:24 +00001002 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +02001003 // Set horizontal alignment
1004 if ($this->wm_hor_alignment === 'R')
1005 {
1006 $x_shad += $this->orig_width - ($fontwidth * strlen($this->wm_text));
1007 $x_axis += $this->orig_width - ($fontwidth * strlen($this->wm_text));
1008 }
1009 elseif ($this->wm_hor_alignment === 'C')
1010 {
1011 $x_shad += floor(($this->orig_width - ($fontwidth * strlen($this->wm_text))) / 2);
1012 $x_axis += floor(($this->orig_width - ($fontwidth * strlen($this->wm_text))) / 2);
1013 }
1014
Andrey Andreev8323ae62011-12-31 18:39:10 +02001015 /* Set RGB values for text and shadow
1016 *
1017 * First character is #, so we don't really need it.
1018 * Get the rest of the string and split it into 2-length
1019 * hex values:
1020 */
1021 $txt_color = str_split(substr($this->wm_font_color, 1, 6), 2);
Andrey Andreev64dbdfb2011-12-30 14:14:07 +02001022 $txt_color = imagecolorclosest($src_img, hexdec($txt_color[0]), hexdec($txt_color[1]), hexdec($txt_color[2]));
Andrey Andreev8323ae62011-12-31 18:39:10 +02001023 $drp_color = str_split(substr($this->wm_shadow_color, 1, 6), 2);
Ronald Beilsma8f80bc42012-01-12 16:41:49 +01001024 $drp_color = imagecolorclosest($src_img, hexdec($drp_color[0]), hexdec($drp_color[1]), hexdec($drp_color[2]));
Andrey Andreev64dbdfb2011-12-30 14:14:07 +02001025
Andrey Andreev8e70b792012-01-12 20:19:24 +02001026 // Add the text to the source image
Andrey Andreev64dbdfb2011-12-30 14:14:07 +02001027 if ($this->wm_use_truetype)
1028 {
1029 imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text);
1030 imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text);
1031 }
1032 else
1033 {
1034 imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);
1035 imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);
1036 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001037 }
1038
Andrey Andreev8e70b792012-01-12 20:19:24 +02001039 // Output the final image
Derek Allard2067d1a2008-11-13 22:59:24 +00001040 if ($this->dynamic_output == TRUE)
1041 {
1042 $this->image_display_gd($src_img);
1043 }
1044 else
1045 {
1046 $this->image_save_gd($src_img);
1047 }
1048
1049 imagedestroy($src_img);
1050
1051 return TRUE;
1052 }
1053
1054 // --------------------------------------------------------------------
1055
1056 /**
1057 * Create Image - GD
1058 *
1059 * This simply creates an image resource handle
1060 * based on the type of image being processed
1061 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001062 * @param string
1063 * @return resource
1064 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001065 public function image_create_gd($path = '', $image_type = '')
Derek Allard2067d1a2008-11-13 22:59:24 +00001066 {
1067 if ($path == '')
1068 $path = $this->full_src_path;
1069
1070 if ($image_type == '')
1071 $image_type = $this->image_type;
1072
1073
1074 switch ($image_type)
1075 {
1076 case 1 :
1077 if ( ! function_exists('imagecreatefromgif'))
1078 {
1079 $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
1080 return FALSE;
1081 }
1082
1083 return imagecreatefromgif($path);
1084 break;
1085 case 2 :
1086 if ( ! function_exists('imagecreatefromjpeg'))
1087 {
1088 $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
1089 return FALSE;
1090 }
1091
1092 return imagecreatefromjpeg($path);
1093 break;
1094 case 3 :
1095 if ( ! function_exists('imagecreatefrompng'))
1096 {
1097 $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
1098 return FALSE;
1099 }
1100
1101 return imagecreatefrompng($path);
1102 break;
1103
1104 }
1105
1106 $this->set_error(array('imglib_unsupported_imagecreate'));
1107 return FALSE;
1108 }
1109
1110 // --------------------------------------------------------------------
1111
1112 /**
1113 * Write image file to disk - GD
1114 *
1115 * Takes an image resource as input and writes the file
1116 * to the specified destination
1117 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001118 * @param resource
1119 * @return bool
1120 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001121 public function image_save_gd($resource)
Derek Allard2067d1a2008-11-13 22:59:24 +00001122 {
1123 switch ($this->image_type)
1124 {
1125 case 1 :
1126 if ( ! function_exists('imagegif'))
1127 {
1128 $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
1129 return FALSE;
1130 }
1131
Derek Jones541ddbd2008-12-09 15:25:31 +00001132 if ( ! @imagegif($resource, $this->full_dst_path))
1133 {
1134 $this->set_error('imglib_save_failed');
1135 return FALSE;
1136 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001137 break;
1138 case 2 :
1139 if ( ! function_exists('imagejpeg'))
1140 {
1141 $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
1142 return FALSE;
1143 }
1144
Derek Jones541ddbd2008-12-09 15:25:31 +00001145 if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality))
1146 {
1147 $this->set_error('imglib_save_failed');
1148 return FALSE;
1149 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001150 break;
1151 case 3 :
1152 if ( ! function_exists('imagepng'))
1153 {
1154 $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
1155 return FALSE;
1156 }
1157
Derek Jones541ddbd2008-12-09 15:25:31 +00001158 if ( ! @imagepng($resource, $this->full_dst_path))
1159 {
1160 $this->set_error('imglib_save_failed');
1161 return FALSE;
1162 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001163 break;
1164 default :
1165 $this->set_error(array('imglib_unsupported_imagecreate'));
1166 return FALSE;
1167 break;
1168 }
1169
1170 return TRUE;
1171 }
1172
1173 // --------------------------------------------------------------------
1174
1175 /**
1176 * Dynamically outputs an image
1177 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001178 * @param resource
1179 * @return void
1180 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001181 public function image_display_gd($resource)
Derek Allard2067d1a2008-11-13 22:59:24 +00001182 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +02001183 header('Content-Disposition: filename='.$this->source_image.';');
1184 header('Content-Type: '.$this->mime_type);
Derek Allard2067d1a2008-11-13 22:59:24 +00001185 header('Content-Transfer-Encoding: binary');
1186 header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');
1187
1188 switch ($this->image_type)
1189 {
Barry Mienydd671972010-10-04 16:33:58 +02001190 case 1 : imagegif($resource);
Derek Allard2067d1a2008-11-13 22:59:24 +00001191 break;
1192 case 2 : imagejpeg($resource, '', $this->quality);
1193 break;
1194 case 3 : imagepng($resource);
1195 break;
1196 default : echo 'Unable to display the image';
1197 break;
1198 }
1199 }
1200
1201 // --------------------------------------------------------------------
1202
1203 /**
1204 * Re-proportion Image Width/Height
1205 *
1206 * When creating thumbs, the desired width/height
1207 * can end up warping the image due to an incorrect
1208 * ratio between the full-sized image and the thumb.
1209 *
1210 * This function lets us re-proportion the width/height
1211 * if users choose to maintain the aspect ratio when resizing.
1212 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001213 * @return void
1214 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001215 public function image_reproportion()
Derek Allard2067d1a2008-11-13 22:59:24 +00001216 {
Andrey Andreev8e70b792012-01-12 20:19:24 +02001217 if (($this->width == 0 && $this->height == 0) OR $this->orig_width == 0 OR $this->orig_height == 0
1218 OR ( ! preg_match('/^[0-9]+$/', $this->width) && ! preg_match('/^[0-9]+$/', $this->height))
1219 OR ! preg_match('/^[0-9]+$/', $this->orig_width) OR ! preg_match('/^[0-9]+$/', $this->orig_height))
Derek Allard2067d1a2008-11-13 22:59:24 +00001220 {
Andrey Andreev8e70b792012-01-12 20:19:24 +02001221 return;
Derek Allard2067d1a2008-11-13 22:59:24 +00001222 }
1223
Andrey Andreev8e70b792012-01-12 20:19:24 +02001224 // Sanitize so we don't call preg_match() anymore
1225 $this->width = (int) $this->width;
1226 $this->height = (int) $this->height;
1227
1228 if ($this->master_dim !== 'width' && $this->master_dim !== 'height')
Derek Allard2067d1a2008-11-13 22:59:24 +00001229 {
Andrey Andreev8e70b792012-01-12 20:19:24 +02001230 if ($this->width > 0 && $this->height > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +00001231 {
Andrey Andreev8e70b792012-01-12 20:19:24 +02001232 $this->master_dim = ((($this->orig_height/$this->orig_width) - ($this->height/$this->width)) < 0)
1233 ? 'width' : 'height';
Derek Allard2067d1a2008-11-13 22:59:24 +00001234 }
1235 else
1236 {
Andrey Andreev8e70b792012-01-12 20:19:24 +02001237 $this->master_dim = ($this->height === 0) ? 'width' : 'height';
Derek Allard2067d1a2008-11-13 22:59:24 +00001238 }
1239 }
Andrey Andreev8e70b792012-01-12 20:19:24 +02001240 elseif (($this->master_dim === 'width' && $this->width === 0)
1241 OR ($this->master_dim === 'height' && $this->height === 0))
1242 {
1243 return;
1244 }
1245
1246 if ($this->master_dim === 'width')
1247 {
1248 $this->height = (int) ceil($this->width*$this->orig_height/$this->orig_width);
1249 }
1250 else
1251 {
1252 $this->width = (int) ceil($this->orig_width*$this->height/$this->orig_height);
1253 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001254 }
1255
1256 // --------------------------------------------------------------------
1257
1258 /**
1259 * Get image properties
1260 *
1261 * A helper function that gets info about the file
1262 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001263 * @param string
1264 * @return mixed
1265 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001266 public function get_image_properties($path = '', $return = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +00001267 {
1268 // For now we require GD but we should
1269 // find a way to determine this using IM or NetPBM
1270
1271 if ($path == '')
Andrey Andreev8e70b792012-01-12 20:19:24 +02001272 {
Derek Allard2067d1a2008-11-13 22:59:24 +00001273 $path = $this->full_src_path;
Andrey Andreev8e70b792012-01-12 20:19:24 +02001274 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001275
1276 if ( ! file_exists($path))
1277 {
1278 $this->set_error('imglib_invalid_path');
1279 return FALSE;
1280 }
1281
Phil Sturgeon901998a2011-08-26 10:03:33 +01001282 $vals = getimagesize($path);
Derek Allard2067d1a2008-11-13 22:59:24 +00001283 $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
Andrey Andreeva92b9032011-12-24 19:05:58 +02001284 $mime = (isset($types[$vals[2]])) ? 'image/'.$types[$vals[2]] : 'image/jpg';
Derek Allard2067d1a2008-11-13 22:59:24 +00001285
1286 if ($return == TRUE)
1287 {
Andrey Andreeva92b9032011-12-24 19:05:58 +02001288 return array(
1289 'width' => $vals[0],
1290 'height' => $vals[1],
1291 'image_type' => $vals[2],
1292 'size_str' => $vals[3],
1293 'mime_type' => $mime
1294 );
Derek Allard2067d1a2008-11-13 22:59:24 +00001295 }
1296
Andrey Andreeva92b9032011-12-24 19:05:58 +02001297 $this->orig_width = $vals[0];
1298 $this->orig_height = $vals[1];
1299 $this->image_type = $vals[2];
1300 $this->size_str = $vals[3];
Derek Allard2067d1a2008-11-13 22:59:24 +00001301 $this->mime_type = $mime;
1302
1303 return TRUE;
1304 }
1305
1306 // --------------------------------------------------------------------
1307
1308 /**
1309 * Size calculator
1310 *
1311 * This function takes a known width x height and
Andrey Andreev2c8baeb2012-01-19 15:45:28 +02001312 * recalculates it to a new size. Only one
Derek Allard2067d1a2008-11-13 22:59:24 +00001313 * new variable needs to be known
1314 *
1315 * $props = array(
Andrey Andreev2c8baeb2012-01-19 15:45:28 +02001316 * 'width' => $width,
1317 * 'height' => $height,
1318 * 'new_width' => 40,
1319 * 'new_height' => ''
1320 * );
Derek Allard2067d1a2008-11-13 22:59:24 +00001321 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001322 * @param array
1323 * @return array
1324 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001325 public function size_calculator($vals)
Derek Allard2067d1a2008-11-13 22:59:24 +00001326 {
1327 if ( ! is_array($vals))
1328 {
1329 return;
1330 }
1331
1332 $allowed = array('new_width', 'new_height', 'width', 'height');
1333
1334 foreach ($allowed as $item)
1335 {
1336 if ( ! isset($vals[$item]) OR $vals[$item] == '')
1337 $vals[$item] = 0;
1338 }
1339
1340 if ($vals['width'] == 0 OR $vals['height'] == 0)
1341 {
1342 return $vals;
1343 }
1344
1345 if ($vals['new_width'] == 0)
1346 {
1347 $vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']);
1348 }
1349 elseif ($vals['new_height'] == 0)
1350 {
1351 $vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']);
1352 }
1353
1354 return $vals;
1355 }
1356
1357 // --------------------------------------------------------------------
1358
1359 /**
1360 * Explode source_image
1361 *
1362 * This is a helper function that extracts the extension
Derek Jones4b9c6292011-07-01 17:40:48 -05001363 * from the source_image. This function lets us deal with
Andrey Andreev2c8baeb2012-01-19 15:45:28 +02001364 * source_images with multiple periods, like: my.cool.jpg
Derek Allard2067d1a2008-11-13 22:59:24 +00001365 * It returns an associative array with two elements:
Derek Jones4b9c6292011-07-01 17:40:48 -05001366 * $array['ext'] = '.jpg';
Derek Allard2067d1a2008-11-13 22:59:24 +00001367 * $array['name'] = 'my.cool';
1368 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001369 * @param array
1370 * @return array
1371 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001372 public function explode_name($source_image)
Derek Allard2067d1a2008-11-13 22:59:24 +00001373 {
Derek Jones08cae632009-02-10 20:03:29 +00001374 $ext = strrchr($source_image, '.');
1375 $name = ($ext === FALSE) ? $source_image : substr($source_image, 0, -strlen($ext));
Barry Mienydd671972010-10-04 16:33:58 +02001376
Derek Jones08cae632009-02-10 20:03:29 +00001377 return array('ext' => $ext, 'name' => $name);
Derek Allard2067d1a2008-11-13 22:59:24 +00001378 }
1379
1380 // --------------------------------------------------------------------
1381
1382 /**
1383 * Is GD Installed?
1384 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001385 * @return bool
1386 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001387 public function gd_loaded()
Derek Allard2067d1a2008-11-13 22:59:24 +00001388 {
1389 if ( ! extension_loaded('gd'))
1390 {
Andrey Andreeva92b9032011-12-24 19:05:58 +02001391 /* As it is stated in the PHP manual, dl() is not always available
1392 * and even if so - it could generate an E_WARNING message on failure
1393 */
Andrey Andreev8e70b792012-01-12 20:19:24 +02001394 return (function_exists('dl') && @dl('gd.so'));
Derek Allard2067d1a2008-11-13 22:59:24 +00001395 }
1396
1397 return TRUE;
1398 }
1399
1400 // --------------------------------------------------------------------
1401
1402 /**
1403 * Get GD version
1404 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001405 * @return mixed
1406 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001407 public function gd_version()
Derek Allard2067d1a2008-11-13 22:59:24 +00001408 {
1409 if (function_exists('gd_info'))
1410 {
1411 $gd_version = @gd_info();
Andrey Andreev8e70b792012-01-12 20:19:24 +02001412 return preg_replace('/\D/', '', $gd_version['GD Version']);
Derek Allard2067d1a2008-11-13 22:59:24 +00001413 }
1414
1415 return FALSE;
1416 }
1417
1418 // --------------------------------------------------------------------
1419
1420 /**
1421 * Set error message
1422 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001423 * @param string
1424 * @return void
1425 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001426 public function set_error($msg)
Derek Allard2067d1a2008-11-13 22:59:24 +00001427 {
1428 $CI =& get_instance();
1429 $CI->lang->load('imglib');
1430
1431 if (is_array($msg))
1432 {
1433 foreach ($msg as $val)
1434 {
1435
1436 $msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
1437 $this->error_msg[] = $msg;
1438 log_message('error', $msg);
1439 }
1440 }
1441 else
1442 {
1443 $msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
1444 $this->error_msg[] = $msg;
1445 log_message('error', $msg);
1446 }
1447 }
1448
1449 // --------------------------------------------------------------------
1450
1451 /**
1452 * Show error messages
1453 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001454 * @param string
1455 * @return string
1456 */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001457 public function display_errors($open = '<p>', $close = '</p>')
Derek Allard2067d1a2008-11-13 22:59:24 +00001458 {
Andrey Andreev2c8baeb2012-01-19 15:45:28 +02001459 return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
Derek Allard2067d1a2008-11-13 22:59:24 +00001460 }
1461
1462}
Derek Allard2067d1a2008-11-13 22:59:24 +00001463
1464/* End of file Image_lib.php */
Andrey Andreev4eea9892011-12-19 12:05:41 +02001465/* Location: ./system/libraries/Image_lib.php */