WordPress - 上传时模糊图像

WordPress - Blur Image on Upload

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

我尝试使用 isst($meta['sizes']['background-image-blurred']['file']) 来确定是否制作了一个,如果没有则 copy() 源文件,但是没有为图像生成 WordPress "metadata" (对于非 WordPress 用户,元数据与您想象的不同),因此在使用 wp_get_attachment_image.

显示时会出现 height/width 未定义的问题

所以我确信使用如下所示的 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;

    }    

我认为你需要耍点小花招,为什么你不想使用尺寸为 1 x 15 X 5[=21= 的图像] 所以每次不管图像是什么,它都会为该图像生成缩略图。

然后 'wp_generate_attachment_metadata' 破解这些东西并从原始图像生成图像并替换 1 x 1如果您在任何地方使用 'background-image-blurred' 用于显示或其他计算目的,您需要在任何地方使用 'background-image-blurred' 10=]

希望你明白我的想法,我认为它有点乱,但应该可以正常工作。

关注 wp_handle_upload() 函数怎么样?

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

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

当我重读你的问题时,我意识到这一定是 add_image_size() 的问题,因为它发生在与上传的图像大小相同或更小的图像上。我曾经 运行 遇到过这个问题,以及(重新)为新主题生成替代尺寸的图像。在我的例子中,在 add_image_size() 上没有满足宽度或高度参数。

我想在 Wordpress Code Reference 中验证这一点,并在底部附近发现了一位贡献者的评论,该评论与您面临的问题完全相同,尽管没有解决方案 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).

我认为在你的情况下有一个变通解决方案,因为你使用的是 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 "expand" 我们的图像到所需的比例,或者我们可以创建一个新的白色 Imagick canvas 我们需要的大小并将图像覆盖到左上角,这样我们在新图像的下方和右侧有空白。然后,您将使用 add_image_size 裁剪参数来切断多余的白色。例如,add_image_size('background-image-blurred', 1920, 1080, array('left','top')) 设置从图像的左上角开始裁剪。

一个 outside-the-box 建议:既然您只是模糊图像而不对图像进行任何其他更改,为什么不让 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,使其渲染更高效。否则,还是为子孙后代积蓄吧。

不幸的是,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. 过滤器在保存之前捕获元数据,因此一旦您 return $元数据,任何更改也将被保存。如果您查看源代码:https://core.trac.wordpress.org/browser/tags/3.8.1/src/wp-admin/includes/image.php#L72 此处,您可以确切地了解它是如何工作的。我还确认使用 wp4.3

  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

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