WordPress - Blur Image on Upload
When I was first reading your question I was unsure if you were having problems setting the image or generating the image or both. I thought the issue with setting the image might be that you needed to update the post image with wp_update_attachment_metadata
after using wp_generate_attachment_metadata
to have the post use the new image instead.
When I reread your question I realized it had to be an issue with the add_image_size()
because it happens with an image the same size or smaller than the one uploaded. I had once run into this issue as well with (re)generating an alternate size image for a new theme. In my case it was that either the width or the height parameter was not being met on add_image_size()
.
I wanted to verify this in the Wordpress Code Reference and found a comment by a contributor near the bottom that is exactly the same issue you face, albeit without a solution posted.
If you upload an image whose dimensions match the add_image_size() when crop is set to true, in the $meta object accessed by the wp_generate_attachment_metadata filter, that matching image size will not be available. Also, image sizes that have larger dimensions than an uploaded photo will not be available either.
(Thus if you are using a technique to create something like a monochrome derivative image, you won’t be able to get it to work if the uploaded image is exactly the same size as the image size you’re using for your black and white version).
I think in your case there is a workaround solution since you are using Imagick, in the fact that you can do some image math. Using the borderImage
function simply add a border to each image up to 1 pixel larger than the image you have uploaded. Since the add_image_size()
crops from center by default that should trigger the resize to the size you need and solve the issue.
For example you want dimensions of 1920 x 1080. Using Imagick getSize
you can check the size of the image. Lets say it is exactly 1920 x 1080, but as we know this will not trigger the blur. So using borderImage
we add a 1 pixel white border to the image. This should trigger wordpress to resize the image to 1920 x 1080 as long as crop is set to true.
If the image is smaller but relatively close to the needed size we just make the border lets say 10 pixels and so on to fill in the size, and let wordpress crop from center. This will work with proportional images only.
If the image is a good bit smaller, lets say 200 x 800, we should consider adding a different add_image_size()
option to handle smaller images. If you need to forge ahead then we can either use Imagick to "expand" our image to the needed proportions OR we can create a new white Imagick canvas the size we need and overlay the image to top left such that we have whitespace below and to the right of our new image. You would then use the add_image_size crop parameter to cutoff the excess white. For example, add_image_size('background-image-blurred', 1920, 1080, array('left','top'))
to set the crop starting from the top left of the image.
Unfortunately wp hasn't got a filter to force a size so what you can do is hook in after and resize your image if not created and pop it into the metadata.
I haven't got imagick so you will have to try these functions yourself, but you have the correct process above, you just need to update the filename and type in the array below. PS don't output anything within the filter!
function custom_img_size(){
add_image_size( 'background-image-blurred', 1920, 1080, true );
}
add_action( 'after_setup_theme', 'custom_img_size' );
add_filter('wp_generate_attachment_metadata', 'force_add_size', 100);
function force_add_size( $metadata ) {
if(!isset($metadata['sizes']['background-image-blurred'])){
//not set so initiate our custom size...
//I dont have imagick installed so just use your functions here to duplicate
//note original file = $filename update the $newfilename below...
//sample resize code ...
$upload_dir = wp_upload_dir();
$filename= $upload_dir['basedir'].'/'.$metadata['file'];
$extension = strtolower(strrchr($metadata['file'], '.'));
$newfilename= str_replace($extension, '-1200x1080', $filename).$extension;
copy($filename, $newfilename );
//end sample resize code.....
$filetype= 'image/jpeg';
$metadata['sizes']['background-image-blurred']= array(
"file"=> $newfilename,
"width"=> 1920,
"height"=> 1080,
"mime-type"=> $filetype
);
}
return $metadata;
}
Updates
This is designed to only catch where your existing filter has failed to create your blurred custom size otherwise it does nothing. You should still include your original filters. You may have an issue in the original code: You are deleting the original file in your filters and this will cause issues as there is a postmeta field called '_wp_attached_file' that will need updating. I have included a note below on this.
The filter catches the metadata before saving so any changes are also going to be saved once you return the $metadata. If you look at the source code: https://core.trac.wordpress.org/browser/tags/3.8.1/src/wp-admin/includes/image.php#L72 here you can see exactly how it works. I've also confirmed using wp4.3
I have attempted to insert the imagick functions you need below. I havent tested as i dont actually have it installed anywhere. (imagemagick is actually a wonderful opensource program but very server intensive). Try this function in place of the one above:
add_filter('wp_generate_attachment_metadata', 'force_add_size', 100, 2); function force_add_size( $metadata, $id ){ $upload_dir = wp_upload_dir(); $filename= $upload_dir['basedir'].'/'.$metadata['file']; $extension = strtolower(strrchr($metadata['file'], '.')); $newfilename= str_replace($extension, '-blurred', $filename).$extension; $image_resource = new Imagick( $filename); $image_resource->resizeImage(1920,1080,Imagick::FILTER_LANCZOS,.3); $image_resource->writeImage( $newfilename ); //http://www.dylanbeattie.net/magick/filters/result.html unlink( $filename );//delete original image altogether ---> you might want to update the post meta on this '_wp_attached_file' , you can actually get the attachment id from the filter, i have added it above. It would be best to have a actual image url in there! something like $sfile= str_replace($upload_dir['basedir'],'', $newfilename); update_post_meta($id, '_wp_attached_file', $sfile ); switch($extension){ case '.jpg': case '.jpeg': $type = 'image/jpeg'; break; case '.gif': $type = 'image/gif'; break; case '.png': $type = 'image/png'; break; default: $type = 'image/jpeg'; // you might want a conditional to check its actually a image...imagick will do this for you as well....it shouldnt get this far if not a image. break; } $metadata['sizes']['background-image-blurred']= array( "file"=> $newfilename, "width"=> 1920,//your custom image size, has to be this! you could get the global var and check for sizes but its this size in particular we want? "height"=> 1080, "mime-type"=> $type ); return $metadata; }
update to prevent the image stretching out smaller images replace the imagick code with this.
$upload_dir = wp_upload_dir();
$filename= $upload_dir['basedir'].'/'.$metadata['file'];
$extension = strtolower(strrchr($metadata['file'], '.'));
$newfilename= str_replace($extension, '-blurred', $filename).$extension;
$image_resource = new Imagick( $filename);
if($image_resource->getImageWidth() <= 1920 || $image_resource->getImageHeight() > <= 1020) {
return $metadata;
}
$image_resource->resizeImage(1920,1080,Imagick::FILTER_LANCZOS,.3);
$image_resource->writeImage( $newfilename );
//http://www.dylanbeattie.net/magick/filters/result.html