0

Im trying to convert an image to BLOB and based my code on this SO post:

Blob from DataURL?

I can't tell if my code is wrong or if there's something wrong with the code from the SO post. Somewhere between these 2 functions the image is being corrupted. You can see the difference in file sizes in the console.logs. In the example it starts out at 45kb and ends up 1.83kb by the end of the code.

const captureImageFallback = (file) => {
  posts.photo = file;
  let context = canvas.value.getContext("2d");

  let reader = new FileReader();
  reader.onload = (event) => {
    let img = new Image();
    img.onload = () => {
      canvas.value.width = img.width;
      canvas.value.height = img.height;
      context.drawImage(img, 0, 0);
      imageCaptured.value = true;
    };
    img.src = event.target.result;
    console.log("img.src=", img.src);
  };
  console.log("file=", file.target.files[0]);
  reader.readAsDataURL(file.target.files[0]);
  console.log("reader=", reader);
  console.log("canvas.value=", canvas.value);
  posts.photo = dataURItoBlob(canvas.value.toDataURL());
  console.log("posts.photo=", posts.photo);
};


function dataURItoBlob(dataURI) {
      // convert base64 to raw binary data held in a string
      // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
      var byteString = atob(dataURI.split(",")[1]);
      // var byteString = Buffer.from(dataURI, "base64");

      // separate out the mime component
      var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];

      // write the bytes of the string to an ArrayBuffer
      var ab = new ArrayBuffer(byteString.length);

      // create a view into the buffer
      var ia = new Uint8Array(ab);

      // set the bytes of the buffer to the correct values
      for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
      }

      // write the ArrayBuffer to a blob, and you're done
      var blob = new Blob([ab], { type: mimeString });
      return blob;
    }

Here's printout of all the console.logs:

https://i.stack.imgur.com/oA1ke.png


Is the problem in the captureImageFallback code? The image is successfully loading into the canvas so I can't figure out where things are going wrong.

I've never done this before but I noticed the first console.log, console.log(img.src), is printed out last. Is that the issue here? Is there some asynchronous behavior I'm not aware of?

Do you see anything wrong with the code?


EDIT

This code also ends up in a corrupted file. The resulting Blob is also 1.83kb and blank. Does that mean it's not reading the canvas correctly? Not converting to Blob correctly?

const captureImageFallback = (file) => {
  posts.photo = file;
  let context = canvas.value.getContext("2d");

  let reader = new FileReader();
  reader.onload = (event) => {
    let img = new Image();
    img.onload = () => {
      canvas.value.width = img.width;
      canvas.value.height = img.height;
      context.drawImage(img, 0, 0);
      imageCaptured.value = true;
    };
    img.src = event.target.result;
    canvas.value.toBlob((blob) => {
      posts.photo = blob;
    });
  };
  reader.readAsDataURL(event.target.files[0]);
};

And skipping canvas and using:

 img.src = URL.createObjectURL(file.target.files[0])

results in:

"blob:http://localhost:8080/8a894003-4fe6-470e-b0a3-88dca7982547"

instead of just a "Blob" that I can send to a database

Eric Andre
  • 204
  • 2
  • 9
  • Not sure why you'd do any of that though. You already have the image as a Blob, if you want to display it, just do `img.src = URL.createObjectURL(file.target.files[0])`. And if you really want to export the canvas to a Blob, then use its `toBlob()` method. – Kaiido Oct 16 '22 at 11:34
  • I need the Blob to send it over a server into firebase storage. – Eric Andre Oct 16 '22 at 12:17
  • @Kaiido read my edit – Eric Andre Oct 16 '22 at 12:27
  • Read the linked answer. And if all you want is to send the blob to your server, why don't you send directly `file.target.files[0]`, that's a Blob already. – Kaiido Oct 16 '22 at 13:36
  • Because it's an "event" not a blob https://i.imgur.com/2dhdAxm.png – Eric Andre Oct 16 '22 at 13:44
  • I read the suggested answer and its premise is the `context.drawImage(img, 0, 0);` line of code is executing before the image is loaded therefore rendering blank. So I moved the code around, did useTimeouts, tried everything I could think of and it still didn't work. So Idk if the premise of that answer is even correct. It was never definitively answered. – Eric Andre Oct 16 '22 at 13:44
  • `file` is an Event, `file.target.files[0]` is a File, which implements the Blob interface. And the premise of the linked question is that they are calling `toDataURL()` before the image is painted on the canvas. – Kaiido Oct 16 '22 at 13:48
  • I just know setting `posts.photo = file.target.files[0]` results in dev tools telling me it's an event, not a Blob. I'm not using toDataUrl() so I don't know how to equate it. I setTimeouts on every individual line of code trying to allow time for the delay but I couldn't get it to work. But I can at least conclude the problem is with the canvas and trying to make the blob before the image is rendered onto the canvas, right? – Eric Andre Oct 16 '22 at 14:40
  • If `file.target.files[0]` was anything else but a `Blob`, your `readAsDataURL()` call would throw. And in your first snippet you have a call to `toDataURL()`, which is performed before `drawImage()`, in your new snippet you replaced it with `toBlob()`, but it's still called before `drawImage()` is performed. – Kaiido Oct 17 '22 at 05:30

0 Answers0