wp/wp-includes/class-wp-image-editor-gd.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    62 	 */
    62 	 */
    63 	public static function supports_mime_type( $mime_type ) {
    63 	public static function supports_mime_type( $mime_type ) {
    64 		$image_types = imagetypes();
    64 		$image_types = imagetypes();
    65 		switch ( $mime_type ) {
    65 		switch ( $mime_type ) {
    66 			case 'image/jpeg':
    66 			case 'image/jpeg':
    67 				return ( $image_types & IMG_JPG ) != 0;
    67 				return ( $image_types & IMG_JPG ) !== 0;
    68 			case 'image/png':
    68 			case 'image/png':
    69 				return ( $image_types & IMG_PNG ) != 0;
    69 				return ( $image_types & IMG_PNG ) !== 0;
    70 			case 'image/gif':
    70 			case 'image/gif':
    71 				return ( $image_types & IMG_GIF ) != 0;
    71 				return ( $image_types & IMG_GIF ) !== 0;
    72 			case 'image/webp':
    72 			case 'image/webp':
    73 				return ( $image_types & IMG_WEBP ) != 0;
    73 				return ( $image_types & IMG_WEBP ) !== 0;
       
    74 			case 'image/avif':
       
    75 				return ( $image_types & IMG_AVIF ) !== 0 && function_exists( 'imageavif' );
    74 		}
    76 		}
    75 
    77 
    76 		return false;
    78 		return false;
    77 	}
    79 	}
    78 
    80 
   109 			$this->image = @imagecreatefromwebp( $this->file );
   111 			$this->image = @imagecreatefromwebp( $this->file );
   110 		} else {
   112 		} else {
   111 			$this->image = @imagecreatefromstring( $file_contents );
   113 			$this->image = @imagecreatefromstring( $file_contents );
   112 		}
   114 		}
   113 
   115 
       
   116 		// AVIF may not work with imagecreatefromstring().
       
   117 		if (
       
   118 			function_exists( 'imagecreatefromavif' ) &&
       
   119 			( 'image/avif' === wp_get_image_mime( $this->file ) )
       
   120 		) {
       
   121 			$this->image = @imagecreatefromavif( $this->file );
       
   122 		} else {
       
   123 			$this->image = @imagecreatefromstring( $file_contents );
       
   124 		}
       
   125 
   114 		if ( ! is_gd_image( $this->image ) ) {
   126 		if ( ! is_gd_image( $this->image ) ) {
   115 			return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file );
   127 			return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file );
   116 		}
   128 		}
   117 
   129 
   118 		$size = wp_getimagesize( $this->file );
   130 		$size = wp_getimagesize( $this->file );
   161 	 * At minimum, either a height or width must be provided. If one of the two is set
   173 	 * At minimum, either a height or width must be provided. If one of the two is set
   162 	 * to null, the resize will maintain aspect ratio according to the provided dimension.
   174 	 * to null, the resize will maintain aspect ratio according to the provided dimension.
   163 	 *
   175 	 *
   164 	 * @since 3.5.0
   176 	 * @since 3.5.0
   165 	 *
   177 	 *
   166 	 * @param int|null $max_w Image width.
   178 	 * @param int|null   $max_w Image width.
   167 	 * @param int|null $max_h Image height.
   179 	 * @param int|null   $max_h Image height.
   168 	 * @param bool     $crop
   180 	 * @param bool|array $crop  {
       
   181 	 *     Optional. Image cropping behavior. If false, the image will be scaled (default).
       
   182 	 *     If true, image will be cropped to the specified dimensions using center positions.
       
   183 	 *     If an array, the image will be cropped using the array to specify the crop location:
       
   184 	 *
       
   185 	 *     @type string $0 The x crop position. Accepts 'left' 'center', or 'right'.
       
   186 	 *     @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
       
   187 	 * }
   169 	 * @return true|WP_Error
   188 	 * @return true|WP_Error
   170 	 */
   189 	 */
   171 	public function resize( $max_w, $max_h, $crop = false ) {
   190 	public function resize( $max_w, $max_h, $crop = false ) {
   172 		if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) ) {
   191 		if ( ( $this->size['width'] === $max_w ) && ( $this->size['height'] === $max_h ) ) {
   173 			return true;
   192 			return true;
   174 		}
   193 		}
   175 
   194 
   176 		$resized = $this->_resize( $max_w, $max_h, $crop );
   195 		$resized = $this->_resize( $max_w, $max_h, $crop );
   177 
   196 
   188 	}
   207 	}
   189 
   208 
   190 	/**
   209 	/**
   191 	 * @param int        $max_w
   210 	 * @param int        $max_w
   192 	 * @param int        $max_h
   211 	 * @param int        $max_h
   193 	 * @param bool|array $crop
   212 	 * @param bool|array $crop  {
       
   213 	 *     Optional. Image cropping behavior. If false, the image will be scaled (default).
       
   214 	 *     If true, image will be cropped to the specified dimensions using center positions.
       
   215 	 *     If an array, the image will be cropped using the array to specify the crop location:
       
   216 	 *
       
   217 	 *     @type string $0 The x crop position. Accepts 'left' 'center', or 'right'.
       
   218 	 *     @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
       
   219 	 * }
   194 	 * @return resource|GdImage|WP_Error
   220 	 * @return resource|GdImage|WP_Error
   195 	 */
   221 	 */
   196 	protected function _resize( $max_w, $max_h, $crop = false ) {
   222 	protected function _resize( $max_w, $max_h, $crop = false ) {
   197 		$dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
   223 		$dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
   198 
   224 
   234 	 *     maintain aspect ratio according to the source image.
   260 	 *     maintain aspect ratio according to the source image.
   235 	 *
   261 	 *
   236 	 *     @type array ...$0 {
   262 	 *     @type array ...$0 {
   237 	 *         Array of height, width values, and whether to crop.
   263 	 *         Array of height, width values, and whether to crop.
   238 	 *
   264 	 *
   239 	 *         @type int  $width  Image width. Optional if `$height` is specified.
   265 	 *         @type int        $width  Image width. Optional if `$height` is specified.
   240 	 *         @type int  $height Image height. Optional if `$width` is specified.
   266 	 *         @type int        $height Image height. Optional if `$width` is specified.
   241 	 *         @type bool $crop   Optional. Whether to crop the image. Default false.
   267 	 *         @type bool|array $crop   Optional. Whether to crop the image. Default false.
   242 	 *     }
   268 	 *     }
   243 	 * }
   269 	 * }
   244 	 * @return array An array of resized images' metadata by size.
   270 	 * @return array An array of resized images' metadata by size.
   245 	 */
   271 	 */
   246 	public function multi_resize( $sizes ) {
   272 	public function multi_resize( $sizes ) {
   263 	 * @since 5.3.0
   289 	 * @since 5.3.0
   264 	 *
   290 	 *
   265 	 * @param array $size_data {
   291 	 * @param array $size_data {
   266 	 *     Array of size data.
   292 	 *     Array of size data.
   267 	 *
   293 	 *
   268 	 *     @type int  $width  The maximum width in pixels.
   294 	 *     @type int        $width  The maximum width in pixels.
   269 	 *     @type int  $height The maximum height in pixels.
   295 	 *     @type int        $height The maximum height in pixels.
   270 	 *     @type bool $crop   Whether to crop the image to exact dimensions.
   296 	 *     @type bool|array $crop   Whether to crop the image to exact dimensions.
   271 	 * }
   297 	 * }
   272 	 * @return array|WP_Error The image data array for inclusion in the `sizes` array in the image meta,
   298 	 * @return array|WP_Error The image data array for inclusion in the `sizes` array in the image meta,
   273 	 *                        WP_Error object on error.
   299 	 *                        WP_Error object on error.
   274 	 */
   300 	 */
   275 	public function make_subsize( $size_data ) {
   301 	public function make_subsize( $size_data ) {
   322 	 * @param int  $dst_h   Optional. The destination height.
   348 	 * @param int  $dst_h   Optional. The destination height.
   323 	 * @param bool $src_abs Optional. If the source crop points are absolute.
   349 	 * @param bool $src_abs Optional. If the source crop points are absolute.
   324 	 * @return true|WP_Error
   350 	 * @return true|WP_Error
   325 	 */
   351 	 */
   326 	public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) {
   352 	public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) {
   327 		// If destination width/height isn't specified,
   353 		/*
   328 		// use same as width/height from source.
   354 		 * If destination width/height isn't specified,
       
   355 		 * use same as width/height from source.
       
   356 		 */
   329 		if ( ! $dst_w ) {
   357 		if ( ! $dst_w ) {
   330 			$dst_w = $src_w;
   358 			$dst_w = $src_w;
   331 		}
   359 		}
   332 		if ( ! $dst_h ) {
   360 		if ( ! $dst_h ) {
   333 			$dst_h = $src_h;
   361 			$dst_h = $src_h;
   423 	 * Saves current in-memory image to file.
   451 	 * Saves current in-memory image to file.
   424 	 *
   452 	 *
   425 	 * @since 3.5.0
   453 	 * @since 3.5.0
   426 	 * @since 5.9.0 Renamed `$filename` to `$destfilename` to match parent class
   454 	 * @since 5.9.0 Renamed `$filename` to `$destfilename` to match parent class
   427 	 *              for PHP 8 named parameter support.
   455 	 *              for PHP 8 named parameter support.
       
   456 	 * @since 6.0.0 The `$filesize` value was added to the returned array.
   428 	 *
   457 	 *
   429 	 * @param string|null $destfilename Optional. Destination filename. Default null.
   458 	 * @param string|null $destfilename Optional. Destination filename. Default null.
   430 	 * @param string|null $mime_type    Optional. The mime-type. Default null.
   459 	 * @param string|null $mime_type    Optional. The mime-type. Default null.
   431 	 * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
   460 	 * @return array|WP_Error {
       
   461 	 *     Array on success or WP_Error if the file failed to save.
       
   462 	 *
       
   463 	 *     @type string $path      Path to the image file.
       
   464 	 *     @type string $file      Name of the image file.
       
   465 	 *     @type int    $width     Image width.
       
   466 	 *     @type int    $height    Image height.
       
   467 	 *     @type string $mime-type The mime type of the image.
       
   468 	 *     @type int    $filesize  File size of the image.
       
   469 	 * }
   432 	 */
   470 	 */
   433 	public function save( $destfilename = null, $mime_type = null ) {
   471 	public function save( $destfilename = null, $mime_type = null ) {
   434 		$saved = $this->_save( $this->image, $destfilename, $mime_type );
   472 		$saved = $this->_save( $this->image, $destfilename, $mime_type );
   435 
   473 
   436 		if ( ! is_wp_error( $saved ) ) {
   474 		if ( ! is_wp_error( $saved ) ) {
   440 
   478 
   441 		return $saved;
   479 		return $saved;
   442 	}
   480 	}
   443 
   481 
   444 	/**
   482 	/**
       
   483 	 * @since 3.5.0
       
   484 	 * @since 6.0.0 The `$filesize` value was added to the returned array.
       
   485 	 *
   445 	 * @param resource|GdImage $image
   486 	 * @param resource|GdImage $image
   446 	 * @param string|null      $filename
   487 	 * @param string|null      $filename
   447 	 * @param string|null      $mime_type
   488 	 * @param string|null      $mime_type
   448 	 * @return array|WP_Error
   489 	 * @return array|WP_Error {
       
   490 	 *     Array on success or WP_Error if the file failed to save.
       
   491 	 *
       
   492 	 *     @type string $path      Path to the image file.
       
   493 	 *     @type string $file      Name of the image file.
       
   494 	 *     @type int    $width     Image width.
       
   495 	 *     @type int    $height    Image height.
       
   496 	 *     @type string $mime-type The mime type of the image.
       
   497 	 *     @type int    $filesize  File size of the image.
       
   498 	 * }
   449 	 */
   499 	 */
   450 	protected function _save( $image, $filename = null, $mime_type = null ) {
   500 	protected function _save( $image, $filename = null, $mime_type = null ) {
   451 		list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
   501 		list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
   452 
   502 
   453 		if ( ! $filename ) {
   503 		if ( ! $filename ) {
   454 			$filename = $this->generate_filename( null, null, $extension );
   504 			$filename = $this->generate_filename( null, null, $extension );
       
   505 		}
       
   506 
       
   507 		if ( function_exists( 'imageinterlace' ) ) {
       
   508 			/**
       
   509 			 * Filters whether to output progressive images (if available).
       
   510 			 *
       
   511 			 * @since 6.5.0
       
   512 			 *
       
   513 			 * @param bool   $interlace Whether to use progressive images for output if available. Default false.
       
   514 			 * @param string $mime_type The mime type being saved.
       
   515 			 */
       
   516 			imageinterlace( $image, apply_filters( 'image_save_progressive', false, $mime_type ) );
   455 		}
   517 		}
   456 
   518 
   457 		if ( 'image/gif' === $mime_type ) {
   519 		if ( 'image/gif' === $mime_type ) {
   458 			if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) ) {
   520 			if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) ) {
   459 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   521 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   469 			}
   531 			}
   470 		} elseif ( 'image/jpeg' === $mime_type ) {
   532 		} elseif ( 'image/jpeg' === $mime_type ) {
   471 			if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) {
   533 			if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) {
   472 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   534 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   473 			}
   535 			}
   474 		} elseif ( 'image/webp' == $mime_type ) {
   536 		} elseif ( 'image/webp' === $mime_type ) {
   475 			if ( ! function_exists( 'imagewebp' ) || ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) ) ) {
   537 			if ( ! function_exists( 'imagewebp' )
       
   538 				|| ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) )
       
   539 			) {
       
   540 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
       
   541 			}
       
   542 		} elseif ( 'image/avif' === $mime_type ) {
       
   543 			if ( ! function_exists( 'imageavif' )
       
   544 				|| ! $this->make_image( $filename, 'imageavif', array( $image, $filename, $this->get_quality() ) )
       
   545 			) {
   476 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   546 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   477 			}
   547 			}
   478 		} else {
   548 		} else {
   479 			return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   549 			return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
   480 		}
   550 		}
   521 				return imagegif( $this->image );
   591 				return imagegif( $this->image );
   522 			case 'image/webp':
   592 			case 'image/webp':
   523 				if ( function_exists( 'imagewebp' ) ) {
   593 				if ( function_exists( 'imagewebp' ) ) {
   524 					header( 'Content-Type: image/webp' );
   594 					header( 'Content-Type: image/webp' );
   525 					return imagewebp( $this->image, null, $this->get_quality() );
   595 					return imagewebp( $this->image, null, $this->get_quality() );
       
   596 				} else {
       
   597 					// Fall back to JPEG.
       
   598 					header( 'Content-Type: image/jpeg' );
       
   599 					return imagejpeg( $this->image, null, $this->get_quality() );
   526 				}
   600 				}
   527 				// Fall back to the default if webp isn't supported.
   601 			case 'image/avif':
       
   602 				if ( function_exists( 'imageavif' ) ) {
       
   603 					header( 'Content-Type: image/avif' );
       
   604 					return imageavif( $this->image, null, $this->get_quality() );
       
   605 				}
       
   606 				// Fall back to JPEG.
   528 			default:
   607 			default:
   529 				header( 'Content-Type: image/jpeg' );
   608 				header( 'Content-Type: image/jpeg' );
   530 				return imagejpeg( $this->image, null, $this->get_quality() );
   609 				return imagejpeg( $this->image, null, $this->get_quality() );
   531 		}
   610 		}
   532 	}
   611 	}