js实现图片虚化_Web前端之高斯模糊图片记

题记 前端需求之高斯模糊图片

最近工作中有一个需求,客户提交图片,服务器根据图片生成内容,并将内容显示,要求高斯模糊处理用户的图片并作为作品展示的背景,类似于苹果设备上的高斯模糊背景。用户提交的图片分网络图片地址、终端设备上传两种。要求兼容各大浏览器。

解决方案一:CSS3滤镜

在CSS3 中规定了一个新的图形特效:filter ,可以对元素进行模糊、锐化或者元素变色。 filter 目的是用来调整图片、背景和边界的渲染。

在CSS3 中已经实现了filter 的一些预定义函数,MDN 中介绍如下: filter: url("filters.svg#filter-id");

filter: blur(5px);

filter: brightness(0.4);

filter: contrast(200%);

filter: drop-shadow(16px 16px 20px blue);

filter: grayscale(50%);

filter: hue-rotate(90deg);

filter: invert(75%);

filter: opacity(25%);

filter: saturate(30%);

filter: sepia(60%);

/* Apply multiple filters */

filter: contrast(175%) brightness(3%);

/* Global values */

filter: inherit;

filter: initial;

filter: unset;

其中blur() 正是对元素进行高斯模糊,顺便添加了brightness() 函数增加前景背景明暗对比度。

-webkit-filter: blur(10px) brightness(.5); /* Chrome, Opera */

-moz-filter: blur(10px) brightness(.5);

-ms-filter: blur(10px) brightness(.5);

filter: blur(10px) brightness(.5);background-image: url(/*用户图片地址*/);

在谷歌浏览器、火狐浏览器、Edge 浏览器中展示,效果不错,但是在IE 中不行。

CSS3 filter 的浏览器兼容列表如下:

IE的CSS filter

IE 没有实现CSS3 的filter ,因为它们本来就有自己的filter 滤镜实现。IE 中的filter 实现了和CSS3 中 filter 类似的方法,但是filter 方法的调用却与CSS3 中的filter 方法大相径庭。Microsoft 早在 IE 4.0 中就开始了filter 的支持,很明显CSS3 中的filter 借鉴了IE 的思想却用了比IE 更切合的方式实现了这些方法,为IE 点赞。关于IE 中的CSS-filter 的知识详见关于IE中CSS-filter滤镜小知识介绍。于是添加上IE 中的高斯模糊实现:

filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=10, MakeShadow=false); /* IE6~IE9 */

到这里发现并没有万事大吉,大家会发现IE filter 代码中的注释是IE6~IE9。IE10、IE11是不支持CSS 中 filter 的语法的,想来可能是Microsoft 想在IE 10 后支持CSS3 中的filter 却发现与之前的实现有冲突,然后不得不舍弃,最终也没拿出方案吧。所以只得寻找新的方案。

解决方案二:HTML5 之 canvas

canvas 中有一个getImageData() 方法,可以获取图片上的像素点信息,还有一个方法putImageData() 可以将图像的像素点信息修改后写入到canvas 上,canvas 也提供了方法toDataURL() 将图像信息导出成路径供其它用处(譬如作为其他元素的背景),将canvas 画图作为其他元素的背景可查看使用canvas 绘制背景图-Jerry Qu 的介绍。我们获取图片的信息后对图片信息进行转化后写回canvas ,就能得到想要的效果。当然,使用不同的算法会得到不同的结果,canvas 生成马赛克图片 介绍了不同的图片处理插件,有兴趣的可以在上面详细了解。我们要使用的是高斯模糊的插件,对高斯模糊算法,阮老师的一篇译文——高斯模糊算法 介绍的很不错,主要涉及正态分布。不过我们现成的实现,在网上找到这个JS插件——StackBlur.js,Demo地址:http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html 。

该插件可以实现高斯模糊效果,主要使用里面的方法

function stackBlurImage( imageID, canvasID, radius, blurAlphaChannel )

其中, imageID 是html 页面中要高斯模糊的原图片标签ID,canvasID 是canvas 画图的ID,radius 是要高斯模糊的半径,blurAlphaChannel 涉及半透明(未详细研究)。

于是敲定解决方案:在html 页面中插入隐藏标签和隐藏的标签,使用插件中方法设置作品展示的背景。方案敲定开始编码,写完后上传了一张图片,服务器保存后将图片地址保存后返回图片地址,前端处理。测试,通过,完美兼容各大浏览器。

问题出现在项目改造,使用独立的图片服务器后,图片服务器和Web 服务器在不同的域下,所以在运行 stackBlurImage() 是浏览器报出了如下错误:

Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.

造成这个问题的原因是图片跨域,在canvas 修改图片信息的时候,像其他数据一样,图片信息的访问也有域的限制,跨域图片的详细介绍可参见MDN 上的讲解:CORS enable image  。跨域限制是html 规范上要求的,各个浏览器是否实现虽有差别,但至少Chrome 上是不行的(存在其他浏览器并未对canvas 中的这一点做限制),看到一些博客介绍修改浏览器设置也可以突破这个限制,但显然这不是产品级的解决方案。

存在这个问题的不仅仅是因为文件服务器独立出来,如果用户提交的是第三方网站的图片地址,一样存在这个问题,只是当时未发现而已。于是考虑使用JS 将图片下载到本地再使用,可是JS 也有跨域的限制,仍然不可行。

尝试解决方案三:CSS3 之 transform

CSS3 提供了很多变换,其中 transform 就可以对元素进行旋转(rotate)、位移(translate)、缩放(scale)、倾斜(skew)等2D3D转换(MDN讲解:transform),当然,这些转换斗是以 matrix(矩阵) 为基础方法在坐标系统中对可视化模型的坐标空间进行操作。既然如此,若有合适的矩阵是否能达到元素“高斯模糊的效果”呢?于是对 matrix(矩阵) 进行探究。

matrix(矩阵) 主要原理是对元素点集合的各个点坐标进行线性代数转换,以达到元素变形的目的。CSS3 transform 的2D转换 matrix() 方法写法如下:

transform: matrix(a,b,c,d,e,f);

这六个参数对应的矩阵就是:

坐标转换的过程如下:

3*3矩阵每一行的第1个值与后面1*3的第1个值相乘,第2个值与第2个相乘,第3个与第3个,然后相加。2D转换使用了3*3矩阵,3D 转换多了一个Z轴,使用的是4*4矩阵。两种转换的本质是一样的,只是复杂度不同。上面这一段介绍来自张旭鑫的博客,理解CSS3 transform中的Matrix(矩阵) 。他的另一篇博客对 3D 转换进行了详细而又个性的介绍,好吧,CSS3 3D transform变换,不过如此 。感谢大神们的分享。

也就是说 transform 转换的实质是对坐标点的变化,并不能对图片的像素点数据进行操作,能进行各种变形,却改变不了元素的本质,高斯模糊改变了图片的像素点,transform 并不能解决我们的问题。

解决方案四:SVG高斯模糊

SVG 是用XML格式定义在Web 平台上的矢量图,它是一个开放标准,它将图像信息以XML 文本形式进行保存和传输,SVG 里也提供了滤镜来该表元素的显示,其中包括高斯模糊。我们先来看看SVG 的浏览器兼容性:

回顾我们使用的过的解决办法,方案二有同源策略的限制,方案三不可用,方案一兼容了除IE10+外的主流浏览器,如果我们使用SVG滤镜将IE10+ 的坑填上,便得到一个完美的解决方案。根据 SVG 的教程 中的介绍,SVG 滤镜主要使用了 和 标记。保存一个名为 blur.svg 的SVG 文件,文件内容如下:

xmlns="http://www.w3.org/2000/svg"

xmlns:xlink="http://www.w3.org/1999/xlink"

xmlns:ev="http://www.w3.org/2001/xml-events"

baseProfile="full">

红色部位的代码便提供了一个高斯模糊滤镜(模糊半径为10), 标记提供了要模糊的图片,属性 xlink:href 是图片的地址,属性 filter 根据ID 应用了红色代码定义的滤镜,然后SVG 作为背景图片载入:

.blur {

background-image: url(blur.svg);

}

这样就达到了我们的目的——高斯模糊图片,但仍然存在一个问题,以上的SVG 文件单独于html 页面,需要额外的维护,要命的是图片的地址很难改变,于是我们把以上 SVG 标签的内容作为内联元素放在了 html 页面中,并和作品展示的容器同级。然后将他们的父元素 position 设为 relative ,作品容器背景色设为透明。对 标签应用以下样式作为作品容器的背景,

width: 120%;

height: 120%;

position:absolute;

top:-10%;

left:-10%;

最后是使用 JS 调节 标签中的 宽高属性以完美展示。

至此,问题得以解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

r语言中残差与回归值的残差图_用R语言做回归分析_iris数据集/longley数据集

机器学习课程2 回归分析【题目1】使用R对内置鸢尾花数据集iris(在R提示符下输入iris回车可看到内容)进行回归分析,自行选择因变量和自变量,注意Species这个分类变量的处理方法。解答:1.iris数据集介绍鸢尾花(iris)是数据挖掘常用到的一个数据…

Java 8————Collectors中的中的joining 方法和mapping方法

先定义好后面做示例要用的数据&#xff1a; List<User> listUser new ArrayList<>(); listUser.add(new User("李白", 20, true)); listUser.add(new User("杜甫", 40, true)); listUser.add(new User("李清照", 18, false)); lis…

BOM -- browser object model

操作浏览器窗口 一、 innerWidth / innerHeight 获取浏览器可视区的宽高(不包含开发者工具区域) window.innerWidth px window.innerHeight px二、 outerWidth / outerHeight 获取浏览器软件界面的宽高 window.outerWidth px window.outerHeight px三、 screenTop / scr…

vue 拓扑组件_vue 集成 vis-network 实现网络拓扑图的方法

vis.js 网站https://visjs.org/vs code 下安装命令npm install vis-network在vue 下引入 vis-network组件const vis require("vis-network/dist/vis-network.min.js");require("vis-network/dist/vis-network.min.css");例子代码使用let DIR "/jtop…

编译器说 Lambda 表达式中的变量必须是 final 的,我偏不信

偶尔&#xff0c;我们需要在 Lambda 表达式中修改变量的值&#xff0c;但如果直接尝试修改的话&#xff0c;编译器不会视而不见听而不闻&#xff0c;它会警告我们说&#xff1a;“variable used in lambda expression should be final or effectively final”。 这个问题发生的…

window 事件

一、 onscroll ⇒ 页面滚动是事件 // 当页面发生滚动就会触发这个事件 window.onscroll function () {console.log(我会随着鼠标滚动改变); }二、 onresize ⇒ 窗口改变事件 // 当窗口大小发生改变就会触发这个事件 window.onresize function () {console.log(我会随着窗口…

pandas series取值_【小学生级】pandas入门到精通备查表——AI未来系列3

在未来面前&#xff0c;每个人都是学生江海升月明&#xff0c;天涯共此时&#xff0c;关注江时&#xff01;引子篇为AI未来系列第三篇&#xff0c;中阶部分开始。pandas的数据分析功能比excel强太多&#xff0c;基本上学会pandas&#xff0c;走遍天下都不怕。这是我的备查字典&…

java中为final变量赋值的几种方式

java中为final变量赋值的几种方式 前言 使用final修饰变量&#xff0c;很多人第一时间想到的就是不可变。然后以为变量必须得在声明的时候就为其赋初始值&#xff0c;其实不然&#xff0c;本文将详细讲解java中使用final修改的变量的赋值问题。 被final修饰的变量的几种赋值方…

instanceof 和 对象转型

一、instanceof 判断某个对象是否属于某个类 father1 instanceof Father; // true// 如果有子类继承父类的话 son instanceof Father; // true二、对象转型 子转父 > 自动转&#xff08;向下转型&#xff09; 父转子 > 强转&#xff08;向上转型&#xff09; 三、Obj…

java类验证和装载顺序_Java JVM类加载顺序详解

首页 > 基础教程 > 基础知识 > JDK&JRE&JVMJava JVM类加载顺序详解JVM加载就是寻找一个类或是一个接口的二进制形式并用该二进制形式来构造代表这个类或是这个接口的class对象的过程&#xff0c;其中类或接口的名称是给定了的。当然名称也可以通过计算得到&am…

从lambda表达式看final关键字

Variable used in lambda expression should be final or effectively final 想必大家在开发java程序的时候应该经常见到。 这是因为在lambda的匿名表达式里需要传入final的对象&#xff0c;那么这是为什么呢&#xff1f; 因为lambda是匿名表达式&#xff0c;它是在新开的一个…

linux中负载值为多少正常_Linux系统中load average平均负载

系统平均负载被定义为在特定时间间隔内运行队列中的平均进程数。如果一个进程满足以下条件则其就会位于运行队列中&#xff1a;1)它没有在等待I/O操作的结果2)它没有主动进入等待状态(也就是没有调用wait)3)没有被停止(例如&#xff1a;等待终止)英译文&#xff1a;http://blog…

lambda里面赋值局部变量必须是final原因

public class LambdaTest {public static void main(String ... args){int portNumber 1337;Runnable r ()-> {portNumber 1338;System.out.println(portNumber);};r.run();} }如上代码&#xff0c;lambda里面要访问局部变量会报如照片错误&#xff1a; 在介绍为什么会报…

classin安卓手机安装条件_ClassIn上课官方软件下载-ClassIn安卓版本 v3.0.7.1_5577安卓网...

ClassIn上课官方软件下载分享给大家。ClassIn在线互动教室是一对多直播互动教学平台&#xff01;培养学习能力更强大的学习者&#xff01;班级群课下互动答疑收发作业&#xff01;记录学习成长历程&#xff0c;展示学习成果&#xff01;【软件说明】欢迎使用ClassIn&#xff01…

lambda表达式或者匿名函数中为什么要求外部变量为final

1、参考博客 关于Lambda表达式里面修改外部变量问题JDK8之前&#xff0c;匿名内部类访问的局部变量为什么必须要用final修饰 2、匿名内部类 在jdk7之前&#xff0c;匿名内部类访问外部类的局部变量时&#xff0c;那么这个局部变量必须用final修饰符修饰&#xff0c;如下图1所…

location 和 history

Location 对象&#xff1a;封装了浏览器地址栏的 URL 信息 一、hash 返回 URL 中 hash(#后跟零个或者多个字符), 如果不包含, 返回空字符串 # 位置标识符 : 当前页面的位置信息, 比如: 跳转顶部 console.log(location.hash); // ""二、host : 返回服务器名称和端口…

ble芯片 全称_蓝牙芯片都有哪些厂商?一文解答

蓝牙5新标准是蓝牙技术自1999年诞生以来推出的第十个标准版本。其性能上大幅提升&#xff0c;可归结为&#xff1a;更快、更长、更给力&#xff0c;非常适合运用于无线可穿戴、工业和智能家居等领域。但蓝牙技术产品能否真正进人批量生产在于芯片制造技术能否跟得上&#xff0c…

你知道Java中final和static修饰的变量是在什么时候赋值的吗?

开始 一位朋友在群里问了这样一个问题&#xff1a; 本着乐于助人的想法&#xff0c;我当时给出的回答&#xff1a; 后来我总觉得哪里不对劲&#xff0c;仔细翻阅了《Java虚拟机规范》和《深入理解Java虚拟机》这一部分的内容&#xff0c;害&#xff01;发现自己理解的有问题。…

获取元素大小和位置的方式

一、直接获取元素样式属性值 – element.style.width console.log(div.style.width); // 500px console.log(parseInt(div.style.width)); // 500 console.log(typeof (div.style.width)); // string二、Offset 偏移量 offsetWidth width padding border offsetHeight he…

mybatis 取查询值_MyBatis-SELECT基本查询

1、返回一个LISTselect * from tbl_employee where last_name like #{lastName}2、将查询记录封装为一个Mapselect * from tbl_employee where id#{id}返回一条记录的map&#xff1b;key就是列名&#xff0c;值就是对应的值。3、多条记录封装为一个mapMapKey("id")pu…