JavaScript实现Base64编码转换


Posted in Javascript onApril 23, 2016

简介

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外的两个可打印符号在不同的系统中而不同,一般为+和/。

转换原理

Base64的直接数据源是二进制序列(Binary Sequence)。当然,你也可以将图片、文本和音视频转换成二进制序列,再然后转换为Base64编码。我们这里讨论的是如何将二进制转换为Base64编码,对于如何将图片,文本和音视频转换为二进制序列敬请期待。

在转换前,先定义一张索引表,这张表规定了如何转换:

JavaScript实现Base64编码转换

转换的时候我们先将二进制序列分组,每6个比特为一组。但是如果编码的字节数不能被3整除,那么最后就会多出1个或两个字节,可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行base64的编码。在编码后的base64文本后加上一个或两个'='号,代表补足的字节数。也就是说,当最后剩余一个八位字节(一个byte)时,最后一个6位的base64字节块有四位是0值,最后附加上两个等号;如果最后剩余两个八位字节(2个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。 参考下表:

JavaScript实现Base64编码转换

JavaScript实现Base64

原理明白了以后,实现起来就很容易了。

define(function(require, exports, module) {
 
  var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""); //索引表
 
  /**
   * @author laixiangran@163.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 laixiangran@163.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);
  }
 
  /**
   * @author laixiangran@163.com
   * @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;
  }

  /**
   * @author laixiangran@163.com
   * @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接口得到。具体实现为:

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的编码

具体实现为:

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将图像绘制出来。

具体的代码实现为:

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);
 
}
Javascript 相关文章推荐
js表数据排序 sort table data
Feb 18 Javascript
基于jquery的兼容各种浏览器的iframe自适应高度的脚本
Aug 13 Javascript
关于onScroll事件在IE6下每次滚动触发三次bug说明
Sep 21 Javascript
非主流的textarea自增长实现js代码
Dec 20 Javascript
jquery简单的拖动效果实现原理及示例
Jul 26 Javascript
JavaScript 中的日期和时间及表示标准介绍
Aug 21 Javascript
JS检测输入字符是否包含非法字符的示例代码
Feb 11 Javascript
input file上传 图片预览功能实例代码
Oct 25 Javascript
实例分析编写vue组件方法
Feb 12 Javascript
Easyui 关闭jquery-easui tab标签页前触发事件的解决方法
Apr 28 jQuery
js 将线性数据转为树形的示例代码
May 28 Javascript
JS实现放烟花效果
Mar 10 Javascript
jQuery UI库中dialog对话框功能使用全解析
Apr 23 #Javascript
详解jQuery UI库中文本输入自动补全功能的用法
Apr 23 #Javascript
AngularJS中的过滤器filter用法完全解析
Apr 22 #Javascript
举例讲解如何判断JavaScript中对象的类型
Apr 22 #Javascript
使用jQuery制作基础的Web图片轮播效果
Apr 22 #Javascript
使用jQuery UI库开发Web界面的简单入门指引
Apr 22 #Javascript
jQuery 监控键盘一段时间没输入
Apr 22 #Javascript
You might like
特详细的PHPMYADMIN简明安装教程
2008/08/01 PHP
PHP整合PayPal支付
2015/06/11 PHP
php正则修正符用法实例详解
2016/12/29 PHP
PHP实现websocket通信的方法示例
2018/08/28 PHP
Discuz! 6.1_jQuery兼容问题
2008/09/23 Javascript
JavaScript的变量作用域深入理解
2009/10/25 Javascript
javascript 主动派发事件总结
2011/08/09 Javascript
15个款优秀的 jQuery 图片特效插件推荐
2011/11/21 Javascript
如何在JavaScript中实现私有属性的写类方式(一)
2013/12/04 Javascript
JS实现下拉菜单赋值到文本框的方法
2015/08/18 Javascript
JavaScript提高性能知识点汇总
2016/01/15 Javascript
jQuery实现手机自定义弹出输入框
2016/06/13 Javascript
Vuejs仿网易云音乐实现听歌及搜索功能
2017/03/30 Javascript
详解vue axios二次封装
2018/07/22 Javascript
小程序实现五星点评效果
2018/11/03 Javascript
layer设置maxWidth及maxHeight解决方案
2019/07/26 Javascript
解决vux 中popup 组件Mask 遮罩在最上层的问题
2020/11/03 Javascript
Python随机生成彩票号码的方法
2015/03/05 Python
深入学习python的yield和generator
2016/03/10 Python
Python IDLE入门简介
2017/12/08 Python
python实现简单tftp(基于udp协议)
2018/07/30 Python
django从请求到响应的过程深入讲解
2018/08/01 Python
Python爬虫实现使用beautifulSoup4爬取名言网功能案例
2019/09/15 Python
Python列表解析操作实例总结
2020/02/26 Python
python实现opencv+scoket网络实时图传
2020/03/20 Python
Python3 io文本及原始流I/O工具用法详解
2020/03/23 Python
python实现Pyecharts实现动态地图(Map、Geo)
2020/03/25 Python
使用Python防止SQL注入攻击的实现示例
2020/05/21 Python
使用Dajngo 通过代码添加xadmin用户和权限(组)
2020/07/03 Python
基于 Python 实践感知器分类算法
2021/01/07 Python
美国波道夫·古德曼百货官网:Bergdorf Goodman
2017/11/07 全球购物
销售人员自我评价怎么写
2013/09/19 职场文书
开工仪式策划方案
2014/05/23 职场文书
民主生活会主持词
2015/07/01 职场文书
2015年高校保卫处工作总结
2015/07/23 职场文书
Python语言规范之Pylint的详细用法
2021/06/24 Python