bfi-thumb.php (24080B)
1 <?php 2 /* 3 * bfi_thumb - WP Image Resizer v1.3 4 * 5 * (c) 2013 Benjamin F. Intal / Gambit 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 /** Uses WP's Image Editor Class to resize and filter images 22 * 23 * @param $url string the local image URL to manipulate 24 * @param $params array the options to perform on the image. Keys and values supported: 25 * 'width' int pixels 26 * 'height' int pixels 27 * 'opacity' int 0-100 28 * 'color' string hex-color #000000-#ffffff 29 * 'grayscale' bool 30 * 'negate' bool 31 * 'crop' bool 32 * 'crop_only' bool 33 * 'crop_x' bool string 34 * 'crop_y' bool string 35 * 'crop_width' bool string 36 * 'crop_height' bool string 37 * 'quality' int 1-100 38 * @param $single boolean, if false then an array of data will be returned 39 * 40 * @return string|array containing the url of the resized modified image 41 */ 42 43 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly. 44 45 if ( ! defined( 'BFITHUMB_UPLOAD_DIR' ) ) { 46 define( 'BFITHUMB_UPLOAD_DIR', 'elementor/thumbs' ); 47 } 48 49 if ( ! function_exists( 'bfi_thumb' ) ) { 50 51 function bfi_thumb( $url, $params = array(), $single = true ) { 52 $class = BFI_Class_Factory::getNewestVersion( 'BFI_Thumb' ); 53 54 return call_user_func( array( $class, 'thumb' ), $url, $params, $single ); 55 } 56 } 57 58 59 /** 60 * Class factory, this is to make sure that when multiple bfi_thumb scripts 61 * are used (e.g. a plugin and a theme both use it), we always use the 62 * latest version. 63 */ 64 if ( ! class_exists( 'BFI_Class_Factory' ) ) { 65 66 class BFI_Class_Factory { 67 68 public static $versions = array(); 69 public static $latestClass = array(); 70 71 public static function addClassVersion( $baseClassName, $className, $version ) { 72 if ( empty( self::$versions[ $baseClassName ] ) ) { 73 self::$versions[ $baseClassName ] = array(); 74 } 75 self::$versions[ $baseClassName ][] = array( 76 'class' => $className, 77 'version' => $version, 78 ); 79 } 80 81 public static function getNewestVersion( $baseClassName ) { 82 if ( empty( self::$latestClass[ $baseClassName ] ) ) { 83 usort( self::$versions[ $baseClassName ], array( __CLASS__, "versionCompare" ) ); 84 self::$latestClass[ $baseClassName ] = self::$versions[ $baseClassName ][0]['class']; 85 unset( self::$versions[ $baseClassName ] ); 86 } 87 88 return self::$latestClass[ $baseClassName ]; 89 } 90 91 public static function versionCompare( $a, $b ) { 92 return version_compare( $a['version'], $b['version'] ) == 1 ? -1 : 1; 93 } 94 } 95 } 96 97 98 /* 99 * Change the default image editors 100 */ 101 add_filter( 'wp_image_editors', 'bfi_wp_image_editor' ); 102 103 // Instead of using the default image editors, use our extended ones 104 if ( ! function_exists( 'bfi_wp_image_editor' ) ) { 105 106 function bfi_wp_image_editor( $editorArray ) { 107 // Make sure that we use the latest versions 108 return array( 109 BFI_Class_Factory::getNewestVersion( 'BFI_Image_Editor_GD' ), 110 BFI_Class_Factory::getNewestVersion( 'BFI_Image_Editor_Imagick' ), 111 ); 112 } 113 } 114 115 116 /* 117 * Include the WP Image classes 118 */ 119 120 require_once ABSPATH . WPINC . '/class-wp-image-editor.php'; 121 require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php'; 122 require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php'; 123 124 125 /* 126 * Enhanced Imagemagick Image Editor 127 */ 128 129 130 if ( ! class_exists( 'BFI_Image_Editor_Imagick_1_3' ) ) { 131 132 BFI_Class_Factory::addClassVersion( 'BFI_Image_Editor_Imagick', 'BFI_Image_Editor_Imagick_1_3', '1.3' ); 133 134 class BFI_Image_Editor_Imagick_1_3 extends WP_Image_Editor_Imagick { 135 136 /** Changes the opacity of the image 137 * 138 * @supports 3.5.1 139 * @access public 140 * 141 * @param float $opacity (0.0-1.0) 142 * 143 * @return boolean|WP_Error 144 */ 145 public function opacity( $opacity ) { 146 $opacity /= 100; 147 148 try { 149 // From: http://stackoverflow.com/questions/3538851/php-imagick-setimageopacity-destroys-transparency-and-does-nothing 150 // preserves transparency 151 //$this->image->setImageOpacity($opacity); 152 return $this->image->evaluateImage( Imagick::EVALUATE_MULTIPLY, $opacity, Imagick::CHANNEL_ALPHA ); 153 } catch ( Exception $e ) { 154 return new WP_Error( 'image_opacity_error', $e->getMessage() ); 155 } 156 } 157 158 /** Tints the image a different color 159 * 160 * @supports 3.5.1 161 * @access public 162 * 163 * @param string hex color e.g. #ff00ff 164 * 165 * @return boolean|WP_Error 166 */ 167 public function colorize( $hexColor ) { 168 try { 169 return $this->image->colorizeImage( $hexColor, 1.0 ); 170 } catch ( Exception $e ) { 171 return new WP_Error( 'image_colorize_error', $e->getMessage() ); 172 } 173 } 174 175 /** Makes the image grayscale 176 * 177 * @supports 3.5.1 178 * @access public 179 * 180 * @return boolean|WP_Error 181 */ 182 public function grayscale() { 183 try { 184 return $this->image->modulateImage( 100, 0, 100 ); 185 } catch ( Exception $e ) { 186 return new WP_Error( 'image_grayscale_error', $e->getMessage() ); 187 } 188 } 189 190 /** Negates the image 191 * 192 * @supports 3.5.1 193 * @access public 194 * 195 * @return boolean|WP_Error 196 */ 197 public function negate() { 198 try { 199 return $this->image->negateImage( false ); 200 } catch ( Exception $e ) { 201 return new WP_Error( 'image_negate_error', $e->getMessage() ); 202 } 203 } 204 } 205 } 206 207 208 /* 209 * Enhanced GD Image Editor 210 */ 211 212 213 if ( ! class_exists( 'BFI_Image_Editor_GD_1_3' ) ) { 214 215 BFI_Class_Factory::addClassVersion( 'BFI_Image_Editor_GD', 'BFI_Image_Editor_GD_1_3', '1.3' ); 216 217 class BFI_Image_Editor_GD_1_3 extends WP_Image_Editor_GD { 218 219 /** Rotates current image counter-clockwise by $angle. 220 * Ported from image-edit.php 221 * Added presevation of alpha channels 222 * 223 * @since 3.5.0 224 * @access public 225 * 226 * @param float $angle 227 * 228 * @return boolean|WP_Error 229 */ 230 public function rotate( $angle ) { 231 if ( function_exists( 'imagerotate' ) ) { 232 $rotated = imagerotate( $this->image, $angle, 0 ); 233 234 // Add alpha blending 235 imagealphablending( $rotated, true ); 236 imagesavealpha( $rotated, true ); 237 238 if ( is_resource( $rotated ) ) { 239 imagedestroy( $this->image ); 240 $this->image = $rotated; 241 $this->update_size(); 242 243 return true; 244 } 245 } 246 247 return new WP_Error( 'image_rotate_error', 'Image rotate failed.', $this->file ); 248 } 249 250 /** Changes the opacity of the image 251 * 252 * @supports 3.5.1 253 * @access public 254 * 255 * @param float $opacity (0.0-1.0) 256 * 257 * @return boolean|WP_Error 258 */ 259 public function opacity( $opacity ) { 260 $opacity /= 100; 261 262 $filtered = $this->_opacity( $this->image, $opacity ); 263 264 if ( is_resource( $filtered ) ) { 265 // imagedestroy($this->image); 266 $this->image = $filtered; 267 268 return true; 269 } 270 271 return new WP_Error( 'image_opacity_error', 'Image opacity change failed.', $this->file ); 272 } 273 274 275 // from: http://php.net/manual/en/function.imagefilter.php 276 // params: image resource id, opacity (eg. 0.0-1.0) 277 protected function _opacity( $image, $opacity ) { 278 if ( ! function_exists( 'imagealphablending' ) || ! function_exists( 'imagecolorat' ) || ! function_exists( 'imagecolorallocatealpha' ) || ! function_exists( 'imagesetpixel' ) ) { 279 return false; 280 } 281 282 // get image width and height 283 $w = imagesx( $image ); 284 $h = imagesy( $image ); 285 286 // turn alpha blending off 287 imagealphablending( $image, false ); 288 289 // find the most opaque pixel in the image (the one with the smallest alpha value) 290 $minalpha = 127; 291 for ( $x = 0; $x < $w; $x++ ) { 292 for ( $y = 0; $y < $h; $y++ ) { 293 $alpha = ( imagecolorat( $image, $x, $y ) >> 24 ) & 0xFF; 294 if ( $alpha < $minalpha ) { 295 $minalpha = $alpha; 296 } 297 } 298 } 299 300 // loop through image pixels and modify alpha for each 301 for ( $x = 0; $x < $w; $x++ ) { 302 for ( $y = 0; $y < $h; $y++ ) { 303 304 // get current alpha value (represents the TANSPARENCY!) 305 $colorxy = imagecolorat( $image, $x, $y ); 306 $alpha = ( $colorxy >> 24 ) & 0xFF; 307 308 // calculate new alpha 309 if ( $minalpha !== 127 ) { 310 $alpha = 127 + 127 * $opacity * ( $alpha - 127 ) / ( 127 - $minalpha ); 311 } else { 312 $alpha += 127 * $opacity; 313 } 314 315 // get the color index with new alpha 316 $alphacolorxy = imagecolorallocatealpha( $image, ( $colorxy >> 16 ) & 0xFF, ( $colorxy >> 8 ) & 0xFF, $colorxy & 0xFF, $alpha ); 317 318 // set pixel with the new color + opacity 319 if ( ! imagesetpixel( $image, $x, $y, $alphacolorxy ) ) { 320 return false; 321 } 322 } 323 } 324 325 imagesavealpha( $image, true ); 326 327 return $image; 328 } 329 330 /** Tints the image a different color 331 * 332 * @supports 3.5.1 333 * @access public 334 * 335 * @param string hex color e.g. #ff00ff 336 * 337 * @return boolean|WP_Error 338 */ 339 public function colorize( $hexColor ) { 340 if ( function_exists( 'imagefilter' ) && function_exists( 'imagesavealpha' ) && function_exists( 'imagealphablending' ) ) { 341 342 $hexColor = preg_replace( '#^\##', '', $hexColor ); 343 $r = hexdec( substr( $hexColor, 0, 2 ) ); 344 $g = hexdec( substr( $hexColor, 2, 2 ) ); 345 $b = hexdec( substr( $hexColor, 2, 2 ) ); 346 347 imagealphablending( $this->image, false ); 348 if ( imagefilter( $this->image, IMG_FILTER_COLORIZE, $r, $g, $b, 0 ) ) { 349 imagesavealpha( $this->image, true ); 350 351 return true; 352 } 353 } 354 355 return new WP_Error( 'image_colorize_error', 'Image color change failed.', $this->file ); 356 } 357 358 /** Makes the image grayscale 359 * 360 * @supports 3.5.1 361 * @access public 362 * 363 * @return boolean|WP_Error 364 */ 365 public function grayscale() { 366 if ( function_exists( 'imagefilter' ) ) { 367 if ( imagefilter( $this->image, IMG_FILTER_GRAYSCALE ) ) { 368 return true; 369 } 370 } 371 372 return new WP_Error( 'image_grayscale_error', 'Image grayscale failed.', $this->file ); 373 } 374 375 /** Negates the image 376 * 377 * @supports 3.5.1 378 * @access public 379 * 380 * @return boolean|WP_Error 381 */ 382 public function negate() { 383 if ( function_exists( 'imagefilter' ) ) { 384 if ( imagefilter( $this->image, IMG_FILTER_NEGATE ) ) { 385 return true; 386 } 387 } 388 389 return new WP_Error( 'image_negate_error', 'Image negate failed.', $this->file ); 390 } 391 } 392 } 393 394 395 /* 396 * Main Class 397 */ 398 if ( ! class_exists( 'BFI_Thumb_1_3' ) ) { 399 400 BFI_Class_Factory::addClassVersion( 'BFI_Thumb', 'BFI_Thumb_1_3', '1.3' ); 401 402 class BFI_Thumb_1_3 { 403 404 /** Uses WP's Image Editor Class to resize and filter images 405 * Inspired by: https://github.com/sy4mil/Aqua-Resizer/blob/master/aq_resizer.php 406 * 407 * @param $url string the local image URL to manipulate 408 * @param $params array the options to perform on the image. Keys and values supported: 409 * 'width' int pixels 410 * 'height' int pixels 411 * 'opacity' int 0-100 412 * 'color' string hex-color #000000-#ffffff 413 * 'grayscale' bool 414 * 'crop' bool 415 * 'negate' bool 416 * 'crop_only' bool 417 * 'crop_x' bool string 418 * 'crop_y' bool string 419 * 'crop_width' bool string 420 * 'crop_height' bool string 421 * 'quality' int 1-100 422 * @param $single boolean, if false then an array of data will be returned 423 * 424 * @return string|array 425 */ 426 public static function thumb( $url, $params = array(), $single = true ) { 427 extract( $params ); 428 429 //validate inputs 430 if ( ! $url ) { 431 return false; 432 } 433 434 $crop_only = isset( $crop_only ) ? $crop_only : false; 435 436 //define upload path & dir 437 $upload_info = wp_upload_dir(); 438 $upload_dir = $upload_info['basedir']; 439 $upload_url = $upload_info['baseurl']; 440 $theme_url = get_template_directory_uri(); 441 $theme_dir = get_template_directory(); 442 443 // find the path of the image. Perform 2 checks: 444 // #1 check if the image is in the uploads folder 445 if ( strpos( $url, $upload_url ) !== false ) { 446 $rel_path = str_replace( $upload_url, '', $url ); 447 $img_path = $upload_dir . $rel_path; 448 // #2 check if the image is in the current theme folder 449 } else if ( strpos( $url, $theme_url ) !== false ) { 450 $rel_path = str_replace( $theme_url, '', $url ); 451 $img_path = $theme_dir . $rel_path; 452 } 453 454 // Fail if we can't find the image in our WP local directory 455 if ( empty( $img_path ) ) { 456 return $url; 457 } 458 459 // check if img path exists, and is an image indeed 460 if ( ! @file_exists( $img_path ) || ! getimagesize( $img_path ) ) { 461 return $url; 462 } 463 464 // This is the filename 465 $basename = basename( $img_path ); 466 467 //get image info 468 $info = pathinfo( $img_path ); 469 $ext = $info['extension']; 470 list( $orig_w, $orig_h ) = getimagesize( $img_path ); 471 472 // support percentage dimensions. compute percentage based on 473 // the original dimensions 474 if ( isset( $width ) ) { 475 if ( stripos( $width, '%' ) !== false ) { 476 $width = (int) ( (float) str_replace( '%', '', $width ) / 100 * $orig_w ); 477 } 478 } 479 if ( isset( $height ) ) { 480 if ( stripos( $height, '%' ) !== false ) { 481 $height = (int) ( (float) str_replace( '%', '', $height ) / 100 * $orig_h ); 482 } 483 } 484 485 // The only purpose of this is to determine the final width and height 486 // without performing any actual image manipulation, which will be used 487 // to check whether a resize was previously done. 488 if ( isset( $width ) && $crop_only === false ) { 489 //get image size after cropping 490 $dims = image_resize_dimensions( $orig_w, $orig_h, $width, isset( $height ) ? $height : null, isset( $crop ) ? $crop : false ); 491 $dst_w = isset( $dims[4] ) ? $dims[4] : null; 492 $dst_h = isset( $dims[5] ) ? $dims[5] : null; 493 } else if ( $crop_only === true ) { 494 // we don't want a resize, 495 // but only a crop in the image 496 497 // get x position to start croping 498 $src_x = ( isset( $crop_x ) ) ? $crop_x : 0; 499 500 // get y position to start croping 501 $src_y = ( isset( $crop_y ) ) ? $crop_y : 0; 502 503 // width of the crop 504 if ( isset( $crop_width ) ) { 505 $src_w = $crop_width; 506 } else if ( isset( $width ) ) { 507 $src_w = $width; 508 } else { 509 $src_w = $orig_w; 510 } 511 512 // height of the crop 513 if ( isset( $crop_height ) ) { 514 $src_h = $crop_height; 515 } else if ( isset( $height ) ) { 516 $src_h = $height; 517 } else { 518 $src_h = $orig_h; 519 } 520 521 // set the width resize with the crop 522 if ( isset( $crop_width ) && isset( $width ) ) { 523 $dst_w = $width; 524 } else { 525 $dst_w = null; 526 } 527 528 // set the height resize with the crop 529 if ( isset( $crop_height ) && isset( $height ) ) { 530 $dst_h = $height; 531 } else { 532 $dst_h = null; 533 } 534 535 // allow percentages 536 if ( isset( $dst_w ) ) { 537 if ( stripos( $dst_w, '%' ) !== false ) { 538 $dst_w = (int) ( (float) str_replace( '%', '', $dst_w ) / 100 * $orig_w ); 539 } 540 } 541 if ( isset( $dst_h ) ) { 542 if ( stripos( $dst_h, '%' ) !== false ) { 543 $dst_h = (int) ( (float) str_replace( '%', '', $dst_h ) / 100 * $orig_h ); 544 } 545 } 546 547 $dims = image_resize_dimensions( $src_w, $src_h, $dst_w, $dst_h, false ); 548 $dst_w = $dims[4]; 549 $dst_h = $dims[5]; 550 551 // Make the pos x and pos y work with percentages 552 if ( stripos( $src_x, '%' ) !== false ) { 553 $src_x = (int) ( (float) str_replace( '%', '', $width ) / 100 * $orig_w ); 554 } 555 if ( stripos( $src_y, '%' ) !== false ) { 556 $src_y = (int) ( (float) str_replace( '%', '', $height ) / 100 * $orig_h ); 557 } 558 559 // allow center to position crop start 560 if ( $src_x === 'center' ) { 561 $src_x = ( $orig_w - $src_w ) / 2; 562 } 563 if ( $src_y === 'center' ) { 564 $src_y = ( $orig_h - $src_h ) / 2; 565 } 566 } 567 568 // create the suffix for the saved file 569 // we can use this to check whether we need to create a new file or just use an existing one. 570 $suffix = (string) filemtime( $img_path ) . ( isset( $width ) ? str_pad( (string) $width, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( isset( $height ) ? str_pad( (string) $height, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( isset( $opacity ) ? str_pad( (string) $opacity, 3, '0', STR_PAD_LEFT ) : '100' ) . ( isset( $color ) ? str_pad( preg_replace( '#^\##', '', $color ), 8, '0', STR_PAD_LEFT ) : '00000000' ) . ( isset( $grayscale ) ? ( $grayscale ? '1' : '0' ) : '0' ) . ( isset( $crop ) ? ( $crop ? '1' : '0' ) : '0' ) . ( isset( $negate ) ? ( $negate ? '1' : '0' ) : '0' ) . ( isset( $crop_only ) ? ( $crop_only ? '1' : '0' ) : '0' ) . ( isset( $src_x ) ? str_pad( (string) $src_x, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( isset( $src_y ) ? str_pad( (string) $src_y, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( isset( $src_w ) ? str_pad( (string) $src_w, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( isset( $src_h ) ? str_pad( (string) $src_h, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( isset( $dst_w ) ? str_pad( (string) $dst_w, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( isset( $dst_h ) ? str_pad( (string) $dst_h, 5, '0', STR_PAD_LEFT ) : '00000' ) . ( ( isset ( $quality ) && $quality > 0 && $quality <= 100 ) ? ( $quality ? (string) $quality : '0' ) : '0' ); 571 $suffix = self::base_convert_arbitrary( $suffix, 10, 36 ); 572 573 // use this to check if cropped image already exists, so we can return that instead 574 $dst_rel_path = str_replace( '.' . $ext, '', basename( $img_path ) ); 575 576 // If opacity is set, change the image type to png 577 if ( isset( $opacity ) ) { 578 $ext = 'png'; 579 } 580 581 582 // Create the upload subdirectory, this is where 583 // we store all our generated images 584 if ( defined( 'BFITHUMB_UPLOAD_DIR' ) ) { 585 $upload_dir .= "/" . BFITHUMB_UPLOAD_DIR; 586 $upload_url .= "/" . BFITHUMB_UPLOAD_DIR; 587 } else { 588 $upload_dir .= "/bfi_thumb"; 589 $upload_url .= "/bfi_thumb"; 590 } 591 if ( ! is_dir( $upload_dir ) ) { 592 wp_mkdir_p( $upload_dir ); 593 } 594 595 596 // desination paths and urls 597 $destfilename = "{$upload_dir}/{$dst_rel_path}-{$suffix}.{$ext}"; 598 599 // The urls generated have lower case extensions regardless of the original case 600 $ext = strtolower( $ext ); 601 $img_url = "{$upload_url}/{$dst_rel_path}-{$suffix}.{$ext}"; 602 603 // if file exists, just return it 604 if ( @file_exists( $destfilename ) && getimagesize( $destfilename ) ) { 605 } else { 606 // perform resizing and other filters 607 $editor = wp_get_image_editor( $img_path ); 608 609 if ( is_wp_error( $editor ) ) { 610 return false; 611 } 612 613 /* 614 * Perform image manipulations 615 */ 616 if ( $crop_only === false ) { 617 if ( ( isset( $width ) && $width ) || ( isset( $height ) && $height ) ) { 618 if ( is_wp_error( $editor->resize( isset( $width ) ? $width : null, isset( $height ) ? $height : null, isset( $crop ) ? $crop : false ) ) ) { 619 return false; 620 } 621 } 622 } else { 623 if ( is_wp_error( $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h ) ) ) { 624 return false; 625 } 626 } 627 628 if ( isset( $negate ) ) { 629 if ( $negate ) { 630 if ( is_wp_error( $editor->negate() ) ) { 631 return false; 632 } 633 } 634 } 635 636 if ( isset( $opacity ) ) { 637 if ( is_wp_error( $editor->opacity( $opacity ) ) ) { 638 return false; 639 } 640 } 641 642 if ( isset( $grayscale ) ) { 643 if ( $grayscale ) { 644 if ( is_wp_error( $editor->grayscale() ) ) { 645 return false; 646 } 647 } 648 } 649 650 if ( isset( $color ) ) { 651 if ( is_wp_error( $editor->colorize( $color ) ) ) { 652 return false; 653 } 654 } 655 656 // set the image quality (1-100) to save this image at 657 if ( isset( $quality ) && $quality > 0 && $quality <= 100 && $ext != 'png' ) { 658 $editor->set_quality( $quality ); 659 } 660 661 // save our new image 662 $mime_type = isset( $opacity ) ? 'image/png' : null; 663 $resized_file = $editor->save( $destfilename, $mime_type ); 664 } 665 666 //return the output 667 if ( $single ) { 668 $image = $img_url; 669 } else { 670 //array return 671 $image = array( 672 0 => $img_url, 673 1 => isset( $dst_w ) ? $dst_w : $orig_w, 674 2 => isset( $dst_h ) ? $dst_h : $orig_h, 675 ); 676 } 677 678 return $image; 679 } 680 681 /** Shortens a number into a base 36 string 682 * 683 * @param $number string a string of numbers to convert 684 * @param $fromBase starting base 685 * @param $toBase base to convert the number to 686 * 687 * @return string base converted characters 688 */ 689 protected static function base_convert_arbitrary( $number, $fromBase, $toBase ) { 690 $digits = '0123456789abcdefghijklmnopqrstuvwxyz'; 691 $length = strlen( $number ); 692 $result = ''; 693 694 $nibbles = array(); 695 for ( $i = 0; $i < $length; ++$i ) { 696 $nibbles[ $i ] = strpos( $digits, $number[ $i ] ); 697 } 698 699 do { 700 $value = 0; 701 $newlen = 0; 702 703 for ( $i = 0; $i < $length; ++$i ) { 704 705 $value = $value * $fromBase + $nibbles[ $i ]; 706 707 if ( $value >= $toBase ) { 708 $nibbles[ $newlen++ ] = (int) ( $value / $toBase ); 709 $value %= $toBase; 710 } else if ( $newlen > 0 ) { 711 $nibbles[ $newlen++ ] = 0; 712 } 713 } 714 715 $length = $newlen; 716 $result = $digits[ $value ] . $result; 717 } while ( $newlen != 0 ); 718 719 return $result; 720 } 721 } 722 } 723 724 725 // don't use the default resizer since we want to allow resizing to larger sizes (than the original one) 726 // Parts are copied from media.php 727 // Crop is always applied (just like timthumb) 728 // Don't use this inside the admin since sometimes images in the media library get resized 729 if ( ! is_admin() ) { 730 add_filter( 'image_resize_dimensions', 'bfi_image_resize_dimensions', 10, 5 ); 731 } 732 733 if ( ! function_exists( 'bfi_image_resize_dimensions' ) ) { 734 function bfi_image_resize_dimensions( $payload, $orig_w, $orig_h, $dest_w, $dest_h, $crop = false ) { 735 $aspect_ratio = $orig_w / $orig_h; 736 737 $new_w = $dest_w; 738 $new_h = $dest_h; 739 740 if ( empty( $new_w ) || $new_w < 0 ) { 741 $new_w = intval( $new_h * $aspect_ratio ); 742 } 743 744 if ( empty( $new_h ) || $new_h < 0 ) { 745 $new_h = intval( $new_w / $aspect_ratio ); 746 } 747 748 $size_ratio = max( $new_w / $orig_w, $new_h / $orig_h ); 749 750 $crop_w = round( $new_w / $size_ratio ); 751 $crop_h = round( $new_h / $size_ratio ); 752 $s_x = floor( ( $orig_w - $crop_w ) / 2 ); 753 $s_y = floor( ( $orig_h - $crop_h ) / 2 ); 754 755 // Safe guard against super large or zero images which might cause 500 errors 756 if ( $new_w > 5000 || $new_h > 5000 || $new_w <= 0 || $new_h <= 0 ) { 757 return null; 758 } 759 760 // the return array matches the parameters to imagecopyresampled() 761 // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h 762 return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h ); 763 } 764 } 765 766 767 // This function allows us to latch on WP image functions such as 768 // the_post_thumbnail, get_image_tag and wp_get_attachment_image_src 769 // so that you won't have to use the function bfi_thumb in order to do resizing. 770 // To make this work, in the WP image functions, when specifying an 771 // array for the image dimensions, add a 'bfi_thumb' => true to 772 // the array, then add your normal $params arguments. 773 // 774 // e.g. the_post_thumbnail( array( 1024, 400, 'bfi_thumb' => true, 'grayscale' => true ) ); 775 add_filter( 'image_downsize', 'bfi_image_downsize', 1, 3 ); 776 777 if ( ! function_exists( 'bfi_image_downsize' ) ) { 778 function bfi_image_downsize( $out, $id, $size ) { 779 if ( ! is_array( $size ) ) { 780 return false; 781 } 782 if ( ! array_key_exists( 'bfi_thumb', $size ) ) { 783 return false; 784 } 785 if ( empty( $size['bfi_thumb'] ) ) { 786 return false; 787 } 788 789 $img_url = wp_get_attachment_url( $id ); 790 791 $params = $size; 792 $params['width'] = $size[0]; 793 $params['height'] = $size[1]; 794 795 $resized_img_url = bfi_thumb( $img_url, $params ); 796 797 return array( $resized_img_url, $size[0], $size[1], false ); 798 } 799 }