我需要在Web Worker中按比例缩放图像数组。如果我在Web Worker之外,可以使用Canvas和drawImage来复制图像的某些部分或将其缩放。
看起来在Web Worker中不能使用Canvas,那么我该怎么办?是否有任何纯JavaScript库可以帮助我?
非常感谢提前。
我需要在Web Worker中按比例缩放图像数组。如果我在Web Worker之外,可以使用Canvas和drawImage来复制图像的某些部分或将其缩放。
看起来在Web Worker中不能使用Canvas,那么我该怎么办?是否有任何纯JavaScript库可以帮助我?
非常感谢提前。
缩放图像可以通过不同的方式实现,但它们都可以归结为从图像中删除或创建像素。由于图像本质上是像素值的矩阵(调整大小为数组),因此您可以将图像放大看作扩展该数组并填充空白,将图像缩小看作通过留出值来缩小数组。
话虽如此,通常编写适用于数组的自己的JavaScript比例函数并不难。由于我理解您已经将图像以JavaScript数组的形式获取,因此您可以将该数组传递到Web Worker中的消息中,使用您的比例函数进行缩放,并将缩放后的数组发送回主线程。
在表示方面,建议您使用Uint8ClampedArray,该数组专为RGBA(带有alpha通道的颜色)编码图像而设计,比普通JavaScript数组更有效。您还可以轻松将Uint8ClampedArray对象发送到Web Worker中的消息中,因此这不会成为问题。另一个好处是Uint8ClampedArray在Canvas API的ImageData数据类型中使用(替换CanvasPixelArray)。这意味着,如果您想要,在画布上绘制缩放后的图像非常容易,只需使用ctx.getImageData()获取画布2D上下文的当前ImageData,然后将其数据属性更改为缩放后的Uint8ClampedArray对象即可。
顺便说一下,如果您还没有将图像转换为数组,可以使用相同的方法。首先在画布上绘制图像,然后使用当前ImageData对象的数据属性以Uint8ClampedArray形式检索图像。
关于放大图像的缩放方法,基本上需要实现两个组件。第一个组件是将已知像素(即要缩放的图像中的像素)分配到您创建的较大新数组中。一种明显的方法是均匀地将所有像素分配到空间中。例如,如果将图像的宽度增加两倍,则只需在每个像素之后简单地跳过一个位置,留下空白。
第二个组件是填充这些空白,这可能有点不太直接。然而,有一些方法是相当容易的。(另一方面,如果您对计算机视觉或图像处理有一些了解,您可能需要查看一些更高级的方法。)一种简单而明显的方法是使用最近邻插值法来插入每个未知的像素位置(即最接近已知像素值的最近像素),通过复制已知像素的颜色来进行。当你将图像缩放得太大时,这通常会导致更大的像素效果(更大的同色块)。除了复制最接近像素的颜色之外,您还可以取几个附近已知像素的平均值。可能甚至与权重相结合,使较近的像素在平均值中占据更多比较远的像素。其他方法包括使用高斯模糊来模糊图像。如果您想找出哪种方法最适合您的应用程序,请查看一些关于图像插值的页面。当然,记住,放大总是意味着填充一些实际上并不存在的东西。如果您这样做得太多,这总是会看起来很糟糕。此外,我相信有一些JavaScript库可以为您完成此操作,取决于它们的方法,您也可以使用importScripts在Web Worker中加载它们。但我认为,在这种情况下,自己编写并量身定制更容易且更有趣。
根据您的编程技能和需要扩展的速度,您可以尝试在WebGL上使用GPU而不是CPU来执行此操作。但在这种情况下,可能会有点过度。此外,您可以尝试将图像分成几个部分,并尝试在多个Web Worker上对各个部分进行缩放,使其变为多线程。虽然后面组合部分并不容易。也许当您需要在客户端缩放许多图像时,多线程更有意义。
所有这一切都取决于您的应用程序、图像以及您自己的技能和需求。
总之,希望这大致回答了您的问题。
self.postMessage(bufferToReturn, [bufferToReturn]);
self.postMessage({buffer:bufferToReturn, width:500, height:500}, [bufferToReturn]);
webWorker.addEventListener('message', function(event) {your code here})
监听已发布的消息。(在这种情况下,被发布的事件来自 Web Worker,而进行监听的事件则在普通 JS 代码中。方式相同,只需交换 'self' 和 'webWorker' 变量即可)
② 在浏览器端的 Javascript 中(与 worker 端不同),您可以使用 imageData.data.set() 来“简单地”更改数据属性并将其放回画布中。
var imageData = context2d.createImageData(width, height);
imageData.data.set(new Uint8ClampedArray(bufferToReturn));
context2d.putImageData(imageData, x_offset, y_offset);