Subversion-Projekte lars-tiefland.ci

Revision

Revision 1257 | Revision 2107 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
68 lars 1
<?php
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
2049 lars 9
 * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
68 lars 10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
2049 lars 32
 * @copyright	Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
68 lars 33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	https://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
39
 
40
/**
41
 * Image Manipulation class
42
 *
43
 * @package		CodeIgniter
44
 * @subpackage	Libraries
45
 * @category	Image_lib
46
 * @author		EllisLab Dev Team
47
 * @link		https://codeigniter.com/user_guide/libraries/image_lib.html
48
 */
49
class CI_Image_lib {
50
 
51
	/**
52
	 * PHP extension/library to use for image manipulation
53
	 * Can be: imagemagick, netpbm, gd, gd2
54
	 *
55
	 * @var string
56
	 */
57
	public $image_library		= 'gd2';
58
 
59
	/**
60
	 * Path to the graphic library (if applicable)
61
	 *
62
	 * @var string
63
	 */
64
	public $library_path		= '';
65
 
66
	/**
67
	 * Whether to send to browser or write to disk
68
	 *
69
	 * @var bool
70
	 */
71
	public $dynamic_output		= FALSE;
72
 
73
	/**
74
	 * Path to original image
75
	 *
76
	 * @var string
77
	 */
78
	public $source_image		= '';
79
 
80
	/**
81
	 * Path to the modified image
82
	 *
83
	 * @var string
84
	 */
85
	public $new_image		= '';
86
 
87
	/**
88
	 * Image width
89
	 *
90
	 * @var int
91
	 */
92
	public $width			= '';
93
 
94
	/**
95
	 * Image height
96
	 *
97
	 * @var int
98
	 */
99
	public $height			= '';
100
 
101
	/**
102
	 * Quality percentage of new image
103
	 *
104
	 * @var int
105
	 */
106
	public $quality			= 90;
107
 
108
	/**
109
	 * Whether to create a thumbnail
110
	 *
111
	 * @var bool
112
	 */
113
	public $create_thumb		= FALSE;
114
 
115
	/**
116
	 * String to add to thumbnail version of image
117
	 *
118
	 * @var string
119
	 */
120
	public $thumb_marker		= '_thumb';
121
 
122
	/**
123
	 * Whether to maintain aspect ratio when resizing or use hard values
124
	 *
125
	 * @var bool
126
	 */
127
	public $maintain_ratio		= TRUE;
128
 
129
	/**
130
	 * auto, height, or width.  Determines what to use as the master dimension
131
	 *
132
	 * @var string
133
	 */
134
	public $master_dim		= 'auto';
135
 
136
	/**
137
	 * Angle at to rotate image
138
	 *
139
	 * @var string
140
	 */
141
	public $rotation_angle		= '';
142
 
143
	/**
144
	 * X Coordinate for manipulation of the current image
145
	 *
146
	 * @var int
147
	 */
148
	public $x_axis			= '';
149
 
150
	/**
151
	 * Y Coordinate for manipulation of the current image
152
	 *
153
	 * @var int
154
	 */
155
	public $y_axis			= '';
156
 
157
	// --------------------------------------------------------------------------
158
	// Watermark Vars
159
	// --------------------------------------------------------------------------
160
 
161
	/**
162
	 * Watermark text if graphic is not used
163
	 *
164
	 * @var string
165
	 */
166
	public $wm_text			= '';
167
 
168
	/**
169
	 * Type of watermarking.  Options:  text/overlay
170
	 *
171
	 * @var string
172
	 */
173
	public $wm_type			= 'text';
174
 
175
	/**
176
	 * Default transparency for watermark
177
	 *
178
	 * @var int
179
	 */
180
	public $wm_x_transp		= 4;
181
 
182
	/**
183
	 * Default transparency for watermark
184
	 *
185
	 * @var int
186
	 */
187
	public $wm_y_transp		= 4;
188
 
189
	/**
190
	 * Watermark image path
191
	 *
192
	 * @var string
193
	 */
194
	public $wm_overlay_path		= '';
195
 
196
	/**
197
	 * TT font
198
	 *
199
	 * @var string
200
	 */
201
	public $wm_font_path		= '';
202
 
203
	/**
204
	 * Font size (different versions of GD will either use points or pixels)
205
	 *
206
	 * @var int
207
	 */
208
	public $wm_font_size		= 17;
209
 
210
	/**
211
	 * Vertical alignment:   T M B
212
	 *
213
	 * @var string
214
	 */
215
	public $wm_vrt_alignment	= 'B';
216
 
217
	/**
218
	 * Horizontal alignment: L R C
219
	 *
220
	 * @var string
221
	 */
222
	public $wm_hor_alignment	= 'C';
223
 
224
	/**
225
	 * Padding around text
226
	 *
227
	 * @var int
228
	 */
229
	public $wm_padding			= 0;
230
 
231
	/**
232
	 * Lets you push text to the right
233
	 *
234
	 * @var int
235
	 */
236
	public $wm_hor_offset		= 0;
237
 
238
	/**
239
	 * Lets you push text down
240
	 *
241
	 * @var int
242
	 */
243
	public $wm_vrt_offset		= 0;
244
 
245
	/**
246
	 * Text color
247
	 *
248
	 * @var string
249
	 */
250
	protected $wm_font_color	= '#ffffff';
251
 
252
	/**
253
	 * Dropshadow color
254
	 *
255
	 * @var string
256
	 */
257
	protected $wm_shadow_color	= '';
258
 
259
	/**
260
	 * Dropshadow distance
261
	 *
262
	 * @var int
263
	 */
264
	public $wm_shadow_distance	= 2;
265
 
266
	/**
267
	 * Image opacity: 1 - 100  Only works with image
268
	 *
269
	 * @var int
270
	 */
271
	public $wm_opacity		= 50;
272
 
273
	// --------------------------------------------------------------------------
274
	// Private Vars
275
	// --------------------------------------------------------------------------
276
 
277
	/**
278
	 * Source image folder
279
	 *
280
	 * @var string
281
	 */
282
	public $source_folder		= '';
283
 
284
	/**
285
	 * Destination image folder
286
	 *
287
	 * @var string
288
	 */
289
	public $dest_folder		= '';
290
 
291
	/**
292
	 * Image mime-type
293
	 *
294
	 * @var string
295
	 */
296
	public $mime_type		= '';
297
 
298
	/**
299
	 * Original image width
300
	 *
301
	 * @var int
302
	 */
303
	public $orig_width		= '';
304
 
305
	/**
306
	 * Original image height
307
	 *
308
	 * @var int
309
	 */
310
	public $orig_height		= '';
311
 
312
	/**
313
	 * Image format
314
	 *
315
	 * @var string
316
	 */
317
	public $image_type		= '';
318
 
319
	/**
320
	 * Size of current image
321
	 *
322
	 * @var string
323
	 */
324
	public $size_str		= '';
325
 
326
	/**
327
	 * Full path to source image
328
	 *
329
	 * @var string
330
	 */
331
	public $full_src_path		= '';
332
 
333
	/**
334
	 * Full path to destination image
335
	 *
336
	 * @var string
337
	 */
338
	public $full_dst_path		= '';
339
 
340
	/**
341
	 * File permissions
342
	 *
343
	 * @var	int
344
	 */
345
	public $file_permissions = 0644;
346
 
347
	/**
348
	 * Name of function to create image
349
	 *
350
	 * @var string
351
	 */
352
	public $create_fnc		= 'imagecreatetruecolor';
353
 
354
	/**
355
	 * Name of function to copy image
356
	 *
357
	 * @var string
358
	 */
359
	public $copy_fnc		= 'imagecopyresampled';
360
 
361
	/**
362
	 * Error messages
363
	 *
364
	 * @var array
365
	 */
366
	public $error_msg		= array();
367
 
368
	/**
369
	 * Whether to have a drop shadow on watermark
370
	 *
371
	 * @var bool
372
	 */
373
	protected $wm_use_drop_shadow	= FALSE;
374
 
375
	/**
376
	 * Whether to use truetype fonts
377
	 *
378
	 * @var bool
379
	 */
380
	public $wm_use_truetype	= FALSE;
381
 
382
	/**
383
	 * Initialize Image Library
384
	 *
385
	 * @param	array	$props
386
	 * @return	void
387
	 */
388
	public function __construct($props = array())
389
	{
390
		if (count($props) > 0)
391
		{
392
			$this->initialize($props);
393
		}
394
 
395
		log_message('info', 'Image Lib Class Initialized');
396
	}
397
 
398
	// --------------------------------------------------------------------
399
 
400
	/**
401
	 * Initialize image properties
402
	 *
403
	 * Resets values in case this class is used in a loop
404
	 *
405
	 * @return	void
406
	 */
407
	public function clear()
408
	{
409
		$props = array('thumb_marker', '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');
410
 
411
		foreach ($props as $val)
412
		{
413
			$this->$val = '';
414
		}
415
 
416
		$this->image_library 		= 'gd2';
417
		$this->dynamic_output 		= FALSE;
418
		$this->quality 				= 90;
419
		$this->create_thumb 		= FALSE;
420
		$this->thumb_marker 		= '_thumb';
421
		$this->maintain_ratio 		= TRUE;
422
		$this->master_dim 			= 'auto';
423
		$this->wm_type 				= 'text';
424
		$this->wm_x_transp 			= 4;
425
		$this->wm_y_transp 			= 4;
426
		$this->wm_font_size 		= 17;
427
		$this->wm_vrt_alignment 	= 'B';
428
		$this->wm_hor_alignment 	= 'C';
429
		$this->wm_padding 			= 0;
430
		$this->wm_hor_offset 		= 0;
431
		$this->wm_vrt_offset 		= 0;
432
		$this->wm_font_color		= '#ffffff';
433
		$this->wm_shadow_distance 	= 2;
434
		$this->wm_opacity 			= 50;
435
		$this->create_fnc 			= 'imagecreatetruecolor';
436
		$this->copy_fnc 			= 'imagecopyresampled';
437
		$this->error_msg 			= array();
438
		$this->wm_use_drop_shadow 	= FALSE;
439
		$this->wm_use_truetype 		= FALSE;
440
	}
441
 
442
	// --------------------------------------------------------------------
443
 
444
	/**
445
	 * initialize image preferences
446
	 *
447
	 * @param	array
448
	 * @return	bool
449
	 */
450
	public function initialize($props = array())
451
	{
452
		// Convert array elements into class variables
453
		if (count($props) > 0)
454
		{
455
			foreach ($props as $key => $val)
456
			{
457
				if (property_exists($this, $key))
458
				{
459
					if (in_array($key, array('wm_font_color', 'wm_shadow_color'), TRUE))
460
					{
461
						if (preg_match('/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i', $val, $matches))
462
						{
463
							/* $matches[1] contains our hex color value, but it might be
464
							 * both in the full 6-length format or the shortened 3-length
465
							 * value.
466
							 * We'll later need the full version, so we keep it if it's
467
							 * already there and if not - we'll convert to it. We can
468
							 * access string characters by their index as in an array,
469
							 * so we'll do that and use concatenation to form the final
470
							 * value:
471
							 */
472
							$val = (strlen($matches[1]) === 6)
473
								? '#'.$matches[1]
474
								: '#'.$matches[1][0].$matches[1][0].$matches[1][1].$matches[1][1].$matches[1][2].$matches[1][2];
475
						}
476
						else
477
						{
478
							continue;
479
						}
480
					}
481
					elseif (in_array($key, array('width', 'height'), TRUE) && ! ctype_digit((string) $val))
482
					{
483
						continue;
484
					}
485
 
486
					$this->$key = $val;
487
				}
488
			}
489
		}
490
 
491
		// Is there a source image? If not, there's no reason to continue
492
		if ($this->source_image === '')
493
		{
494
			$this->set_error('imglib_source_image_required');
495
			return FALSE;
496
		}
497
 
498
		/* Is getimagesize() available?
499
		 *
500
		 * We use it to determine the image properties (width/height).
501
		 * Note: We need to figure out how to determine image
502
		 * properties using ImageMagick and NetPBM
503
		 */
504
		if ( ! function_exists('getimagesize'))
505
		{
506
			$this->set_error('imglib_gd_required_for_props');
507
			return FALSE;
508
		}
509
 
510
		$this->image_library = strtolower($this->image_library);
511
 
512
		/* Set the full server path
513
		 *
514
		 * The source image may or may not contain a path.
515
		 * Either way, we'll try use realpath to generate the
516
		 * full server path in order to more reliably read it.
517
		 */
518
		if (($full_source_path = realpath($this->source_image)) !== FALSE)
519
		{
520
			$full_source_path = str_replace('\\', '/', $full_source_path);
521
		}
522
		else
523
		{
524
			$full_source_path = $this->source_image;
525
		}
526
 
527
		$x = explode('/', $full_source_path);
528
		$this->source_image = end($x);
529
		$this->source_folder = str_replace($this->source_image, '', $full_source_path);
530
 
531
		// Set the Image Properties
532
		if ( ! $this->get_image_properties($this->source_folder.$this->source_image))
533
		{
534
			return FALSE;
535
		}
536
 
537
		/*
538
		 * Assign the "new" image name/path
539
		 *
540
		 * If the user has set a "new_image" name it means
541
		 * we are making a copy of the source image. If not
542
		 * it means we are altering the original. We'll
543
		 * set the destination filename and path accordingly.
544
		 */
545
		if ($this->new_image === '')
546
		{
2049 lars 547
			$this->dest_image  = $this->source_image;
68 lars 548
			$this->dest_folder = $this->source_folder;
549
		}
2049 lars 550
		elseif (strpos($this->new_image, '/') === FALSE && strpos($this->new_image, '\\') === FALSE)
68 lars 551
		{
2049 lars 552
			$this->dest_image  = $this->new_image;
68 lars 553
			$this->dest_folder = $this->source_folder;
554
		}
555
		else
556
		{
2049 lars 557
			// Is there a file name?
558
			if ( ! preg_match('#\.(jpg|jpeg|gif|png)$#i', $this->new_image))
68 lars 559
			{
2049 lars 560
				$this->dest_image  = $this->source_image;
561
				$this->dest_folder = $this->new_image;
68 lars 562
			}
563
			else
564
			{
2049 lars 565
				$x = explode('/', str_replace('\\', '/', $this->new_image));
566
				$this->dest_image  = end($x);
567
				$this->dest_folder = str_replace($this->dest_image, '', $this->new_image);
68 lars 568
			}
569
 
2049 lars 570
			$this->dest_folder = realpath($this->dest_folder).'/';
68 lars 571
		}
572
 
573
		/* Compile the finalized filenames/paths
574
		 *
575
		 * We'll create two master strings containing the
576
		 * full server path to the source image and the
577
		 * full server path to the destination image.
578
		 * We'll also split the destination image name
579
		 * so we can insert the thumbnail marker if needed.
580
		 */
581
		if ($this->create_thumb === FALSE OR $this->thumb_marker === '')
582
		{
583
			$this->thumb_marker = '';
584
		}
585
 
586
		$xp = $this->explode_name($this->dest_image);
587
 
588
		$filename = $xp['name'];
589
		$file_ext = $xp['ext'];
590
 
591
		$this->full_src_path = $this->source_folder.$this->source_image;
592
		$this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext;
593
 
594
		/* Should we maintain image proportions?
595
		 *
596
		 * When creating thumbs or copies, the target width/height
597
		 * might not be in correct proportion with the source
598
		 * image's width/height. We'll recalculate it here.
599
		 */
600
		if ($this->maintain_ratio === TRUE && ($this->width !== 0 OR $this->height !== 0))
601
		{
602
			$this->image_reproportion();
603
		}
604
 
605
		/* Was a width and height specified?
606
		 *
607
		 * If the destination width/height was not submitted we
608
		 * will use the values from the actual file
609
		 */
610
		if ($this->width === '')
611
		{
612
			$this->width = $this->orig_width;
613
		}
614
 
615
		if ($this->height === '')
616
		{
617
			$this->height = $this->orig_height;
618
		}
619
 
620
		// Set the quality
621
		$this->quality = trim(str_replace('%', '', $this->quality));
622
 
623
		if ($this->quality === '' OR $this->quality === 0 OR ! ctype_digit($this->quality))
624
		{
625
			$this->quality = 90;
626
		}
627
 
628
		// Set the x/y coordinates
629
		is_numeric($this->x_axis) OR $this->x_axis = 0;
630
		is_numeric($this->y_axis) OR $this->y_axis = 0;
631
 
632
		// Watermark-related Stuff...
633
		if ($this->wm_overlay_path !== '')
634
		{
635
			$this->wm_overlay_path = str_replace('\\', '/', realpath($this->wm_overlay_path));
636
		}
637
 
638
		if ($this->wm_shadow_color !== '')
639
		{
640
			$this->wm_use_drop_shadow = TRUE;
641
		}
642
		elseif ($this->wm_use_drop_shadow === TRUE && $this->wm_shadow_color === '')
643
		{
644
			$this->wm_use_drop_shadow = FALSE;
645
		}
646
 
647
		if ($this->wm_font_path !== '')
648
		{
649
			$this->wm_use_truetype = TRUE;
650
		}
651
 
652
		return TRUE;
653
	}
654
 
655
	// --------------------------------------------------------------------
656
 
657
	/**
658
	 * Image Resize
659
	 *
660
	 * This is a wrapper function that chooses the proper
661
	 * resize function based on the protocol specified
662
	 *
663
	 * @return	bool
664
	 */
665
	public function resize()
666
	{
667
		$protocol = ($this->image_library === 'gd2') ? 'image_process_gd' : 'image_process_'.$this->image_library;
668
		return $this->$protocol('resize');
669
	}
670
 
671
	// --------------------------------------------------------------------
672
 
673
	/**
674
	 * Image Crop
675
	 *
676
	 * This is a wrapper function that chooses the proper
677
	 * cropping function based on the protocol specified
678
	 *
679
	 * @return	bool
680
	 */
681
	public function crop()
682
	{
683
		$protocol = ($this->image_library === 'gd2') ? 'image_process_gd' : 'image_process_'.$this->image_library;
684
		return $this->$protocol('crop');
685
	}
686
 
687
	// --------------------------------------------------------------------
688
 
689
	/**
690
	 * Image Rotate
691
	 *
692
	 * This is a wrapper function that chooses the proper
693
	 * rotation function based on the protocol specified
694
	 *
695
	 * @return	bool
696
	 */
697
	public function rotate()
698
	{
699
		// Allowed rotation values
700
		$degs = array(90, 180, 270, 'vrt', 'hor');
701
 
702
		if ($this->rotation_angle === '' OR ! in_array($this->rotation_angle, $degs))
703
		{
704
			$this->set_error('imglib_rotation_angle_required');
705
			return FALSE;
706
		}
707
 
708
		// Reassign the width and height
709
		if ($this->rotation_angle === 90 OR $this->rotation_angle === 270)
710
		{
711
			$this->width	= $this->orig_height;
712
			$this->height	= $this->orig_width;
713
		}
714
		else
715
		{
716
			$this->width	= $this->orig_width;
717
			$this->height	= $this->orig_height;
718
		}
719
 
720
		// Choose resizing function
721
		if ($this->image_library === 'imagemagick' OR $this->image_library === 'netpbm')
722
		{
723
			$protocol = 'image_process_'.$this->image_library;
724
			return $this->$protocol('rotate');
725
		}
726
 
727
		return ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
728
			? $this->image_mirror_gd()
729
			: $this->image_rotate_gd();
730
	}
731
 
732
	// --------------------------------------------------------------------
733
 
734
	/**
735
	 * Image Process Using GD/GD2
736
	 *
737
	 * This function will resize or crop
738
	 *
739
	 * @param	string
740
	 * @return	bool
741
	 */
742
	public function image_process_gd($action = 'resize')
743
	{
744
		$v2_override = FALSE;
745
 
746
		// If the target width/height match the source, AND if the new file name is not equal to the old file name
747
		// we'll simply make a copy of the original with the new name... assuming dynamic rendering is off.
748
		if ($this->dynamic_output === FALSE && $this->orig_width === $this->width && $this->orig_height === $this->height)
749
		{
750
			if ($this->source_image !== $this->new_image && @copy($this->full_src_path, $this->full_dst_path))
751
			{
752
				chmod($this->full_dst_path, $this->file_permissions);
753
			}
754
 
755
			return TRUE;
756
		}
757
 
758
		// Let's set up our values based on the action
759
		if ($action === 'crop')
760
		{
761
			// Reassign the source width/height if cropping
762
			$this->orig_width  = $this->width;
763
			$this->orig_height = $this->height;
764
 
765
			// GD 2.0 has a cropping bug so we'll test for it
766
			if ($this->gd_version() !== FALSE)
767
			{
768
				$gd_version = str_replace('0', '', $this->gd_version());
769
				$v2_override = ($gd_version == 2);
770
			}
771
		}
772
		else
773
		{
774
			// If resizing the x/y axis must be zero
775
			$this->x_axis = 0;
776
			$this->y_axis = 0;
777
		}
778
 
779
		// Create the image handle
780
		if ( ! ($src_img = $this->image_create_gd()))
781
		{
782
			return FALSE;
783
		}
784
 
785
		/* Create the image
786
		 *
787
		 * Old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater"
788
		 * it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment
789
		 * below should that ever prove inaccurate.
790
		 *
791
		 * if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor') && $v2_override === FALSE)
792
		 */
793
		if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor'))
794
		{
795
			$create	= 'imagecreatetruecolor';
796
			$copy	= 'imagecopyresampled';
797
		}
798
		else
799
		{
800
			$create	= 'imagecreate';
801
			$copy	= 'imagecopyresized';
802
		}
803
 
804
		$dst_img = $create($this->width, $this->height);
805
 
806
		if ($this->image_type === 3) // png we can actually preserve transparency
807
		{
808
			imagealphablending($dst_img, FALSE);
809
			imagesavealpha($dst_img, TRUE);
810
		}
811
 
812
		$copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height);
813
 
814
		// Show the image
815
		if ($this->dynamic_output === TRUE)
816
		{
817
			$this->image_display_gd($dst_img);
818
		}
819
		elseif ( ! $this->image_save_gd($dst_img)) // Or save it
820
		{
821
			return FALSE;
822
		}
823
 
824
		// Kill the file handles
825
		imagedestroy($dst_img);
826
		imagedestroy($src_img);
827
 
828
		chmod($this->full_dst_path, $this->file_permissions);
829
 
830
		return TRUE;
831
	}
832
 
833
	// --------------------------------------------------------------------
834
 
835
	/**
836
	 * Image Process Using ImageMagick
837
	 *
838
	 * This function will resize, crop or rotate
839
	 *
840
	 * @param	string
841
	 * @return	bool
842
	 */
843
	public function image_process_imagemagick($action = 'resize')
844
	{
845
		// Do we have a vaild library path?
846
		if ($this->library_path === '')
847
		{
848
			$this->set_error('imglib_libpath_invalid');
849
			return FALSE;
850
		}
851
 
852
		if ( ! preg_match('/convert$/i', $this->library_path))
853
		{
854
			$this->library_path = rtrim($this->library_path, '/').'/convert';
855
		}
856
 
857
		// Execute the command
858
		$cmd = $this->library_path.' -quality '.$this->quality;
859
 
860
		if ($action === 'crop')
861
		{
862
			$cmd .= ' -crop '.$this->width.'x'.$this->height.'+'.$this->x_axis.'+'.$this->y_axis;
863
		}
864
		elseif ($action === 'rotate')
865
		{
866
			$cmd .= ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
867
					? ' -flop'
868
					: ' -rotate '.$this->rotation_angle;
869
		}
870
		else // Resize
871
		{
872
			if($this->maintain_ratio === TRUE)
873
			{
874
				$cmd .= ' -resize '.$this->width.'x'.$this->height;
875
			}
876
			else
877
			{
878
				$cmd .= ' -resize '.$this->width.'x'.$this->height.'\!';
879
			}
880
		}
881
 
2049 lars 882
		$cmd .= ' '.escapeshellarg($this->full_src_path).' '.escapeshellarg($this->full_dst_path).' 2>&1';
68 lars 883
 
884
		$retval = 1;
885
		// exec() might be disabled
886
		if (function_usable('exec'))
887
		{
888
			@exec($cmd, $output, $retval);
889
		}
890
 
891
		// Did it work?
892
		if ($retval > 0)
893
		{
894
			$this->set_error('imglib_image_process_failed');
895
			return FALSE;
896
		}
897
 
898
		chmod($this->full_dst_path, $this->file_permissions);
899
 
900
		return TRUE;
901
	}
902
 
903
	// --------------------------------------------------------------------
904
 
905
	/**
906
	 * Image Process Using NetPBM
907
	 *
908
	 * This function will resize, crop or rotate
909
	 *
910
	 * @param	string
911
	 * @return	bool
912
	 */
913
	public function image_process_netpbm($action = 'resize')
914
	{
915
		if ($this->library_path === '')
916
		{
917
			$this->set_error('imglib_libpath_invalid');
918
			return FALSE;
919
		}
920
 
921
		// Build the resizing command
922
		switch ($this->image_type)
923
		{
924
			case 1 :
925
				$cmd_in		= 'giftopnm';
926
				$cmd_out	= 'ppmtogif';
927
				break;
928
			case 2 :
929
				$cmd_in		= 'jpegtopnm';
930
				$cmd_out	= 'ppmtojpeg';
931
				break;
932
			case 3 :
933
				$cmd_in		= 'pngtopnm';
934
				$cmd_out	= 'ppmtopng';
935
				break;
936
		}
937
 
938
		if ($action === 'crop')
939
		{
940
			$cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height;
941
		}
942
		elseif ($action === 'rotate')
943
		{
944
			switch ($this->rotation_angle)
945
			{
946
				case 90:	$angle = 'r270';
947
					break;
948
				case 180:	$angle = 'r180';
949
					break;
950
				case 270:	$angle = 'r90';
951
					break;
952
				case 'vrt':	$angle = 'tb';
953
					break;
954
				case 'hor':	$angle = 'lr';
955
					break;
956
			}
957
 
958
			$cmd_inner = 'pnmflip -'.$angle.' ';
959
		}
960
		else // Resize
961
		{
962
			$cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height;
963
		}
964
 
965
		$cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp';
966
 
967
		$retval = 1;
968
		// exec() might be disabled
969
		if (function_usable('exec'))
970
		{
971
			@exec($cmd, $output, $retval);
972
		}
973
 
974
		// Did it work?
975
		if ($retval > 0)
976
		{
977
			$this->set_error('imglib_image_process_failed');
978
			return FALSE;
979
		}
980
 
981
		// With NetPBM we have to create a temporary image.
982
		// If you try manipulating the original it fails so
983
		// we have to rename the temp file.
984
		copy($this->dest_folder.'netpbm.tmp', $this->full_dst_path);
985
		unlink($this->dest_folder.'netpbm.tmp');
986
		chmod($this->full_dst_path, $this->file_permissions);
987
 
988
		return TRUE;
989
	}
990
 
991
	// --------------------------------------------------------------------
992
 
993
	/**
994
	 * Image Rotate Using GD
995
	 *
996
	 * @return	bool
997
	 */
998
	public function image_rotate_gd()
999
	{
1000
		// Create the image handle
1001
		if ( ! ($src_img = $this->image_create_gd()))
1002
		{
1003
			return FALSE;
1004
		}
1005
 
1006
		// Set the background color
1007
		// This won't work with transparent PNG files so we are
1008
		// going to have to figure out how to determine the color
1009
		// of the alpha channel in a future release.
1010
 
1011
		$white = imagecolorallocate($src_img, 255, 255, 255);
1012
 
1013
		// Rotate it!
1014
		$dst_img = imagerotate($src_img, $this->rotation_angle, $white);
1015
 
1016
		// Show the image
1017
		if ($this->dynamic_output === TRUE)
1018
		{
1019
			$this->image_display_gd($dst_img);
1020
		}
1021
		elseif ( ! $this->image_save_gd($dst_img)) // ... or save it
1022
		{
1023
			return FALSE;
1024
		}
1025
 
1026
		// Kill the file handles
1027
		imagedestroy($dst_img);
1028
		imagedestroy($src_img);
1029
 
1030
		chmod($this->full_dst_path, $this->file_permissions);
1031
 
1032
		return TRUE;
1033
	}
1034
 
1035
	// --------------------------------------------------------------------
1036
 
1037
	/**
1038
	 * Create Mirror Image using GD
1039
	 *
1040
	 * This function will flip horizontal or vertical
1041
	 *
1042
	 * @return	bool
1043
	 */
1044
	public function image_mirror_gd()
1045
	{
1046
		if ( ! $src_img = $this->image_create_gd())
1047
		{
1048
			return FALSE;
1049
		}
1050
 
1051
		$width  = $this->orig_width;
1052
		$height = $this->orig_height;
1053
 
1054
		if ($this->rotation_angle === 'hor')
1055
		{
1056
			for ($i = 0; $i < $height; $i++)
1057
			{
1058
				$left = 0;
1059
				$right = $width - 1;
1060
 
1061
				while ($left < $right)
1062
				{
1063
					$cl = imagecolorat($src_img, $left, $i);
1064
					$cr = imagecolorat($src_img, $right, $i);
1065
 
1066
					imagesetpixel($src_img, $left, $i, $cr);
1067
					imagesetpixel($src_img, $right, $i, $cl);
1068
 
1069
					$left++;
1070
					$right--;
1071
				}
1072
			}
1073
		}
1074
		else
1075
		{
1076
			for ($i = 0; $i < $width; $i++)
1077
			{
1078
				$top = 0;
1079
				$bottom = $height - 1;
1080
 
1081
				while ($top < $bottom)
1082
				{
1083
					$ct = imagecolorat($src_img, $i, $top);
1084
					$cb = imagecolorat($src_img, $i, $bottom);
1085
 
1086
					imagesetpixel($src_img, $i, $top, $cb);
1087
					imagesetpixel($src_img, $i, $bottom, $ct);
1088
 
1089
					$top++;
1090
					$bottom--;
1091
				}
1092
			}
1093
		}
1094
 
1095
		// Show the image
1096
		if ($this->dynamic_output === TRUE)
1097
		{
1098
			$this->image_display_gd($src_img);
1099
		}
1100
		elseif ( ! $this->image_save_gd($src_img)) // ... or save it
1101
		{
1102
			return FALSE;
1103
		}
1104
 
1105
		// Kill the file handles
1106
		imagedestroy($src_img);
1107
 
1108
		chmod($this->full_dst_path, $this->file_permissions);
1109
 
1110
		return TRUE;
1111
	}
1112
 
1113
	// --------------------------------------------------------------------
1114
 
1115
	/**
1116
	 * Image Watermark
1117
	 *
1118
	 * This is a wrapper function that chooses the type
1119
	 * of watermarking based on the specified preference.
1120
	 *
1121
	 * @return	bool
1122
	 */
1123
	public function watermark()
1124
	{
1125
		return ($this->wm_type === 'overlay') ? $this->overlay_watermark() : $this->text_watermark();
1126
	}
1127
 
1128
	// --------------------------------------------------------------------
1129
 
1130
	/**
1131
	 * Watermark - Graphic Version
1132
	 *
1133
	 * @return	bool
1134
	 */
1135
	public function overlay_watermark()
1136
	{
1137
		if ( ! function_exists('imagecolortransparent'))
1138
		{
1139
			$this->set_error('imglib_gd_required');
1140
			return FALSE;
1141
		}
1142
 
1143
		// Fetch source image properties
1144
		$this->get_image_properties();
1145
 
1146
		// Fetch watermark image properties
1147
		$props		= $this->get_image_properties($this->wm_overlay_path, TRUE);
1148
		$wm_img_type	= $props['image_type'];
1149
		$wm_width	= $props['width'];
1150
		$wm_height	= $props['height'];
1151
 
1152
		// Create two image resources
1153
		$wm_img  = $this->image_create_gd($this->wm_overlay_path, $wm_img_type);
1154
		$src_img = $this->image_create_gd($this->full_src_path);
1155
 
1156
		// Reverse the offset if necessary
1157
		// When the image is positioned at the bottom
1158
		// we don't want the vertical offset to push it
1159
		// further down. We want the reverse, so we'll
1160
		// invert the offset. Same with the horizontal
1161
		// offset when the image is at the right
1162
 
1163
		$this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]);
1164
		$this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]);
1165
 
1166
		if ($this->wm_vrt_alignment === 'B')
1167
			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
1168
 
1169
		if ($this->wm_hor_alignment === 'R')
1170
			$this->wm_hor_offset = $this->wm_hor_offset * -1;
1171
 
1172
		// Set the base x and y axis values
1173
		$x_axis = $this->wm_hor_offset + $this->wm_padding;
1174
		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
1175
 
1176
		// Set the vertical position
1177
		if ($this->wm_vrt_alignment === 'M')
1178
		{
1179
			$y_axis += ($this->orig_height / 2) - ($wm_height / 2);
1180
		}
1181
		elseif ($this->wm_vrt_alignment === 'B')
1182
		{
1183
			$y_axis += $this->orig_height - $wm_height;
1184
		}
1185
 
1186
		// Set the horizontal position
1187
		if ($this->wm_hor_alignment === 'C')
1188
		{
1189
			$x_axis += ($this->orig_width / 2) - ($wm_width / 2);
1190
		}
1191
		elseif ($this->wm_hor_alignment === 'R')
1192
		{
1193
			$x_axis += $this->orig_width - $wm_width;
1194
		}
1195
 
1196
		// Build the finalized image
1197
		if ($wm_img_type === 3 && function_exists('imagealphablending'))
1198
		{
1199
			@imagealphablending($src_img, TRUE);
1200
		}
1201
 
1202
		// Set RGB values for text and shadow
1203
		$rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp);
1204
		$alpha = ($rgba & 0x7F000000) >> 24;
1205
 
1206
		// make a best guess as to whether we're dealing with an image with alpha transparency or no/binary transparency
1207
		if ($alpha > 0)
1208
		{
1209
			// copy the image directly, the image's alpha transparency being the sole determinant of blending
1210
			imagecopy($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height);
1211
		}
1212
		else
1213
		{
1214
			// set our RGB value from above to be transparent and merge the images with the specified opacity
1215
			imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp));
1216
			imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity);
1217
		}
1218
 
1219
		// We can preserve transparency for PNG images
1220
		if ($this->image_type === 3)
1221
		{
1222
			imagealphablending($src_img, FALSE);
1223
			imagesavealpha($src_img, TRUE);
1224
		}
1225
 
1226
		// Output the image
1227
		if ($this->dynamic_output === TRUE)
1228
		{
1229
			$this->image_display_gd($src_img);
1230
		}
1231
		elseif ( ! $this->image_save_gd($src_img)) // ... or save it
1232
		{
1233
			return FALSE;
1234
		}
1235
 
1236
		imagedestroy($src_img);
1237
		imagedestroy($wm_img);
1238
 
1239
		return TRUE;
1240
	}
1241
 
1242
	// --------------------------------------------------------------------
1243
 
1244
	/**
1245
	 * Watermark - Text Version
1246
	 *
1247
	 * @return	bool
1248
	 */
1249
	public function text_watermark()
1250
	{
1251
		if ( ! ($src_img = $this->image_create_gd()))
1252
		{
1253
			return FALSE;
1254
		}
1255
 
1256
		if ($this->wm_use_truetype === TRUE && ! file_exists($this->wm_font_path))
1257
		{
1258
			$this->set_error('imglib_missing_font');
1259
			return FALSE;
1260
		}
1261
 
1262
		// Fetch source image properties
1263
		$this->get_image_properties();
1264
 
1265
		// Reverse the vertical offset
1266
		// When the image is positioned at the bottom
1267
		// we don't want the vertical offset to push it
1268
		// further down. We want the reverse, so we'll
1269
		// invert the offset. Note: The horizontal
1270
		// offset flips itself automatically
1271
 
1272
		if ($this->wm_vrt_alignment === 'B')
1273
		{
1274
			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
1275
		}
1276
 
1277
		if ($this->wm_hor_alignment === 'R')
1278
		{
1279
			$this->wm_hor_offset = $this->wm_hor_offset * -1;
1280
		}
1281
 
1282
		// Set font width and height
1283
		// These are calculated differently depending on
1284
		// whether we are using the true type font or not
1285
		if ($this->wm_use_truetype === TRUE)
1286
		{
1287
			if (empty($this->wm_font_size))
1288
			{
1289
				$this->wm_font_size = 17;
1290
			}
1291
 
1292
			if (function_exists('imagettfbbox'))
1293
			{
1294
				$temp = imagettfbbox($this->wm_font_size, 0, $this->wm_font_path, $this->wm_text);
1295
				$temp = $temp[2] - $temp[0];
1296
 
1297
				$fontwidth = $temp / strlen($this->wm_text);
1298
			}
1299
			else
1300
			{
1301
				$fontwidth = $this->wm_font_size - ($this->wm_font_size / 4);
1302
			}
1303
 
1304
			$fontheight = $this->wm_font_size;
1305
			$this->wm_vrt_offset += $this->wm_font_size;
1306
		}
1307
		else
1308
		{
1309
			$fontwidth  = imagefontwidth($this->wm_font_size);
1310
			$fontheight = imagefontheight($this->wm_font_size);
1311
		}
1312
 
1313
		// Set base X and Y axis values
1314
		$x_axis = $this->wm_hor_offset + $this->wm_padding;
1315
		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
1316
 
1317
		if ($this->wm_use_drop_shadow === FALSE)
1318
		{
1319
			$this->wm_shadow_distance = 0;
1320
		}
1321
 
1322
		$this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]);
1323
		$this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]);
1324
 
1325
		// Set vertical alignment
1326
		if ($this->wm_vrt_alignment === 'M')
1327
		{
1328
			$y_axis += ($this->orig_height / 2) + ($fontheight / 2);
1329
		}
1330
		elseif ($this->wm_vrt_alignment === 'B')
1331
		{
1332
			$y_axis += $this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight / 2);
1333
		}
1334
 
1335
		// Set horizontal alignment
1336
		if ($this->wm_hor_alignment === 'R')
1337
		{
1338
			$x_axis += $this->orig_width - ($fontwidth * strlen($this->wm_text)) - $this->wm_shadow_distance;
1339
		}
1340
		elseif ($this->wm_hor_alignment === 'C')
1341
		{
1342
			$x_axis += floor(($this->orig_width - ($fontwidth * strlen($this->wm_text))) / 2);
1343
		}
1344
 
1345
		if ($this->wm_use_drop_shadow)
1346
		{
1347
			// Offset from text
1348
			$x_shad = $x_axis + $this->wm_shadow_distance;
1349
			$y_shad = $y_axis + $this->wm_shadow_distance;
1350
 
1351
			/* Set RGB values for shadow
1352
			 *
1353
			 * First character is #, so we don't really need it.
1354
			 * Get the rest of the string and split it into 2-length
1355
			 * hex values:
1356
			 */
1357
			$drp_color = str_split(substr($this->wm_shadow_color, 1, 6), 2);
1358
			$drp_color = imagecolorclosest($src_img, hexdec($drp_color[0]), hexdec($drp_color[1]), hexdec($drp_color[2]));
1359
 
1360
			// Add the shadow to the source image
1361
			if ($this->wm_use_truetype)
1362
			{
1363
				imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text);
1364
			}
1365
			else
1366
			{
1367
				imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);
1368
			}
1369
		}
1370
 
1371
		/* Set RGB values for text
1372
		 *
1373
		 * First character is #, so we don't really need it.
1374
		 * Get the rest of the string and split it into 2-length
1375
		 * hex values:
1376
		 */
1377
		$txt_color = str_split(substr($this->wm_font_color, 1, 6), 2);
1378
		$txt_color = imagecolorclosest($src_img, hexdec($txt_color[0]), hexdec($txt_color[1]), hexdec($txt_color[2]));
1379
 
1380
		// Add the text to the source image
1381
		if ($this->wm_use_truetype)
1382
		{
1383
			imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text);
1384
		}
1385
		else
1386
		{
1387
			imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);
1388
		}
1389
 
1390
		// We can preserve transparency for PNG images
1391
		if ($this->image_type === 3)
1392
		{
1393
			imagealphablending($src_img, FALSE);
1394
			imagesavealpha($src_img, TRUE);
1395
		}
1396
 
1397
		// Output the final image
1398
		if ($this->dynamic_output === TRUE)
1399
		{
1400
			$this->image_display_gd($src_img);
1401
		}
1402
		else
1403
		{
1404
			$this->image_save_gd($src_img);
1405
		}
1406
 
1407
		imagedestroy($src_img);
1408
 
1409
		return TRUE;
1410
	}
1411
 
1412
	// --------------------------------------------------------------------
1413
 
1414
	/**
1415
	 * Create Image - GD
1416
	 *
1417
	 * This simply creates an image resource handle
1418
	 * based on the type of image being processed
1419
	 *
1420
	 * @param	string
1421
	 * @param	string
1422
	 * @return	resource
1423
	 */
1424
	public function image_create_gd($path = '', $image_type = '')
1425
	{
1426
		if ($path === '')
1427
		{
1428
			$path = $this->full_src_path;
1429
		}
1430
 
1431
		if ($image_type === '')
1432
		{
1433
			$image_type = $this->image_type;
1434
		}
1435
 
1436
		switch ($image_type)
1437
		{
1438
			case 1:
1439
				if ( ! function_exists('imagecreatefromgif'))
1440
				{
1441
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
1442
					return FALSE;
1443
				}
1444
 
1445
				return imagecreatefromgif($path);
1446
			case 2:
1447
				if ( ! function_exists('imagecreatefromjpeg'))
1448
				{
1449
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
1450
					return FALSE;
1451
				}
1452
 
1453
				return imagecreatefromjpeg($path);
1454
			case 3:
1455
				if ( ! function_exists('imagecreatefrompng'))
1456
				{
1457
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
1458
					return FALSE;
1459
				}
1460
 
1461
				return imagecreatefrompng($path);
1462
			default:
1463
				$this->set_error(array('imglib_unsupported_imagecreate'));
1464
				return FALSE;
1465
		}
1466
	}
1467
 
1468
	// --------------------------------------------------------------------
1469
 
1470
	/**
1471
	 * Write image file to disk - GD
1472
	 *
1473
	 * Takes an image resource as input and writes the file
1474
	 * to the specified destination
1475
	 *
1476
	 * @param	resource
1477
	 * @return	bool
1478
	 */
1479
	public function image_save_gd($resource)
1480
	{
1481
		switch ($this->image_type)
1482
		{
1483
			case 1:
1484
				if ( ! function_exists('imagegif'))
1485
				{
1486
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
1487
					return FALSE;
1488
				}
1489
 
1490
				if ( ! @imagegif($resource, $this->full_dst_path))
1491
				{
1492
					$this->set_error('imglib_save_failed');
1493
					return FALSE;
1494
				}
1495
			break;
1496
			case 2:
1497
				if ( ! function_exists('imagejpeg'))
1498
				{
1499
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
1500
					return FALSE;
1501
				}
1502
 
1503
				if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality))
1504
				{
1505
					$this->set_error('imglib_save_failed');
1506
					return FALSE;
1507
				}
1508
			break;
1509
			case 3:
1510
				if ( ! function_exists('imagepng'))
1511
				{
1512
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
1513
					return FALSE;
1514
				}
1515
 
1516
				if ( ! @imagepng($resource, $this->full_dst_path))
1517
				{
1518
					$this->set_error('imglib_save_failed');
1519
					return FALSE;
1520
				}
1521
			break;
1522
			default:
1523
				$this->set_error(array('imglib_unsupported_imagecreate'));
1524
				return FALSE;
1525
			break;
1526
		}
1527
 
1528
		return TRUE;
1529
	}
1530
 
1531
	// --------------------------------------------------------------------
1532
 
1533
	/**
1534
	 * Dynamically outputs an image
1535
	 *
1536
	 * @param	resource
1537
	 * @return	void
1538
	 */
1539
	public function image_display_gd($resource)
1540
	{
1541
		header('Content-Disposition: filename='.$this->source_image.';');
1542
		header('Content-Type: '.$this->mime_type);
1543
		header('Content-Transfer-Encoding: binary');
1544
		header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');
1545
 
1546
		switch ($this->image_type)
1547
		{
1548
			case 1	:	imagegif($resource);
1549
				break;
1550
			case 2	:	imagejpeg($resource, NULL, $this->quality);
1551
				break;
1552
			case 3	:	imagepng($resource);
1553
				break;
1554
			default:	echo 'Unable to display the image';
1555
				break;
1556
		}
1557
	}
1558
 
1559
	// --------------------------------------------------------------------
1560
 
1561
	/**
1562
	 * Re-proportion Image Width/Height
1563
	 *
1564
	 * When creating thumbs, the desired width/height
1565
	 * can end up warping the image due to an incorrect
1566
	 * ratio between the full-sized image and the thumb.
1567
	 *
1568
	 * This function lets us re-proportion the width/height
1569
	 * if users choose to maintain the aspect ratio when resizing.
1570
	 *
1571
	 * @return	void
1572
	 */
1573
	public function image_reproportion()
1574
	{
1575
		if (($this->width === 0 && $this->height === 0) OR $this->orig_width === 0 OR $this->orig_height === 0
1576
			OR ( ! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height))
1577
			OR ! ctype_digit((string) $this->orig_width) OR ! ctype_digit((string) $this->orig_height))
1578
		{
1579
			return;
1580
		}
1581
 
1582
		// Sanitize
1583
		$this->width = (int) $this->width;
1584
		$this->height = (int) $this->height;
1585
 
1586
		if ($this->master_dim !== 'width' && $this->master_dim !== 'height')
1587
		{
1588
			if ($this->width > 0 && $this->height > 0)
1589
			{
1590
				$this->master_dim = ((($this->orig_height/$this->orig_width) - ($this->height/$this->width)) < 0)
1591
							? 'width' : 'height';
1592
			}
1593
			else
1594
			{
1595
				$this->master_dim = ($this->height === 0) ? 'width' : 'height';
1596
			}
1597
		}
1598
		elseif (($this->master_dim === 'width' && $this->width === 0)
1599
			OR ($this->master_dim === 'height' && $this->height === 0))
1600
		{
1601
			return;
1602
		}
1603
 
1604
		if ($this->master_dim === 'width')
1605
		{
1606
			$this->height = (int) ceil($this->width*$this->orig_height/$this->orig_width);
1607
		}
1608
		else
1609
		{
1610
			$this->width = (int) ceil($this->orig_width*$this->height/$this->orig_height);
1611
		}
1612
	}
1613
 
1614
	// --------------------------------------------------------------------
1615
 
1616
	/**
1617
	 * Get image properties
1618
	 *
1619
	 * A helper function that gets info about the file
1620
	 *
1621
	 * @param	string
1622
	 * @param	bool
1623
	 * @return	mixed
1624
	 */
1625
	public function get_image_properties($path = '', $return = FALSE)
1626
	{
1627
		// For now we require GD but we should
1628
		// find a way to determine this using IM or NetPBM
1629
 
1630
		if ($path === '')
1631
		{
1632
			$path = $this->full_src_path;
1633
		}
1634
 
1635
		if ( ! file_exists($path))
1636
		{
1637
			$this->set_error('imglib_invalid_path');
1638
			return FALSE;
1639
		}
1640
 
1641
		$vals = getimagesize($path);
2049 lars 1642
		if ($vals === FALSE)
1643
		{
1644
			$this->set_error('imglib_invalid_image');
1645
			return FALSE;
1646
		}
1647
 
68 lars 1648
		$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
2049 lars 1649
		$mime = isset($types[$vals[2]]) ? 'image/'.$types[$vals[2]] : 'image/jpg';
68 lars 1650
 
1651
		if ($return === TRUE)
1652
		{
1653
			return array(
2049 lars 1654
				'width'      => $vals[0],
1655
				'height'     => $vals[1],
1656
				'image_type' => $vals[2],
1657
				'size_str'   => $vals[3],
1658
				'mime_type'  => $mime
1659
			);
68 lars 1660
		}
1661
 
2049 lars 1662
		$this->orig_width  = $vals[0];
1663
		$this->orig_height = $vals[1];
1664
		$this->image_type  = $vals[2];
1665
		$this->size_str    = $vals[3];
1666
		$this->mime_type   = $mime;
68 lars 1667
 
1668
		return TRUE;
1669
	}
1670
 
1671
	// --------------------------------------------------------------------
1672
 
1673
	/**
1674
	 * Size calculator
1675
	 *
1676
	 * This function takes a known width x height and
1677
	 * recalculates it to a new size. Only one
1678
	 * new variable needs to be known
1679
	 *
1680
	 *	$props = array(
1681
	 *			'width'		=> $width,
1682
	 *			'height'	=> $height,
1683
	 *			'new_width'	=> 40,
1684
	 *			'new_height'	=> ''
1685
	 *		);
1686
	 *
1687
	 * @param	array
1688
	 * @return	array
1689
	 */
1690
	public function size_calculator($vals)
1691
	{
1692
		if ( ! is_array($vals))
1693
		{
1694
			return;
1695
		}
1696
 
1697
		$allowed = array('new_width', 'new_height', 'width', 'height');
1698
 
1699
		foreach ($allowed as $item)
1700
		{
1701
			if (empty($vals[$item]))
1702
			{
1703
				$vals[$item] = 0;
1704
			}
1705
		}
1706
 
1707
		if ($vals['width'] === 0 OR $vals['height'] === 0)
1708
		{
1709
			return $vals;
1710
		}
1711
 
1712
		if ($vals['new_width'] === 0)
1713
		{
1714
			$vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']);
1715
		}
1716
		elseif ($vals['new_height'] === 0)
1717
		{
1718
			$vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']);
1719
		}
1720
 
1721
		return $vals;
1722
	}
1723
 
1724
	// --------------------------------------------------------------------
1725
 
1726
	/**
1727
	 * Explode source_image
1728
	 *
1729
	 * This is a helper function that extracts the extension
1730
	 * from the source_image.  This function lets us deal with
1731
	 * source_images with multiple periods, like: my.cool.jpg
1732
	 * It returns an associative array with two elements:
1733
	 * $array['ext']  = '.jpg';
1734
	 * $array['name'] = 'my.cool';
1735
	 *
1736
	 * @param	array
1737
	 * @return	array
1738
	 */
1739
	public function explode_name($source_image)
1740
	{
1741
		$ext = strrchr($source_image, '.');
1742
		$name = ($ext === FALSE) ? $source_image : substr($source_image, 0, -strlen($ext));
1743
 
1744
		return array('ext' => $ext, 'name' => $name);
1745
	}
1746
 
1747
	// --------------------------------------------------------------------
1748
 
1749
	/**
1750
	 * Is GD Installed?
1751
	 *
1752
	 * @return	bool
1753
	 */
1754
	public function gd_loaded()
1755
	{
1756
		if ( ! extension_loaded('gd'))
1757
		{
1758
			/* As it is stated in the PHP manual, dl() is not always available
1759
			 * and even if so - it could generate an E_WARNING message on failure
1760
			 */
1761
			return (function_exists('dl') && @dl('gd.so'));
1762
		}
1763
 
1764
		return TRUE;
1765
	}
1766
 
1767
	// --------------------------------------------------------------------
1768
 
1769
	/**
1770
	 * Get GD version
1771
	 *
1772
	 * @return	mixed
1773
	 */
1774
	public function gd_version()
1775
	{
1776
		if (function_exists('gd_info'))
1777
		{
1778
			$gd_version = @gd_info();
1779
			return preg_replace('/\D/', '', $gd_version['GD Version']);
1780
		}
1781
 
1782
		return FALSE;
1783
	}
1784
 
1785
	// --------------------------------------------------------------------
1786
 
1787
	/**
1788
	 * Set error message
1789
	 *
1790
	 * @param	string
1791
	 * @return	void
1792
	 */
1793
	public function set_error($msg)
1794
	{
1795
		$CI =& get_instance();
1796
		$CI->lang->load('imglib');
1797
 
1798
		if (is_array($msg))
1799
		{
1800
			foreach ($msg as $val)
1801
			{
1802
				$msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val);
1803
				$this->error_msg[] = $msg;
1804
				log_message('error', $msg);
1805
			}
1806
		}
1807
		else
1808
		{
1809
			$msg = ($CI->lang->line($msg) === FALSE) ? $msg : $CI->lang->line($msg);
1810
			$this->error_msg[] = $msg;
1811
			log_message('error', $msg);
1812
		}
1813
	}
1814
 
1815
	// --------------------------------------------------------------------
1816
 
1817
	/**
1818
	 * Show error messages
1819
	 *
1820
	 * @param	string
1821
	 * @param	string
1822
	 * @return	string
1823
	 */
1824
	public function display_errors($open = '<p>', $close = '</p>')
1825
	{
1826
		return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
1827
	}
1828
 
1829
}