Is it possible to generate an image (blob or data-url) in a web worker from a canvas context's getImageData?
<p><strong>Background Setup</strong></p>

<p>I have a web application that deals with creating images from a set of other images. The way I've chosen to do that is by reading in a set of images and placing them on an HTML canvas. Then, I export each canvas as a jpeg to a third-party API using <code>toDataURL</code> and converting it into a Blob. The issue I am facing is that I have many of these canvases all exporting data as a jpg and it is consuming a lot of resources. The application slows and becomes unresponsive as each canvas attempts to call <code>toDataURL</code>.</p>

<p><strong>Question</strong></p>

<p>I've found that calling a canvas's <code>toDataUrl()</code> or <code>toBlob()</code> can be very slow especially for large canvas sizes. I'd like to utilize the multi-threaded nature of web workers. </p>

<p>First, I tried passing in the canvas object but an error was thrown. It turns out objects are a problem and that it seems they either get converted into strings or fail when they can't be cloned. Either way, I found that passing a context's image data does work. The data is passed in the form of raw RGB values as a <code>Uint8ClampedArray</code> from the canvas context's method <code>getImageData()</code>.</p>

<p><strong>Main.js</strong></p>

<pre><code>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)
});
</code></pre>

<p><strong>myWorker.js</strong></p>

<pre><code>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'});
}
</code></pre>

<p>I think it comes down to knowing how to convert a <code>Uint8ClampedArray</code> which holds the RGB information into the jpg/png data.</p>

<p>The reason why I think this might be useful is that I believe that <code>getImageData</code> just copies an existing data structure from the canvas context and therefore is not as costly as <code>toDataUrl</code>. I captured the cpu profile while calling something similar to the code block below:</p>

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

<p>and got:</p>

<p><a href="https://i.stack.imgur.com/IrlqD.png" rel="noreferrer"><img src="https://i.stack.imgur.com/IrlqD.png" alt="Performance results from getImageData and toDataURL"></a></p>

<p>So, given that, I'd like to offload the brunt of the process into a web worker. I don't even mind if it takes longer inside the web worker as long as its happening in another process.</p>

<p>Couple of extra thoughts about it:</p>

<ul>
<li>Adding an extra library to do the conversion is okay, but bonus points for offering how to add an external library as a dependency to web worker files. Right now I'm using browserify for the application. Perhaps create another browserified bundle for the web worker?</li>
<li>I need a jpeg in the end (for a third party API) so converting it to a png is only so good as to be a step in the conversion to a jpeg.</li>
<li>I've tried lowering the <code>encoderOptions</code>, the second option in <code>toDataURL</code>, as a way to speed up the process, but I haven't seen much of a change</li>
</ul>