--- 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() );