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 Excel读取和写入操作(模板操作)实现代码
Apr 11 Javascript
关于JS判断图片是否加载完成且获取图片宽度的方法
Apr 09 Javascript
JQuery设置文本框和密码框得到焦点时的样式
Aug 30 Javascript
JavaScript获得url查询参数的方法
Jul 02 Javascript
15个值得开发人员关注的jQuery开发技巧和心得总结【经典收藏】
May 25 Javascript
jQuery 生成svg矢量二维码
Aug 09 Javascript
BootStrap便签页的简单应用
Jan 06 Javascript
vue 动态改变静态图片以及请求网络图片的实现方法
Feb 07 Javascript
解决百度Echarts图表坐标轴越界的方法
Oct 17 Javascript
关于自定义Egg.js的请求级别日志详解
Dec 12 Javascript
js中数组对象去重的两种方法
Jan 18 Javascript
前端开发之便利店收银系统代码
Dec 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新手上路(十三)
2006/10/09 PHP
PHP 数字左侧自动补0
2008/03/31 PHP
php模拟服务器实现autoindex效果的方法
2015/03/10 PHP
PHP实现的最大正向匹配算法示例
2017/12/19 PHP
laravel框架上传图片实现实时预览功能
2019/10/14 PHP
IE 条件注释详解总结(附实例代码)
2009/08/29 Javascript
JqGrid web打印实现代码
2011/05/31 Javascript
js实现动态改变字体大小代码
2014/01/02 Javascript
jquery实现显示已选用户
2014/07/21 Javascript
jquery插件Jplayer使用方法简析
2016/04/22 Javascript
JavaScript面向对象编写购物车功能
2016/08/19 Javascript
浅谈时钟的生成(js手写简洁代码)
2016/08/20 Javascript
深入理解JavaScript定时机制
2016/10/27 Javascript
[原创]JS基于FileSaver.js插件实现文件保存功能示例
2016/12/08 Javascript
解析JavaScript模仿块级作用域
2016/12/29 Javascript
jQuery简单获取DIV和A标签元素位置的方法
2017/02/07 Javascript
浅谈node的事件机制
2017/10/09 Javascript
JavaScript设计模式之命令模式实例分析
2019/01/16 Javascript
详解微信小程序实现仿微信聊天界面(各种细节处理)
2019/02/17 Javascript
JS实现计算小于非负数n的素数的数量算法示例
2019/02/26 Javascript
vue获取时间戳转换为日期格式代码实例
2019/04/17 Javascript
swiper4实现移动端导航切换
2020/10/16 Javascript
基于vue实现微博三方登录流程解析
2020/11/04 Javascript
vue开发chrome插件,实现获取界面数据和保存到数据库功能
2020/12/01 Vue.js
[00:43]魔廷新尊——痛苦女王至宝捆绑包
2020/06/12 DOTA
python的正则表达式re模块的常用方法
2013/03/09 Python
简单了解python filter、map、reduce的区别
2020/01/14 Python
X/HTML5 和 XHTML2
2008/10/17 HTML / CSS
潘多拉意大利官方网上商城:网上选购PANDORA珠宝
2018/10/07 全球购物
马来西亚和新加坡巴士票在线预订:CatchThatBus
2018/11/17 全球购物
英国现代市场:ARKET
2019/04/10 全球购物
机电一体化专业应届本科生求职信
2013/09/27 职场文书
档案管理员岗位职责
2013/12/01 职场文书
新年晚会主持词
2014/03/24 职场文书
2014年党课学习材料
2014/05/11 职场文书
个人查摆问题自查报告
2014/10/16 职场文书