wp/wp-includes/class-wp-image-editor.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
--- a/wp/wp-includes/class-wp-image-editor.php	Tue Dec 15 15:52:01 2020 +0100
+++ b/wp/wp-includes/class-wp-image-editor.php	Wed Sep 21 18:19:35 2022 +0200
@@ -15,9 +15,12 @@
 	protected $file              = null;
 	protected $size              = null;
 	protected $mime_type         = null;
+	protected $output_mime_type  = null;
 	protected $default_mime_type = 'image/jpeg';
 	protected $quality           = false;
-	protected $default_quality   = 82;
+
+	// Deprecated since 5.8.1. See get_default_quality() below.
+	protected $default_quality = 82;
 
 	/**
 	 * Each instance handles a single file.
@@ -64,7 +67,7 @@
 	 * @since 3.5.0
 	 * @abstract
 	 *
-	 * @return bool|WP_Error True if loaded; WP_Error on failure.
+	 * @return true|WP_Error True if loaded; WP_Error on failure.
 	 */
 	abstract public function load();
 
@@ -93,7 +96,7 @@
 	 * @param int|null $max_w Image width.
 	 * @param int|null $max_h Image height.
 	 * @param bool     $crop
-	 * @return bool|WP_Error
+	 * @return true|WP_Error
 	 */
 	abstract public function resize( $max_w, $max_h, $crop = false );
 
@@ -129,7 +132,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
 	 */
 	abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false );
 
@@ -140,7 +143,7 @@
 	 * @abstract
 	 *
 	 * @param float $angle
-	 * @return bool|WP_Error
+	 * @return true|WP_Error
 	 */
 	abstract public function rotate( $angle );
 
@@ -152,7 +155,7 @@
 	 *
 	 * @param bool $horz Flip along Horizontal Axis
 	 * @param bool $vert Flip along Vertical Axis
-	 * @return bool|WP_Error
+	 * @return true|WP_Error
 	 */
 	abstract public function flip( $horz, $vert );
 
@@ -163,7 +166,7 @@
 	 * @abstract
 	 *
 	 * @param string $mime_type The mime type of the image.
-	 * @return bool|WP_Error True on success, WP_Error object or false on failure.
+	 * @return true|WP_Error True on success, WP_Error object on failure.
 	 */
 	abstract public function stream( $mime_type = null );
 
@@ -224,6 +227,11 @@
 	 * @return true|WP_Error True if set successfully; WP_Error on failure.
 	 */
 	public function set_quality( $quality = null ) {
+		// Use the output mime type if present. If not, fall back to the input/initial mime type.
+		$mime_type = ! empty( $this->output_mime_type ) ? $this->output_mime_type : $this->mime_type;
+		// Get the default quality setting for the mime type.
+		$default_quality = $this->get_default_quality( $mime_type );
+
 		if ( null === $quality ) {
 			/**
 			 * Filters the default image compression quality setting.
@@ -238,9 +246,9 @@
 			 * @param int    $quality   Quality level between 1 (low) and 100 (high).
 			 * @param string $mime_type Image mime type.
 			 */
-			$quality = apply_filters( 'wp_editor_set_quality', $this->default_quality, $this->mime_type );
+			$quality = apply_filters( 'wp_editor_set_quality', $default_quality, $mime_type );
 
-			if ( 'image/jpeg' === $this->mime_type ) {
+			if ( 'image/jpeg' === $mime_type ) {
 				/**
 				 * Filters the JPEG compression quality for backward-compatibility.
 				 *
@@ -261,7 +269,7 @@
 			}
 
 			if ( $quality < 0 || $quality > 100 ) {
-				$quality = $this->default_quality;
+				$quality = $default_quality;
 			}
 		}
 
@@ -279,6 +287,27 @@
 	}
 
 	/**
+	 * Returns the default compression quality setting for the mime type.
+	 *
+	 * @since 5.8.1
+	 *
+	 * @param string $mime_type
+	 * @return int The default quality setting for the mime type.
+	 */
+	protected function get_default_quality( $mime_type ) {
+		switch ( $mime_type ) {
+			case 'image/webp':
+				$quality = 86;
+				break;
+			case 'image/jpeg':
+			default:
+				$quality = $this->default_quality;
+		}
+
+		return $quality;
+	}
+
+	/**
 	 * Returns preferred mime-type and extension based on provided
 	 * file's extension and mime, or current file's extension and mime.
 	 *
@@ -316,6 +345,35 @@
 			$new_ext   = $file_ext;
 		}
 
+		/**
+		 * Filters the image editor output format mapping.
+		 *
+		 * Enables filtering the mime type used to save images. By default,
+		 * the mapping array is empty, so the mime type matches the source image.
+		 *
+		 * @see WP_Image_Editor::get_output_format()
+		 *
+		 * @since 5.8.0
+		 *
+		 * @param string[] $output_format {
+		 *     An array of mime type mappings. Maps a source mime type to a new
+		 *     destination mime type. Default empty array.
+		 *
+		 *     @type string ...$0 The new mime type.
+		 * }
+		 * @param string $filename  Path to the image.
+		 * @param string $mime_type The source image mime type.
+		 * }
+		 */
+		$output_format = apply_filters( 'image_editor_output_format', array(), $filename, $mime_type );
+
+		if ( isset( $output_format[ $mime_type ] )
+			&& $this->supports_mime_type( $output_format[ $mime_type ] )
+		) {
+			$mime_type = $output_format[ $mime_type ];
+			$new_ext   = $this->get_extension( $mime_type );
+		}
+
 		// Double-check that the mime-type selected is supported by the editor.
 		// If not, choose a default instead.
 		if ( ! $this->supports_mime_type( $mime_type ) ) {
@@ -332,13 +390,28 @@
 			$new_ext   = $this->get_extension( $mime_type );
 		}
 
-		if ( $filename ) {
+		// Ensure both $filename and $new_ext are not empty.
+		// $this->get_extension() returns false on error which would effectively remove the extension
+		// from $filename. That shouldn't happen, files without extensions are not supported.
+		if ( $filename && $new_ext ) {
 			$dir = pathinfo( $filename, PATHINFO_DIRNAME );
 			$ext = pathinfo( $filename, PATHINFO_EXTENSION );
 
 			$filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}";
 		}
 
+		if ( $mime_type && ( $mime_type !== $this->mime_type ) ) {
+			// The image will be converted when saving. Set the quality for the new mime-type if not already set.
+			if ( $mime_type !== $this->output_mime_type ) {
+				$this->output_mime_type = $mime_type;
+				$this->set_quality();
+			}
+		} elseif ( ! empty( $this->output_mime_type ) ) {
+			// Reset output_mime_type and quality.
+			$this->output_mime_type = null;
+			$this->set_quality();
+		}
+
 		return array( $filename, $new_ext, $mime_type );
 	}
 
@@ -365,9 +438,13 @@
 		$new_ext = strtolower( $extension ? $extension : $ext );
 
 		if ( ! is_null( $dest_path ) ) {
-			$_dest_path = realpath( $dest_path );
-			if ( $_dest_path ) {
-				$dir = $_dest_path;
+			if ( ! wp_is_stream( $dest_path ) ) {
+				$_dest_path = realpath( $dest_path );
+				if ( $_dest_path ) {
+					$dir = $_dest_path;
+				}
+			} else {
+				$dir = $dest_path;
 			}
 		}
 
@@ -545,13 +622,11 @@
 	 * @return string|false
 	 */
 	protected static function get_extension( $mime_type = null ) {
-		$extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) );
-
-		if ( empty( $extensions[0] ) ) {
+		if ( empty( $mime_type ) ) {
 			return false;
 		}
 
-		return $extensions[0];
+		return wp_get_default_extension_for_mime_type( $mime_type );
 	}
 }