2014-02-13 29 views
3

我需要一種基於alpha蒙版將「筆觸」(輪廓)和陰影效果添加到透明PNG圖像的方法,唯一能找到的解決方案是使用自定義SVG濾鏡。 (注:Web應用程序的,我需要這些效果是我自己私人使用的,所以沒關係,這個解決方案不是對舊版瀏覽器兼容的移動上...。)參數化和重用HTML5中定義的自定義SVG過濾器?

我從來沒有使用過SVG之前,但是單獨創建筆劃和陰影過濾器非常簡單。不幸的是,我無法找到一個方法來創建一個沒有實際複製並粘貼過濾器進入一個新的一個結合效果,如下面的代碼:

<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg"> 

    <!-- drop shadow --> 
    <filter id="drop-shadow"> 
     <feGaussianBlur in="SourceAlpha" stdDeviation="4" /> 
     <feOffset result="m_offsetBlurred" dx="12" dy="12" /> 
     <feFlood result="m_floodTrans50" flood-color="rgba(0,0,0,0.5)" /> 
     <feComposite result="m_offsetBlurredTrans50" in="m_floodTrans50" in2="m_offsetBlurred" operator="in" /> 
     <feMerge> 
      <feMergeNode in="m_offsetBlurredTrans50" /> 
      <feMergeNode in="SourceGraphic" /> 
     </feMerge> 
    </filter> 


    <!-- outer stroke --> 
    <filter id="outer-stroke"> 
     <!-- create rectangle of the desired color --> 
     <feFlood result="m_floodRect" flood-color="black" /> 

     <!-- create copy of png's alpha mask and expand --> 
     <feMorphology result="m_expandedMask" in="SourceAlpha" operator="dilate" radius="1" /> 

     <!-- "cut out" a section of the flood fill matching the expanded copy --> 
     <feComposite result="m_expandedColored" in="m_floodRect" in2="m_expandedMask" operator="in" /> 

     <!-- blend it behind the original shape to create the outline effect --> 
     <feBlend in="SourceGraphic" in2="m_expandedColored" mode="normal" /> 
    </filter> 


    <!-- drop shadow & outer stroke (must copy & paste the 2 filters above, which violates the DRY principle) --> 
    <filter id="outer-stroke-drop-shadow"> 
     <!-- create rectangle of the desired color --> 
     <feFlood result="m_floodRect" flood-color="black" /> 

     <!-- create copy of png's alpha mask and expand --> 
     <feMorphology result="m_expandedMask" in="SourceAlpha" operator="dilate" radius="1" /> 

     <!-- "cut out" a section of the flood fill matching the expanded copy --> 
     <feComposite result="m_expandedColored" in="m_floodRect" in2="m_expandedMask" operator="in" /> 

     <!-- blend it behind the original shape to create the outline effect --> 
     <feBlend result="m_stroked" in="SourceGraphic" in2="m_expandedColored" mode="normal" /> 

     <!-- add drop shadow --> 
     <feGaussianBlur result="m_blurred" in="SourceAlpha" stdDeviation="4" /> 
     <feOffset result="m_offsetBlurred" in="m_blurred" dx="12" dy="12" /> 
     <feFlood result="m_floodTrans50" flood-color="rgba(0,0,0,0.5)" /> 
     <feComposite result="m_offsetBlurredTrans50" in="m_floodTrans50" in2="m_offsetBlurred" operator="in" /> 
     <feMerge> 
      <feMergeNode in="m_offsetBlurredTrans50" /> 
      <feMergeNode in="m_stroked" /> 
     </feMerge> 
    </filter> 
</svg> 


<style> 
    .fx_drop_shadow    { filter: url('#drop-shadow'); } 
    .fx_outer_stroke    { filter: url('#outer-stroke'); } 
    .fx_outer_stroke_drop_shadow { filter: url('#outer-stroke-drop-shadow'); } 
</style> 


<div> 
    <img src="gfx/odd_shape.png" /> 
    <img src="gfx/odd_shape.png" class="fx_drop_shadow" /> 
    <img src="gfx/odd_shape.png" class="fx_outer_stroke" /> 
    <img src="gfx/odd_shape.png" class="fx_outer_stroke_drop_shadow" /> 
</div> 

這裏是如何將上面的代碼渲染HTML5文檔中:

SVG filters applied to a PNG image

這裏是原來的PNG圖形(odd_shape.png):

enter image description here

問題1:如何重新使用前2個過濾器(drop-shadowouter-stroke),所以我可以簡單地將它們,而不必複製並粘貼它們組合過濾器(outer-stroke-drop-shadow)。

問題2:是否有可能參數自定義過濾器,這樣可以指定的東西,如筆觸顏色或陰影的透明度?這會使它們更加可重用。


感謝。

+0

對於重複使用,您可以使用「XML包括」喜歡這裏引用的那些基礎的方法:http://stackoverflow.com/questions/5121052/can-we-import- xml-file-into-another-xml-file。 對於參數化來說,某種類型的預處理器(認爲LESS或Compass)可能會訣竅,儘管快速谷歌沒有顯示任何現有的svg預處理器。您的項目是否使用構建/任務運行器,如grunt? – Egg

+0

如果您使用JavaScript,您可以克隆您的基本過濾器,然後向克隆中添加/刪除各種需要的元素,給它一個新的ID並應用它。 –

回答

2

這裏是在我測試這兩個瀏覽器(Firefox和Chrome)的作品的完整解決方案...

解決方案問題1:無我測試支持的瀏覽器在filter property指定多個過濾器,所以結合用戶定義的過濾器的最好(也許是唯一的)方法是使用Michael Mullany建議的技術:將它們按順序應用於嵌套的<g>元素,根據需要創建過濾器圖形。

求解問題2: W3C有用於SVG Parameters一個工作草案,草案包括polyfill script使用和測試所提出的功能。通過param()功能屬性值(例如,param(shadowColor) black)聲明參數並且通過類似查詢字符串的接口(例如,foo.svg?shadowColor=red)或通過容器的子元素(例如,<param name="shadowColor" value="red"/>)來定義參數。

下面提供了兩種解決方案的演示代碼,以及Firefox的屏幕截圖。


中的mypage.html:

<object type="image/svg+xml" data="filters.svg?osColor=lime&dsAlpha=0.4"></object> 
<object type="image/svg+xml" data="filters.svg?osColor=white&osWidth=4&dsAlpha=0.8&dsBlurSigma=8&dsOffsetX=32"></object> 


在filters.svg:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300px" height="320px" viewBox="0 0 300 320"> 
    <defs> 
     <filter id="dropShadow" width="150%"> 
      <feGaussianBlur in="SourceAlpha" stdDeviation="param(dsBlurSigma) 4" /> 
      <feOffset result="m_offsetBlurred" dx="param(dsOffsetX) 12" dy="param(dsOffsetY) 12" /> 
      <feComponentTransfer result="m_offsetBlurredTranslucent" in="m_offsetBlurred"> 
       <feFuncA type="linear" slope="param(dsAlpha) 0.5" /> 
      </feComponentTransfer> 
      <feMerge> 
       <feMergeNode in="m_offsetBlurredTranslucent" /> 
       <feMergeNode in="SourceGraphic" /> 
      </feMerge> 
     </filter> 
     <filter id="outerStroke" width="150%"> 
      <feFlood result="m_floodRect" flood-color="param(osColor) black" /> 
      <feMorphology result="m_expandedMask" in="SourceAlpha" operator="dilate" radius="param(osWidth) 1" /> 
      <feComposite result="m_expandedColored" in="m_floodRect" in2="m_expandedMask" operator="in" /> 
      <feBlend in="SourceGraphic" in2="m_expandedColored" mode="normal" /> 
     </filter> 
    </defs> 

    <!-- combine stroke & drop shadow --> 
    <g style='filter:url(#dropShadow);' width='300' height='320'> 
     <g style='filter:url(#outerStroke);'> 
      <image width='240' height='280' xlink:href="gfx/odd_shape.png"></image> 
     </g> 
    </g> 

    <!-- use polyfill from http://dev.w3.org/SVG/modules/param/master/SVGParamPrimer.html --> 
    <script type="text/ecmascript" xlink:href="http://dev.w3.org/SVG/modules/param/master/param.js" /> 
</svg> 

其結果是:

enter image description here

+0

不知道參數,它們看起來非常有用! –

+0

@MichaelMullany:很高興聽到。如果您發現它有用,請提出答案。謝謝。 – etherice

1

SVG 1.1過濾器規範包含include another filter by reference的能力,但只有IE10 +(和Firefox - 感謝Robert!)支持此功能。您可以通過在使用包裝組元素的又一層元素嵌套中應用它們來組合濾鏡。雖然它不是特別優雅。

沒有能力參數化SVG過濾器本身(雖然當然,您可以通過JavaScript來做任何事情)。該規範包括將對象的筆觸和填充用作過濾器輸入的功能,但這些僅在今天的Firefox和IE10 +(不包括Chrome和Safari)中受支持。

+0

Firefox也支持以供參考。 –

+0

過濾器規範確實有能力引用另一個過濾元素來「複製」它的子元素,但它被定義爲只有在其他過濾元素沒有自己的子元素時才起作用。 –

+0

謝謝。 +1爲您提供幫助。請參閱我的答案,瞭解我找到的完整解決方案,包括參數化過濾器。 – etherice

1

回答問題1:

Filter Effects spec不會讓你有一個線性表多重效果,例如:

filter: url(#outer-stroke) drop-shadow(5px 5px 10px black); 

甚至:

filter: url(#outer-stroke) url(#drop-shadow); 

無論但是這個實施還是另一個問題。在Chrome中,您目前只能以這種方式合併shorthand syntax。效果以您指定的順序應用。

回答問題2:

如果使用drop-shadow shorthand可以指定陰影顏色爲RGBA,它給你的不透明度。

+0

謝謝。 +1爲您提供幫助。不幸的是,我測試的瀏覽器都沒有允許我在一個'filter'屬性中指定多個過濾器。但是,我能夠嵌套''元素並以這種方式創建過濾器鏈。請參閱我的答案,瞭解我找到的完整解決方案,包括參數化過濾器。 – etherice