zoukankan      html  css  js  c++  java
  • 高斯模糊滤镜效果解析

    前言

    这个东西呢不管看起来,听起来都很高大上哈.鄙人比较懒,知道有这么个东西,却一直没去研究.感叹技术日新月异,有时候觉得自己掉队好远了.这不项目中便遇到了使用这家伙的情况.这次需要做一个音乐类app,需要有毛玻璃的高大上效果.这个效果在众多音乐app中非常常见,也确实非常漂亮.但在网页端见得比较少.大概是兼容性和性能问题吧(强烈吐槽性能).也没办法,有需求就得想办法去实现是不是,不过最讨厌跟那群UE,PM撕逼.如果对她们说这个东西很麻烦,不好实现.然后她们一副哥哥你一定可以的!!花痴表情强行绑架了我.哎,谁让我是程序员呢. 其实吧我自己也挺想去实现这个东西的。默默的给自己打了一针鸡血便投入无尽的搜寻,学习中.

     css3-filter

    搜索一番,找到这个属性filter:blur(5px)。赶快去实现一把。

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4 <meta http-equiv="content-type" content="text/html; charset=utf-8">
     5 <title></title>
     6 <style>
     7 .d1{
     8     background-image:url('./lp.png');
     9     background-size:cover;
    10     -webkit-filter:blur(10px);
    11     filter:blur(10px);
    12     width:300px;
    13     height:300px;
    14 }
    15 </style>
    16 </head>
    17 <body>
    18     
    19     <div class="d1"></div>
    20 </body>
    21 </html>

    咳咳, 献上一个萌妹子.实在找不到图片了.O(∩_∩)O哈哈~

    blur的效果就是虚化图片.值越大虚化得越厉害.

    瞬间高大上了有木有!! 

    ....

    ....

    ....

    然而事情并没有这么简单.滤镜算法是对图片的像素点做处理,也就是说你需要设置一张背景图.当前元素设置滤镜属性后,元素里面的内容也会被影响.就拿上面的例子来说,如果元素里面有文字的话,那么文字也看不见了.聪明的你肯定会想到再叠一层不就完了嘛.事实情况也确实如此(这不是废话么...)让我们来看下

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title></title>
    <style>
    
    .wrap{
        position:relative;
        width:300px;
        height:300px;
        line-height:300px;
        text-align:center;
    }
    .d1{
        background-image:url('./lp.png');
        background-size:cover;
        -webkit-filter:blur(10px);
        filter:blur(10px);
        position: absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
        z-index:-1;
    }
    
    </style>
    </head>
    <body>
        
        <div class="wrap">
            <div class="d1"></div>
            <div class="content">我爱你老婆</div>    
        </div>
    </body>
    </html>
    View Code

    完美!

    .....

    .....

    .....

    然而事情并没有这么简单!

    歌词多是用白色字体,毛玻璃还是太亮了,容易混淆. 嘿嘿,其实也简单,再加上一点背景透明度就好啦.

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title></title>
    <style>
    
    .wrap{
        position:relative;
        width:300px;
        height:300px;
    }
    .d1{
        background-image:url('./lp.png');
        background-size:cover;
        -webkit-filter:blur(10px);
        filter:blur(10px);
        position: absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
        z-index:-1;
    }
    
    .content{
        width:100%;
        height:100%;
        line-height:300px;
        color:#fff;
        text-align:center;
        background-color:rgba(0,0,0,0.3);
    }
    
    </style>
    </head>
    <body>
        
        <div class="wrap">
            <div class="d1"></div>
            <div class="content">我爱你老婆</div>    
        </div>
    </body>
    </html>
    View Code

    看这下是不是好多啦. 恩比较有玻璃质感了.其实吧,还有个坑爹的问题, 加了滤镜blur的元素就变成透明的了,虽然有背景图也还是透明的.所以在需要毛玻璃覆盖底层的情况下,得再叠一层,添加一个背景色.

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title></title>
    <style>
    
    .wrap{
        position:relative;
        width:300px;
        height:300px;
    }
    .filter{
        background-image:url('./lp.png');
        background-size:cover;
        -webkit-filter:blur(10px);
        filter:blur(10px);
        position: absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
        z-index:-1;
    }
    .filter-bg{
        position:absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
        background-color:#333;
        z-index:-2;
    }
    
    .content{
        width:100%;
        height:100%;
        line-height:300px;
        color:#fff;
        text-align:center;
        background-color:rgba(0,0,0,0.3);
    }
    
    </style>
    </head>
    <body>
        
        <div class="wrap">
            <div class="filter-bg"></div>
            <div class="filter"></div>
            <div class="content">我爱你老婆</div>    
        </div>
    </body>
    </html>
    View Code

    咱们可以隐约的发现,在图片的四周模糊效果不是很好,这种情况在blur的值越大的时候越明显,趋势是模糊区域向图像中颜色明显的地方靠近,边缘地方就显得透明,甚至貌似没有模糊.建议blur的值设置在30以下.

    似乎问题就这么解决了!!

    真的解决了?!

    真的?

    svg-<filter>

    我兴奋的,天真的以为事情就这么完了,然而当我附上动画后,让毛玻璃动起来时,整个人都崩溃了. fuck! 哥才买的6s玫瑰金,卡得跟屎一样.当然补充下前提条件,是在播放音乐的时候拖动页面,页面元素数量一般.但不至于播放个音乐拖垮了整个页面性能吧.二愣子的我拖着电脑就去找pm了,你看,就是你要做这种效果,卡得跟方便面一样一条一条的.搞不定,砍需求!

    pm碍于我愤怒的表情,打起了太极.你先冷静冷静.什么事儿都好商量.你要不喝点儿饮料?

    我当然接受了(你们不要用异样的眼光看着我).  喝着饮料平静了下心情,这事儿吧总得解决.和pm鬼扯了半天还是觉得要保留这个效果,不然做了那么久就白费了.况且一个好的工程师(注意我没有用程序员!)就得迎难而上啊,创造力和解决问题的能力才是工程师们的价值所在.首先还是得定位问题,为了确定是filter属性的锅,我把滤镜层给删掉,卧槽丝滑般流畅.看来这属性真是性能堪忧啊.那怎么办呢,我最终还是抱向了google的大腿.一番搜索,果然不负众望.原来除了css3之外,svg和canvas也是可以实现滤镜效果的.我试了下svg,效果真是好得出奇.很流畅.将我们刚才的filter层替换为svg实现

    <svg version="1.1" 
         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">     
        <defs>
            <filter id="blur">
                <feGaussianBlur stdDeviation="10" />
            </filter>
        </defs>
        <image xlink:href="./mm.jpg" x="0" y="0" height="200" width="200" filter="url(#blur)"/>
    </svg>
    View Code

    <filter>标签用来描述滤镜,其id属性唯一标识一个滤镜.<filter>标签必须写在<defs>标签内.<defs>标签是对特殊效果进行描述.

    最终效果不卡.我猜测应该是实现机制不同,svg添加上滤镜后就会把它当成一个图片来处理,不会重复消耗cpu计算.而css3的filter属性应该是在滚动的时候会动态计算,在做一些比较复杂的效果时候,卡顿就很明显.

    使用svg的滤镜依然会使得svg层变得透明,在不希望透明的时候记得添加一层背景色.

    canvas

    用svg的时候遇到一个诡异的问题, 在手机上.把滤镜层隐藏,或者visibility:hidden, 切换的时候,滤镜不见了,图片还在.但是没有了模糊效果.怀疑是性能问题,不能及时重绘渲染.或者svg的滤镜只渲染一次.所以考虑用canvas来做高斯模糊.因为canvas渲染完毕后就是一张图片.不会再发生改变.

    2016年04月24日补充: 后来无意中发现使用了

    高斯算法参考 高斯算法原理

    找到一个高斯算法库,stackBlur.js . 里面有一行注释,需要关注下,是关于getImageDate.获取本地图片的,需要删掉try,catch那段代码.这里又遇到一个问题.canvas的getImageDate有同源策略,只能操作同域的图片资源.

    处理库API: stackBlurImage( sourceImageID, targetCanvasID, radius, blurAlphaChannel );

    • sourceImageID表示要模糊的图片的id, 默认这个图片要隐藏;
    • targetCanvasID表示要显示模糊图片的canvas元素的id;
    • radius表示模糊的半径大小。不过,根据我的对比测试,radius好像与CSS中filter滤镜的模糊值不是1:1匹配的,反倒是有些类似2:1. 也就是这里的20px的半径模糊近似于CSS中blur滤镜值设置为10px;
    • blurAlphaChannel为布尔属性,表示aplha透明通道是否要模糊,true表示要模糊。

    兼容性对比

    咱们再来对比一下兼容性,可见svg稍好,在安卓上都是4.4才支持.另一方面,在移动端,毛玻璃效果在ios上是没问题的. 但有相当一部分安卓不支持.

    其他滤镜效果没用过,似乎也不太常用,也不多说了,网上都能查到.

    总结

    • css3滤镜方便,性能不好,适合做静止的简单效果. 如果滤镜之上有浮层动画,会非常卡.
    • svg滤镜性能好,适合做多层运动,但是有不能重绘的问题
    • css3滤镜需要添加背景图,svg滤镜背景可以是画出来的
    • css3和svg的高斯模糊滤镜都会使得该层变得透明
    • 高斯模糊在图片的边缘效果不太好,可以放大图片width=105%
    • 兼容性二者差不多,svg稍好

    参考资料:

  • 相关阅读:
    POJ 2991(线段树)
    UVa_1592
    紫书 -- 大整数类
    在结构体中添加成员函数/C++
    双向队列
    用埃氏筛法生成质数表
    poj 3687(拓扑排序)
    它们其实都是“图”-- 最小生成树
    最小生成树(MST, Minimum Spanning Tree)
    他们其实都是“图”--最短路
  • 原文地址:https://www.cnblogs.com/fly-snow/p/5131052.html
Copyright © 2011-2022 走看看