The question:
I wonder if there is a way to scale down uploaded media exactly to 50%.
From what I see, with add_image_size
you can only specify a width and a height in pixel.
The idea is to upload high resolution images for Retina displays and then let WordPress generate a custom image size scaled down for standard displays.
The best would be apply this to both the original image as well as all the others custom thumbnail generated.
Thanks for the help.
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 1
You can use image_downsize
filter and to catch when WordPress wants a downscaled image and not original, and actually a size what doesn’t exist.
add_filter( 'image_downsize', 'wpse_60890_retina_scale', 10, 3 );
function wpse_60890_retina_scale( $value, $id, $size ) {
if ( $size == 'wpse_60890_retina_scaled' ) {
if ( !is_array( $imagedata = wp_get_attachment_metadata( $id ) ) )
return false;
$img_url = wp_get_attachment_url( $id );
$img_url_basename = wp_basename( $img_url );
if ( isset( $imagedata['sizes']['wpse_60890_retina_scaled'] ) ) {
$intermediate = $imagedata['sizes']['wpse_60890_retina_scaled'];
$url = str_replace($img_url_basename, $intermediate['file'], $img_url);
return array( $url, $data['width'], $data['height'] );
}
$file = get_attached_file( $id );
$image = wp_load_image( $file );
if ( !is_resource( $image ) )
return new WP_Error( 'error_loading_image', $image, $file );
$size = @getimagesize( $file );
if ( !$size )
return new WP_Error( 'invalid_image', __('Could not read image size'), $file );
list( $orig_w, $orig_h, $orig_type ) = $size;
$max_w = round( $orig_w / 2 );
$max_h = round( $orig_h / 2 );
$resized = image_make_intermediate_size( $file, $max_w, $max_h );
$imagedata['sizes']['wpse_60890_retina_scaled'] = $resized;
wp_update_attachment_metadata( $id, $imagedata );
$url = str_replace($img_url_basename, $resized['file'], $img_url);
return array( $url, $resized['width'], $resized['height'] );
}
return $value;
}
Now you have to determine where you need full size or scaled by 50%.
For example you have
echo 'full size:' . wp_get_attachment_image( $attachment->ID, 'full' );
echo 'scaled by 50%: ' . wp_get_attachment_image( $attachment->ID, 'wpse_60890_retina_scaled' );
Method 2
I could not use @nvartolomei solution the way it was. It was not functional but still a good starting point.
Here is my final solution:
I add 3 new image sizes
by doubling the original 3 sizes.
- large_retina
- medium_retina
- thumbnail_retina
Then I put filter when you call them in PHP in order to replace with
and height
by their non retina equivalent (since it’s not always about dividing by 2).
- original : src=
image.jpg
width=4800
height=4000
- large(600×600) : src=
image-600x500.jpg
width=600
height=500
-
large_retina(600×600) : src=
image-1200x1000.jpg
width=600
height=500
-
original : src=
image.jpg
width=900
height=750
- large(600×600) : src=
image-600x500.jpg
width=600
height=500
- large_retina(600×600) : src=
image.jpg
width=600
height=500
function.php:
add_action( 'init', 'cjg_register_sizes' );
add_filter( 'image_downsize', 'cjg_retina_scale', 10, 3 );
function cjg_register_sizes(){
add_image_size( 'large_retina', get_option( 'large_size_w' ) * 2 , get_option( 'large_size_h' ) * 2 );
add_image_size( 'medium_retina', get_option( 'medium_size_w' ) * 2 , get_option( 'medium_size_h' ) * 2 );
add_image_size( 'thumbnail_retina', get_option( 'thumbnail_size_w' ) * 2 , get_option( 'thumbnail_size_h' ) * 2 );
}
function cjg_retina_scale( $value, $id, $size ) {
if ( $size == 'large_retina' OR $size == 'medium_retina' OR $size == 'thumbnail_retina' ) {
if ( !is_array( $imagedata = wp_get_attachment_metadata( $id ) ) )
return false;
if ( $size == 'large_retina') $regular_size = 'large';
elseif ( $size == 'medium_retina') $regular_size = 'medium';
else $regular_size = 'thumbnail';
$img_url = wp_get_attachment_url( $id );
$img_url_basename = wp_basename( $img_url );
if ( isset( $imagedata['sizes'][$regular_size] ) ) {
$width = $imagedata['sizes'][$regular_size]['width'];
$height = $imagedata['sizes'][$regular_size]['height'];
if ( isset( $imagedata['sizes'][$size] ) )
$url = str_replace($img_url_basename, $imagedata['sizes'][$size]['file'], $img_url);
else
$url = $img_url;
}else{
$url = $img_url;
$width = $imagedata['width'];
$height = $imagedata['height'];
}
return array( $url, $width, $height );
}
return $value;
}
Now you can just call your images this way
wp_get_attachment_image( $attachment->ID, 'thumbnail_retina' );
wp_get_attachment_image( $attachment->ID, 'medium_retina' );
wp_get_attachment_image( $attachment->ID, 'large_retina' );
Important: after adding the 3 new sizes, I regenerated all thumbnails with the regenerate-thumbnails plugin
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0