从Base64编码的PNG图片中获取高度和宽度尺寸

18

我有这个:

data:image/png;base64,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

我想使用JavaScript从这个字符串中获取高度和宽度。我该如何做?这是否可行?

您可以假设可以访问jQuery,window.btoawindow.atob


5
将它放在一个“图像”对象中。 - SLaks
具体来说,我正在寻找一些可以解析和读取base64字符串并执行两个操作的东西:(1)验证它是PNG(注意:对我来说,所有PNG都具有初始子字符串“iVBORw0KGgoAAAANSUhEUgAAA”),以及(2)从IHDR标头确定宽度、高度(如果可能的话,也希望获得其余部分:位深度、颜色类型、压缩模式、过滤器和交错)。如果可能的话,我想避免使用canvas或Image。 - Travis Smith
你很可能无法编写比浏览器本机解析器更快的Javascript PNG解析器。 - SLaks
我不相信用JavaScript/jQuery可以获取这些信息,因为这些信息仅由浏览器处理,且以我所知并未向JavaScript公开。这让我想知道数据URI来自何处,以及在它到达网页之前是否无法获取信息。 - Sygmoral
3
可以使用纯JS解析PNG文件格式。 - SLaks
6个回答

41

我确信能从PNG图片中解析出那个数据,但是假设支持数据URI(因为我们可以假定存在atob),您只需创建一个图像并等待其加载(这适用于任何格式):

var image = document.createElement('img');

image.addEventListener('load', function() {
    // image.width × image.height
});

image.src = 'data:image/png;base64,…';

这里有一个演示。


好的,显然你希望手动提取这些信息。PNG文件以字节 89 50 4E 47 0D 01 1A 0A 开始,接着是包含宽度和高度的IHDR块,并且必须作为第一个块。(耶,更容易了!)一个块具有4个字节的长度、4个字节的类型,以及一个长度字节的内容。IHDR的内容以4个字节的宽度和4个字节的高度开头,因此PNG的宽度和高度始终是字节16-24!如果你喜欢,可以进行所有这些检查,但对于一种假设PNG有效的简单方法:

function toInt32(bytes) {
    return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
}

function getDimensions(data) {
    return {
        width: toInt32(data.slice(16, 20)),
        height: toInt32(data.slice(20, 24))
    };
}

var base64Characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

function base64Decode(data) {
    var result = [];
    var current = 0;

    for(var i = 0, c; c = data.charAt(i); i++) {
        if(c === '=') {
            if(i !== data.length - 1 && (i !== data.length - 2 || data.charAt(i + 1) !== '=')) {
                throw new SyntaxError('Unexpected padding character.');
            }

            break;
        }

        var index = base64Characters.indexOf(c);

        if(index === -1) {
            throw new SyntaxError('Invalid Base64 character.');
        }

        current = (current << 6) | index;

        if(i % 4 === 3) {
            result.push(current >> 16, (current & 0xff00) >> 8, current & 0xff);
            current = 0;
        }
    }

    if(i % 4 === 1) {
        throw new SyntaxError('Invalid length for a Base64 string.');
    }

    if(i % 4 === 2) {
        result.push(current >> 4);
    } else if(i % 4 === 3) {
        current <<= 6;
        result.push(current >> 16, (current & 0xff00) >> 8);
    }

    return result;
}

function getPngDimensions(dataUri) {
    if (dataUri.substring(0, 22) !== 'data:image/png;base64,') {
        throw new Error('Unsupported data URI format');
    }

    // 32 base64 characters encode the necessary 24 bytes
    return getDimensions(base64Decode(dataUri.substr(22, 32)));
}

var dimensions = getPngDimensions('data:image/png;base64,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');

console.log(dimensions.width + ' × ' + dimensions.height);


3
我会选择使用 new Image() - Musa
这个很好用!所以我为我的问题表达不清道歉。请参见上面的新评论。 - Travis Smith
@TravisSmith:好的 :D 经过艰苦努力、辛勤劳动和刻苦工作,我阅读了一段规范,并为此制作了一个东西。不过你可能需要添加一些错误检查。 - Ry-
1
对于那些在通过DOM快捷方式上碰壁的人,通过new Image()document.createElement("IMG")创建的IMG在加载之前不会有尺寸。我以为BASE64图像会立即“加载”... 错了!添加“load”事件侦听器,然后再根据高度和宽度进行操作是关键。这是我犯下的可耻的疏忽。 :( - Eric L.
1
根据规范(https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement),还有`naturalHeight`和`naturalWidth`属性,在实际显示和设置<img>时可能更为合适。 - Deiwin
显示剩余3条评论

21

三年后,这里是一个新的更新的ES6版本,它借助于类型数组提供了同步功能,您不必将整个图像加载到内存中才能弄清楚它。因此速度更快 :)

此外,它不需要任何DOM,因此可以在Workers内部工作。

function getPngDimensions(base64) {
  const header = atob(base64.slice(0, 50)).slice(16,24)
  const uint8 = Uint8Array.from(header, c => c.charCodeAt(0))
  const dataView = new DataView(uint8.buffer)

  return {
    width: dataView.getInt32(0),
    height: dataView.getInt32(4)
  }
}

// Just to get some Base64 PNG example
const canvas = document.createElement('canvas')
const base64 = canvas.toDataURL().split(',')[1]

const dimensions = getPngDimensions(base64)
console.log(dimensions)


我的建议是尽可能使用类型化数组而非Base64,尽可能使用blob而非类型化数组。Base64是较差的容器,并且使用更多的内存。

因此,如果您已经有一个blob,这里有一个解决方案:

document.createElement('canvas').toBlob(async blob => {
  // blob.arrayBuffer() is the new way to read stuff
  // It may not work in all browsers
  let dv = new DataView(await blob.slice(16, 24).arrayBuffer())

  console.log({
    width: dv.getInt32(0),
    height: dv.getInt32(4)
  })
})

// You could also try out the new experimental createImageBitmap.
// Don't use image or canvas, but this also works in web workers.
// And it also works for more than just PNG images.
// We could expect this is more heavier/slower than just reading bytes 16-24.
document.createElement('canvas').toBlob(async blob => {
  const bitmap = await createImageBitmap(blob)
  const { width, height } = bitmap
  bitmap.close() // GC
  console.log({ width, height })
})


1
太好了!你能帮忙提供这个函数的JPEG版本吗?规格说明对我来说太高深了! - case2000
我得到了负高度的值 **{width: 4718592 height: -1962920}**。该图像的分辨率为2400x2400。 - Musab Akram
嗯,我刚试着将画布改为2400x2400,完全没问题。你有没有尝试过除了PNG以外的其他格式?(这只适用于PNG)。 - Endless
无法工作,出现以下错误:"Uncaught DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded" - Siraj Ali
@SirajAli 你在处理PNG吗?如果atob不起作用,那么请尝试我提供的其他方法之一。尝试获取一个arrayBuffer并读取位置16和24处的Int32。 - Endless

7

实时演示

var imgData = 'data:image/png;base64,iVBORw0.........';    
var img = new Image();       
img.onload = function(){
  alert(img.width +' '+ img.height );
};
img.src = imgData;

我对我的问题表述不够清晰,非常抱歉。请参见上面的新评论。 - Travis Smith

5

使用jQuery:

var width, height;
$('<img/>').load(function(){
    width = $(this).width();
    height = $(this).height();
    // Call whatever function here that requires the width/height
}).attr('src', datauri)

13
你可以假设有访问jQuerywindow.btoawindow.atob的权限。 - Sygmoral
我对我的问题表述不够清晰,非常抱歉。请参见上面的新评论。 - Travis Smith
@SeanKendle: $('<img/>') 本身创建了一个图像元素,可以使用它(请注意标签:它是创建而不是选择)。该图像实际上不会出现在文档中。 - Sygmoral
1
我知道这一点,我的意思是变量img是否像$(this)那样隐含了什么? - Sean Kendle
哦,我的天,你是对的...我误解了。事实上,我应该写成$(this).width()而不是img.width() - Sygmoral
显示剩余3条评论

3

Node.js 中:

function getPNGSize (buffer) {
  if (buffer.toString('ascii', 12, 16) === 'CgBI') {
    return {
      'width': buffer.readUInt32BE(32),
      'height': buffer.readUInt32BE(36)
    };
  }
  return {
    'width': buffer.readUInt32BE(16),
    'height': buffer.readUInt32BE(20)
  };
}
getPNGSize(buffer)

3
可以解释一下12-16字节的含义吗? - Endless
所有那些神奇的数字和字符串是什么? - Peter Mortensen

0
你可以简单地使用Image。这将返回一个元组[<width>, <height>]
async function getBase64Dimensions(src) {
  return new Promise((resolve, reject) => {
    const image = new Image();

    image.src = src;

    image.onload = () => resolve([image.width, image.height]);
    image.onerror = () => reject();
  });
}

如果你像我一样不能没有类型注解:

async function getBase64Dimensions(src: string) {
  return new Promise<[number, number]>((resolve, reject) => {
    const image = new Image();

    image.src = src;

    image.onload = () => resolve([image.width, image.height]);
    image.onerror = () => reject();
  });
}

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