[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Base WordPress Image Editor 4 * 5 * @package WordPress 6 * @subpackage Image_Editor 7 */ 8 9 /** 10 * Base image editor class from which implementations extend 11 * 12 * @since 3.5.0 13 */ 14 abstract class WP_Image_Editor { 15 protected $file = null; 16 protected $size = null; 17 protected $mime_type = null; 18 protected $default_mime_type = 'image/jpeg'; 19 protected $quality = false; 20 protected $default_quality = 82; 21 22 /** 23 * Each instance handles a single file. 24 * 25 * @param string $file Path to the file to load. 26 */ 27 public function __construct( $file ) { 28 $this->file = $file; 29 } 30 31 /** 32 * Checks to see if current environment supports the editor chosen. 33 * Must be overridden in a subclass. 34 * 35 * @since 3.5.0 36 * 37 * @abstract 38 * 39 * @param array $args 40 * @return bool 41 */ 42 public static function test( $args = array() ) { 43 return false; 44 } 45 46 /** 47 * Checks to see if editor supports the mime-type specified. 48 * Must be overridden in a subclass. 49 * 50 * @since 3.5.0 51 * 52 * @abstract 53 * 54 * @param string $mime_type 55 * @return bool 56 */ 57 public static function supports_mime_type( $mime_type ) { 58 return false; 59 } 60 61 /** 62 * Loads image from $this->file into editor. 63 * 64 * @since 3.5.0 65 * @abstract 66 * 67 * @return true|WP_Error True if loaded; WP_Error on failure. 68 */ 69 abstract public function load(); 70 71 /** 72 * Saves current image to file. 73 * 74 * @since 3.5.0 75 * @abstract 76 * 77 * @param string $destfilename 78 * @param string $mime_type 79 * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string} 80 */ 81 abstract public function save( $destfilename = null, $mime_type = null ); 82 83 /** 84 * Resizes current image. 85 * 86 * At minimum, either a height or width must be provided. 87 * If one of the two is set to null, the resize will 88 * maintain aspect ratio according to the provided dimension. 89 * 90 * @since 3.5.0 91 * @abstract 92 * 93 * @param int|null $max_w Image width. 94 * @param int|null $max_h Image height. 95 * @param bool $crop 96 * @return true|WP_Error 97 */ 98 abstract public function resize( $max_w, $max_h, $crop = false ); 99 100 /** 101 * Resize multiple images from a single source. 102 * 103 * @since 3.5.0 104 * @abstract 105 * 106 * @param array $sizes { 107 * An array of image size arrays. Default sizes are 'small', 'medium', 'large'. 108 * 109 * @type array $size { 110 * @type int $width Image width. 111 * @type int $height Image height. 112 * @type bool $crop Optional. Whether to crop the image. Default false. 113 * } 114 * } 115 * @return array An array of resized images metadata by size. 116 */ 117 abstract public function multi_resize( $sizes ); 118 119 /** 120 * Crops Image. 121 * 122 * @since 3.5.0 123 * @abstract 124 * 125 * @param int $src_x The start x position to crop from. 126 * @param int $src_y The start y position to crop from. 127 * @param int $src_w The width to crop. 128 * @param int $src_h The height to crop. 129 * @param int $dst_w Optional. The destination width. 130 * @param int $dst_h Optional. The destination height. 131 * @param bool $src_abs Optional. If the source crop points are absolute. 132 * @return true|WP_Error 133 */ 134 abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ); 135 136 /** 137 * Rotates current image counter-clockwise by $angle. 138 * 139 * @since 3.5.0 140 * @abstract 141 * 142 * @param float $angle 143 * @return true|WP_Error 144 */ 145 abstract public function rotate( $angle ); 146 147 /** 148 * Flips current image. 149 * 150 * @since 3.5.0 151 * @abstract 152 * 153 * @param bool $horz Flip along Horizontal Axis 154 * @param bool $vert Flip along Vertical Axis 155 * @return true|WP_Error 156 */ 157 abstract public function flip( $horz, $vert ); 158 159 /** 160 * Streams current image to browser. 161 * 162 * @since 3.5.0 163 * @abstract 164 * 165 * @param string $mime_type The mime type of the image. 166 * @return true|WP_Error True on success, WP_Error object on failure. 167 */ 168 abstract public function stream( $mime_type = null ); 169 170 /** 171 * Gets dimensions of image. 172 * 173 * @since 3.5.0 174 * 175 * @return array { 176 * Dimensions of the image. 177 * 178 * @type int $width The image width. 179 * @type int $height The image height. 180 * } 181 */ 182 public function get_size() { 183 return $this->size; 184 } 185 186 /** 187 * Sets current image size. 188 * 189 * @since 3.5.0 190 * 191 * @param int $width 192 * @param int $height 193 * @return true 194 */ 195 protected function update_size( $width = null, $height = null ) { 196 $this->size = array( 197 'width' => (int) $width, 198 'height' => (int) $height, 199 ); 200 return true; 201 } 202 203 /** 204 * Gets the Image Compression quality on a 1-100% scale. 205 * 206 * @since 4.0.0 207 * 208 * @return int Compression Quality. Range: [1,100] 209 */ 210 public function get_quality() { 211 if ( ! $this->quality ) { 212 $this->set_quality(); 213 } 214 215 return $this->quality; 216 } 217 218 /** 219 * Sets Image Compression quality on a 1-100% scale. 220 * 221 * @since 3.5.0 222 * 223 * @param int $quality Compression Quality. Range: [1,100] 224 * @return true|WP_Error True if set successfully; WP_Error on failure. 225 */ 226 public function set_quality( $quality = null ) { 227 if ( null === $quality ) { 228 /** 229 * Filters the default image compression quality setting. 230 * 231 * Applies only during initial editor instantiation, or when set_quality() is run 232 * manually without the `$quality` argument. 233 * 234 * The WP_Image_Editor::set_quality() method has priority over the filter. 235 * 236 * @since 3.5.0 237 * 238 * @param int $quality Quality level between 1 (low) and 100 (high). 239 * @param string $mime_type Image mime type. 240 */ 241 $quality = apply_filters( 'wp_editor_set_quality', $this->default_quality, $this->mime_type ); 242 243 if ( 'image/jpeg' === $this->mime_type ) { 244 /** 245 * Filters the JPEG compression quality for backward-compatibility. 246 * 247 * Applies only during initial editor instantiation, or when set_quality() is run 248 * manually without the `$quality` argument. 249 * 250 * The WP_Image_Editor::set_quality() method has priority over the filter. 251 * 252 * The filter is evaluated under two contexts: 'image_resize', and 'edit_image', 253 * (when a JPEG image is saved to file). 254 * 255 * @since 2.5.0 256 * 257 * @param int $quality Quality level between 0 (low) and 100 (high) of the JPEG. 258 * @param string $context Context of the filter. 259 */ 260 $quality = apply_filters( 'jpeg_quality', $quality, 'image_resize' ); 261 } 262 263 if ( $quality < 0 || $quality > 100 ) { 264 $quality = $this->default_quality; 265 } 266 } 267 268 // Allow 0, but squash to 1 due to identical images in GD, and for backward compatibility. 269 if ( 0 === $quality ) { 270 $quality = 1; 271 } 272 273 if ( ( $quality >= 1 ) && ( $quality <= 100 ) ) { 274 $this->quality = $quality; 275 return true; 276 } else { 277 return new WP_Error( 'invalid_image_quality', __( 'Attempted to set image quality outside of the range [1,100].' ) ); 278 } 279 } 280 281 /** 282 * Returns preferred mime-type and extension based on provided 283 * file's extension and mime, or current file's extension and mime. 284 * 285 * Will default to $this->default_mime_type if requested is not supported. 286 * 287 * Provides corrected filename only if filename is provided. 288 * 289 * @since 3.5.0 290 * 291 * @param string $filename 292 * @param string $mime_type 293 * @return array { filename|null, extension, mime-type } 294 */ 295 protected function get_output_format( $filename = null, $mime_type = null ) { 296 $new_ext = null; 297 298 // By default, assume specified type takes priority. 299 if ( $mime_type ) { 300 $new_ext = $this->get_extension( $mime_type ); 301 } 302 303 if ( $filename ) { 304 $file_ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) ); 305 $file_mime = $this->get_mime_type( $file_ext ); 306 } else { 307 // If no file specified, grab editor's current extension and mime-type. 308 $file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) ); 309 $file_mime = $this->mime_type; 310 } 311 312 // Check to see if specified mime-type is the same as type implied by 313 // file extension. If so, prefer extension from file. 314 if ( ! $mime_type || ( $file_mime == $mime_type ) ) { 315 $mime_type = $file_mime; 316 $new_ext = $file_ext; 317 } 318 319 // Double-check that the mime-type selected is supported by the editor. 320 // If not, choose a default instead. 321 if ( ! $this->supports_mime_type( $mime_type ) ) { 322 /** 323 * Filters default mime type prior to getting the file extension. 324 * 325 * @see wp_get_mime_types() 326 * 327 * @since 3.5.0 328 * 329 * @param string $mime_type Mime type string. 330 */ 331 $mime_type = apply_filters( 'image_editor_default_mime_type', $this->default_mime_type ); 332 $new_ext = $this->get_extension( $mime_type ); 333 } 334 335 if ( $filename ) { 336 $dir = pathinfo( $filename, PATHINFO_DIRNAME ); 337 $ext = pathinfo( $filename, PATHINFO_EXTENSION ); 338 339 $filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}"; 340 } 341 342 return array( $filename, $new_ext, $mime_type ); 343 } 344 345 /** 346 * Builds an output filename based on current file, and adding proper suffix 347 * 348 * @since 3.5.0 349 * 350 * @param string $suffix 351 * @param string $dest_path 352 * @param string $extension 353 * @return string filename 354 */ 355 public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) { 356 // $suffix will be appended to the destination filename, just before the extension. 357 if ( ! $suffix ) { 358 $suffix = $this->get_suffix(); 359 } 360 361 $dir = pathinfo( $this->file, PATHINFO_DIRNAME ); 362 $ext = pathinfo( $this->file, PATHINFO_EXTENSION ); 363 364 $name = wp_basename( $this->file, ".$ext" ); 365 $new_ext = strtolower( $extension ? $extension : $ext ); 366 367 if ( ! is_null( $dest_path ) ) { 368 if ( ! wp_is_stream( $dest_path ) ) { 369 $_dest_path = realpath( $dest_path ); 370 if ( $_dest_path ) { 371 $dir = $_dest_path; 372 } 373 } else { 374 $dir = $dest_path; 375 } 376 } 377 378 return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}"; 379 } 380 381 /** 382 * Builds and returns proper suffix for file based on height and width. 383 * 384 * @since 3.5.0 385 * 386 * @return string|false suffix 387 */ 388 public function get_suffix() { 389 if ( ! $this->get_size() ) { 390 return false; 391 } 392 393 return "{$this->size['width']}x{$this->size['height']}"; 394 } 395 396 /** 397 * Check if a JPEG image has EXIF Orientation tag and rotate it if needed. 398 * 399 * @since 5.3.0 400 * 401 * @return bool|WP_Error True if the image was rotated. False if not rotated (no EXIF data or the image doesn't need to be rotated). 402 * WP_Error if error while rotating. 403 */ 404 public function maybe_exif_rotate() { 405 $orientation = null; 406 407 if ( is_callable( 'exif_read_data' ) && 'image/jpeg' === $this->mime_type ) { 408 $exif_data = @exif_read_data( $this->file ); 409 410 if ( ! empty( $exif_data['Orientation'] ) ) { 411 $orientation = (int) $exif_data['Orientation']; 412 } 413 } 414 415 /** 416 * Filters the `$orientation` value to correct it before rotating or to prevemnt rotating the image. 417 * 418 * @since 5.3.0 419 * 420 * @param int $orientation EXIF Orientation value as retrieved from the image file. 421 * @param string $file Path to the image file. 422 */ 423 $orientation = apply_filters( 'wp_image_maybe_exif_rotate', $orientation, $this->file ); 424 425 if ( ! $orientation || 1 === $orientation ) { 426 return false; 427 } 428 429 switch ( $orientation ) { 430 case 2: 431 // Flip horizontally. 432 $result = $this->flip( true, false ); 433 break; 434 case 3: 435 // Rotate 180 degrees or flip horizontally and vertically. 436 // Flipping seems faster and uses less resources. 437 $result = $this->flip( true, true ); 438 break; 439 case 4: 440 // Flip vertically. 441 $result = $this->flip( false, true ); 442 break; 443 case 5: 444 // Rotate 90 degrees counter-clockwise and flip vertically. 445 $result = $this->rotate( 90 ); 446 447 if ( ! is_wp_error( $result ) ) { 448 $result = $this->flip( false, true ); 449 } 450 451 break; 452 case 6: 453 // Rotate 90 degrees clockwise (270 counter-clockwise). 454 $result = $this->rotate( 270 ); 455 break; 456 case 7: 457 // Rotate 90 degrees counter-clockwise and flip horizontally. 458 $result = $this->rotate( 90 ); 459 460 if ( ! is_wp_error( $result ) ) { 461 $result = $this->flip( true, false ); 462 } 463 464 break; 465 case 8: 466 // Rotate 90 degrees counter-clockwise. 467 $result = $this->rotate( 90 ); 468 break; 469 } 470 471 return $result; 472 } 473 474 /** 475 * Either calls editor's save function or handles file as a stream. 476 * 477 * @since 3.5.0 478 * 479 * @param string|stream $filename 480 * @param callable $function 481 * @param array $arguments 482 * @return bool 483 */ 484 protected function make_image( $filename, $function, $arguments ) { 485 $stream = wp_is_stream( $filename ); 486 if ( $stream ) { 487 ob_start(); 488 } else { 489 // The directory containing the original file may no longer exist when using a replication plugin. 490 wp_mkdir_p( dirname( $filename ) ); 491 } 492 493 $result = call_user_func_array( $function, $arguments ); 494 495 if ( $result && $stream ) { 496 $contents = ob_get_contents(); 497 498 $fp = fopen( $filename, 'w' ); 499 500 if ( ! $fp ) { 501 ob_end_clean(); 502 return false; 503 } 504 505 fwrite( $fp, $contents ); 506 fclose( $fp ); 507 } 508 509 if ( $stream ) { 510 ob_end_clean(); 511 } 512 513 return $result; 514 } 515 516 /** 517 * Returns first matched mime-type from extension, 518 * as mapped from wp_get_mime_types() 519 * 520 * @since 3.5.0 521 * 522 * @param string $extension 523 * @return string|false 524 */ 525 protected static function get_mime_type( $extension = null ) { 526 if ( ! $extension ) { 527 return false; 528 } 529 530 $mime_types = wp_get_mime_types(); 531 $extensions = array_keys( $mime_types ); 532 533 foreach ( $extensions as $_extension ) { 534 if ( preg_match( "/{$extension}/i", $_extension ) ) { 535 return $mime_types[ $_extension ]; 536 } 537 } 538 539 return false; 540 } 541 542 /** 543 * Returns first matched extension from Mime-type, 544 * as mapped from wp_get_mime_types() 545 * 546 * @since 3.5.0 547 * 548 * @param string $mime_type 549 * @return string|false 550 */ 551 protected static function get_extension( $mime_type = null ) { 552 $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) ); 553 554 if ( empty( $extensions[0] ) ) { 555 return false; 556 } 557 558 return $extensions[0]; 559 } 560 } 561
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Jan 23 01:00:05 2021 | Cross-referenced by PHPXref 0.7.1 |