wp/wp-includes/class-wp-image-editor-gd.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
--- a/wp/wp-includes/class-wp-image-editor-gd.php	Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-includes/class-wp-image-editor-gd.php	Fri Sep 05 18:40:08 2025 +0200
@@ -64,13 +64,15 @@
 		$image_types = imagetypes();
 		switch ( $mime_type ) {
 			case 'image/jpeg':
-				return ( $image_types & IMG_JPG ) != 0;
+				return ( $image_types & IMG_JPG ) !== 0;
 			case 'image/png':
-				return ( $image_types & IMG_PNG ) != 0;
+				return ( $image_types & IMG_PNG ) !== 0;
 			case 'image/gif':
-				return ( $image_types & IMG_GIF ) != 0;
+				return ( $image_types & IMG_GIF ) !== 0;
 			case 'image/webp':
-				return ( $image_types & IMG_WEBP ) != 0;
+				return ( $image_types & IMG_WEBP ) !== 0;
+			case 'image/avif':
+				return ( $image_types & IMG_AVIF ) !== 0 && function_exists( 'imageavif' );
 		}
 
 		return false;
@@ -111,6 +113,16 @@
 			$this->image = @imagecreatefromstring( $file_contents );
 		}
 
+		// AVIF may not work with imagecreatefromstring().
+		if (
+			function_exists( 'imagecreatefromavif' ) &&
+			( 'image/avif' === wp_get_image_mime( $this->file ) )
+		) {
+			$this->image = @imagecreatefromavif( $this->file );
+		} else {
+			$this->image = @imagecreatefromstring( $file_contents );
+		}
+
 		if ( ! is_gd_image( $this->image ) ) {
 			return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file );
 		}
@@ -163,13 +175,20 @@
 	 *
 	 * @since 3.5.0
 	 *
-	 * @param int|null $max_w Image width.
-	 * @param int|null $max_h Image height.
-	 * @param bool     $crop
+	 * @param int|null   $max_w Image width.
+	 * @param int|null   $max_h Image height.
+	 * @param bool|array $crop  {
+	 *     Optional. Image cropping behavior. If false, the image will be scaled (default).
+	 *     If true, image will be cropped to the specified dimensions using center positions.
+	 *     If an array, the image will be cropped using the array to specify the crop location:
+	 *
+	 *     @type string $0 The x crop position. Accepts 'left' 'center', or 'right'.
+	 *     @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
+	 * }
 	 * @return true|WP_Error
 	 */
 	public function resize( $max_w, $max_h, $crop = false ) {
-		if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) ) {
+		if ( ( $this->size['width'] === $max_w ) && ( $this->size['height'] === $max_h ) ) {
 			return true;
 		}
 
@@ -190,7 +209,14 @@
 	/**
 	 * @param int        $max_w
 	 * @param int        $max_h
-	 * @param bool|array $crop
+	 * @param bool|array $crop  {
+	 *     Optional. Image cropping behavior. If false, the image will be scaled (default).
+	 *     If true, image will be cropped to the specified dimensions using center positions.
+	 *     If an array, the image will be cropped using the array to specify the crop location:
+	 *
+	 *     @type string $0 The x crop position. Accepts 'left' 'center', or 'right'.
+	 *     @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
+	 * }
 	 * @return resource|GdImage|WP_Error
 	 */
 	protected function _resize( $max_w, $max_h, $crop = false ) {
@@ -236,9 +262,9 @@
 	 *     @type array ...$0 {
 	 *         Array of height, width values, and whether to crop.
 	 *
-	 *         @type int  $width  Image width. Optional if `$height` is specified.
-	 *         @type int  $height Image height. Optional if `$width` is specified.
-	 *         @type bool $crop   Optional. Whether to crop the image. Default false.
+	 *         @type int        $width  Image width. Optional if `$height` is specified.
+	 *         @type int        $height Image height. Optional if `$width` is specified.
+	 *         @type bool|array $crop   Optional. Whether to crop the image. Default false.
 	 *     }
 	 * }
 	 * @return array An array of resized images' metadata by size.
@@ -265,9 +291,9 @@
 	 * @param array $size_data {
 	 *     Array of size data.
 	 *
-	 *     @type int  $width  The maximum width in pixels.
-	 *     @type int  $height The maximum height in pixels.
-	 *     @type bool $crop   Whether to crop the image to exact dimensions.
+	 *     @type int        $width  The maximum width in pixels.
+	 *     @type int        $height The maximum height in pixels.
+	 *     @type bool|array $crop   Whether to crop the image to exact dimensions.
 	 * }
 	 * @return array|WP_Error The image data array for inclusion in the `sizes` array in the image meta,
 	 *                        WP_Error object on error.
@@ -324,8 +350,10 @@
 	 * @return true|WP_Error
 	 */
 	public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) {
-		// If destination width/height isn't specified,
-		// use same as width/height from source.
+		/*
+		 * If destination width/height isn't specified,
+		 * use same as width/height from source.
+		 */
 		if ( ! $dst_w ) {
 			$dst_w = $src_w;
 		}
@@ -425,10 +453,20 @@
 	 * @since 3.5.0
 	 * @since 5.9.0 Renamed `$filename` to `$destfilename` to match parent class
 	 *              for PHP 8 named parameter support.
+	 * @since 6.0.0 The `$filesize` value was added to the returned array.
 	 *
 	 * @param string|null $destfilename Optional. Destination filename. Default null.
 	 * @param string|null $mime_type    Optional. The mime-type. Default null.
-	 * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
+	 * @return array|WP_Error {
+	 *     Array on success or WP_Error if the file failed to save.
+	 *
+	 *     @type string $path      Path to the image file.
+	 *     @type string $file      Name of the image file.
+	 *     @type int    $width     Image width.
+	 *     @type int    $height    Image height.
+	 *     @type string $mime-type The mime type of the image.
+	 *     @type int    $filesize  File size of the image.
+	 * }
 	 */
 	public function save( $destfilename = null, $mime_type = null ) {
 		$saved = $this->_save( $this->image, $destfilename, $mime_type );
@@ -442,10 +480,22 @@
 	}
 
 	/**
+	 * @since 3.5.0
+	 * @since 6.0.0 The `$filesize` value was added to the returned array.
+	 *
 	 * @param resource|GdImage $image
 	 * @param string|null      $filename
 	 * @param string|null      $mime_type
-	 * @return array|WP_Error
+	 * @return array|WP_Error {
+	 *     Array on success or WP_Error if the file failed to save.
+	 *
+	 *     @type string $path      Path to the image file.
+	 *     @type string $file      Name of the image file.
+	 *     @type int    $width     Image width.
+	 *     @type int    $height    Image height.
+	 *     @type string $mime-type The mime type of the image.
+	 *     @type int    $filesize  File size of the image.
+	 * }
 	 */
 	protected function _save( $image, $filename = null, $mime_type = null ) {
 		list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
@@ -454,6 +504,18 @@
 			$filename = $this->generate_filename( null, null, $extension );
 		}
 
+		if ( function_exists( 'imageinterlace' ) ) {
+			/**
+			 * Filters whether to output progressive images (if available).
+			 *
+			 * @since 6.5.0
+			 *
+			 * @param bool   $interlace Whether to use progressive images for output if available. Default false.
+			 * @param string $mime_type The mime type being saved.
+			 */
+			imageinterlace( $image, apply_filters( 'image_save_progressive', false, $mime_type ) );
+		}
+
 		if ( 'image/gif' === $mime_type ) {
 			if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) ) {
 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
@@ -471,8 +533,16 @@
 			if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) {
 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
 			}
-		} elseif ( 'image/webp' == $mime_type ) {
-			if ( ! function_exists( 'imagewebp' ) || ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) ) ) {
+		} elseif ( 'image/webp' === $mime_type ) {
+			if ( ! function_exists( 'imagewebp' )
+				|| ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) )
+			) {
+				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
+			}
+		} elseif ( 'image/avif' === $mime_type ) {
+			if ( ! function_exists( 'imageavif' )
+				|| ! $this->make_image( $filename, 'imageavif', array( $image, $filename, $this->get_quality() ) )
+			) {
 				return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
 			}
 		} else {
@@ -523,8 +593,17 @@
 				if ( function_exists( 'imagewebp' ) ) {
 					header( 'Content-Type: image/webp' );
 					return imagewebp( $this->image, null, $this->get_quality() );
+				} else {
+					// Fall back to JPEG.
+					header( 'Content-Type: image/jpeg' );
+					return imagejpeg( $this->image, null, $this->get_quality() );
 				}
-				// Fall back to the default if webp isn't supported.
+			case 'image/avif':
+				if ( function_exists( 'imageavif' ) ) {
+					header( 'Content-Type: image/avif' );
+					return imageavif( $this->image, null, $this->get_quality() );
+				}
+				// Fall back to JPEG.
 			default:
 				header( 'Content-Type: image/jpeg' );
 				return imagejpeg( $this->image, null, $this->get_quality() );