WordPress - 上传时模糊图像

Posted

技术标签:

【中文标题】WordPress - 上传时模糊图像【英文标题】:WordPress - Blur Image on Upload 【发布时间】:2016-03-26 10:31:26 【问题描述】:

所以我正在关注example given here(我将其修改为仅模糊,无水印),以便在上传时在 WordPress 中制作模糊图像。问题是,如果上传的文件大小完全相同,或者小于设置的大小,那么 WordPress 将不会生成图像,因此不会产生模糊的图像。

我尝试使用isst($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 模糊,考虑到我正在进行的所有其他动画,它的效率还不够。 “问题是,如果上传的文件大小完全相同,或者小于设置的大小”我不确定是否完全正确地理解这一点,您正在尝试替换现有图片? 不,我正在尝试生成上传文件的新模糊版本。与wp_generate_attachment_metadata 相关的评论只有在制作新版本时才会被调用(如果尺寸太小或相同,则不会产生任何新内容)。 【参考方案1】:

不幸的是,wp 没有过滤器来强制调整大小,所以你可以做的是在之后挂钩并调整你的图像(如果没有创建)并将其弹出到元数据中。

我没有imagick,所以你必须自己尝试这些函数,但你上面的过程是正确的,你只需要更新文件名并输入下面的数组。 PS不要在过滤器内输出任何东西!

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;


更新

    这旨在仅捕获现有过滤器未能创建模糊自定义尺寸的地方,否则它什么也不做。您仍应包含原始过滤器。您可能在原始代码中遇到问题:您正在删除过滤器中的原始文件,这将导致问题,因为有一个名为“_wp_attached_file”的 postmeta 字段需要更新。我在下面附上了一个注释。

    过滤器会在保存之前捕获元数据,因此一旦您返回 $metadata,任何更改也将被保存。如果你查看源代码:https://core.trac.wordpress.org/browser/tags/3.8.1/src/wp-admin/includes/image.php#L72 这里你可以确切地看到它是如何工作的。我也确认使用 wp4.3

    我试图在下面插入您需要的 imagick 函数。我没有测试过,因为我实际上并没有将它安装在任何地方。 (imagemagick 实际上是一个很棒的开源程序,但服务器非常密集)。试试这个函数来代替上面的那个:

    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

【讨论】:

我认为这可能是要走的路。不是一个完整的答案,但我在 7 天的赏金期内最好的答案。 你觉得缺少什么,生病看看? 嗯,我不是 100% 知道 Imagick 代码需要去哪里,而且图像并不总是image/jpeg 对吗?而且您将高度/宽度硬编码为1920x1080,它可能并不总是这样(并且也将-1200x1080 添加到文件名中。另外,我认为wp_generate_attachment_metadata 过滤器在创建元数据后运行,所以新的模糊图像不会将其元数据正确添加到数据库中(我想,我需要测试一下)。 大卫,这似乎有效,除了它也删除了原始图像。我需要非模糊和模糊图像。有什么想法吗? 我注释掉了unlink,它起作用了,但似乎模糊图像和非模糊图像之间的纵横比发生了变化。【参考方案2】:

当我第一次阅读您的问题时,我不确定您是否在设置图像或生成图像时遇到问题,或两者兼而有之。我认为设置图像的问题可能是您需要在使用wp_generate_attachment_metadata 之后使用wp_update_attachment_metadata 更新帖子图像才能让帖子使用新图像。

当我重新阅读您的问题时,我意识到这一定是add_image_size() 的问题,因为它发生在与上传的图像大小相同或更小的图像上。我曾经遇到过这个问题,以及(重新)为新主题生成备用尺寸图像。在我的情况下,add_image_size() 上没有满足宽度或高度参数。

我想在Wordpress Code Reference 中验证这一点,并在底部附近找到了一位贡献者的评论,这与您面临的问题完全相同,尽管没有发布解决方案。

如果您上传的图片尺寸与 add_image_size() 当crop设置为true时,在$meta对象访问的 wp_generate_attachment_metadata 过滤器,匹配的图像大小将 不可用。此外,尺寸大于 上传的照片也将不可用。

(因此,如果您使用一种技术来创建类似 单色衍生图像,如果 上传的图片与您的图片尺寸完全相同 用于您的黑白版本)。

我认为在您的情况下,由于您使用的是 Imagick,因此有一个解决方案,事实上您可以进行一些图像数学运算。使用borderImage 函数只需为每个图像添加一个边框,该边框最多比您上传的图像大 1 像素。由于add_image_size() 默认从中心裁剪,这应该会触发将大小调整为您需要的大小并解决问题。

例如,您想要 1920 x 1080 的尺寸。使用 Imagick getSize 您可以检查图像的大小。可以说它正好是 1920 x 1080,但我们知道这不会触发模糊。因此,使用borderImage,我们为图像添加了一个 1 像素的白色边框。只要将crop设置为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 限制。我为这项努力投了赞成票!【参考方案3】:

我认为您需要花点心思,为什么您不尝试使用 1 x 15 X 5 大小的图像,所以每次无论什么时候图像会生成该图像的缩略图。

'wp_generate_attachment_metadata' 破解材料并从原始图像生成图像并将 1 x 1 图像替换为您想要的模糊图像如果您在任何地方使用 'background-image-blurred' 进行显示或其他计算目的,您需要欺骗过滤器。

希望你明白我认为这有点 hack 但应该可以正常工作。

【讨论】:

【参考方案4】:

关注wp_handle_upload()函数怎么样?

Here is an example 如何使用它来模糊图像。

【讨论】:

是的,很好的提示。你知道wp_handle_upload是否在wp_generate_attachment_metadata之前被调用? 如果你用 wp_handle_upload() 上传 orig img...模糊它...然后在模糊的 img 上调用 wp_generate_attachment_metadata 怎么办? 你试过我的建议了吗? 一直在尝试,但很难将其转化为我的情况(作为所有上传的过滤器)。这不是一个真正的直接答案,它更像是一个建议,有帮助,但我希望得到更详细的内容。【参考方案5】:

一个开箱即用的建议:既然您只是模糊图像而不对图像进行任何其他更改,为什么不让 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,使其渲染效率更高。否则,仍然为后代保存。

【讨论】:

【参考方案6】:

您所指的示例使用了 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 ); 

【讨论】:

以上是关于WordPress - 上传时模糊图像的主要内容,如果未能解决你的问题,请参考以下文章

WordPress:如何在上传时使用当前日期重命名图像?

如何在上传图像时修复WordPress上的HTTP错误?

实战Wordpres的CSRF漏洞利用

php [自定义图像尺寸]添加自定义尺寸图像(上传媒体时的新尺寸)#wordpress #php

php 这个WordPress插件演示了如何使用WordPress提供的可拖动元文件构建自己的插件页面,需要WordPr

导入WordPress将图像作为外部URL的特色图像发布