I tried to transfer an image drawn to an offscreen canvas by a web worker to a visible canvas. It works in Chrome, but not in Firefox. No error was thrown in the console, but the visible canvas remains blank. Below is my complete program (index.html). Is this an issue with how Firefox handles worker and canvas? Is there a fix to this? Thanks!
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script>
window.addEventListener('load', function () {
const w = 600, h = 400;
const blob = new Blob(['(' + render.toString() + ')()'], {type: 'text/javascript'});
const worker = new Worker(URL.createObjectURL(blob));
const offs = document.getElementById('worker').transferControlToOffscreen();
worker.postMessage({ msg: 'load', canvas: offs }, [offs]);
// draw image in offscreen canvas
document.getElementById('render').addEventListener('click', function () {
worker.postMessage({ msg: 'draw' });
});
// transfer image to main canvas
document.getElementById('transfer').addEventListener('click', function () {
const img = document.getElementById('worker');
const ctx = document.getElementById('main').getContext('2d');
ctx.clearRect(0, 0, w, h);
ctx.drawImage(img, 0, 0, w, h, 0, 0, w, h);
});
});
// worker for rendering
function render() {
let canvas;
onmessage = function(e) {
if (e.data.msg === 'load') {
canvas = e.data.canvas;
} else if (e.data.msg === 'draw') {
ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(150, 150, 300, 200);
}
}
}
</script>
</head>
<body>
<div>
<p>
<canvas id="main" width="600" height="400"></canvas>
<canvas id="worker" width="600" height="400" style="display: none"></canvas>
</p>
<p>
<button id="render">Render</button>
<button id="transfer">Transfer</button>
</p>
</div>
</body>
</html>
This is indeed a bug, and I filed BUG 1833496.
For a fix, we'll need to wait a bit, but the last few bugs I opened against their
OffscreenCanvasyoung implementation were fixed rapidly, so there is hope this one gets fixed too.If you need a workaround, you could transfer your
OffscreenCanvasto anImageBitmap, transfer that back to your main thread throughpostMessage()and draw it when needed: