diff --git a/src/wp-includes/class-wp-image-editor.php b/src/wp-includes/class-wp-image-editor.php index e7070b1ca6..fed0fc16e8 100644 --- a/src/wp-includes/class-wp-image-editor.php +++ b/src/wp-includes/class-wp-image-editor.php @@ -414,8 +414,8 @@ abstract class WP_Image_Editor { // 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(); } + $this->set_quality(); } elseif ( ! empty( $this->output_mime_type ) ) { // Reset output_mime_type and quality. $this->output_mime_type = null; diff --git a/tests/phpunit/tests/image/editor.php b/tests/phpunit/tests/image/editor.php index 487dad0664..be4591451d 100644 --- a/tests/phpunit/tests/image/editor.php +++ b/tests/phpunit/tests/image/editor.php @@ -105,9 +105,6 @@ class Tests_Image_Editor extends WP_Image_UnitTestCase { // Ensure wp_editor_set_quality filter applies if it exists before editor instantiation. $this->assertSame( 100, $editor->get_quality() ); - - // Clean up. - remove_filter( 'wp_editor_set_quality', $func_100_percent ); } /** @@ -119,18 +116,25 @@ class Tests_Image_Editor extends WP_Image_UnitTestCase { $editor = wp_get_image_editor( DIR_TESTDATA . '/images/test-image.png' ); $editor->set_mime_type( 'image/png' ); // Ensure mime-specific filters act properly. + // Quality setting for the source image. For PNG the fallback default of 82 is used. + $this->assertSame( 82, $editor->get_quality(), 'Default quality setting is 82.' ); + // Set conversions for uploaded images. add_filter( 'image_editor_output_format', array( $this, 'image_editor_output_formats' ) ); // Quality setting for the source image. For PNG the fallback default of 82 is used. $this->assertSame( 82, $editor->get_quality(), 'Default quality setting is 82.' ); - // Quality should change to the output format's value. - // A PNG image will be converted to WEBP whose quialty should be 86. + // When saving, quality should change to the output format's value. + // A PNG image will be converted to WebP whose quality should be 86. $editor->save(); - $this->assertSame( 86, $editor->get_quality(), 'Output image format is WEBP. Quality setting for it should be 86.' ); + $this->assertSame( 86, $editor->get_quality(), 'Output image format is WebP. Quality setting for it should be 86.' ); - // Removing PNG to WEBP conversion on save. Quality setting should reset to the default. + // Saving again should not change the quality. + $editor->save(); + $this->assertSame( 86, $editor->get_quality(), 'Output image format is WebP. Quality setting for it should be 86.' ); + + // Removing PNG to WebP conversion on save. Quality setting should reset to the default. remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_formats' ) ); $editor->save(); $this->assertSame( 82, $editor->get_quality(), 'After removing image conversion quality setting should reset to the default of 82.' ); @@ -149,9 +153,9 @@ class Tests_Image_Editor extends WP_Image_UnitTestCase { $this->assertSame( 56, $editor->get_quality(), 'Filtered default quality for JPEG is 56.' ); // Quality should change to the output format's value as filtered above. - // A JPEG image will be converted to WEBP whose quialty should be 42. + // A JPEG image will be converted to WebP whose quialty should be 42. $editor->save(); - $this->assertSame( 42, $editor->get_quality(), 'Image conversion from JPEG to WEBP. Filtered WEBP quality shoild be 42.' ); + $this->assertSame( 42, $editor->get_quality(), 'Image conversion from JPEG to WEBP. Filtered WEBP quality should be 42.' ); // After removing the conversion the quality setting should reset to the filtered value for the original image type, JPEG. remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_formats' ) ); @@ -161,8 +165,6 @@ class Tests_Image_Editor extends WP_Image_UnitTestCase { $editor->get_quality(), 'After removing image conversion the quality setting should reset to the filtered value for JPEG, 56.' ); - - remove_filter( 'wp_editor_set_quality', array( $this, 'image_editor_change_quality' ) ); } /** diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index 820da7ed3d..0d5ac75863 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -3621,6 +3621,97 @@ EOF; // Clean up the above filter. remove_filter( 'wp_omit_loading_attr_threshold', '__return_null', 100 ); } + + /** + * Test that generated files with the `image_editor_output_format` applied use the correct + * quality level based on their mime type. + * + * @ticket 56442 + */ + public function test_quality_with_image_conversion_file_sizes() { + add_filter( 'image_editor_output_format', array( $this, 'image_editor_output_jpeg' ) ); + $temp_dir = get_temp_dir(); + $file = $temp_dir . '/33772.jpg'; + copy( DIR_TESTDATA . '/images/33772.jpg', $file ); + + // Set JPEG output quality very low and WebP quality very high, this should force all generated WebP images to + // be larger than the the matching generated JPEGs. + add_filter( 'wp_editor_set_quality', array( $this, 'image_editor_change_quality_low_jpeg' ), 10, 2 ); + + $editor = wp_get_image_editor( $file ); + + // Verify that the selected editor supports WebP output. + if ( ! $editor->supports_mime_type( 'image/webp' ) ) { + $this->markTestSkipped( 'WebP is not supported by the selected image editor.' ); + } + + $attachment_id = self::factory()->attachment->create_object( + array( + 'post_mime_type' => 'image/jpeg', + 'file' => $file, + ) + ); + + add_filter( 'big_image_size_threshold', array( $this, 'add_big_image_size_threshold' ) ); + + // Generate all sizes as JPEGs. + $jpeg_sizes = wp_generate_attachment_metadata( $attachment_id, $file ); + remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_jpeg' ) ); + + // Generate all sizes as WebP. + add_filter( 'image_editor_output_format', array( $this, 'image_editor_output_webp' ) ); + $webp_sizes = wp_generate_attachment_metadata( $attachment_id, $file ); + remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_webp' ) ); + + // The main (scaled) image: the JPEG should be smaller than the WebP. + $this->assertLessThan( $webp_sizes['filesize'], $jpeg_sizes['filesize'], 'The JPEG should be smaller than the WebP.' ); + + // Sub-sizes: for each size, the JPEGs should be smaller than the WebP. + $sizes_to_compare = array_intersect_key( $jpeg_sizes['sizes'], $webp_sizes['sizes'] ); + foreach ( $sizes_to_compare as $size => $size_data ) { + $this->assertLessThan( $webp_sizes['sizes'][ $size ]['filesize'], $jpeg_sizes['sizes'][ $size ]['filesize'] ); + } + } + + /** + * Add threshold to create a `-scaled` output image for testing. + */ + public function add_big_image_size_threshold() { + return 1000; + } + + /** + * Output JPEG files. + */ + public function image_editor_output_jpeg() { + return array( 'image/jpeg' => 'image/jpeg' ); + } + + /** + * Output WebP files. + */ + public function image_editor_output_webp() { + return array( 'image/jpeg' => 'image/webp' ); + } + + /** + * Changes the quality using very low quality for JPEGs and very high quality + * for WebPs, used to verify the filter is applying correctly. + * + * @param int $quality Default quality. + * @param string $mime_type Image mime-type. + * @return int The changed quality. + */ + public function image_editor_change_quality_low_jpeg( $quality, $mime_type ) { + if ( 'image/jpeg' === $mime_type ) { + return 1; + } elseif ( 'image/webp' === $mime_type ) { + return 100; + } else { + return 30; + } + } + } /**