wp/wp-admin/includes/image.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
--- a/wp/wp-admin/includes/image.php	Fri Sep 05 18:40:08 2025 +0200
+++ b/wp/wp-admin/includes/image.php	Fri Sep 05 18:52:52 2025 +0200
@@ -261,101 +261,128 @@
 		$image_meta['image_meta'] = $exif_meta;
 	}
 
-	// Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
-	if ( 'image/png' !== $imagesize['mime'] ) {
+	/**
+	 * Filters the "BIG image" threshold value.
+	 *
+	 * If the original image width or height is above the threshold, it will be scaled down. The threshold is
+	 * used as max width and max height. The scaled down image will be used as the largest available size, including
+	 * the `_wp_attached_file` post meta value.
+	 *
+	 * Returning `false` from the filter callback will disable the scaling.
+	 *
+	 * @since 5.3.0
+	 *
+	 * @param int    $threshold     The threshold value in pixels. Default 2560.
+	 * @param array  $imagesize     {
+	 *     Indexed array of the image width and height in pixels.
+	 *
+	 *     @type int $0 The image width.
+	 *     @type int $1 The image height.
+	 * }
+	 * @param string $file          Full path to the uploaded image file.
+	 * @param int    $attachment_id Attachment post ID.
+	 */
+	$threshold = (int) apply_filters( 'big_image_size_threshold', 2560, $imagesize, $file, $attachment_id );
+
+	/*
+	 * If the original image's dimensions are over the threshold,
+	 * scale the image and use it as the "full" size.
+	 */
+	$scale_down = false;
+	$convert    = false;
+
+	if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) {
+		// The image will be converted if needed on saving.
+		$scale_down = true;
+	} else {
+		// The image may need to be converted regardless of its dimensions.
+		$output_format = wp_get_image_editor_output_format( $file, $imagesize['mime'] );
 
-		/**
-		 * Filters the "BIG image" threshold value.
-		 *
-		 * If the original image width or height is above the threshold, it will be scaled down. The threshold is
-		 * used as max width and max height. The scaled down image will be used as the largest available size, including
-		 * the `_wp_attached_file` post meta value.
-		 *
-		 * Returning `false` from the filter callback will disable the scaling.
-		 *
-		 * @since 5.3.0
-		 *
-		 * @param int    $threshold     The threshold value in pixels. Default 2560.
-		 * @param array  $imagesize     {
-		 *     Indexed array of the image width and height in pixels.
-		 *
-		 *     @type int $0 The image width.
-		 *     @type int $1 The image height.
-		 * }
-		 * @param string $file          Full path to the uploaded image file.
-		 * @param int    $attachment_id Attachment post ID.
-		 */
-		$threshold = (int) apply_filters( 'big_image_size_threshold', 2560, $imagesize, $file, $attachment_id );
+		if (
+			is_array( $output_format ) &&
+			array_key_exists( $imagesize['mime'], $output_format ) &&
+			$output_format[ $imagesize['mime'] ] !== $imagesize['mime']
+		) {
+			$convert = true;
+		}
+	}
+
+	if ( $scale_down || $convert ) {
+		$editor = wp_get_image_editor( $file );
+
+		if ( is_wp_error( $editor ) ) {
+			// This image cannot be edited.
+			return $image_meta;
+		}
 
-		/*
-		 * If the original image's dimensions are over the threshold,
-		 * scale the image and use it as the "full" size.
-		 */
-		if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) {
-			$editor = wp_get_image_editor( $file );
+		if ( $scale_down ) {
+			// Resize the image. This will also convet it if needed.
+			$resized = $editor->resize( $threshold, $threshold );
+		} elseif ( $convert ) {
+			// The image will be converted (if possible) when saved.
+			$resized = true;
+		}
+
+		$rotated = null;
 
-			if ( is_wp_error( $editor ) ) {
-				// This image cannot be edited.
-				return $image_meta;
+		// If there is EXIF data, rotate according to EXIF Orientation.
+		if ( ! is_wp_error( $resized ) && is_array( $exif_meta ) ) {
+			$resized = $editor->maybe_exif_rotate();
+			$rotated = $resized; // bool true or WP_Error
+		}
+
+		if ( ! is_wp_error( $resized ) ) {
+			/*
+			 * Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
+			 * This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
+			 */
+			if ( $scale_down ) {
+				$saved = $editor->save( $editor->generate_filename( 'scaled' ) );
+			} elseif ( $convert ) {
+				// Pass an empty string to avoid adding a suffix to converted file names.
+				$saved = $editor->save( $editor->generate_filename( '' ) );
+			} else {
+				$saved = $editor->save();
 			}
 
-			// Resize the image.
-			$resized = $editor->resize( $threshold, $threshold );
-			$rotated = null;
-
-			// If there is EXIF data, rotate according to EXIF Orientation.
-			if ( ! is_wp_error( $resized ) && is_array( $exif_meta ) ) {
-				$resized = $editor->maybe_exif_rotate();
-				$rotated = $resized;
-			}
+			if ( ! is_wp_error( $saved ) ) {
+				$image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
 
-			if ( ! is_wp_error( $resized ) ) {
-				/*
-				 * Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
-				 * This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
-				 */
-				$saved = $editor->save( $editor->generate_filename( 'scaled' ) );
-
-				if ( ! is_wp_error( $saved ) ) {
-					$image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
-
-					// If the image was rotated update the stored EXIF data.
-					if ( true === $rotated && ! empty( $image_meta['image_meta']['orientation'] ) ) {
-						$image_meta['image_meta']['orientation'] = 1;
-					}
-				} else {
-					// TODO: Log errors.
+				// If the image was rotated update the stored EXIF data.
+				if ( true === $rotated && ! empty( $image_meta['image_meta']['orientation'] ) ) {
+					$image_meta['image_meta']['orientation'] = 1;
 				}
 			} else {
 				// TODO: Log errors.
 			}
-		} elseif ( ! empty( $exif_meta['orientation'] ) && 1 !== (int) $exif_meta['orientation'] ) {
-			// Rotate the whole original image if there is EXIF data and "orientation" is not 1.
-
-			$editor = wp_get_image_editor( $file );
+		} else {
+			// TODO: Log errors.
+		}
+	} elseif ( ! empty( $exif_meta['orientation'] ) && 1 !== (int) $exif_meta['orientation'] ) {
+		// Rotate the whole original image if there is EXIF data and "orientation" is not 1.
+		$editor = wp_get_image_editor( $file );
 
-			if ( is_wp_error( $editor ) ) {
-				// This image cannot be edited.
-				return $image_meta;
-			}
-
-			// Rotate the image.
-			$rotated = $editor->maybe_exif_rotate();
+		if ( is_wp_error( $editor ) ) {
+			// This image cannot be edited.
+			return $image_meta;
+		}
 
-			if ( true === $rotated ) {
-				// Append `-rotated` to the image file name.
-				$saved = $editor->save( $editor->generate_filename( 'rotated' ) );
+		// Rotate the image.
+		$rotated = $editor->maybe_exif_rotate();
 
-				if ( ! is_wp_error( $saved ) ) {
-					$image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
+		if ( true === $rotated ) {
+			// Append `-rotated` to the image file name.
+			$saved = $editor->save( $editor->generate_filename( 'rotated' ) );
 
-					// Update the stored EXIF data.
-					if ( ! empty( $image_meta['image_meta']['orientation'] ) ) {
-						$image_meta['image_meta']['orientation'] = 1;
-					}
-				} else {
-					// TODO: Log errors.
+			if ( ! is_wp_error( $saved ) ) {
+				$image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );
+
+				// Update the stored EXIF data.
+				if ( ! empty( $image_meta['image_meta']['orientation'] ) ) {
+					$image_meta['image_meta']['orientation'] = 1;
 				}
+			} else {
+				// TODO: Log errors.
 			}
 		}
 	}
@@ -543,6 +570,7 @@
  *
  * @since 2.1.0
  * @since 6.0.0 The `$filesize` value was added to the returned array.
+ * @since 6.7.0 The 'image/heic' mime type is supported.
  *
  * @param int    $attachment_id Attachment ID to process.
  * @param string $file          Filepath of the attached image.
@@ -555,7 +583,7 @@
 	$support   = false;
 	$mime_type = get_post_mime_type( $attachment );
 
-	if ( preg_match( '!^image/!', $mime_type ) && file_is_displayable_image( $file ) ) {
+	if ( 'image/heic' === $mime_type || ( preg_match( '!^image/!', $mime_type ) && file_is_displayable_image( $file ) ) ) {
 		// Make thumbnails and other intermediate sizes.
 		$metadata = wp_create_image_subsizes( $file, $attachment_id );
 	} elseif ( wp_attachment_is( 'video', $attachment ) ) {