How to reduce original image quality on upload?

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.

A) We could therefore use something like the following, to modify the quality of the original jpeg image file (to e.g. 90) during uploads:

/**
 * A) Modify the quality of original jpeg images to 90, during uploads
 */
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.

B) 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, during uploads
 */
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 with an image of our kitchen wall clock. Here we can see that when the full size image is re-saved, with quality 5, then all the intermediate sizes:

  • A) are also at low quality.
  • B) are not affected.

Here are the combined results:

a

b

Leave a Comment