通过把文件的二进制数据转为16进制字符转再进行相应的判断获取图片格式以及宽高等
二进制转字符串
- 通过
readAsBinaryString
转换blob
对象为二进制字符串
- 通过
charCodeAt
转换二进制字符串
为Unicode
码 - 将
Unicode
码转换为16进制
async blobToString(blob){
return new Promise(resolve=>{
const reader = new FileReader()
reader.onload = function () {
const l= reader.result.split('')
const m = l.map(v=>v.charCodeAt())
const x = m.map(v=>v.toString(16).toUpperCase())
const y = x.map(v=>v.padStart(2,'0')) //不足2位补0
const ret = y.join(' ')
resolve(ret)
}
reader.readAsBinaryString(blob)
})
}
获取宽高
移除空格并以16
进制为基数转换为整形
async getRectByOffset(file,widthOffset,heightOffset,reverse){
let width = await this.blobToString(file.slice(...widthOffset))
let height = await this.blobToString(file.slice(...heightOffset))
if(reverse){
// 比如gif 的宽,6和7 是反着排的 大小端存储
// 比如6位是89,7位是02, gif就是 0289 而不是8902的值 切分后翻转一下
width = [width.slice(3,5),width.slice(0,2)].join(' ')
height = [height.slice(3,5),height.slice(0,2)].join(' ')
}
const w = parseInt(width.replace(' ', ''),16)
const h = parseInt(height.replace(' ', ''),16)
return {w,h}
}
判断PNG
png格式文件信息前8位保存格式信息为89 50 4E 47 0D 0A 1A 0A
宽保存在18
位到20
位
高保存在22
位到24
位
async isPng(file){
const ret = await this.blobToString(file.slice(0,8))
const ispng = ret==='89 50 4E 47 0D 0A 1A 0A'
if(ispng){
console.log('png宽高',w,h)
const {w,h} = await this.getRectByOffset(file,[18,20],[22,24])
if(w>IMG_WIDTH_LIMIT || h>IMG_HEIGHT_LIMIT){
this.$message.error("png图片宽高不得超过!"+IMG_WIDTH_LIMIT+'和'+IMG_HEIGHT_LIMIT);
return false
}
}
return ispng
}
判断jpg
async isJpg(file){
// jpg开头两个是 FF D8
// 结尾两个是 FF D9
const len = file.size
const start = await this.blobToString(file.slice(0,2))
const tail = await this.blobToString(file.slice(-2,len))
const isjpg = start==='FF D8' && tail==='FF D9'
if(isjpg){
const heightStart = parseInt('A3',16)
const widthStart = parseInt('A5',16)
const {w,h} = await this.getRectByOffset(file,[widthStart,widthStart+2],[heightStart,heightStart+2])
console.log('jpg大小',w, h)
}
return isjpg
}
判断gif
async isGif(file){
const ret = await this.blobToString(file.slice(0,6))
const isgif = (ret==='47 49 46 38 39 61') || (ret==='47 49 46 38 37 61')
if(isgif){
console.log('文件是gif')
const {w,h} = await this.getRectByOffset(file,[6,8],[8,10],true)
console.log('gif宽高',w,h)
if(w>IMG_WIDTH_LIMIT || h>IMG_HEIGHT_LIMIT){
this.$message.error("gif图片宽高不得超过!"+IMG_WIDTH_LIMIT+'和'+IMG_HEIGHT_LIMIT);
return false
}
}
return isgif
// 文件头16进制 47 49 46 38 39 61 或者47 49 46 38 37 61
// 分别是89年和87年的规范
// const tmp = '47 49 46 38 39 61'.split(' ')
// .map(v=>parseInt(v,16))
// .map(v=>String.fromCharCode(v))
// console.log('gif头信息',tmp)
// // 或者把字符串转为16进制 两个方法用那个都行
// const tmp1 = 'GIF89a'.split('')
// .map(v=>v.charCodeAt())
// .map(v=>v.toString(16))
// console.log('gif头信息',tmp1)
// return ret ==='GIF89a' || ret==='GIF87a'
// 文件头标识 (6 bytes) 47 49 46 38 39(37) 61
}