`

在浏览器中解析Base64编码图像

 
阅读更多


上一篇介绍中,我们将二进制文件(BLOB)保存为Base64编码的文本,这些文本可以内嵌在XML的标签中,因此二进制信息它可以随着XML文件被拷贝、下载而不用担心信息会缺失。这项技术也在email邮件中被广泛使用。

浏览器对Base64的支持
图像是最经常被使用的一种二进制文件。而现代的浏览器的进步日新月异,IE7,FireFox和其他浏览器为包括Base64在内各种编码的图像信息提供了很好的支持。因此图形信息可以以下面的形式呈现在页面中、

Java代码收藏代码
  1. <imgsrc="data:image/gif;base64,R0lGODlhDwAPAKECAAAAzMzM/////
  2. wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLlN48CXF8m2iQ3YmmKqVlRtW4ML
  3. wWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw=="
  4. alt="Base64encodedimage"width="150"height="150"/>



这种data: URI的格式能把Base64(或其他数据)可以内嵌在image标签的属性当中(或者CSS中)。我们可以看到在大部分浏览器中的显示效果:


这种做法有利有弊,好处是浏览器可以在一个连接中得到完成的页面内容,不好的地方时图像的大小会增加1/3。因此,这种内嵌的方法适合对小的图形元素比如图标、圆角等等进行处理,从而减少浏览器打开的连接数,但对大的照片、图片(量少而大)等等则不应该使用Base64编码以免影响下载速度。

为了得到刚才的Base64编码,我们将上一篇的Java修改成Struts Action,并借用了JIMI进行图形的读取和格式转换,Base64编码器则改为更普遍的Apache Commons组件,代码如下:

Java代码收藏代码
  1. publicclassBase64ImageActionextendsActionSupport{
  2. privatefinalstaticStringgalleryName="gallery";
  3. privatestaticStringparent=null;
  4. privateStringencodeString=null;
  5. publicStringgetEncodeString(){
  6. returnencodeString;
  7. }
  8. publicvoidsetEncodeString(StringencodeString){
  9. this.encodeString=encodeString;
  10. }
  11. privateStringgetImageFullPath(){
  12. parent=newFile(this.getClass().getClassLoader().getResource(
  13. File.separator).getPath()).getParent()+File.separator+"flag.jpg";
  14. }
  15. publicStringexecute(){
  16. ByteArrayOutputStreamoutput=newByteArrayOutputStream();
  17. try{
  18. JimiReaderreader=Jimi.createJimiReader(this.getImageFullPath());
  19. Imageimage=reader.getImage();
  20. Jimi.putImage("image/png",image,output);
  21. output.flush();
  22. output.close();
  23. this.encodeString=Base64.encodeBase64String(output.toByteArray());
  24. }catch(IOExceptione){
  25. e.printStackTrace();
  26. }catch(JimiExceptione){
  27. e.printStackTrace();
  28. }
  29. returnSUCCESS;
  30. }
  31. }


对应的View端是个十分简单的Freemarker模板:

Html代码收藏代码
  1. <html>
  2. <head>
  3. <title>Hello,World</title>
  4. </head>
  5. <body>
  6. <imgsrc="data:image/png;base64,${encodeString}"/>
  7. </body>
  8. </html>



处理古代浏览器
世界总是不是那么完美,尽管大部分现代浏览器对Base64的处理都十分完善,但是我们不能不考虑到一些“古老”的浏览器,而现在还是普遍使用的“古老”的浏览器,就当属IE6,在IE6里试图浏览上面的图片可能会得到一个红叉叉。我们不得不为IE6做一些特殊处理,利用下面的javascript,我们把Base64字串传回服务器端,重新解析成图片

Javascript代码收藏代码
  1. //aregularexpressiontotestforBase64data
  2. varBASE64_DATA=/^data:.*;base64/i;
  3. //pathtothePHPmodulethatwilldecodetheencodeddata
  4. varbase64Path="/my/path/base64.php";
  5. functionfixBase64(img){
  6. //checktheimagesource
  7. if(BASE64_DATA.test(img.src)){
  8. //passthedatatothePHProutine
  9. img.src=base64Path+"?"+img.src.slice(5);
  10. }
  11. };
  12. //fiximagesonpageload
  13. onload=function(){
  14. for(vari=0;i<document.images.length;i++){
  15. fixBase64(document.images[i]);
  16. }
  17. };


服务器端的Struts可以参考上面的例子做反向操作,具体从略。

更完美的方法
将Base64传回服务器解码是不错的IE6补丁,但是违背了我们的初衷,对IE6来说,浏览器连接数并未有任何减少。更直接的想法,是否能用Javascript直接在浏览器中,对Base64文本进行解码呢?我们构思的场景如下:服务器端先将图片转换成PNG格式以方便客户端进行处理,Base64编码之后,利用JSON将文本传递给浏览器客户端进行处理。

我们选择PNG图形格式是因为PNG已经俨然成为新的Web图形标准,它格式非常简单,可以很方便的用javascript进行处理而不需要借助浏览器的支持。我们知道javascript直接不能处理二进制数据,但是现在这不是个问题,服务器端已经准备好了Base64编码的文本数据,现在我们只需要一个javascript的Base64解析器,你可以在这里找到一个notmasteryet的Base64解析器。

现在PNG图形格式采用了DEFLATE作为唯一的压缩算法,该算法也广泛应用在ZIP,GZIP等压缩格式中。PNG图像格式文件(或者称为数据流)由一个8字节的PNG文件署名(PNG file signature)域和按照特定结构组织的3个以上的数据块(chunk)组成。

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,其中图像数据块IDAT(image data chunk):它存储实际的数据, PNG总的数据流采用DEFLAT进行压缩。此外还擦用三角过滤“delta filters”来过滤每一行的像素的未压缩数据。DEFLAT和delta压缩在其他数据和文本处理中也被广泛应用。PNG格式你可以参考<a href="http://www.libpng.org/pub/png/spec/1.1/PNG-Contents.html">官方文档</a>。

很棒的,notmasteryet也为我们提供了一个DEFLAT解压器。

最后,我们把这些组合起来:

Html代码收藏代码
  1. <!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <htmlxmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <title>DemoJavaScriptPNGViewer</title>
  5. </head>
  6. <bodyonload="show(gravatar);">
  7. <scriptsrc="../Source/Base64.js"type="text/javascript"></script>
  8. <scriptsrc="../Source/Deflate.js"type="text/javascript"></script>
  9. <scriptsrc="../Source/PNG.js"type="text/javascript"></script>
  10. <scripttype="text/javascript">
  11. vargravatar='iVBORw0KGgoAAAANSUhEUgAAA.......数据从略......55CYII=';
  12. String.prototype.padRight=function(c,n){
  13. vartxt='';
  14. for(vari=0;i<n-this.length;i++)txt+=c;
  15. returntxt+this;
  16. };
  17. functionshow(data){
  18. varpng=newPNG(data);
  19. varimg=document.getElementById('image'),limg=document.getElementById('largeimage');
  20. document.getElementById('nativeimage').src='data:image/png;base64,'+data;
  21. img.innerHTML='';
  22. limg.innerHTML='';
  23. img.style.width=png.width+'px';
  24. img.style.height=png.height+'px';
  25. limg.style.width=(png.width*3)+'px';
  26. limg.style.width=(png.height*3)+'px';
  27. varline;
  28. while(line=png.readLine())
  29. {
  30. for(varx=0;x<line.length;x++){
  31. varpx=document.createElement('div'),px2=document.createElement('div');
  32. px.className=px2.className='pixel';
  33. px.style.backgroundColor=px2.style.backgroundColor='#'+line[x].toString(16).padRight('0',6);
  34. img.appendChild(px);
  35. limg.appendChild(px2);
  36. }
  37. }
  38. }
  39. </script>
  40. <divid="image"></div>
  41. <divid="largeimage"></div>
  42. <imgid="nativeimage"/>
  43. </body>
  44. </html>



相关的javascript请到blogs.ejb.cc下载。

还可以更完美
回顾上一篇的例子,我们用了ihard.net提供了Base64编码,它提供一个GZIP编码参数,你可以发现如此编码之后的文本大小和原来的图形大小相差无几。利用上一节提供了javascript是不是可以解决Base64编码后文件大小增加的问题?留着思考吧。

分享到:
评论

相关推荐

    JS在浏览器中解析Base64编码图像

    主要介绍了JS在浏览器中解析Base64编码图像的相关资料,需要的朋友可以参考下

    js 显示base64编码的二进制流网页图片

    base64简单地说,它把一些 8-bit 数据翻译成标准 ASCII 字符,我们把图像文件的内容直接写在了HTML 文件中,这样做的好处是,节省了一个HTTP 请求

    Andoffline:某些Android短信/通话应用程序的工具包,base64编码器,VCF解析器-开源

    CALL和CONTACT的浏览器保存到导出的SMS,CALL和CONTACT,VCF解析器的PDF文件支持以下工具:...-使用USB将手机连接到PC-安装Android应用-在桌面应用上创建作业-启动PC侦听器和电话接收器**有关更多详细信息,请参见pdf...

    C#编程经验技巧宝典

    79 &lt;br&gt;0115 如何判断是否为数字 79 &lt;br&gt;0116 如何在字符串中查找指定字符 79 &lt;br&gt;0117 如何在字符串中用一子串替换另一子串 80 &lt;br&gt;0118 将新字符串添加到已有字符串中 80 &lt;br&gt;0119 如何在...

    vc++ 应用源码包_1

    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...

    vc++ 应用源码包_2

    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...

    vc++ 应用源码包_6

    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...

    vc++ 应用源码包_5

    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...

    vc++ 应用源码包_3

    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...

    java 面试题 总结

    在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。...

    超级有影响力霸气的Java面试题大全文档

    在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。...

    vc++ 开发实例源码包

    代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...

    易语言模块914个

    Base64编解码.ec BASE64编解码模块.ec Bios信息.ec BMP滤镜模块.ec BoyChong-神2多方式取IP模块.ec BoyChong专用常用模块2.ec BPL专用更新模块.ec cards.ec coolp.ec Cool皮肤模块.ec copy_dir.ec CPU...

    1345个易语言模块

    BASE64编解码模块.ec Bios.ec Bios 信息.ec BMP加密数据.ec BMP滤镜模块.ec BOX.EC BPL专用更新模块.ec BPL综合模 块.ec BPL高级模块.ec ButtonEx.ec bzfec.ec cards.ec change.ec CM.ec commodity.ec coolp.ec Cool...

    1350多个精品易语言模块

    BASE64编解码模块.ec Bios.ec Bios 信息.ec BMP加密数据.ec BMP滤镜模块.ec BOX.EC BPL专用更新模块.ec BPL综合模 块.ec BPL高级模块.ec ButtonEx.ec bzfec.ec cards.ec change.ec CM.ec commodity.ec coolp.ec Cool...

Global site tag (gtag.js) - Google Analytics