0

I am trying to draw images from a data URL (obtained from user-provided files) onto a canvas using the Canvas API and then using JsZip to package the resulting images in a zip file which is to be downloaded.

Note: The canvas is never actually displayed to the user. It only serves as a framebuffer.

The problem is the image is not drawn onto the canvas when using the 'drawImage' function in the following way (from a different solution):

const url = URL.createObjectURL(acceptedFiles[image])
const img = new Image()
img.onload = () => ctx.drawImage(img, column, row, imageWidth, imageHeight)
img.src = url

I'm not sure why onload is being used here but it seems quite counterintuitive to me as the canvas in not supposed to be seen by the user. Other functions like 'fillRect' work fine it's only 'drawImage' that is not working for me.

I'm not sure if and how I would use a different CanvasImageSource but this code results in nothing but a blank screen.

Another issue is with how the resulting image is archived.

I am using JsZip to archive the resulting image but that also doesn't work and I am left with an empty zip file. Here is the code that does that:

const filename = `Page ${i + 1}.png`
const data = canvas.toDataURL()
zip.file(filename, data)
  • onload for an image is triggered when the image set to src has fully loaded. if you have a dataURL string you can load it into an image like this `img.src = strDataURI;` i'm not sure that's what you are actually doing however. if you are trying to load a user loaded image from their file system, then this question may help: https://stackoverflow.com/questions/10906734/how-to-upload-image-into-html5-canvas – dqhendricks Sep 06 '22 at 21:28
  • Yes, I am loading the data URL into the image src but still nothing happens. I also checked out the question you linked. It seems like it is just a longer approach to what I did with 'URL.createObjectURL' but I tried it nevertheless. Didn't work :/ – DotDivee Sep 06 '22 at 21:51
  • URL.createObjectURL does not return a dataURL, but rather an objectURL. the question is, where are you getting `acceptedFiles[image]`? is this from a file input's `change` event, like the example in the linked question? we don't see enough code here to tell what the problem is. and also where is the creation of ctx? – dqhendricks Sep 06 '22 at 22:10
  • Yeah I just realised that 'URL.createObjectURL' doesn't make a data URL. Also, quite fortunately, I have managed to figure out the problem. Thanks for the help. – DotDivee Sep 06 '22 at 22:47

1 Answers1

0

The image was not drawing because I wasn't awaiting the loading of the image. Awaiting this function solved my problem:

const loadImage = (url: string) => {
  return new Promise<HTMLImageElement>((resolve, reject) => {
    const img = new Image()
    img.onload = () => {
      resolve(img)
    }

    img.onerror = reject

    img.src = url
  })
}

After, I used 'then' to draw the image once it has been loaded:

await loadImage(url).then((imageSource) =>
  ctx.drawImage(
    imageSource,
    column * imageWidth,
    row * imageHeight,
    imageWidth,
    imageHeight
  )
)