Search code examples
javascripthtml5-canvasweb-worker

DOMException: The source image could not be decoded


What could be the reason that the method below throws DOMException: The source image could not be decoded.?

async function drawImage(blob) {
    console.log('Start draw image.')
    console.log(blob);
    if(context === undefined) {
        console.log('Context is not defined.');
    } else if(blob.type === 'image/jpeg') {
        console.log('Drawing image');
        // Error: DOMException: The source image could not be decoded.
        const bmp = await createImageBitmap(blob);
        context.drawImage(bmp, 0, 0);
        bmp.close();
    }
}

The code above runs inside a web worker, specifically after a decode process:

onmessage = async function (e) {
    let jpegBlob = decodeBinary(e.data);
    drawImage(jpegBlob);
}

Solution

  • Well, a broken image would cause this.

    // The same would happen in a Worker thread,
    // it's just easier for StackSnippet to log from main thread
    const context = document.createElement('canvas').getContext('2d');
    
    function decodeBinary() {
      return new Blob(["not an image"], {type: 'image/jpeg'});
    }
    async function drawImage(blob) {
      console.log('Start draw image.')
      console.log(blob);
      if (context === undefined) { // beware, unsupported call to getContext returns `null`, not `undefined`
        console.log('Context is not defined.');
      } else if (blob.type === 'image/jpeg') {
        console.log('Drawing image');
        // Error: DOMException: The source image could not be decoded.
        const bmp = await createImageBitmap(blob);
        context.drawImage(bmp, 0, 0);
        bmp.close();
      }
    }
    
    onmessage = async function(e) {
      let jpegBlob = decodeBinary(e.data);
      drawImage(jpegBlob).catch(console.error);
    }
    
    self.postMessage('', '*');

    So you will want to check the content of your Blob, and to debug your decodeBinary function.

    As a first step, you can check if the file signature matches one of the JPEG image:
    new Uint8Array( (await blob.slice(0,3).arrayBuffer()) ).join("") === "255216255";

    You can also try to pass that Blob to your main thread, create a blob: URL from it, and try to load it in an <img> tag, your browser may be more explicit about what the issue is.