Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript, how can I get image width and height from a blob?

So this is my code snippet (unnecessary code lines are removed):

let imgInput = document.getElementById('id_photo');
imgInput.addEventListener('change', function (e) {
    if (e.target.files) {
        for (let i = 0; i < e.target.files.length; i++) {

        let imageFile = e.target.files[i];
        var reader = new FileReader();

        reader.onload = function (e) {
            var img = document.getElementById(nevermindID);
            img.onload = function() {
                var shape = resizeImage(img) // resizing image for future canvas drawing, returns [width, height] (resized)
                
                var canvas = document.createElement("canvas")
                canvas.width = shape[0]
                canvas.height = shape[1]
                var ctx = canvas.getContext("2d")
                ctx.drawImage(img, 0, 0, shape[0], shape[1])
                // converting to base64 logic and the rest code
            }
            img.src = e.target.result;
        }
        reader.readAsDataURL(imageFile);

    }
}
});

I want to get the uploaded original image's width and height so I can resize it. I can't do it from imageFile as it returns undefined and can't get it from the img variable as it originally depends on my css (in css the <img> tag is in a <div> tag which is not fullscreen, let's say it is 400 pixels). So correspondingly, if I upload 5000x5000 image it will not be the original-sized (hope you got it). My problem is that because my css resizes that div and elements inside, I can't get normal width and height of my original image, so I can resize it then draw with canvas and then convert it to base64.

I try to add this code to img.onload:

var blobURL = URL.createObjectURL(imageFile)

Here I access my original image (which is imageFile), create blob for it and get that blob link. But I can't access that blob link image's width and height. Any suggestions?

Note: I think the problem is in img.onload itself. As in this line I pass that img:

ctx.drawImage(img, 0, 0, shape[0], shape[1])

FYI. This is how it looks when I upload my image. It is about 90x90 pixels here. And that causes the problem with canvas, as img.onload takes those dimensions (90x90) and not the original dimensions which is about 5000x5000 enter image description here

The resized image looks like: enter image description here

Edited:

If anyone is curious, I can paste my solved code version here so you can adjust to it. Leave a comment below.

like image 543
Mammadali Mammadaliyev Avatar asked Jun 04 '26 17:06

Mammadali Mammadaliyev


2 Answers

You can use the Image constructor

const img = new Image();
img.src = imageDataUrl;
img.onload = () => {
   // img.width
   // img.height
 };
like image 193
Mostafa Zaki Avatar answered Jun 07 '26 07:06

Mostafa Zaki


The best is to create an ImageBitmap from this Blob.

In some implementations this avoids having the decoding of the image being made on the main thread and blocking your page, and is anyway a much lighter path than the HTMLImageElement one in every implementation (avoids a network request, the creation of a DOM object, a lot of internal checks etc.).
If you only want to get the size of the image, this also allows you to release the bitmap data from the browser's memory, thanks to the .close() method, while the HTMLImageElement will generally try to cache its bitmap data even after the original DOM element has been destroyed.
And as a bonus, it even works in Web Workers.

(async () => {
  const imgBlob = await getImgBlob();
  const bmp = await createImageBitmap(imgBlob);
  const { width, height } = bmp;
  bmp.close(); // free memory
  console.log(width, height);
})();


// simple helper to get the Blob of an image
async function getImgBlob() {
  const resp = await fetch("https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png");
  return resp.ok ? resp.blob() : Promise.reject(resp.status);
}

If you need to target older browsers, you can use this polyfill of mine.

The only drawback of this method is that it works only for bitmap images, you can't create an ImageBitmap from a Blob of an SVG image, because this kind of image can have no intrinsic dimensions of its own.


And since you are gonna draw that image on a canvas, note that you can also obviously pass this ImageBitmap to drawImage() (before you close it), and that it also even allows you to do the resizing directly:

(async () => {
  const canvas = document.querySelector("canvas");
  const ctx = canvas.getContext("2d");
  const imgBlob = await getImgBlob();
  const originalBmp = await createImageBitmap(imgBlob);
  const { width, height } = originalBmp;
  // we create the resized from the ImageBitmap for even faster processing
  // but we could obviously reuse the Blob here too
  const resizedBmp  = await createImageBitmap(originalBmp, { resizeWidth: 90, resizeHeight: 90 });
  originalBmp.close();
  canvas.width  = width;
  canvas.height = height;
  ctx.drawImage(resizedBmp, 0, 0, width, height);
  resizedBmp.close();
})().catch(console.error);

// simple helper to get the Blob of an image
async function getImgBlob() {
  const resp = await fetch("https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png");
  return resp.ok ? resp.blob() : Promise.reject(resp.status);
}
<canvas></canvas>
like image 26
Kaiido Avatar answered Jun 07 '26 06:06

Kaiido



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!