github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/tinymce/plugins/jbimages/ci/system/libraries/Image_lib.php (about) 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 */ 27 class 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 */