Javascript 是否可以从画布上下文';什么是图像数据?

Javascript 是否可以从画布上下文';什么是图像数据?,javascript,canvas,web-worker,getimagedata,todataurl,Javascript,Canvas,Web Worker,Getimagedata,Todataurl,后台设置 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

后台设置

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
}
我有一个处理从一组其他图像创建图像的web应用程序。我选择的方法是读入一组图像并将它们放置在HTML画布上。然后,我使用
toDataURL
将每个画布作为jpeg导出到第三方API,并将其转换为Blob。我面临的问题是,我有很多这样的画布,所有这些画布都以jpg的形式导出数据,这需要消耗大量资源。当每个画布尝试调用
toDataURL
时,应用程序速度变慢并变得无响应

问题

我发现调用画布的
toDataUrl()
toBlob()
可能非常慢,特别是对于大画布尺寸。我想利用web workers的多线程特性

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

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)
});
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'});
}
myWorker.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)
});
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信息的
uint8clampedaray
转换为jpg/png数据

我认为这可能有用的原因是,我相信
getImageData
只是从画布上下文复制现有的数据结构,因此成本没有
toDataUrl
那么高。我在调用类似于下面代码块的代码时捕获了cpu配置文件:

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

因此,考虑到这一点,我想把这一过程的主要影响转移到一个网络工作者身上。我甚至不介意它在web worker内部花费的时间是否比在另一个进程中发生的时间长

关于它的一些额外想法:

  • 添加一个额外的库来进行转换是可以的,但是提供了如何添加外部库作为web worker文件的依赖项的好处。现在我正在为应用程序使用browserify。也许为web worker创建另一个browserified包
  • 最后我需要一个jpeg(对于第三方API),所以将其转换为png只是转换为jpeg的一个步骤
  • 我已经尝试降低
    encoderOptions
    ,这是
    toDataURL
    中的第二个选项,以此来加速这个过程,但我没有看到太多的变化
----更新---

我想我会将我的解决方案作为npm库共享: . 它解释了如何利用提供的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模块修改的,更具体地说,是从文件修改的。通过将整个encoder.js文件复制到myWorker.js中,我移植了encode函数。它不是很小,但它也非常独立,这使它很容易。我留下的唯一问题是修改代码,使其在为其构建的node.js环境之外工作

事实证明,这相对容易:

  • 将“const”变量声明转换为“var”
  • 删除对
    缓冲区的引用
    。这是一个分两步的过程。首先,删除顶部的atob定义(因为它不是必需的)。其次,在this.encode函数的末尾返回一个
    新的Unit8Array
    。当前版本实际上在缓冲区引用的正上方注释掉了这一点。就用那个,把下面的东西都拿走
  • 正在删除对module.export的引用。这就像删除那一行一样简单,因为我们只需要在这个文件中使用这个函数

  • 我没有精确的时间测量,但它从图像生成时的约10秒延迟时间变为不足一秒的延迟时间。我在这里使用“滞后时间”是指在使用页面时性能缓慢

    这是可能的,但确实很难,我不确定你会有什么好处:你可以创建一个Blob,然后从一个Web工作者那里把它发送回主页。您可以自己对jpeg或png进行编码(即使我建议搜索一些库)。从png开始,比jpeg更清晰。注意:您还需要发送图像的元数据。但是最重的操作是
    ctx.getImageData()
    。我不确定通过将压缩部分传递给Web工作人员,您是否会赢得任何东西。也许您应该向我们展示您的代码,以便我们知道是否可以从中改进某些内容。(例如,您是否使用了一些异步方法以便GUI不会阻塞?@kaido-我更新了问题以反映我对该问题的更多理解。看来getImageData并不像预期的那样繁重。至于我的代码,我正在使用下划线的defer方法来包装canvas.toDataURL,这样就不会锁定UI,但一旦该方法开始(最终会),它就会阻止其他js执行。另外,值得注意的是,我对页面上的许多图像多次这样做,因此成本比报道的400msI找到一个看起来很有希望的库要高:但当我将其插入代码时,它似乎不是浏览器通常使用的正确jpeg编码。我创建了一个问题,希望更好地理解其中的区别: