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 相关文章推荐
用jscript启动sqlserver
Jun 21 Javascript
Jquery颜色选择器ColorPicker实现代码
Nov 14 Javascript
JS滚轮事件onmousewheel使用介绍
Nov 01 Javascript
原生js ActiveXObject获取execl里面的值
Nov 01 Javascript
JS实现清除指定cookies的方法
Sep 20 Javascript
JavaScript表单焦点自动切换代码
Jul 24 Javascript
BootStrap轮播HTML代码(推荐)
Dec 10 Javascript
js实现三级联动效果(简单易懂)
Mar 27 Javascript
Vue的事件响应式进度条组件实例详解
Feb 04 Javascript
vue 使用eventBus实现同级组件的通讯
Mar 02 Javascript
ios设备中angularjs无法改变页面title的解决方法
Sep 13 Javascript
微信小程序使用前置摄像头拍照
Oct 22 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
PHP输出控制功能在简繁体转换中的应用
2006/10/09 PHP
PHP 变量的定义方法
2010/01/26 PHP
PHP-CGI进程CPU 100% 与 file_get_contents 函数的关系分析
2011/08/15 PHP
PHP编码规范的深入探讨
2013/06/06 PHP
Linux下创建nginx脚本-start、stop、reload…
2014/08/03 PHP
总结一些js自定义的函数
2006/08/05 Javascript
Jquery 弹出层插件实现代码
2009/10/24 Javascript
jQuery ready函数滥用分析
2011/02/16 Javascript
jquery遍历checkbox的注意事项说明
2014/02/21 Javascript
图片放大镜jquery.jqzoom.js使用实例附放大镜图标
2014/06/19 Javascript
常用的JS验证和函数汇总
2014/12/23 Javascript
解决layui-table单元格设置为百分比在ie8下不能自适应的问题
2019/09/28 Javascript
图解JS原型和原型链实现原理
2020/09/15 Javascript
基于JS实现操作成功之后自动跳转页面
2020/09/25 Javascript
vue实现下拉菜单树
2020/10/22 Javascript
Python单元测试框架unittest使用方法讲解
2015/04/13 Python
解析Python中的二进制位运算符
2015/05/13 Python
Python简单实现自动删除目录下空文件夹的方法
2017/08/29 Python
django 消息框架 message使用详解
2019/07/22 Python
Python 实现大整数乘法算法的示例代码
2019/09/17 Python
python 实现生成均匀分布的点
2019/12/05 Python
Tensorflow 1.0之后模型文件、权重数值的读取方式
2020/02/12 Python
在python3中使用shuffle函数要注意的地方
2020/02/28 Python
美国最大的骑马用品零售商:HorseLoverZ
2017/01/12 全球购物
GAZMAN官网:澳大利亚领先的男装品牌
2019/12/19 全球购物
售后主管岗位职责
2013/12/08 职场文书
区域销售经理岗位职责
2013/12/10 职场文书
家长对小学生的评语
2014/01/28 职场文书
《影子》教学反思
2014/02/21 职场文书
学校联谊协议书
2014/09/16 职场文书
安全先进个人材料
2014/12/29 职场文书
鉴史问廉观后感
2015/06/10 职场文书
幼儿园小班开学寄语(2016秋季)
2015/12/03 职场文书
研究生毕业登记表的自我鉴定范文
2019/07/15 职场文书
JS前端使用canvas实现扩展物体类和事件派发
2022/08/05 Javascript
MySQL远程无法连接的一些常见原因总结
2022/09/23 MySQL