WordPress - 上传时模糊图片

10

我正在遵循这里给出的示例(我修改了它只模糊,没有水印),在WordPress上传时制作一个模糊图像。问题是,如果上传的文件与设定的尺寸完全相同或更小,则WordPress将不会生成图像,因此也不会生成任何模糊的图像。

我尝试使用isset($meta['sizes']['background-image-blurred']['file'])来确定是否已生成图像,如果没有,则copy()源文件,但是这样就不会为图像生成任何WordPress“元数据”(对于非WordPress人员,元数据与您想象的不同),所以在使用wp_get_attachment_image显示时,它将产生高度/宽度未定义的问题。

因此,我确信使用如下所示的wp_get_attachment_image挂钩可能是错误的方法。它可能需要在图像上传过程中较早发生。

有什么好的方法可以让它正常工作吗?

/**
 * Several functions relatting to blurring images on uploaded.
 * @see https://codeable.io/community/how-to-watermark-wordpress-images-with-imagemagick/
 */ 
    add_image_size( 'background-image-blurred', 1920, 1080, true );

    function generate_blurred_image( $meta ) {

      $time = substr( $meta['file'], 0, 7); // Extract the date in form "2015/04"
      $upload_dir = wp_upload_dir( $time ); // Get the "proper" upload dir

      $filename = $meta['sizes']['background-image-blurred']['file'];
      $meta['sizes']['background-image-blurred']['file'] = blur_image( $filename, $upload_dir );

      return $meta;

    }
    add_filter( 'wp_generate_attachment_metadata', 'generate_blurred_image' );    

    function blur_image( $filename, $upload_dir ) {

      $original_image_path = trailingslashit( $upload_dir['path'] ) . $filename;

      $image_resource = new Imagick( $original_image_path );
      $image_resource->gaussianBlurImage( 10, 100 ); // See: http://phpimagick.com/Imagick/gaussianBlurImage

      return save_blurred_image( $image_resource, $original_image_path );

    }    

    function save_blurred_image( $image_resource, $original_image_path ) {

      $image_data = pathinfo( $original_image_path );

      $new_filename = $image_data['filename'] . '-blurred.' . $image_data['extension'];

      // Build path to new blurred image
      $blurred_image_path = str_replace($image_data['basename'], $new_filename, $original_image_path);

      if ( ! $image_resource->writeImage( $blurred_image_path ) ) {
        return $image_data['basename'];          
      }

      // Delete the placeholder image WordPress made now that it's been blurred
      unlink( $original_image_path );

      return $new_filename;

    }    

顺便提一下,它必须是服务器端模糊。我尝试了CSS/SVG/JS模糊,但考虑到我正在进行的所有其他动画,这些方法都不够高效。 - Drew Baker
问题在于,如果上传的文件大小与设置的大小相同或更小,则我不确定是否理解正确,您是要替换现有的图像吗? - vard
不,我正在尝试生成上传文件的新模糊版本。该评论所涉及的是只有在生成新版本时才会调用wp_generate_attachment_metadata(如果大小太小或相同,则不会生成任何新内容)。 - Drew Baker
6个回答

4

不幸的是,WordPress没有强制大小的过滤器,所以您可以在之后挂钩并调整图像大小(如果未创建),然后将其放入元数据中。

我没有安装imagick,所以您需要自己尝试这些函数,但是您已经掌握了正确的流程,只需更新下面数组中的文件名和类型即可。请勿在过滤器内输出任何内容!

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;

}

更新

  1. 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.

  2. 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

  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;
    }
    

更新为了防止图像拉伸小图像,请将imagick代码替换为以下代码。

$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

你觉得缺少什么,我来看看? - David
我不确定 Imagick 代码需要放在哪里,而且图片并不总是 image/jpeg 对吧?你正在硬编码高度/宽度为 1920x1080,但它可能不会始终是这样的(同时在文件名中添加 -1200x1080)。另外,我认为 wp_generate_attachment_metadata 过滤器是在元数据创建后运行的,因此新的模糊图像将无法正确地将其元数据添加到数据库中(我想,我需要测试一下)。 - Drew Baker
我认为问题在于硬编码的1920x1080。那个尺寸应该是“最大”的,但它应该能够更小,如果比它更大就裁剪一下,但始终生成一个模糊版本,并保留未模糊和模糊的两个版本。 - Drew Baker
我稍后会看一下,但我认为你的意思是如果图像大于尺寸,则裁剪,如果小于则不需要运行该函数?我将更新该函数以将尺寸添加到文件名中,这将解决404问题。你说得对,unlink函数会删除原始文件。 - David
它应该始终生成一个模糊的图像。但有时图像大小不会是 1920x1080。如果源图像是 612x433,则应该生成一个 612x433 的模糊图像,并保留源图像。 - Drew Baker
显示剩余10条评论

1
当我第一次阅读您的问题时,我不确定您是在设置图像还是生成图像或两者都有问题。我认为设置图像的问题可能是您需要在使用wp_generate_attachment_metadata后使用wp_update_attachment_metadata更新帖子图像,以便帖子使用新图像。
当我重新阅读您的问题时,我意识到这必须是与add_image_size()有关,因为它会发生在与上传的图像相同大小或更小的图像上。我曾经遇到过这个问题,因为(重新)为新主题生成备用大小图像。在我的情况下,要么宽度参数,要么高度参数未满足于add_image_size()
我想在Wordpress Code Reference中验证这一点,并在底部找到了一个贡献者的评论,这正是您面临的问题,尽管没有发布解决方案。
如果您上传的图像尺寸与设置crop为true的add_image_size()匹配,在通过wp_generate_attachment_metadata过滤器访问的$meta对象中,该匹配图像大小将不可用。此外,具有比上传的照片更大尺寸的图像大小也将不可用。(因此,如果您正在使用创建类似单色派生图像的技术,则如果上传的图像与您用于黑白版本的图像大小完全相同,则无法使其起作用)。
我认为在您的情况下有一个解决方法,因为您正在使用Imagick,可以执行一些图像数学运算。只需使用borderImage函数向每个图像添加边框,直到比您上传的图像大1像素为止。由于add_image_size()默认从中心裁剪,因此应该触发所需大小的调整并解决问题。
例如,您想要1920 x 1080的尺寸。使用Imagick的getSize函数可以检查图像的大小。假设它恰好是1920 x 1080,但我们知道这不会触发模糊效果。因此,使用borderImage函数为图像添加一个1像素的白色边框。只要将裁剪设置为true,这应该会触发wordpress将图像调整为1920 x 1080的大小。
如果图像比所需尺寸小,但相对接近,则我们只需将边框设置为10个像素等来填补空白,并让wordpress从中心进行裁剪。这仅适用于比例图像。

如果图像较小,比如200 x 800,我们应该考虑添加一个不同的add_image_size()选项来处理较小的图像。如果您需要继续前进,那么我们可以使用Imagick来“扩展”我们的图像到所需的比例,或者我们可以创建一个新的白色Imagick画布,大小为我们所需的大小,并将图像覆盖到左上角,使我们的新图像下方和右侧留有空白。然后,您将使用add_image_size裁剪参数来切掉多余的白色。例如,add_image_size('background-image-blurred',1920,1080,array('left','top'))以从图像的左上角开始设置裁剪。


好主意,但我认为这样做只是为了绕过一些WordPress的限制而创造了很多步骤。我为你的努力点赞! - Drew Baker

0
一个超出常规的建议:既然你只是模糊图像而不对图像进行其他更改,为什么不让CSS来完成这项工作,而不是在服务器上创建另一张图像呢?
.heroBackgroundImage {
    background: url('uploadedimage.jpg'); 
    -webkit-filter: blur(8px);
    -moz-filter: blur(8px); 
    -o-filter: blur(8px); 
    -ms-filter: blur(8px); 
    filter: blur(8px);
    -webkit-transform: translate3d(0,0,0);
}

减轻服务器的负担,让客户端处理。

编辑:刚看到您的评论,不能使用CSS。添加webkit-transform将效果移动到GPU上,使其更有效地渲染。否则,仍然为后世保存。


0

我认为你需要稍微做一些手脚,为什么不尝试使用大小为1 x 15 X 5的图像,这样每次无论图像如何,都会生成该图像的缩略图。

并在'wp_generate_attachment_metadata'中对其进行处理,从原始图像生成图像,并用所需的模糊图像替换1 x 1图像。当然,在使用'background-image-blurred'进行显示或其他计算目的时,您需要在过滤器上进行调整。

希望你明白了我的想法,我认为这有点像黑客攻击,但应该能正常工作。


0

是的,好建议。你知道 wp_handle_upload 是否在 wp_generate_attachment_metadata 之前被调用了吗? - Drew Baker
如果您使用 wp_handle_upload() 上传原始图像......对其进行模糊处理......然后在模糊的图像上调用 wp_generate_attachment_metadata,会发生什么? - webguy
你试过我的建议了吗? - webguy
一直在尝试,但很难将其翻译到我的情况中(作为所有上传的过滤器)。这并不是一个直接的答案,更像是一个建议,有帮助但我希望得到更详细的回答。 - Drew Baker

0

您所提到的示例使用了WordPress过滤器。

问题在于:WordPress过滤器始终绑定到特定的图像分辨率,因此无论其分辨率如何,您都无法处理该图像。

我的建议是避免使用过滤器。相反,在更早的时间点预处理图像。请查看下面的示例代码,它将在交给WordPress控制之前最初模糊图像:

    // perform new upload
    include_once( ABSPATH . 'wp-admin/includes/image.php' );
    $imagetype = end(explode('/', getimagesize($imageurl)['mime']));
    $uniq_name = date('dmY').''.(int) microtime(true); 
    $filename = $uniq_name.'.'.$imagetype;

    $uploaddir = wp_upload_dir();
    $uploadfile = $uploaddir['path'] . '/' . $filename;
    $contents= file_get_contents($imageurl);
    $savefile = fopen($uploadfile, 'w');
    fwrite($savefile, $contents);
    fclose($savefile);

    // apply blur
    $image_resource = new Imagick( $uploadfile );
    $image_resource->resizeImage(500, 500, null, 1);
    $image_resource->blurImage( 40, 20 );
    $image_data = pathinfo( $uploadfile );

    $new_filename = $image_data['filename'] . '-blur.' . $image_data['extension'];
    $blur_image_path = str_replace($image_data['basename'], $new_filename, $uploadfile);
    if ( ! $image_resource->writeImage( $blur_image_path ) ) {
        unlink( $uploadfile );
        return ""; // fixme
    }

    unlink( $uploadfile );

    $wp_filetype = wp_check_filetype(basename($filename), null );
    $attachment = array(
        'post_mime_type' => $wp_filetype['type'],
        'post_title' => $imageurlHash,
        'post_content' => '',
        'post_status' => 'inherit'
    );

    $attach_id = wp_insert_attachment( $attachment, $blur_image_path );
    $imagenew = get_post( $attach_id );
    $fullsizepath = get_attached_file( $imagenew->ID );
    $attach_data = wp_generate_attachment_metadata( $attach_id, $fullsizepath );
    wp_update_attachment_metadata( $attach_id, $attach_data ); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接