簡介
Base64
是一種基於64個可列印字元來表示二進位制資料的表示方法。由於2的6次方等於64,所以每6個位元為一個單元,對應某個可列印字元。三個位元組有24個位元,對應於4個Base64
單元,即3個位元組需要用4個可列印字元來表示。它可用來作為電子郵件的傳輸編碼。在Base64
中的可列印字元包括字母A-Z
、a-z
、數字0-9
,這樣共有62個字元,此外的兩個可列印符號在不同的系統中而不同,一般為+
和/
。
轉換原理
Base64的直接資料來源是二進位制序列(Binary Sequence)。當然,你也可以將圖片、文字和音視訊轉換成二進位制序列,再然後轉換為Base64編碼。我們這裡討論的是如何將二進位制轉換為Base64編碼,對於如何將圖片,文字和音視訊轉換為二進位制序列敬請期待。
在轉換前,先定義一張索引表,這張表規定了如何轉換。
轉換的時候我們先將二進位制序列分組,每6個位元為一組。但是如果編碼的位元組數不能被3整除,那麼最後就會多出1個或兩個位元組,可以使用下面的方法進行處理:先使用0位元組值在末尾補足,使其能夠被3整除,然後再進行base64的編碼。在編碼後的base64文字後加上一個或兩個’=’號,代表補足的位元組數。也就是說,當最後剩餘一個八位位元組(一個byte)時,最後一個6位的base64位元組塊有四位是0值,最後附加上兩個等號;如果最後剩餘兩個八位位元組(2個byte)時,最後一個6位的base位元組塊有兩位是0值,最後附加一個等號。 參考下表:
用JavaScript實現Base64
原理明白了以後,實現起來就很容易了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
define(function(require, exports, module) { var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""); //索引表 /** * @author natumsol@gmail.com * @description 將二進位制序列轉換為Base64編碼 * @param {String} * @return {String} */ function binToBase64(bitString) { var result = ""; var tail = bitString.length % 6; var bitStringTemp1 = bitString.substr(0, bitString.length - tail); var bitStringTemp2 = bitString.substr(bitString.length - tail, tail); for (var i = 0; i < bitStringTemp1.length; i += 6) { var index = parseInt(bitStringTemp1.substr(i, 6), 2); result += code[index]; } bitStringTemp2 += new Array(7 - tail).join("0"); if (tail) { result += code[parseInt(bitStringTemp2, 2)]; result += new Array((6 - tail) / 2 + 1).join("="); } return result; } /** * @author natumsol@gmail.com * @description 將base64編碼轉換為二進位制序列 * @param {String} * @return {String} */ function base64ToBin(str) { var bitString = ""; var tail = 0; for (var i = 0; i < str.length; i++) { if (str[i] != "=") { var decode = code.indexOf(str[i]).toString(2); bitString += (new Array(7 - decode.length)).join("0") + decode; } else { tail++; } } return bitString.substr(0, bitString.length - tail * 2); } /** * @description 將字元轉換為二進位制序列 * @param {String} str * @return {String} */ function stringToBin(str) { var result = ""; for (var i = 0; i < str.length; i++) { var charCode = str.charCodeAt(i).toString(2); result += (new Array(9 - charCode.length).join("0") + charCode); } return result; } /** * @description 將二進位制序列轉換為字串 * @param {String} Bin */ function BinToStr(Bin) { var result = ""; for (var i = 0; i < Bin.length; i += 8) { result += String.fromCharCode(parseInt(Bin.substr(i, 8), 2)); } return result; } exports.base64 = function(str) { return binToBase64(stringToBin(str)); } exports.decodeBase64 = function(str) { return BinToStr(base64ToBin(str)); } }) |
將圖片資料進行Base64編碼
將圖片資料轉換為Base64,首先要獲取到圖片的二進位制資料。圖片的二進位制資料可以通過canvas
介面得到。具體實現為:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function getCanvas(w, h) { var c = document.createElement('canvas'); c.width = w; c.height = h; return c; } function getPixels(img) { var c = getCanvas(img.width, img.height); var ctx = c.getContext('2d'); ctx.drawImage(img, 0, 0); return ctx.getImageData(0, 0, c.width, c.height); } |
取到圖片的二進位制資料後,接下來就要進行編碼了。因為圖片不僅包含畫素資訊,還包含長度,寬度資訊。所以在編碼畫素資訊的同時也應將寬度和高度資訊按某一約定進行編碼,我是這樣處理的:
- 將圖片的畫素數值資料轉換為二進位制序列;
- 將寬度和高度資訊組合成字串
$$width,height$$
,轉換為二進位制序列; - 將圖片畫素資訊的二進位制序列和圖片寬高度的二進位制序列組合起來,然後再進行Base64的編碼
具體實現為:
1 2 3 4 5 6 7 8 9 10 11 |
function img2Base64(img) { var imgData = getPixels(img).data; var imgWidth = getPixels(img).width; var imgHeight = getPixels(img).height; var bin = ""; for (var i = 0; i < imgData.length; i++) { bin += base.numToString(imgData[i]); } bin = bin + base.stringToBin("$$" + imgWidth + "," + imgHeight + "$$"); return base.binToBase64(bin); } |
將圖片Base64資料進行解碼
解碼是編碼的逆過程。過程大致為:
- 將圖片的Base64資訊進行解碼,得到包含圖片畫素資訊和寬高度資訊的二進位制序列;
- 然後將這個二進位制序列解碼成字串,獲取高度和寬度資訊;
- 去除二進位制序列中的高度和寬度資訊,得到畫素資訊;
- 根據畫素資訊生成畫素矩陣;
- 根據畫素矩陣、寬度和高度建立圖片物件
ImageData
; - 利用
putImageData
將影象繪製出來。
具體的程式碼實現為:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function paint(imgData) { var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); ctx.fillRect(0, 0, imgData.width, imgData.height); ctx.putImageData(imgData, 0, 0); } function base642img(data) { var str = base.BinToStr(base.base64ToBin(data)); var imgWidth = str.match(/\$\$(\d+),(\d+)\$\$$/, "")[1]; var imgHeight = str.match(/\$\$(\d+),(\d+)\$\$$/, "")[2] var imgData = base.base64ToBin(data).replace(base.stringToBin("$$" + imgWidth + "," + imgHeight + "$$"), ""); var ImageDataArray = new Uint8ClampedArray(imgWidth * imgHeight * 4); for (var i = 0; i < ImageDataArray.length; i++) { ImageDataArray[i] = parseInt(imgData.substr(i * 8, 8), 2); } return new ImageData(ImageDataArray, imgWidth, imgHeight); } |
DEMO演示
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式