日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

在瀏覽器中解析Base64編碼圖像

 ThinkTank_引擎 2015-05-07
原文發(fā)表在:blogs. 作者: Ray_Linn



上一篇介紹中,我們將二進(jìn)制文件(BLOB)保存為Base64編碼的文本,這些文本可以內(nèi)嵌在XML的標(biāo)簽中,因此二進(jìn)制信息它可以隨著XML文件被拷貝、下載而不用擔(dān)心信息會(huì)缺失。這項(xiàng)技術(shù)也在email郵件中被廣泛使用。



瀏覽器對Base64的支持

圖像是最經(jīng)常被使用的一種二進(jìn)制文件。而現(xiàn)代的瀏覽器的進(jìn)步日新月異,IE7,F(xiàn)ireFox和其他瀏覽器為包括Base64在內(nèi)各種編碼的圖像信息提供了很好的支持。因此圖形信息可以以下面的形式呈現(xiàn)在頁面中、

Java代碼 復(fù)制代碼 收藏代碼
  1. <img src="data:image/gif;base64,R0lGODlhDwAPAKECAAAAzMzM/////  
  2. wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLlN48CXF8m2iQ3YmmKqVlRtW4ML  
  3. wWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw=="  
  4. alt="Base64 encoded image" width="150" height="150"/>  




這種data: URI的格式能把Base64(或其他數(shù)據(jù))可以內(nèi)嵌在image標(biāo)簽的屬性當(dāng)中(或者CSS中)。我們可以看到在大部分瀏覽器中的顯示效果:





這種做法有利有弊,好處是瀏覽器可以在一個(gè)連接中得到完成的頁面內(nèi)容,不好的地方時(shí)圖像的大小會(huì)增加1/3。因此,這種內(nèi)嵌的方法適合對小的圖形元素比如圖標(biāo)、圓角等等進(jìn)行處理,從而減少瀏覽器打開的連接數(shù),但對大的照片、圖片(量少而大)等等則不應(yīng)該使用Base64編碼以免影響下載速度。



為了得到剛才的Base64編碼,我們將上一篇的Java修改成Struts Action,并借用了JIMI進(jìn)行圖形的讀取和格式轉(zhuǎn)換,Base64編碼器則改為更普遍的Apache Commons組件,代碼如下:

Java代碼 復(fù)制代碼 收藏代碼
  1. public class Base64ImageAction extends ActionSupport {  
  2.   
  3.     private final static String galleryName = "gallery";  
  4.     private static String parent = null;  
  5.          private String encodeString = null;  
  6.   
  7.     public String getEncodeString() {  
  8.         return encodeString;  
  9.     }  
  10.   
  11.     public void setEncodeString(String encodeString) {  
  12.         this.encodeString = encodeString;  
  13.     }  
  14.   
  15.   
  16.     private String getImageFullPath() {  
  17.         parent = new File(this.getClass().getClassLoader().getResource(  
  18.                     File.separator).getPath()).getParent()+File.separator+"flag.jpg";  
  19.     }  
  20.   
  21.     public String execute() {  
  22.         ByteArrayOutputStream output = new ByteArrayOutputStream();  
  23.         try {  
  24.             JimiReader reader = Jimi.createJimiReader(this.getImageFullPath());  
  25.             Image image = reader.getImage();  
  26.             Jimi.putImage("image/png", image, output);  
  27.             output.flush();  
  28.             output.close();  
  29.             this.encodeString = Base64.encodeBase64String(output.toByteArray());  
  30.         } catch (IOException e) {  
  31.             e.printStackTrace();  
  32.         } catch (JimiException e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.       
  36.         return SUCCESS;  
  37.     }  
  38. }  


對應(yīng)的View端是個(gè)十分簡單的Freemarker模板:

Html代碼 復(fù)制代碼 收藏代碼
  1. <html>  
  2. <head>  
  3. <title>Hello,World</title>  
  4. </head>  
  5. <body>  
  6. <img src="data:image/png;base64,${encodeString}" />  
  7. </body>  
  8. </html>  




處理古代瀏覽器

世界總是不是那么完美,盡管大部分現(xiàn)代瀏覽器對Base64的處理都十分完善,但是我們不能不考慮到一些“古老”的瀏覽器,而現(xiàn)在還是普遍使用的“古老”的瀏覽器,就當(dāng)屬IE6,在IE6里試圖瀏覽上面的圖片可能會(huì)得到一個(gè)紅叉叉。我們不得不為IE6做一些特殊處理,利用下面的javascript,我們把Base64字串傳回服務(wù)器端,重新解析成圖片

Javascript代碼 復(fù)制代碼 收藏代碼
  1. // a regular expression to test for Base64 data  
  2. var BASE64_DATA = /^data:.*;base64/i;  
  3. // path to the PHP module that will decode the encoded data  
  4. var base64Path = "/my/path/base64.php";  
  5. function fixBase64(img) {  
  6.   // check the image source  
  7.   if (BASE64_DATA.test(img.src)) {  
  8.     // pass the data to the PHP routine  
  9.     img.src = base64Path + "?" + img.src.slice(5);  
  10.   }  
  11. };  
  12. // fix images on page load  
  13. onload = function() {  
  14.   for (var i = 0; i < document.images.length; i++) {  
  15.     fixBase64(document.images[i]);  
  16.   }  
  17. };  


服務(wù)器端的Struts可以參考上面的例子做反向操作,具體從略。



更完美的方法

將Base64傳回服務(wù)器解碼是不錯(cuò)的IE6補(bǔ)丁,但是違背了我們的初衷,對IE6來說,瀏覽器連接數(shù)并未有任何減少。更直接的想法,是否能用Javascript直接在瀏覽器中,對Base64文本進(jìn)行解碼呢?我們構(gòu)思的場景如下:服務(wù)器端先將圖片轉(zhuǎn)換成PNG格式以方便客戶端進(jìn)行處理,Base64編碼之后,利用JSON將文本傳遞給瀏覽器客戶端進(jìn)行處理。



我們選擇PNG圖形格式是因?yàn)镻NG已經(jīng)儼然成為新的Web圖形標(biāo)準(zhǔn),它格式非常簡單,可以很方便的用javascript進(jìn)行處理而不需要借助瀏覽器的支持。我們知道javascript直接不能處理二進(jìn)制數(shù)據(jù),但是現(xiàn)在這不是個(gè)問題,服務(wù)器端已經(jīng)準(zhǔn)備好了Base64編碼的文本數(shù)據(jù),現(xiàn)在我們只需要一個(gè)javascript的Base64解析器,你可以在這里找到一個(gè)notmasteryet的Base64解析器。



現(xiàn)在PNG圖形格式采用了DEFLATE作為唯一的壓縮算法,該算法也廣泛應(yīng)用在ZIP,GZIP等壓縮格式中。PNG圖像格式文件(或者稱為數(shù)據(jù)流)由一個(gè)8字節(jié)的PNG文件署名(PNG file signature)域和按照特定結(jié)構(gòu)組織的3個(gè)以上的數(shù)據(jù)塊(chunk)組成。



PNG定義了兩種類型的數(shù)據(jù)塊,一種是稱為關(guān)鍵數(shù)據(jù)塊(critical chunk),這是標(biāo)準(zhǔn)的數(shù)據(jù)塊,另一種叫做輔助數(shù)據(jù)塊(ancillary chunks),這是可選的數(shù)據(jù)塊。關(guān)鍵數(shù)據(jù)塊定義了4個(gè)標(biāo)準(zhǔn)數(shù)據(jù)塊,其中圖像數(shù)據(jù)塊IDAT(image data chunk):它存儲(chǔ)實(shí)際的數(shù)據(jù), PNG總的數(shù)據(jù)流采用DEFLAT進(jìn)行壓縮。此外還擦用三角過濾“delta filters”來過濾每一行的像素的未壓縮數(shù)據(jù)。DEFLAT和delta壓縮在其他數(shù)據(jù)和文本處理中也被廣泛應(yīng)用。PNG格式你可以參考<a href="http://www./pub/png/spec/1.1/PNG-Contents.html">官方文檔</a>。



很棒的,notmasteryet也為我們提供了一個(gè)DEFLAT解壓器。



最后,我們把這些組合起來:

Html代碼 復(fù)制代碼 收藏代碼
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2.   
  3. <html xmlns="http://www./1999/xhtml">  
  4. <head>  
  5.     <title>Demo JavaScript PNG Viewer</title>  
  6.  </head>  
  7. <body onload="show(gravatar);">  
  8. <script src="../Source/Base64.js" type="text/javascript"></script>  
  9. <script src="../Source/Deflate.js" type="text/javascript"></script>  
  10. <script src="../Source/PNG.js" type="text/javascript"></script>  
  11.   
  12. <script type="text/javascript">  
  13. var gravatar = 'iVBORw0KGgoAAAANSUhEUgAAA.......數(shù)據(jù)從略......55CYII=';  
  14. String.prototype.padRight = function(c, n){  
  15.     var txt = '';  
  16.     for(var i=0;i<n-this.length;i++) txt += c;  
  17.     return txt + this;  
  18. };  
  19. function show(data){  
  20.     var png = new PNG(data);  
  21.     var img = document.getElementById('image'), limg = document.getElementById('largeimage');  
  22.     document.getElementById('nativeimage').src = 'data:image/png;base64,' + data;  
  23.     img.innerHTML = '';  
  24.     limg.innerHTML = '';  
  25.     img.style.width = png.width + 'px';  
  26.     img.style.height = png.height + 'px';  
  27.     limg.style.width = (png.width * 3) + 'px';  
  28.     limg.style.width = (png.height * 3) + 'px';  
  29.     var line;  
  30.     while(line = png.readLine())  
  31.     {  
  32.         for (var x = 0; x < line.length; x++){  
  33.             var px = document.createElement('div'), px2 = document.createElement('div');  
  34.             px.className = px2.className = 'pixel';  
  35.             px.style.backgroundColor = px2.style.backgroundColor = '#' + line[x].toString(16).padRight('0', 6);  
  36.             img.appendChild(px);  
  37.             limg.appendChild(px2);  
  38.         }  
  39.     }  
  40. }  
  41. </script>  
  42. <div id="image"></div>  
  43. <div id="largeimage"></div>  
  44. <img id="nativeimage" />  
  45. </body>  
  46. </html>  




相關(guān)的javascript請到blogs.下載。



還可以更完美

回顧上一篇的例子,我們用了ihard.net提供了Base64編碼,它提供一個(gè)GZIP編碼參數(shù),你可以發(fā)現(xiàn)如此編碼之后的文本大小和原來的圖形大小相差無幾。利用上一節(jié)提供了javascript是不是可以解決Base64編碼后文件大小增加的問題?留著思考吧。








 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多