9月17日凌晨的脑洞,有可能能优化 Canvas2D 版的实现
又是脑洞时刻。查找“css filter canvas”之后发现了一个 StackOverflow 上的回答 。
问题:
I have applied some CSS3 filters to an image on a canvas like this:
-webkit-filter brightness(0%) grayscale(100%) contrast(1000%)
But when I save the image to my computer, the original image is being saved, not the one with applied filters. Is there a way to save the modified version of it?
(很明显,<canvas>
要作为整个 DOM 元素参与样式计算,而不是其上的像素内容,相当于缓冲区内容。所以直接应用样式是不可以的,我以前试过。)
二楼的回答:
Apply the filter in the canvas using a shader, rather than using a CSS style.
Alternately, make a hidden canvas, draw your content to that, apply the CSS3 filter to it, and then use that canvas to output to the visible one.
二楼评论中一位ID为 katspaugh 的同志写道:
Put the filtered canvas into SVG foreignObject
, then insert the serialised SVG as a Base64-encoded image into the visible canvas. (Just kidding)
有趣的是,在回答评论中提到了 <foreignObject>
。看 MDN 上的示例,能嵌入其他命名空间的元素。所以我做了一个实验:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <!DOCTYPE html > <html > <head > </head > <body > <img src ="http://pic19.nipic.com/20120308/7491614_141057681000_2.png" width ="300" height ="300" id ="csimg" > </img > <svg xmlns ="http://www.w3.org/2000/svg" > <defs > <filter id ="feglow0" > <feColorMatrix type ="matrix" values ="0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 1 0" > </feColorMatrix > <feGaussianBlur stdDeviation ="40 40" result ="coloredBlur" > </feGaussianBlur > <feMerge > <feMergeNode in ="coloredBlur" > </feMergeNode > <feMergeNode in ="SourceGraphic" > </feMergeNode > </feMerge > </filter > </defs > </svg > <svg width ="500px" height ="500px" viewBox ="0 0 500 500" xmlns ="http://www.w3.org/2000/svg" > <switch > <foreignObject width ="500" height ="500" requiredExtensions ="http://www.w3.org/1999/xhtml" > <body xmlns ="http://www.w3.org/1999/xhtml" > <canvas style ="filter: url(#feglow0);" id ="canvas" width ="500" height ="500" > </canvas > </body > </foreignObject > <text font-size ="10" font-family ="Verdana" > <tspan x ="10" y ="10" > You see no canvas.</tspan > </text > </switch > </svg > <a href ="javascript:;" onclick ="redraw()" > REDRAW</a > <script type ="text/javascript" > function redraw ( ) { var canvas = document .getElementById ("canvas" ); var context = canvas.getContext ("2d" ); context.drawImage (document .getElementById ("csimg" ), 0 , 0 , 300 , 300 ); } </script > </body > </html >
这次示例应该不存在安全性的问题,保存到本地直接就可以打开预览。注意我在 SVG 内部为 canvas 指定了样式。
但是这引发了浏览器兼容问题。对于 XML 命名空间的声明(见 <foreignObject>
元素和之后的 <body>
元素),Firefox 和 Edge 要求二者都指定命名空间 http://www.w3.org/1999/xhtml
,Chrome 有时候要求二者都不指定命名空间(为空/无属性),IE11 不支持。而且,Chrome 45 和 Maxthon 4(内核为 Chrome 30)行为还不一样,前者要求不指定,后者不支持(Chrome 本来支持,不知道是不是傲游的bug)。
Video Destruction 的示例如果将定时函数换为 requestAnimationFrame()
,会引发严重的效率问题。狂点一通,帧率就从60直降到不到10。相比之下,稳定调用帧率30效果好一些。——直觉上来讲,和 Bulletproof 最初的三维球示例是相反的。
继续。Firefox 和 Edge 支持如下的声明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <svg xmlns ="http://www.w3.org/2000/svg" width ="500" height ="500" > <defs > <filter id ="feglow0" > </filter > </defs > <g filter ="url(#feglow0)" > <foreignObject width ="500" height ="500" requiredExtensions ="http://www.w3.org/1999/xhtml" > <body xmlns ="http://www.w3.org/1999/xhtml" > <canvas id ="canvas" width ="500" height ="500" > </canvas > </body > </foreignObject > </g > </svg >
这么写的时候:
1 2 3 4 5 6 7 8 9 <g filter ="url(#feglow0)" > <foreignObject width ="500" height ="500" > <body > <canvas id ="canvas" width ="500" height ="500" style ="-webkit-filter: url(#feglow0); -moz-filter: url(#feglow0); -ms-filter: url(#feglow0); -o-filter: url(#feglow0); filter: url(#feglow0);" > </canvas > </body > </foreignObject > </g >
在 Firefox、Edge、Chrome 45 上显示正常,Maxthon 4 上无法显示滤镜效果(显示为原图),IE11 不支持。(说明 Chrome 看 filter
属性。)
话说,9月15日(就在前天)的 W3C SVG 2 推荐标准 中就明确指明:
Additionally SVG allows embedded content using HTML5 ‘video’ , ‘audio’ , ‘iframe’ and ‘canvas’ elements.
要是标准早日实现就好了,我就不用那么头疼了……
Pixi?