Media: ensure the wp_editor_set_quality filter consistently passes the correct output mime type.

Ensure that the mime type passed to the `wp_editor_set_quality` filter is correct when the output format is altered with the `image_editor_output_format` filter and the image is saved multiple times, for example when generating sub sizes. Previously, the original image mime type was passed instead of the output type after the initial save.

Props flixos90, peterwilsoncc.
Fixes #56442.




git-svn-id: https://develop.svn.wordpress.org/trunk@54417 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Adam Silverstein 2022-10-07 19:15:59 +00:00
parent 72a43bca8f
commit 16f127dff7
3 changed files with 105 additions and 12 deletions

View File

@ -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;

View File

@ -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' ) );
}
/**

View File

@ -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;
}
}
}
/**