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 select常用操作控制代码
Mar 16 Javascript
查看源码的工具 学习jQuery源码不错的工具
Dec 26 Javascript
Jquery多选下拉列表插件jquery multiselect功能介绍及使用
May 24 Javascript
Javascript实现滚动图片新闻的实例代码
Nov 27 Javascript
Egret引擎开发指南之视觉编程
Sep 03 Javascript
JavaScript的jQuery库中ready方法的学习教程
Aug 14 Javascript
jQuery拖动元素并对元素进行重新排序
Dec 30 Javascript
微信小程序获取用户openid的实现
Dec 24 Javascript
Jquery实现无缝向上循环滚动列表的特效
Feb 13 jQuery
微信小程序 select 下拉框组件功能
Sep 09 Javascript
vue操作dom元素的3种方法示例
Sep 20 Javascript
JavaScript实现点击切换功能
Jan 27 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中Y2K38的漏洞解决方法实例分析
2014/09/22 PHP
php获取今日开始时间和结束时间的方法
2017/02/27 PHP
PHP读取CSV大文件导入数据库的实例
2017/07/24 PHP
thinkphp5框架扩展redis类方法示例
2019/05/06 PHP
jQuery 性能优化指南(2)
2009/05/21 Javascript
jQuery处理图片加载失败的常用方法
2015/06/08 Javascript
jQuery提示插件qTip2用法分析(支持ajax及多种样式)
2016/06/08 Javascript
Javascript日期格式化format函数的使用方法
2016/08/30 Javascript
详解JS-- 浮点数运算处理
2016/11/28 Javascript
JavaScript实现Fly Bird小游戏
2016/12/15 Javascript
JS简单实现数组去重的方法示例
2017/03/27 Javascript
react router 4.0以上的路由应用详解
2017/09/21 Javascript
javaScript产生随机数的用法小结
2018/04/21 Javascript
vue项目环境变量配置的实现方法
2018/10/12 Javascript
详解基于 Node.js 的轻量级云函数功能实现
2019/07/08 Javascript
Vue自定义表单内容检查rules实例
2020/10/30 Javascript
Nest.js环境变量配置与序列化详解
2021/02/21 Javascript
[05:15]DOTA2英雄梦之声_第16期_灰烬之灵
2014/06/21 DOTA
Python标准库之循环器(itertools)介绍
2014/11/25 Python
pygame游戏之旅 按钮上添加文字的方法
2018/11/21 Python
深入浅析Python2.x和3.x版本的主要区别
2018/11/30 Python
python 使用pygame工具包实现贪吃蛇游戏(多彩版)
2019/10/30 Python
使用pandas实现连续数据的离散化处理方式(分箱操作)
2019/11/22 Python
python实现二分类的卡方分箱示例
2019/11/22 Python
python实现超市商品销售管理系统
2019/11/22 Python
Django多层嵌套ManyToMany字段ORM操作详解
2020/05/19 Python
CSS3移动端vw+rem不依赖JS实现响应式布局的方法
2019/01/23 HTML / CSS
介绍一下HTTP、HTTPS和SSL
2012/12/16 面试题
小学班级口号
2014/06/09 职场文书
加强作风建设心得体会
2014/10/22 职场文书
2014年施工员工作总结
2014/11/18 职场文书
2015年体检中心工作总结
2015/05/27 职场文书
PyTorch 如何设置随机数种子使结果可复现
2021/05/12 Python
pytorch 实现变分自动编码器的操作
2021/05/24 Python
CSS+HTML 实现顶部导航栏功能
2021/08/30 HTML / CSS
Python简易开发之制作计算器
2022/04/28 Python