1

I have a vue.js application where I set up vue-workers/web-workers to perform some image processing(scaling/cropping) in the background after a user uploads a couple images.

I decided to go with ImageBitMpas & OffScreenCanvas since Canvas and Image Object is not supported in web workers. I can create an ImageBitMap from my image file using CreateImageBitMap() method. It successfully returns a promise and then resolves to an ImageBitMap. I can print it to my console and see the ImageBitMap gets created! I added a picture of the ImageBitmap printed to the console below.

ImageBitmap is created and error is thrown

var loadingImage = new Image();
loadingImage.onload = () => {

    console.log(createImageBitmap(loadingImage)); // I can see the ImageBitmap logged to console
    const canvas = new OffscreenCanvas(100,100);
    const ctx = canvas.getContext('2d');

    Promise.all([
        createImageBitmaps(loadingImage);
    ]).then(function(result){
        console.log("printing promise resolved");
        console.log(result);
        ctx.drawImage(result,0,0,200,200);  /// <-- this is where error is thrown
    })  

    // other code here .... 

};
loadingImage.src = base64Src; 

Question: Where I am having trouble is when I pass this ImageBitMap to the OffScreenCanvas.draw() method I get an error saying "failed to execute drawImage on OffscreenCanvasRenderer..." You can see the exact error in the console after the ImageBitMap is printed in the picture below.

Has anyone successfully drawn an image to an OffScreenCanvas in a vue-worker/web-worker? Any Example of working code would be greatly appreciated!

Also from my research, it seems like createImageBitMap() is only supported in Chrome?! Is there another way instead of using ImageBitMap to draw to OffScreenCanvas that will work on both chrome and Safari???

vpandher
  • 31
  • 2
  • 5
  • 1
    Please post the code directly in the question and not as a screenshot. Also, if you are in a Worker, what is this `Image` constructor? Not only is createImageBitmap not yet available from a Worker in Safari, but neither is the 2d context of the OffscreenCanvas on any other browser than Chrome. Finally, you can see a working example in this Q/A: https://stackoverflow.com/a/56553680/3702797 – Kaiido Mar 20 '20 at 11:46
  • **Also, if you are in a Worker, what is this Image constructor?** - I didn't add the code for the web worker because I couldn't get it working in the main thread. Ideally once I have a working model, only then would I try to run it in a separate thread/web-worker. – vpandher Mar 20 '20 at 15:59
  • Thanks for replying, I have added my JS code and removed my screenshot. **Not only is createImageBitmap not yet available from a Worker in Safari, but neither is the 2d context of the OffscreenCanvas on any other browser than Chrome.** There are other websites that are able to load and crop multiple images extremely fast in Safari as well, any idea how they might be doing it? Is there a way to draw an image to a canvas(thats supported in both chrome&safari and can work in a web worker) Maybe using Uint8ClampedArray or with an ImageData object ?? – vpandher Mar 20 '20 at 16:47
  • What makes you think they used an offscreen canvas? OffscreenCanvas are meant to offload the main thread CPU by doing CPU intensive operations on an other thread. Cropping an image is not that CPU intensive, you eon't win much. From your code I can already see hou are doing too many CPU intensive opertions by reading binary files as base64 data URL, when you should have just done `createImageBitmap(input.files[n])` (which is polyfillable, using blob URLs). – Kaiido Mar 21 '20 at 01:15

2 Answers2

1

Have you tried using ImageBitmapRenderingContext?

canvas.getContext('bitmaprenderer').transferFromImageBitmap(bitmap);
Don Park
  • 379
  • 1
  • 5
  • 3
0

In the example the type of result is an array, because of Promise.all but that's not supported as image source. Removing Promise.all and directly using the resolved result solves the problem.

var loadingImage = new Image();
loadingImage.onload = () => {

    console.log(createImageBitmap(loadingImage)); // I can see the ImageBitmap logged to console
    const canvas = new OffscreenCanvas(100,100);
    const ctx = canvas.getContext('2d');
    
    createImageBitmap(loadingImage).then(function(result){
        console.log("printing promise resolved");
        console.log(result);
        ctx.drawImage(result,0,0,200,200);  /// <-- this is where error is thrown
    })  

    // other code here .... 

};
loadingImage.src = "https://i.stack.imgur.com/ioGgw.png"; 

This prints, no error (in Chrome):

[object Promise] { ... }
"printing promise resolved"
[object ImageBitmap] {
  close: function close() { [native code] },
  height: 402,
  width: 812
}
lexx9999
  • 736
  • 3
  • 9