摘要:位無符號整數,長度個字節,溢出處理為最大值。所以你拿到的英文字母編碼前后一樣的,但是漢字等字符就不同了。為了直接得到漢字的碼,使用其實還可以選擇使用處理漢字,但是英文又不能正常轉換了。
原文鏈接:https://ssshooter.com/2019-04...
之前做文件上傳和 canvas 修圖時接觸到幾個格式,這里打算整理一下他們的關系
Blob使用 input 獲取文件時,你拿到的就是 file 對象,而 file 繼承于 blob,所以直接講比較陌生的 blob 吧。
BLOB (binary large object),二進制大對象,是一個可以存儲二進制文件的“容器”。
Blob 有什么用使用 Blob 可以讓你在瀏覽器生成一個臨時文件,使用 URL.createObjectURL() 獲取他的鏈接,你就能像服務器文件一樣使用他。
let temp = new Blob(["hello fantasy"]) URL.createObjectURL(temp) // 返回 "blob:https://ssshooter.com/1bf84bba-b53a-4155-8348-33a487e8ab7e"
返回的 url 前面是主機,后面是一個唯一識別碼。
在創建這個臨時文件后,只要不關閉當前頁面,這個文件就會一直存在于內存,你需要主動運行 URL.revokeObjectURL(url) 刪除引用。
從 Blob 中提取數據在控制臺打出 blob 你根本不知道里面是啥,那么怎么讀取 blob 呢?
借助 FileReader,你可以把 Blob 讀取為 Buffer。
FileReader 對象允許 Web 應用程序異步讀取存儲在用戶計算機上的文件(或原始數據緩沖區)的內容,使用 File 或 Blob 對象指定要讀取的文件或數據。
var reader = new FileReader() reader.addEventListener("loadend", function() { // reader.result 包含轉化為類型數組的blob }) reader.readAsArrayBuffer(blob)ArrayBuffer
經過 FileReader 的讀取,你能看到計算機儲存數據的本質 —— 二進制數據。
ArrayBuffer 的編輯ArrayBuffer 類似數組,每一格放入 1Byte(8bit)數據,也就是八位的 0 或 1,所以換成十進制一格最大是 255.
例如:
ArrayBuffer 不能直接操作,而是要通過類型數組對象(下面列出來的)或 DataView 對象來操作,它們會將緩沖區中的數據表示為特定的格式,并通過這些格式來讀寫緩沖區的內容。
Int8Array:8 位有符號整數,長度 1 個字節,溢出處理為 數值%(取模)255。
Uint8Array:8 位無符號整數,長度 1 個字節。
Uint8ClampedArray:8 位無符號整數,長度 1 個字節,溢出處理為 255(最大值)。
Int16Array:16 位有符號整數,長度 2 個字節。
Uint16Array:16 位無符號整數,長度 2 個字節。
Int32Array:32 位有符號整數,長度 4 個字節。
Uint32Array:32 位無符號整數,長度 4 個字節。
Float32Array:32 位浮點數,長度 4 個字節。
Float64Array:64 位浮點數,長度 8 個字節。
對應視圖的轉換還很神奇的,ArrayBuffer 是一個格子 8 位,也就是跟 xx8Array 是一樣的,自然不用轉換,而 16 之后的都是把每幾個格子合成一個。
// 創建 buffer ab = new ArrayBuffer(4) // 創建視圖 a = new Uint8Array(ab) // 通過視圖操作 buffer a[0] = 2 a[1] = 25 a[2] = 31 a[2] = 233
打印 ab 會輸出:
為了方便理解他們如何轉換,我把他轉為 2 進制:
// Int16Array ;["1100100000010", "11101001"] // Int32Array ;["111010010001100100000010"] // Uint8Array ;["10", "11001", "11101001", "0"]
可能還沒能看出來?那再在前面補 0:
// Int16Array ;["0001100100000010", "0000000011101001"] // Int32Array ;["00000000111010010001100100000010"] // Uint8Array ;["00000010", "00011001", "11101001", "00000000"]
這就很明顯能看出:要轉換就要在分組之后把同一組數據從右到左拼接。
不過我自覺一般不太會用到這么細致的 bit 操作(
canvas 與 buffer另外,canvas 可以通過 ctx.createImageData() 得到 ImageData。
ImageData.data 就是一個 Uint8ClampedArray,里面順序放著圖片每一個像素的 rgba 值。你可以對這個 Uint8ClampedArray 進行一系列操作,再用 canvas.toBlob 這個 buffer 變回 Blob,就完成了圖片編輯的操作。
通過這個操作,再結合一些卷積核相關知識,就能完成類似這個卷積核圖片修改器的功能。
Data UrlData Url 是一個前綴為 data: 的協議,你可以借助這個協議在文檔中嵌入一些小文件(最常見就是內聯圖片了),數據格式如下:
data:[][;base64],
mediatype 填入MIME 類型,MIME 也用于服務器返回數據時指定數據類型;base64 是一種編碼方式;后面接著就是數據本體。
幾個例子:
普通文字:data:,Hello%2C%20World!
base64 處理的文字:data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
html 文檔:data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E
執行 script 的 html 文檔:data:text/html,
base64上面提到的 base64 不算是一種加密算法,它只是簡單地將每 3 個 8bit 字符轉換為 4 個 6Bit 字符(base64 只有 2^6 = 64 種字符,因此得名),這樣保證了傳輸中必定使用 ASCII 中可見字符,不會出奇怪的空白字符或是功能性標志 。
由于是 3 個字符變 4 個,那么很明顯了,base64 編碼后,編碼對象的體積會變成原來的 4/3 倍。
特別要注意的是如果 bit 數不能被 3 整除,需要在末尾添加 1 或 2 個 byte(8 或 16bit),并且末尾的 0 不使用 A 而使用 =,這就是為什么 base64 有的編碼結果后面會有一或兩個等號。
喜聞樂見的舉例時間:
前置知識點:utf8 與 unicode 的關系
你可以使用 charCodeAt() 獲取一個字符的 unicode 編碼(0 到 65535 之間的整數),但是 unicode 只是一個碼表,并不是一個具體的編碼方式,utf8 才是。所以你拿到的英文字母編碼前后一樣的,但是漢字(等字符)就不同了。
為了直接得到漢字的 utf8 碼,使用 TextEncoder(其實還可以選擇使用 encodeURIComponent 處理漢字,但是英文又不能正常轉換了)。
下面用 JavaScript 簡單寫個 base64 轉換流程:
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" Array.from(new TextEncoder().encode("碧藍幻想")) .map(val => val.toString(2).padStart(8, 0)) // 轉二進制,補充到八位 .join("") .replace(/([10]{6})/g, "$1,") // 每六位插個逗號用于拆分 .split(",") // 拆分為每 6 位一組 .map(val => parseInt(val.padEnd(6, 0), 2)) // 補充后面的 0(但是沒有補夠) .map(val => b64[val]) .join("")
結果基本是對的,但是后面的 = 還是用了普通的 A 而且位數沒有加夠,所以上面轉換出來的不是標準 base64,僅供參考
base64 算法參考
blob url 與 Data Url 對比blob url
不需要做編碼,省了運算資源
大小也不會改變
在不使用時需要手動刪除引用
關閉頁面鏈接自動廢棄
Data Url
需要編碼,且體積變大 1.3 倍
容易刪除
鏈接不變,保存了可以以后使用
參考
mdn Blob
mdn FileReader
mdn HTMLCanvasElement
阮一峰 ES6 arraybuffer
進階 FileAPI 實現標準
javascript info - blob
附錄 N 進制數的表示方法// 10 var a = 10 // 8 var b = 0o1234567 // 或直接在前面加0,如果后面數字都小于8就自動變成8進制 var c = 01234567 // 2 var d = 0b1010101110101 // 16 var e = 0xe87a90N 進制數轉 10 進制
parseInt(0o1234567, 8) parseInt(0b1010101110101, 2) parseInt(0xe87a90, 16)10 進制數轉 N 進制
;(123456).toString(2) ;(123456).toString(8) ;(123456).toString(16)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105969.html
摘要:常見的源碼轉換,主要是以下三種情況壓縮,減小體積。該項是一個數組,表示可能存在多個文件合并。第一層是行對應,以分號表示,每個分號對應轉換后源碼的一行。在這個位中,左邊的第一位最高位表示是否連續。 這兩天完成了自己的個人任務,準備學習一下前輩們的經驗教訓,在項目組的文檔中發現了一個要求注意的點,如下: Js文件的開頭可以加上類似//@ sourceURL=jquery.extends.j...
閱讀 2649·2021-09-13 10:26
閱讀 1913·2021-09-03 10:28
閱讀 1983·2019-08-30 15:44
閱讀 800·2019-08-29 14:07
閱讀 392·2019-08-29 13:12
閱讀 2148·2019-08-26 11:44
閱讀 2342·2019-08-26 11:36
閱讀 2011·2019-08-26 10:19