I have a custom image size hello-image
:
add_image_size( 'hello-image', 700, 300, true );
Whenever an image is uploaded, I compress the cropped hello-image
sized image to 40%
JPEG compression. It works great in all cases except...
The problem
If the width of the original image is greater than 700px
it works just fine. But if the width of it is less than 700px
, the compression goes to around 0%
.
How to test it
Download the following two images:
Then I have created a plugin which has all the relevant code:
<?php
/*
Plugin Name: WPSE: custom image size and JPEG compression
Description: custom image size and JPEG compression
Author: WPSE
Version: 1.0
*/
// Set JPEG compression quality
add_filter('jpeg_quality', create_function('$quality', 'return 100;'));
add_action('added_post_meta', 'ad_update_jpeg_quality', 10, 4);
function ad_update_jpeg_quality($meta_id, $attach_id, $meta_key, $attach_meta) {
if ($meta_key == '_wp_attachment_metadata') {
$post = get_post($attach_id);
if ($post->post_mime_type == 'image/jpeg' && is_array($attach_meta['sizes'])) {
$pathinfo = pathinfo($attach_meta['file']);
$uploads = wp_upload_dir();
$dir = $uploads['basedir'] . '/' . $pathinfo['dirname'];
foreach ($attach_meta['sizes'] as $size => $value) {
$image = $dir . '/' . $value['file'];
$resource = imagecreatefromjpeg($image);
if ($size == 'large') {
// set the jpeg quality for 'large' size
imagejpeg($resource, $image, 35);
} elseif ($size == 'medium') {
// set the jpeg quality for the 'medium' size
imagejpeg($resource, $image, 35);
} elseif ($size == 'hello-image') {
// set the jpeg quality for the 'hello-image' size
imagejpeg($resource, $image, 40);
} else {
// set the jpeg quality for the rest of sizes
imagejpeg($resource, $image, 35); // 38
}
imagedestroy($resource);
}
}
}
}
// add custom image sizes to media uploader
function my_insert_custom_image_sizes( $sizes ) {
// get the custom image sizes
global $_wp_additional_image_sizes;
// if there are none, just return the built-in sizes
if ( empty( $_wp_additional_image_sizes ) )
return $sizes;
// add all the custom sizes to the built-in sizes
foreach ( $_wp_additional_image_sizes as $id => $data ) {
// take the size ID (e.g., 'my-name'), replace hyphens with spaces,
// and capitalise the first letter of each word
if ( !isset($sizes[$id]) )
$sizes[$id] = ucfirst( str_replace( '-', ' ', $id ) );
}
return $sizes;
}
// Which custom image size selected by default
function my_set_default_image_size () {
return 'hello-image';
}
function custom_image_setup () {
// custom image sizes
add_image_size( 'medium', 300, 9999 ); // medium
add_image_size( 'hello-image', 700, 300, true ); // custom
add_image_size( 'large', 700, 3000 ); // large
add_filter( 'image_size_names_choose', 'my_insert_custom_image_sizes' );
add_filter( 'pre_option_image_default_size', 'my_set_default_image_size' );
}
add_action( 'after_setup_theme', 'custom_image_setup' );
Now, upload the big image and see how the hello-image
image is compressed fine. Then upload the small image and see how the same image size is compressed terribly. So to clarify, this is the results:
700x300 = 40% compression
670x300 = 0% compression
Both of which are generated via the exact same custom image size. What is the cause of this and how can it be fixed?
I should highlight that my colleague posted a question here asking how to avoid creating this image size if the width is lower than 700px
... but I'm a WordPress geek who would rather resolve the cause of the problem than add a hacky fix to it.
Finally, I started seeing this problem in a recent WordPress update, so it may be a bug in core, as opposed to an issue in my code.
Edit: Read the update.