前文中我們聊了 Data URI 和 base64編碼,稍微回顧下。base64編碼 是將數據用 64 個可打印的字符進行編碼的方式,任何數據底層實現都是二進制,所以都可以進行 base64編碼,base64編碼 主要用在數據傳輸過程中(編碼、解碼)。而 Data URI 是將數據用 URI 的形式進行展現。常用的是將圖片進行 base64 編碼,用 Data URI 的形式進行展現,可以說,base64編碼后的字符串是某些 Data URI(這里就包括圖片的 base64 URL) 的一部分。(圖片轉 Base64碼 之后是通過 Data URI scheme來實現顯示的)
那么,如何獲取一張圖片 base64 編碼后的數據呢?Data URI 應用場景小結 的最后我們給出了幾個鏈接,如果不能上網,我們可以用如下幾種方法試試。
我們以 這張圖 為例,它的 base64編碼為:
復制代碼 data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7
chrome
打開 chrome 瀏覽器,將圖片拖入瀏覽器中,打開調試面板(F12),在 Sources 欄下即可看到該圖片的 base64編碼 字符串。
PHP
很多語言都有內置的 base64 encode 以及 decode 函數。比如 PHP 里有 base64_encode()
函數:
復制代碼
-
<?php
-
$file =
"1.gif"
;
// 文件路徑
-
if
($fp = fopen($file,
"rb"
,
0
)) {
-
$binary = fread($fp, filesize($file));
// 文件讀取
-
fclose($fp);
-
$base64 = base64_encode($binary);
// 轉碼
-
echo
$base64;
// 顯示base64碼
-
}
-
?>
echo 出來的東西就是圖片的 base64 編碼。
File API
2016.07.31 補
詳細可以參考 HTML5 File API — 讓前端操作文件變的可能 一文
demo 地址 http://hanzichi.github.io/2016/image2base64/
Canvas
canvas 有內置的 toDataURL()
方法,可以將 canvas 圖像轉換為 Data URI 格式的字符串。其實這個過程有兩步,首先把圖像轉成 PNG 數據,然后再把得到的二進制的 PNG 數據轉成純 ASCII 的 base64 編碼的字符串。(將圖像轉化為Base64字符串的原理或者過程是什么)
將需要編碼的圖片 "弄" 到 canvas 上可以用 drawImage()
API。
復制代碼
-
var img =
new Image();
-
img.onload =
function() {
-
var canvas =
document.createElement(
'canvas');
-
canvas.height = img.height;
-
canvas.width = img.width;
-
var ctx=canvas.getContext(
"2d");
-
ctx.drawImage(img,
0,
0);
-
console.log(canvas.toDataURL());
// 輸出 Data URI
-
}
-
img.src =
'1.gif';
但是該方法與前兩種獲取的 base64 編碼不一樣,我猜想應該是 canvas 圖像轉 png 圖像時改變了 MiME TYPE 所致,那么顯然 base64碼 也不一樣了。但是如果用 png 圖的話也是一樣結果,所以可以判斷將一張 png圖 用 drawImage API 附到 canvas 上,然后再用 toDataURL() 轉為 png 的過程中,其實已經是兩張不同的 png 圖了。
所以 canvas 轉換法其實並不可靠。
后續思考:本來我是想做個簡單的 demo 實現,但是無法獲取上傳文件的絕對路徑地址,如果用 file 控件的話會顯示 fakepath,如 "C:\fakepath\1.png",原因也很好理解,如果上傳文件能獲取該文件在用戶 PC 上的路徑的話,那么豈不是泄露了用戶隱私?用 PHP 的話可以考慮先將文件傳到服務器,然后進行 base64 的編碼,不過服務器得是自家的,用免費的服務器顯然不行(405 Not Allowed)。后續可以考慮用 fileReader 試試。