WordPress-上传时模糊图像


WordPress - Blur Image on Upload

所以我遵循这里给出的例子(我修改为只模糊,无水印),在上传时在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;
    }    

不幸的是,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;
}

更新

  1. 这是为了只捕捉现有过滤器无法创建模糊自定义大小的地方,否则它什么都不做。你仍然应该包括你原来的过滤器。原始代码中可能存在问题:您正在删除筛选器中的原始文件,这将导致问题,因为有一个名为"_wp_attached_file"的postmeta字段需要更新。我在下面对此做了说明。

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

  3. 我试图在下面插入您需要的imagick函数。我还没有测试,因为我实际上没有在任何地方安装它。(imagemagik实际上是一个很棒的开源程序,但非常占用服务器)。试试这个功能来代替上面的功能:

    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

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

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

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

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

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

我认为在你的情况下,有一个变通的解决方案,因为你使用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'))设置从图像左上角开始的裁剪。

我认为你需要弄点小把戏,为什么你不尝试拥有尺寸为1 x 15 x 5的图像,所以每次无论图像是什么,它都会为该图像生成缩略图。

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

希望你有这个想法,我认为这有点麻烦,但应该能正常工作。

关注wp_handle_upload()函数怎么样?

下面是一个如何使用它来模糊图像的例子。

一个开箱即用的建议:既然你只是模糊了图像,而没有对图像进行任何其他更改,为什么不让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变换以将效果移动到GPU,使其渲染更加高效。否则,仍然为子孙后代储蓄。

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