In general I wouldn't recommend modifying the original uploaded image files, just in case we might need to re-generate intermediate sizes.
But let's see if it's possible :-)
We can in general let WordPress choose the image editor, that depends on modules like GD or Imagick, through:
$editor = wp_get_image_editor( $file );
but this can return an WP_Error
object, so we better check it with is_wp_error( $editor )
before using it.
It's useful to let the image editor handle things through methods like set_quality()
and save()
. We can see such an usage example in the Resize Image After Upload plugin, mentioned by @MerchantWeb. This is also used by the core in various ways.
The plugin hooks into the wp_handle_upload
filter to modify the original uploaded jpeg image files, as far as I understand it.
We could therefore use something like the following, to modify the quality of the original jpeg image file to e.g. 90%:
/**
* A) Modify the quality of original jpeg images to 90%
*/
add_filter( 'wp_handle_upload', function( $data )
{
if( ! isset( $data['file'] ) || ! isset( $data['type'] ) )
return $data;
// Target jpeg images
if( in_array( $data['type'], [ 'image/jpg', 'image/jpeg' ] ) )
{
// Check for a valid image editor
$editor = wp_get_image_editor( $data['file'] );
if( ! is_wp_error( $editor ) )
{
// Set the new image quality
$result = $editor->set_quality( 90 );
// Re-save the original image file
if( ! is_wp_error( $result ) )
$editor->save( $data['file'] );
}
}
return $data;
} );
but it looks to me that this will also affect all the intermediate sizes, because this runs before they are generated.
If we take a look at the media_handle_upload()
function, we might consider hooking into the wp_generate_attachment_metadata
filter instead, to modify the original jpeg image file, after the intermediate sizes have been generated?
Here's an example (PHP 5.4+):
/**
* B) Modify the quality of original jpeg images to 90%
*/
add_filter( 'wp_generate_attachment_metadata', function( $metadata, $attachment_id )
{
$file = get_attached_file( $attachment_id );
$type = get_post_mime_type( $attachment_id );
// Target jpeg images
if( in_array( $type, [ 'image/jpg', 'image/jpeg' ] ) )
{
// Check for a valid image editor
$editor = wp_get_image_editor( $file );
if( ! is_wp_error( $editor ) )
{
// Set the new image quality
$result = $editor->set_quality( 90 );
// Re-save the original image file
if( ! is_wp_error( $result ) )
$editor->save( $file );
}
}
return $metadata;
}, 10, 2 );
If we needed to restrict this further, we might wrap this into the wp_handle_upload
hook as well and check for the relevant action context, like wp_handle_upload or sideload.
We might also need to set the quality very low while testing, just to see if it worked ;-)
Note: These are only demos, that would need further testing.
Update: Just did some simple testing. Here we can see that when the full size image is re-saved at %1 quality then all the intermediate sizes (300x200 and 150x150) in:
- A) are also at low quality.
- B) are not affected.