Dan*_*own 3 html css html5-canvas css-filters
我目前正在对 HTML5 Canvas 上的图像应用简单的滤镜效果。类似于此处定义的技术:
HTML5 Canvas 图像对比 在这个HTML5 Rocks 中!博文
但是,这种特殊方法需要在重绘之前迭代每个像素并应用修改器。对于我的特定用例,这需要 150 毫秒以上来重绘我的图像(650 像素 x 650 像素 PNG)
使用CSS3 的过滤器属性(对比度或亮度)应用相同的效果需要不到 10 毫秒。
我的问题是:CSS3 的过滤器属性如何“在幕后”工作?为什么它的性能明显更高?有没有办法在 Canvas 中实现类似的性能?
Canvas 通过 API 公开。JavaScript 是一个运行时,即使这些天进行了严格的优化,如果您要通过 JavaScript 逐像素访问来操作 2D 网格,您将要支付从运行时一直到缓冲区的所述访问的损失包含当前存储在画布中的每个像素的图像。问题与您使用 JavaScript 表达过滤器代码有关,即使进行了优化,运行时的性质也决定了一些无法消除的惩罚。
CSS3 过滤器是一个黑匣子,可以批量进行相同的转换,这意味着GPU着色器程序,例如,直接在 GPU 上运行,访问通常存储在靠近 GPU 的可立即寻址的内存中的图像,以及后者受益于它的SIMD类指令被设计成处理的像素的整个矩阵。此外,访问本地内存的本机代码 - 几乎尽可能快,无需深入了解细节。
即使在 CPU 上运行时,没有任何 GPU 帮助,我们谈论的原生过滤器内核直接操作 RAM 中的图像,没有任何字节码,更重要的是根本不考虑 JavaScript。你声明你想要的过滤器,用户代理在画布图像上调用过滤器程序,就是这样。CPU 还具有处理数据向量的 SIMD 指令,这显然有很大帮助。过滤器代码甚至不是您的,您只能按名称引用它。
现在,如果您可以将某种黑匣子过滤器(例如 CSS 中可用的过滤器之一)直接应用于画布像素数据,您可能会获得与使用 CSS 相同的速度——因为您拥有的最重要的速度障碍是—— - 用 JavaScript 代码表示的逐像素访问 - 被消除。所以这不仅仅是关于 JavaScript,而是关于数据访问的粒度。在这种情况下,将内核应用于批量数据总是比在更高级别上自己编写内核代码要快。简单地说,这让我想到了下面的最后一点。
现在,如果 JavaScript 解释器可以理解您的逐像素循环操作,因为它可以将其全部转换为使用 SIMD 甚至GPU 着色器的本机代码,所有这些都来自您的自由类型 JavaScript 过滤器代码,这将弥补性能差距。但是您会将复杂性转移到 JavaScript 编译器/解释器中,并且在计算机科学中,在这种规模上进行优化的问题还没有完全解决。也许人工智能和机器学习会有所帮助,我不会对此进行推测。请注意,我不是在谈论JIT 将您的 JavaScript编译为等效的本机代码,这已经成为多年的常态,我是在谈论识别自由类型的 JavaScript 代码,类似于已知的甚至任意的图像内核,就像人类一样。然后用给出相同结果但由编译器编写以产生它认为将提供最佳性能的运行时对应物替换所述代码。
在实践中,如果您深入研究Canvas API,我认为您可以优化基于 Canvas 的 JavaScript 朴素的逐像素过滤器。可以通过可以从方法调用中获取的类型来访问图像数据。这种数组类型有一些有趣的“批量”函数,如、、等。在浏览 Canvas API 文档时,您需要像“黑客”一样思考,假设一个演示场景人员的心态——查看可用的方法和数据类型,它们可以为您提供什么。这样做的回报可能是巨大的。Uint8ClampedArrayCanvasRenderingContext2D.getImageData()filterforEachmapreduce
如果这还不够,可以使用WebGL渲染画布,WebGL是一个 API,它是OpenGL 的一个子集,通常实现为专门在 GPU 上运行。着色器保证是 WebGL 的一部分,这意味着您可以获得使用 WebGL 的各种高级和超快画布过滤器程序的免费门票,这些程序是您自己编写但通常在 GPU 上执行的程序。