source: sourcecode/system/libraries/Image_lib.php @ 1

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