繁体   English   中英

是否可以从画布上下文的getImageData在Web worker中生成图像(blob或data-url)?

[英]Is it possible to generate an image (blob or data-url) in a web worker from a canvas context's getImageData?

后台设置

我有一个Web应用程序,处理从一组其他图像创建图像。 我选择这样做的方法是通过读取一组图像并将它们放在HTML画布上。 然后,我使用toDataURL将每个画布作为jpeg导出到第三方API并将其转换为Blob。 我面临的问题是,我有很多这些画布都将数据导出为jpg,并且消耗了大量资源。 当每个画布尝试调用toDataURL ,应用程序会变慢并变得无响应。

我发现调用画布的toDataUrl()toBlob()可能会非常慢,特别是对于大画布大小。 我想利用Web worker的多线程特性。

首先,我尝试传入canvas对象但是抛出了一个错误。 事实证明,对象是一个问题,它们似乎要么被转换为字符串,要么在无法克隆时失败。 无论哪种方式,我发现传递上下文的图像数据确实有效。 数据以原始RGB值的形式作为Uint8ClampedArray从canvas上下文的方法getImageData()传递。

Main.js

var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var worker = new Worker('myWorker.js');
worker.postMessage({
  image: context.getImageData(0, 0, canvas.width, canvas.height)
});

myWorker.js

this.onmessage = function(e) {
  // GOAL: turn e.data.image into an image blob or dataUrl and return it.
  // e.g. this.postMessage(new Blob([e.data.image.data], {type: 'image/jpg'});
}

我认为归结为知道如何将保存RGB信息的Uint8ClampedArray转换为jpg / png数据。

我认为这可能有用的原因是我相信getImageData只是从canvas上下文复制现有的数据结构,因此不像toDataUrl那样昂贵。 我在调用类似于下面代码块的内容时捕获了cpu配置文件:

var image = context.getImageData(0, 0, canvas.width, canvas.height)
var dataUrl = canvas.toDataURL('image/jpeg');

得到了:

性能来自getImageData和toDataURL

所以,考虑到这一点,我想将流程的主要负担转移到网络工作者身上。 我甚至不介意,只要它在另一个进程中发生,它在Web工作者中需要更长的时间。

几个关于它的额外想法:

  • 添加额外的库来进行转换是可以的,但是提供如何添加外部库作为Web工作文件依赖项的奖励点。 现在我正在使用browserify来申请。 也许为Web worker创建另一个浏览器捆绑包?
  • 我最终需要一个jpeg(对于第三方API),所以将它转换为png只是转换为jpeg的一个步骤。
  • 我已经尝试降低了encoderOptions中的第二个选项toDataURL ,作为加速这个过程的一种方法,但我没有看到太多变化

---- ----更新

我想我会分享我作为npm库的解决方案: https ://www.npmjs.com/package/jpeg-web-worker。 它解释了如何利用提供的网络工作者为您做繁重的工作。

---------------------

我找到了一个适合我的解决方案,加快了应用程序和页面的响应速度,同时仍然生成了新的图像。

这是应用代码:

应用

var canvas = $('#myCanvas')[0];
var context = canvas.getContext('2d');
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
var worker = new Worker('myWorker.js');
worker.postMessage({
  image: imageData
});
worker.onmessage = function(e) {
  var blob = new Blob( [e.data.data], {type: 'image/jpeg'} );
  // use blob
}

这是工人代码:

工人

this.onmessage = function(e) {
  var jpgInfo = encode(e.data.image, 50);
  this.postMessage(jpgInfo);
}

function encode() { ... } // ported from jpeg-js

显然,这个答案的大部分来自encode功能。 此功能是从npm模块jpeg-js修改的,更具体地说,是文件encoder.js 我通过将整个encoder.js文件复制到myWorker.js中来移植编码功能。 它不是很小,但它也非常独立,这使它变得容易。 我留下的唯一问题是修改代码,使其在为其构建的node.js环境之外工作。

事实证明这相对容易:

  1. 将“const”变量声明转换为“var”
  2. 删除对Buffer引用。 这是一个两步的过程。 首先,删除顶部的atob定义(因为它不需要)。 其次,在this.encode函数结束时返回一个new Unit8Array的Unit8Array。 当前版本实际上已将此注释放在缓冲区引用的正上方。 只需使用那个并删除下面的所有内容。
  3. 删除对module.export的引用。 这就像删除该行一样简单,因为我们在此文件中只需要此功能。

我没有精确的定时测量,但是当图像生成到滞后时间的第二个时,它从延迟时间的~10秒开始。 我在这里使用“滞后时间”意味着在使用页面时性能低下。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM