前端獲取圖片 exif 流信息

若是你是爲了獲取 exif 解析後的信息,那麼你能夠看這篇 前端獲取圖片exif信息,經過 exif-js 來獲取的。html

看到這裏你要懵逼了,我爲何又要寫一遍。emmmm...由於我需求變了,直接拿到 exif 部分的數據,而後 base64 提交。(giao) 測試地址前端

什麼是 exif

可交換圖像文件格式(英語:Exchangeable image file format,官方簡稱 Exif),是專門爲 數碼相機的照片設定的,能夠記錄數碼照片的屬性信息和拍攝數據。

exif 格式規則

Exif 信息以 0xFFE1 做爲開頭標記後兩個字節表示 Exif 信息的長度。因此 Exif 信息最大爲64 kb,而內部採用 TIFF 格式。git

基於這樣的規則,那其實我要獲取 exif 信息的串就很簡單了。github

僞代碼實現,反正跑不起來

// 獲取開始標記
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,使用了他內部的錯誤控制。segmentfault

判斷類型

由於 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 做爲開頭標記
因此咱們直接找這個信息less

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測試

相關文章
相關標籤/搜索