Raf*_*tro 9 javascript html5 canvas
我需要在Web Worker中以数组形式缩放图像.如果我在网络工作者之外,我可以使用画布和drawImage来复制图像的某些部分或缩放它.
看起来像一个网络工作者,我不能使用画布,所以,我该怎么办?有没有可以帮助我的纯Javascript库?
非常感谢提前.
小智 16
缩放可以通过各种方式完成,但它们都归结为从图像中移除或创建像素.由于图像基本上是像素值的矩阵(调整为数组),因此您可以将图像放大为扩大该数组并填充空白并缩小图像,因为通过保留值来缩小数组.
话虽这么说,在用于数组的JavaScript中编写自己的缩放函数通常并不困难.由于我了解您已经拥有JavaScript数组形式的图像,因此您可以将该数组在消息中传递给Web Worker,将其缩放为您的缩放函数并将缩放的数组发送回主线程.
在表示方面,我建议你使用为RGBA(颜色,带alpha通道)编码图像设计的Uint8ClampedArray,它比普通的JavaScript数组更有效.您还可以轻松地将消息中的Uint8ClampedArray对象发送给Web Worker,这样就不会有问题.另一个好处是Uint8ClampedArray用于Canvas API的ImageData数据类型(在替换CanvasPixelArray之后).这意味着很容易在Canvas上绘制缩放后的图像(如果这是你想要的),只需使用ctx.getImageData()获取画布'2D上下文的当前ImageData并将其数据属性更改为缩放Uint8ClampedArray对象.
顺便说一句,如果您没有将图像作为数组,则可以使用相同的方法.首先在画布上绘制图像,然后使用当前ImageData对象的data属性在Uint8ClampedArray中检索图像.
关于缩放图像的缩放方法,基本上需要实现两个组件.第一个是将已知像素(即正在缩放的图像中的像素)除以已创建的较大的新数组.一种显而易见的方法是均匀地划分空间上的所有像素.例如,如果要将图像的宽度设置为宽度的两倍,则只需在每个像素之后跳过一个位置,在其间留下空白.
然后第二个组件填充那些空白,这可能稍微不那么简单.但是,有几个相当容易.(另一方面,如果您对计算机视觉或图像处理有一些了解,您可能需要查看一些更高级的方法.)一种简单而明显的方法是使用其最近邻居(即最近的)插入每个未知像素位置通过复制已知像素的颜色已知的像素值.当您过度缩放图像时,这通常会导致较大像素(相同颜色的较大块)的影响.您也可以采用附近几个已知像素的平均值,而不是复制最近像素的颜色.可能甚至与权重相结合,你使得更接近的像素在平均值上比在更远的像素上计算得更多.其他方法包括使用高斯模糊图像.如果您想了解哪种方法最适合您的应用,请查看有关图像插值的一些页面.当然,请记住,扩大规模总是意味着填补那些不存在的东西.如果你做得太多,那总是看起来很糟糕.
就缩小而言,通常仅通过将当前阵列中的像素选择转移到较小阵列来移除像素.例如,如果您想要将图像的两倍小,则大致以2为步长迭代当前数组(这取决于图像的尺寸,偶数或奇数,以及您的表示使用).有些方法可以通过删除那些可能错过最多的像素来做到这一点.但我对他们知之甚少.
顺便说一句,所有这些实际上与网络工作者无关.如果您想在主线程上使用JavaScript缩放图像,则可以完全相同的方式执行此操作.或者用其他任何语言表达.然而,Web Workers是一种非常好的方法,可以在单独的线程上而不是在UI线程上进行这些计算,这意味着网站本身似乎没有响应.但是,就像你说的那样,涉及canvas元素的所有内容都需要在主线程上完成,但是可以在任何地方完成扩展数组.
此外,我确信有一些JavaScript库可以为您执行此操作,并且根据他们的方法,您还可以使用importScripts将它们加载到Web Worker中.但我会说,在这种情况下,尝试自己编写它并使其为您的目的量身定做可能会更容易也更有趣.
根据您的编程技巧的高级程度以及您需要扩展的速度,您可以尝试在GPU上而不是使用WebGL在CPU上执行此操作.但在这种情况下,这似乎有点矫枉过正.此外,您可以尝试将图像分成几部分,并尝试在多个Web Workers上缩放单独的部分,使其成为多线程.虽然稍后将这些部分组合起来当然不是一件容易的事.当你有很多需要在客户端扩展的图像时,也许多线程更有意义.
这一切都取决于你的应用程序,图像和你自己的技能和愿望.
无论如何,我希望大致回答你的问题.
我觉得需要有关mslatour答案的一些细节,因为我花了6个小时试图找出如何"......简单地......将其数据属性更改为缩放的Uint8ClampedArray对象".去做这个:
①从Web工作者发回您的阵列.使用表格:
self.postMessage(bufferToReturn, [bufferToReturn]);
Run Code Online (Sandbox Code Playgroud)
如果你不想这样做,就可以将你的缓冲区传递给web worker,也可以从web worker中复制它.(这种方式更快.)(有一些MDN文档,但我无法链接到它,因为我没有代表.抱歉.)无论如何,你也可以将第一个bufferToReturn放在列表或地图中,如下所示:
self.postMessage({buffer:bufferToReturn, width:500, height:500}, [bufferToReturn]);
Run Code Online (Sandbox Code Playgroud)
你使用类似的东西
webWorker.addEventListener('message', function(event) {your code here})
Run Code Online (Sandbox Code Playgroud)
收听发布的消息.(在这种情况下,发布的事件来自Web工作者,并且正在进行监听的事件在您的普通JS代码中.它以相同的方式工作,只需切换'self'和'webWorker'变量.)
②在浏览器端Javascript(而不是工作者端)中,您可以使用imageData .data.set()"简单地"更改数据属性并将其放回画布中.
var imageData = context2d.createImageData(width, height);
imageData.data.set(new Uint8ClampedArray(bufferToReturn));
context2d.putImageData(imageData, x_offset, y_offset);
Run Code Online (Sandbox Code Playgroud)
我要感谢hacks.mozilla.org提醒我存在data.set()方法.
ps我还不知道有任何图书馆可以帮助解决这个问题.抱歉.
| 归档时间: |
|
| 查看次数: |
2748 次 |
| 最近记录: |