Web前端之高斯模糊圖片記

題記 前端需求之高斯模糊圖片

   最近工做中有一個需求,客戶提交圖片,服務器根據圖片生成內容,並將內容顯示,要求高斯模糊處理用戶的圖片並做爲做品展現的背景,相似於蘋果設備上的高斯模糊背景。用戶提交的圖片分網絡圖片地址、終端設備上傳兩種。要求兼容各大瀏覽器。 css

解決方案一:CSS3濾鏡

   在CSS3 中規定了一個新的圖形特效:filter ,能夠對元素進行模糊、銳化或者元素變色。 filter 目的是用來調整圖片、背景和邊界的渲染。 html

   在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;

詳見:MDN中對 filter 的介紹 html5

其中blur() 正是對元素進行高斯模糊,順便添加了brightness() 函數增長前景背景明暗對比度。css3

  -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 中不行。web

CSS3 filter 的瀏覽器兼容列表以下:算法

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 中的高斯模糊實現:canvas

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

   到這裏發現並無萬事大吉,你們會發現IE filter 代碼中的註釋是IE6~IE9。IE十、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 頁面中插入隱藏標籤<img />和隱藏的標籤<canvas></canvas>,使用插件中方法設置做品展現的背景。方案敲定開始編碼,寫完後上傳了一張圖片,服務器保存後將圖片地址保存後返回圖片地址,前端處理。測試,經過,完美兼容各大瀏覽器。

   問題出如今項目改造,使用獨立的圖片服務器後,圖片服務器和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);

這六個參數對應的矩陣就是:

矩陣參數與矩陣對應關係 張鑫旭-鑫空間-鑫生活

座標轉換的過程以下:

CSS3中矩陣位置計算公式 張鑫旭-鑫空間-鑫生活

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 濾鏡主要使用了<defs> 和<filter> 標記。保存一個名爲 blur.svg 的SVG 文件,文件內容以下:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<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="mm1.jpg" x="0" y="0" height="191" width="265" filter="url(#blur)" />
</svg>
紅色部位的代碼便提供了一個高斯模糊濾鏡(模糊半徑爲10),<image> 標記提供了要模糊的圖片,屬性 xlink:href 是圖片的地址,屬性 filter 根據ID 應用了紅色代碼定義的濾鏡,而後SVG 做爲背景圖片載入:

.blur {
    background-image: url(blur.svg);
}

 

這樣就達到了咱們的目的——高斯模糊圖片,但仍然存在一個問題,以上的SVG 文件單獨於html 頁面,須要額外的維護,要命的是圖片的地址很難改變,因而咱們把以上 SVG 標籤的內容做爲內聯元素放在了 html 頁面中,並和做品展現的容器同級。而後將他們的父元素 position 設爲 relative ,做品容器背景色設爲透明。對 <svg> 標籤應用如下樣式做爲做品容器的背景,

width: 120%;
height: 120%;
position:absolute;
top:-10%;
left:-10%;

 

最後是使用 JS 調節 <svg> 標籤中的 <iamge> 寬高屬性以完美展現。

至此,問題得以解決。

相關文章
相關標籤/搜索