diff -r 34716fd837a4 -r be944660c56a wp/wp-includes/class-wp-image-editor-gd.php --- a/wp/wp-includes/class-wp-image-editor-gd.php Tue Dec 15 15:52:01 2020 +0100 +++ b/wp/wp-includes/class-wp-image-editor-gd.php Wed Sep 21 18:19:35 2022 +0200 @@ -17,7 +17,7 @@ /** * GD Resource. * - * @var resource + * @var resource|GdImage */ protected $image; @@ -69,6 +69,8 @@ return ( $image_types & IMG_PNG ) != 0; case 'image/gif': return ( $image_types & IMG_GIF ) != 0; + case 'image/webp': + return ( $image_types & IMG_WEBP ) != 0; // phpcs:ignore PHPCompatibility.Constants.NewConstants.img_webpFound } return false; @@ -79,7 +81,7 @@ * * @since 3.5.0 * - * @return bool|WP_Error True if loaded successfully; WP_Error on failure. + * @return true|WP_Error True if loaded successfully; WP_Error on failure. */ public function load() { if ( $this->image ) { @@ -93,13 +95,28 @@ // Set artificially high because GD uses uncompressed images in memory. wp_raise_memory_limit( 'image' ); - $this->image = @imagecreatefromstring( file_get_contents( $this->file ) ); + $file_contents = @file_get_contents( $this->file ); + + if ( ! $file_contents ) { + return new WP_Error( 'error_loading_image', __( 'File doesn’t exist?' ), $this->file ); + } - if ( ! is_resource( $this->image ) ) { + // WebP may not work with imagecreatefromstring(). + if ( + function_exists( 'imagecreatefromwebp' ) && + ( 'image/webp' === wp_get_image_mime( $this->file ) ) + ) { + $this->image = @imagecreatefromwebp( $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 ); } - $size = @getimagesize( $this->file ); + $size = wp_getimagesize( $this->file ); + if ( ! $size ) { return new WP_Error( 'invalid_image', __( 'Could not read image size.' ), $this->file ); } @@ -138,11 +155,11 @@ /** * Resizes current image. - * Wraps _resize, since _resize returns a GD Resource. + * + * Wraps `::_resize()` which returns a GD resource or GdImage instance. * - * At minimum, either a height or width must be provided. - * If one of the two is set to null, the resize will - * maintain aspect ratio according to the provided dimension. + * At minimum, either a height or width must be provided. If one of the two is set + * to null, the resize will maintain aspect ratio according to the provided dimension. * * @since 3.5.0 * @@ -158,7 +175,7 @@ $resized = $this->_resize( $max_w, $max_h, $crop ); - if ( is_resource( $resized ) ) { + if ( is_gd_image( $resized ) ) { imagedestroy( $this->image ); $this->image = $resized; return true; @@ -174,7 +191,7 @@ * @param int $max_w * @param int $max_h * @param bool|array $crop - * @return resource|WP_Error + * @return resource|GdImage|WP_Error */ protected function _resize( $max_w, $max_h, $crop = false ) { $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop ); @@ -188,7 +205,7 @@ $resized = wp_imagecreatetruecolor( $dst_w, $dst_h ); imagecopyresampled( $resized, $this->image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); - if ( is_resource( $resized ) ) { + if ( is_gd_image( $resized ) ) { $this->update_size( $dst_w, $dst_h ); return $resized; } @@ -304,7 +321,7 @@ * @param int $dst_w Optional. The destination width. * @param int $dst_h Optional. The destination height. * @param bool $src_abs Optional. If the source crop points are absolute. - * @return bool|WP_Error + * @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, @@ -316,7 +333,13 @@ $dst_h = $src_h; } - $dst = wp_imagecreatetruecolor( $dst_w, $dst_h ); + foreach ( array( $src_w, $src_h, $dst_w, $dst_h ) as $value ) { + if ( ! is_numeric( $value ) || (int) $value <= 0 ) { + return new WP_Error( 'image_crop_error', __( 'Image crop failed.' ), $this->file ); + } + } + + $dst = wp_imagecreatetruecolor( (int) $dst_w, (int) $dst_h ); if ( $src_abs ) { $src_w -= $src_x; @@ -327,9 +350,9 @@ imageantialias( $dst, true ); } - imagecopyresampled( $dst, $this->image, 0, 0, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); + imagecopyresampled( $dst, $this->image, 0, 0, (int) $src_x, (int) $src_y, (int) $dst_w, (int) $dst_h, (int) $src_w, (int) $src_h ); - if ( is_resource( $dst ) ) { + if ( is_gd_image( $dst ) ) { imagedestroy( $this->image ); $this->image = $dst; $this->update_size(); @@ -353,7 +376,7 @@ $transparency = imagecolorallocatealpha( $this->image, 255, 255, 255, 127 ); $rotated = imagerotate( $this->image, $angle, $transparency ); - if ( is_resource( $rotated ) ) { + if ( is_gd_image( $rotated ) ) { imagealphablending( $rotated, true ); imagesavealpha( $rotated, true ); imagedestroy( $this->image ); @@ -362,6 +385,7 @@ return true; } } + return new WP_Error( 'image_rotate_error', __( 'Image rotate failed.' ), $this->file ); } @@ -379,7 +403,7 @@ $h = $this->size['height']; $dst = wp_imagecreatetruecolor( $w, $h ); - if ( is_resource( $dst ) ) { + if ( is_gd_image( $dst ) ) { $sx = $vert ? ( $w - 1 ) : 0; $sy = $horz ? ( $h - 1 ) : 0; $sw = $vert ? -$w : $w; @@ -391,6 +415,7 @@ return true; } } + return new WP_Error( 'image_flip_error', __( 'Image flip failed.' ), $this->file ); } @@ -415,9 +440,9 @@ } /** - * @param resource $image - * @param string|null $filename - * @param string|null $mime_type + * @param resource|GdImage $image + * @param string|null $filename + * @param string|null $mime_type * @return array|WP_Error */ protected function _save( $image, $filename = null, $mime_type = null ) { @@ -444,6 +469,10 @@ 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() ) ) ) { + return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); + } } else { return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); } @@ -487,6 +516,12 @@ case 'image/gif': header( 'Content-Type: image/gif' ); return imagegif( $this->image ); + case 'image/webp': + if ( function_exists( 'imagewebp' ) ) { + header( 'Content-Type: image/webp' ); + return imagewebp( $this->image, null, $this->get_quality() ); + } + // Fall back to the default if webp isn't supported. default: header( 'Content-Type: image/jpeg' ); return imagejpeg( $this->image, null, $this->get_quality() );