JavaScript,如何从blob中获取图像的宽度和高度?

5
这是我的代码片段(已删除不必要的代码行):
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);

    }
}
});

我想获取已上传原始图像的宽度和高度,以便我可以调整其大小。我无法从 imageFile 中获取它,因为它返回 undefined,也无法从 img 变量中获取它,因为它最初取决于我的 CSS(在 CSS 中,<img> 标签位于不是全屏的 <div> 标签中,假设它是 400 像素)。因此,相应地,如果我上传的图像大小为 5000x5000,则它将不是原始大小(希望您明白)。我的问题是,因为我的 CSS 调整了该 div 和其中的元素的大小,所以我无法获取原始图像的正常宽度和高度,因此我不能调整大小,然后使用 canvas 绘制,然后将其转换为 base64。
我尝试将以下代码添加到 img.onload 中:
var blobURL = URL.createObjectURL(imageFile)

在这里,我访问我的原始图像(即 imageFile),为它创建 blob 并获取该 blob 链接。但是我无法访问该 blob 链接图像的宽度和高度。有什么建议吗?
注意:我认为问题就在于 img.onload 本身。因为在这一行中,我传递了那个 img
ctx.drawImage(img, 0, 0, shape[0], shape[1])

FYI. 这是我上传图片时的样子。这里大约是90x90像素。这导致了画布的问题,因为img.onload使用的是这些尺寸(90x90),而不是原始尺寸,大约为5000x5000。 输入图像描述 调整大小后的图片如下: 输入图像描述 编辑:
如果有人感兴趣,我可以在下面留言中粘贴我的解决代码版本,以便您进行调整。
3个回答

7
您可以使用图像构造函数。
const img = new Image();
img.src = imageDataUrl;
img.onload = () => {
   // img.width
   // img.height
 };

没错!这对我来说完全可行。谢谢,伙计!这段代码足以解决我的问题 :) 祝你好运! - Mammadali Mammadaliyev
非常好,而且非常容易理解。 - Florjan

6
最好的方法是从这个Blob创建一个ImageBitmap
在某些实现中,这可以避免图像解码在主线程上进行并阻塞您的页面,并且在每个实现中都比HTMLImageElement更轻量级的路径(避免网络请求、DOM对象的创建、许多内部检查等)。如果您只想获取图像的大小,这也允许您通过.close()方法释放浏览器内存中的位图数据,而HTMLImageElement通常会尝试在原始DOM元素被销毁后仍然缓存其位图数据。作为奖励,它甚至可以在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);
}

如果你需要针对旧版浏览器进行定位,你可以使用我的这个polyfill
这种方法唯一的缺点是它只适用于位图图像,你无法从SVG图像的Blob中创建ImageBitmap,因为这种图像可能没有自己的内在尺寸。

既然你将在画布上绘制该图像,请注意你还可以将此ImageBitmap显然传递给drawImage()(在关闭之前),它甚至允许你直接进行调整大小:

(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>


const bitmap: ImageBitmap = await createImageBitmap(blob); const { width, height } = bitmap; console.log(width, height);const bitmap: ImageBitmap = await createImageBitmap(blob); const { width, height } = bitmap; console.log(width, height); - undefined

4

clientHeightclientWidthoffsetHeightoffsetWidthheightwidth 可以获取相对尺寸。要获得原始尺寸,必须使用 .naturalHeight.naturalWidth

HTMLImageElement.naturalWidth
HTMLImageElement 接口的只读 naturalWidth 属性返回 CSS 像素中图像固有(自然)且经过密度校正的宽度。

这是图像在没有任何限制其宽度的情况下绘制的宽度;如果您既不为图像指定宽度,也不将图像放置在限制或明确指定图像宽度的容器中,则此数值就是图像的 CSS 像素宽度。

您可以在此处阅读更多信息:链接

你的代码片段可以使用 .naturalWidth.naturalHeight 进行更新。

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('displayImage');
        img.onload = function() {
          debugger;
          var shape = resizeImage(img) // resizing image for future canvas drawing, returns [width, height] (resized)
          // or just
          // var shape = [image.naturalWidth, image.naturalHeight]
          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])
          
          document.body.appendChild(canvas); // added
          // converting to base64 logic and the rest code
        }
        img.src = e.target.result;
      }
      reader.readAsDataURL(imageFile);
      
    }
  }
});
function resizeImage(image){
  return [image.naturalWidth, image.naturalHeight]
}
img{
  width: 100px;
  heigh: 100px;
}
<img id='displayImage'/>
<input type='file' multiple id='id_photo'/>


此外,如果您只是为了获取图像的src而添加图像,可以尝试使用new Image()来跳过创建额外的DOM元素。

let imgInput = document.getElementById('id_photo');
imgInput.addEventListener('change', function (e) {
  if (e.target.files) {
    Array.from(e.target.files).forEach(file=>{
      const fileReader = new FileReader();
      fileReader.readAsDataURL(file);
      fileReader.onload = (fe) => {
        const image = new Image();
        image.src = fe.currentTarget.result;
        image.onload = function(ie){
          console.log('Width: ' + this.naturalHeight);
          console.log('Height: ' + this.naturalWidth);
        }
      }
    })
  }
});
<input type='file' multiple id='id_photo'/>


请注意,naturalWidth和naturalHeight可能会受到“srcset”属性的影响:https://jsfiddle.net/w07qdhzs/ - Kaiido
是的。但是从文件选择器获取图像,而不是从DOM元素中提取。 - MORÈ
在这种情况下,.width.height也将与固有尺寸匹配。 - Kaiido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接