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 1 或 5 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 - 上传时模糊图像的主要内容,如果未能解决你的问题,请参考以下文章
php [自定义图像尺寸]添加自定义尺寸图像(上传媒体时的新尺寸)#wordpress #php
php 这个WordPress插件演示了如何使用WordPress提供的可拖动元文件构建自己的插件页面,需要WordPr