前端获取图片 exif 流信息

linong

如果你是为了获取 exif 解析后的信息,那么你可以看这篇 前端获取图片exif信息,通过 exif-js 来获取的。

看到这里你要懵逼了,我为什么又要写一遍。emmmm...因为我需求变了,直接拿到 exif 部分的数据,然后 base64 提交。(giao) 测试地址

什么是 exif

可交换图像文件格式(英语:Exchangeable image file format,官方简称 Exif),是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。

exif 格式规则

Exif 信息以 0xFFE1 作为开头标记后两个字节表示 Exif 信息的长度。所以 Exif 信息最大为64 kb,而内部采用 TIFF 格式。

基于这样的规则,那其实我要获取 exif 信息的串就很简单了。

伪代码实现,反正跑不起来


// 获取开始标记
ffe1_idx = blob.indexOf('ffe1');
// 截取后两个字节,用来当长度
exifLength = blob.slice(ffe1_idx, ffe1_idx + 2)
// 截取出exif
exif = blob.slice(ffe1_idx, ffe1_idx + exifLength)
// exif 处理成 base64
btoa(exif)

实现获取 exif 并 base64 编码

我是基于 exif.js,使用了他内部的错误控制。

判断类型

因为 exif 是用于记录数码照片的属性信息和拍摄数据,所以需要是 JPEG

if ((dataView.getUint8(0) != 0xFF) || 
        (dataView.getUint8(1) != 0xD8)) {
    console.log("Not a valid JPEG");
    return { 
        state: 1001, 
        message: 'not a valid jpeg' 
    };
}

查找 Exif 的标志位

image.png
前面我们介绍了 Exif 信息以 0xFFE1 作为开头标记
所以我们直接找这个信息

image.png

将 arrayBuffer 数据以 Uint8 解析并展示 Array.from(new Uint8Array(temp1)).map(v=>[v, v.toString(16).padStart(2, '0'), String.fromCharCode(v)])
var offset = 2, //头两位是类型标记所以跳过
    length = file.byteLength, //文件长度
    marker;
while (offset < length) {
    if (dataView.getUint8(offset) != 0xFF) {
        if (debug) console.log("Not a valid marker at offset " + offset + ", found: " + dataView.getUint8(offset));
        return { state: 1002, message: 'not a valid marker, something is wrong' };
    }
    marker = dataView.getUint8(offset + 1);
    if (debug) console.log(marker);
    if (marker == 225) {
        if (debug) console.log("Found 0xFFE1 marker");
        return readEXIFData(
            dataView, // 数据源
            offset + 4 //跳过 0xffe1 和 长度位
    } else {
        offset += 2 + dataView.getUint16(offset + 2);
    }
}

解析 exif

function readEXIFData(file, start) {
    // 判断是不是 exif 信息,开头应该是字符串 Exif
    if (getStringFromDB(file, start, 4) != "Exif") {
        if (debug) console.log("Not valid EXIF data! " + getStringFromDB(file, start, 4));
        return { state: 1003, message: "Not valid EXIF data! " + getStringFromDB(file, start, 4) };
    }
    // 判断是大数结尾还是小数结尾。
    var bigEnd,
        tiffOffset = start + 6;
    if (file.getUint16(tiffOffset) == 0x4949) {
        bigEnd = false;
    } else if (file.getUint16(tiffOffset) == 0x4D4D) {
        bigEnd = true;
    } else {
        if (debug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
        return { state: 1004, message: "Not valid TIFF data! (no 0x4949 or 0x4D4D)" };
    }

    if (file.getUint16(tiffOffset + 2, !bigEnd) != 0x002A) {
        if (debug) console.log("Not valid TIFF data! (no 0x002A)");
        return { state: 1005, message: "Not valid TIFF data! (no 0x002A)" };
    }

    var firstIFDOffset = file.getUint32(tiffOffset + 4, !bigEnd);
    if (firstIFDOffset < 0x00000008) {
        if (debug) console.log("Not valid TIFF data! (First offset less than 8)", file.getUint32(tiffOffset + 4, !bigEnd));
        return { state: 1006, message: "Not valid TIFF data! (First offset less than 8)" };
    }
    // 截取,这里代码讲道理还是可以优化的。
    var _start = tiffOffset - 10;
    var _end = parseInt(Array.from(new Uint8Array(file.buffer.slice(start-2,start))).map(v=>v.toString(16)).join(''), 16)+start-2
    return {
        state: 1000,
        data: btoa(Array.from(new Uint8Array(file.buffer.slice(_start, _end))).map(v => String.fromCharCode(v)).join(''))
    }

}

image.png

微信公众号:前端linong

欢迎大家关注我的公众号。有疑问也可以加我的微信前端交流群。
clipboard.png

阅读 2.5k

javascript-lNong
只此一生,何必从众

Read-Search-Ask

22.7k 声望
4.8k 粉丝
0 条评论

Read-Search-Ask

22.7k 声望
4.8k 粉丝
文章目录
宣传栏