base-64做爲常見的編碼函數,在基本認證、摘要認證以及一些HTTP擴展中獲得了大量應用。在前端領域,也經常把圖片轉換爲base-64編碼在網絡中傳輸。本文將詳細介紹base64的原理及用js實現base64編碼器的過程html
Base-64編碼能夠將任意一組字節轉換成較長的常見文本字符序列,從而能夠合法地做爲首部字段值。Base-64編碼將用戶輸入或二進制數據,打包成一種安全格式,將其做爲HTTP首部字段的值發送出去,而無須擔憂其中包含會破壞HTTP分析程序的冒號、換行符或二進制值前端
Base-64編碼是做爲MIME多媒體電子郵件標準的一部分開發的,這樣MIME就能夠在不一樣的合法電子郵件網關之間傳輸富文本和任意的二進制數據了。Base-64編碼與將二進制數據文本化表示的uuencode和BinHex標準在本質上很相似,但空間效率更高java
【拆分】chrome
Base-64編碼將一個8位字節序列拆散爲6位的片斷,併爲每一個6位的片斷分配一個字符,這個字符是Base-64字母表中的64個字符之一。這64個輸出字符都是很常見的,能夠安全地放在HTTP首部字段中。這64個字符中包含大小寫字母、數字、+和/,還使用了特殊字符=瀏覽器
下表Base-64的字母表安全
0 A 8 I 16 Q 24 Y 32 g 40 o 48 w 56 4 1 B 9 J 17 R 25 Z 33 h 41 p 49 x 57 5 2 C 10 K 18 S 26 a 34 i 42 q 50 y 58 6 3 D 11 L 19 T 27 b 35 j 43 r 51 z 59 7 4 E 12 M 20 U 28 c 36 k 44 s 52 0 60 8 5 F 13 N 21 V 29 d 37 l 45 t 53 1 61 9 6 G 14 O 22 W 30 e 38 m 46 u 54 2 62 + 7 H 15 P 23 X 31 f 39 n 47 v 55 3 63 /
[注意]因爲Base64編碼用8位字符表示信息中的6個位,因此Base-64編碼字符串大約比原始值擴大了 33%服務器
【編碼實現】網絡
下圖是一個簡單的Base-64編碼實例。在這裏,三個字符組成的輸入值「Ow!」是Base-64編碼的,獲得的是4個字符的Base-64編碼值「T3ch」。它是按如下方式工做的ide
一、字符串「Ow!」被拆分紅3個8位的字節(0x4F、0x7七、0x21)函數
二、這3個字節構成了一個24位的二進制值010011110111011100100001
三、這些位被劃分爲一些6位的序列0100十一、1101十一、011十、100001
四、每一個6位值都表示了從0-63之間的一個數字,對應Base-64字母表中64個 字符之一。獲得的Base-64編碼字符串是個4字符的字符串「T3ch」,而後就可 以經過線路將這個字符串做爲「安全的」8位字符傳送出去,由於只用了一些 移植性最好的字符(字母、數字等)
【填充】
Base-64編碼收到一個8位字節序列,將這個二進制序列流劃分紅6位的塊。二進制序列有時不能正好平均地分紅6位的塊,在這種狀況下,就在序列末尾填充零位,使二進制序列的長度成爲24的倍數(6和8的最小公倍數)
對已填充的二進制串進行編碼時,任何徹底填充(不包含原始數據中的位)的6位組都由特殊的第65個符號「=」表示。若是6位組是部分填充的,就將填充位設置爲0
下表顯示了一些填充實例
初始輸入字符串「a:a」爲3字節(24位)。24是6和8的倍數,所以無需填充,獲得的Base-64編碼字符串爲「YTph」
然而,再增長一個字符,輸入字符串會變成32位長。而6和8的下一個公倍數是48,所以要添加16位的填充碼。填充的前4位是與數據位混合在一塊兒的。獲得的6位組01xxxx,會被看成010000、十進制中的16,或者Base-64編碼的Q來處理。剩下的兩個6位組都是填充碼,用「=」表示
[注意]Base-64編碼的官方規範移步至此
網頁上的每個圖片,都須要消耗一個http請求下載而來的。因此,纔有了雪碧圖技術
不管如何,圖片的下載始終都要向服務器發出請求,要是圖片的下載不用向服務器發出請求,而能夠隨着HTML的下載同時下載到本地那就太好了,而base64正好能解決這個問題
前面提到過Base-64編碼字符串大約比原始值擴大了33%。因此,不是全部的圖片使用base-64編碼都合適
可是,若是圖片足夠小且由於用處的特殊性(如須要平鋪等)沒法被製做成雪碧圖,在整個網站的複用性很高且基本不會被更新。那麼此時使用base64編碼傳輸圖片就可謂好鋼用在刀刃上
好比,一個只有50字節的2px*2px的背景圖。將其轉化成base64編碼,只有100多個字符,相比一個http請求,這種轉換無疑更值得推崇
把要轉化的圖片直接拖入chrome中,使用控制檯中的Source選項,可直接查看圖片的base64編碼
對於字符串來講,在javaScript中,有2個函數分別用來處理解碼和編碼base64字符串:atob()和btoa()
btoa()函數可以從二進制數據「字符串」建立一個base-64編碼的ASCII字符串;相反地,atob()函數可以解碼經過base-64編碼的字符串數據。
console.log(btoa('abc'));//'YWJj' console.log(atob('YWJj'));//'abc'
[注意]IE9-瀏覽器不支持
可是,以上方法有侷限性,就是沒法轉換中文
Uncaught DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
這時,就須要使用編碼方法,先轉換爲btoa()識別的字符,再進行base64編碼,如可使用encodeURI()方法
var str = btoa(encodeURI('小火柴')); console.log(str);//JUU1JUIwJThGJUU3JTgxJUFCJUU2JTlGJUI0 console.log(decodeURI(atob(str)));//'小火柴'
<p style="margin:0">請在下面的框中輸入要轉換的字符</p> <textarea id="ta" cols="30" rows="10"></textarea> <button id="btn1">轉換</button><button id="btn2">反向轉換</button><br> <p style="margin:0">轉換後的字符以下:</p> <textarea id="result" cols="30" rows="10" readonly></textarea> <button id="sel">全選</button> <button id="reset">清空</button> <script> reset.onclick = function(){history.go();} btn1.onclick = function(){result.value = btoa(encodeURI(ta.value));} btn2.onclick = function(){result.value = decodeURI(atob(ta.value));} sel.onclick = function(){ result.focus(); result.select(); } </script>
使用文件File API的readAsDataURL()方法,能夠將文件以數據URI(進行Base64編碼)形式保存在result屬性中
//base64轉換函數 function base64(file){ if(fileData.innerHTML){ fileData.innerHTML = ''; btn.style.display = 'none'; } if(file){ if(/image/.test(file.type)){ var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(){ fileData.innerHTML = reader.result; } }else{ alert("You must select a valid image file!"); } } }
通常地,生成的Base64編碼都比較長,能夠增長一個全選代碼的功能
reader.onload = function(){ fileData.innerHTML = reader.result; btn.style.display = 'inline-block'; btn.onclick = function(){ fileData.focus(); fileData.select(); } }
可使用文件File API選擇圖片文件
//點擊事件替代 targetArea.onclick = function(){file1.click();} //控件選中 file1.onchange = function(){ var file = file1.files[0]; base64(file); }
固然也可使用原生拖拽,實現圖片拖拽,在某個區域顯示Base64編碼的效果
targetArea.ondragenter = function(e){this.style.outline = "1px solid black";} targetArea.ondragleave = function(e){this.style.outline = "";} //拖拽選中 targetArea.ondrop = function(e){ e = e || event; this.style.outline = ""; var file = e.dataTransfer.files[0]; base64(file); }
因爲File API的兼容性限制,如下代碼在IE9-瀏覽器中沒法正常運行
<input id="file1" type="file" accept="image/gif,image/jpeg,image/jpg,image/png,image/x-icon" style="display:none"> <div id="targetArea" style="display:inline-block;vertical-align:middle;height:100px;line-height:50px;width:210px;background:lightblue;">將圖片文件拖放到該區域內<br>或者點擊該區域選擇本地文件</div> <textarea id="fileData" style="vertical-align:middle;width:400px;height:200px;overflow:auto;word-wrap: break-word;"></textarea> <button id="btn" style="display:none;position:absolute;margin:220px 0 0 -80px">全選代碼</button> <script> //base64轉換函數 function base64(file){ if(fileData.innerHTML){ fileData.innerHTML = ''; btn.style.display = 'none'; } if(file){ if(/image/.test(file.type)){ var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(){ fileData.innerHTML = reader.result; btn.style.display = 'inline-block'; btn.onclick = function(){ fileData.focus(); fileData.select(); } } }else{ alert("You must select a valid image file!"); } } } //點擊事件替代 targetArea.onclick = function(){file1.click();} //控件選中 file1.onchange = function(){ var file = file1.files[0]; base64(file); } //兼容事件處理程序 function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } //兼容阻止默認事件 function preventDefault(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } } addEvent(document,'dragover',preventDefault); addEvent(document,'drop',preventDefault); addEvent(targetArea,'dragenter',preventDefault); addEvent(targetArea,'dragover',preventDefault); addEvent(targetArea,'dragleave',preventDefault); addEvent(targetArea,'drop',preventDefault); targetArea.ondragenter = function(e){this.style.outline = "1px solid black";} targetArea.ondragleave = function(e){this.style.outline = "";} //拖拽選中 targetArea.ondrop = function(e){ e = e || event; this.style.outline = ""; var file = e.dataTransfer.files[0]; base64(file); } </script>
出處:http://www.cnblogs.com/xiaohuochai/p/6202207.html