1. 背景
本公司的在制作app定制平台时,有图片上传的功能,只能上传png格式的图片,起初我是直接使用 input 标签中的 accept 属性来限制图片上传的类型,但是这样子做不到准确的限制,用户完全可以通过手动改变图片后缀来躲过限制。
2. 核心思路
- 通过读取图片的二进制数据来识别图片的类型
- 通过前部分的魔数判断图片类型
3. 详细说明
计算机在区分图片类型的时候,并不是通过图片的后缀来区分的,而是通过“魔数”,每张图片在转成二进制后都会在前面附上魔数,不同的类型对应不同的魔数,常见的图片类型对应的魔数如下:
图片类型 | 图片后缀 | 魔数 |
JPEG | jpg/jpeg | 0xFF D8 FF |
PNG | png | 0x89 50 4E 47 0D 1A 0A |
GIF | gif | 0x47 49 46 38(GIF8) |
BMP | bmp | 0x42 4D |
4. 代码实现
<input ref="inputDom" accept="image/png" onchange="onloadImage">
const readBuffer = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => {
resolve(reader.result)
};
reader.onerror = reject
reader.readAsArrayBuffer(file.slice(0, 8))
})
}
const check = (headers) => {
return (buffers, options = {}) => {
headers.every(
(header, index) => header === buffers[options.offset + index]
)
}
}
const isPNG = check([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
const onloadImage = async () => {
if (inputDom.value.files.length <= 0) return
const file = inputDom.value.files[0]
const buffers = await readBuffer(file)
const uint8Array = new Uint8Array(buffers)
if (isPNG(uint8Array)) {
console.log('该图片是png格式')
} else {
console.log('改图片不是png格式')
}
inputDom.value.value = null
}