Skip to content

base64 原理

原理

Base64 索引表:

数值字符数值字符数值字符数值字符
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/

例子:

例一文本(1 Byte)A
二进制位01000001
二进制位(补 0)010000010000
Base64 编码QQ
例二文本(2 Byte)BC
二进制位0100001001000011
二进制位(补 0)010000100100001100
Base64 编码QkM

解析:

  1. 将 A 转换为二进制:01000001

  2. 每 6 个分一份,不足的用 0 补齐:010000/010000 (为什么6个一份?二进制111111表示十进制63,正好6位可以表示全索引表)

  3. 将分好的每一份转为 10 进制,再去索引表取对应值:010000 得到 16,16 对应 Q

  4. A 转换后就得到了 QQ

  5. 在 2 步骤中,补了 4 个 0 就在最终结果后加两个'=',补了 2 个 0,就加一个'='

  6. 最终 A 转换 base64 为:QQ==,BC 转换 base64 为:QkM=

js 实现 base64 转换

javascript
//索引表
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('')

//将二进制转换为base64编码
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
}

//将base64编码转换为二进制
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)
}

//将字符转换为二进制
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
}

//将二进制转换为字符串
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
}

console.log(binToStr(base64ToBin('QQ==')))
console.log(binToBase64(stringToBin('BC')))
//索引表
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('')

//将二进制转换为base64编码
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
}

//将base64编码转换为二进制
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)
}

//将字符转换为二进制
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
}

//将二进制转换为字符串
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
}

console.log(binToStr(base64ToBin('QQ==')))
console.log(binToBase64(stringToBin('BC')))

图片 base64

  1. 通过 canvas 得到图片的二进制数据

  2. 在二进制字符串中"藏好宽高"

  3. 将二进制数据转为 base64

html
<body>
  <img id="img1" src="googlelogo_color_92x30dp.png" />
  <textarea style="width:300px;height:200px;" id="txt1"></textarea>
  <canvas id="myCanvas" width="184" height="60"></canvas>
</body>
<body>
  <img id="img1" src="googlelogo_color_92x30dp.png" />
  <textarea style="width:300px;height:200px;" id="txt1"></textarea>
  <canvas id="myCanvas" width="184" height="60"></canvas>
</body>
javascript
function numToString(num) {
  var bin = num.toString(2)
  return new Array(9 - bin.length).join(0) + bin
}

//获取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)
}

//图片转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 += numToString(imgData[i])
  }

  bin = bin + stringToBin('$$' + imgWidth + ',' + imgHeight + '$$')
  return binToBase64(bin)
}

//绘图
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)
}

//base64转图片
function base642img(data) {
  var str = binToStr(base64ToBin(data))
  var imgWidth = str.match(/\$\$(\d+),(\d+)\$\$$/, '')[1]
  var imgHeight = str.match(/\$\$(\d+),(\d+)\$\$$/, '')[2]
  var imgData = base64ToBin(data).replace(
    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)
}

window.onload = function() {
  const base64 = img2Base64(document.getElementById('img1'))
  document.getElementById('txt1').value = base64
  paint(base642img(base64))
}
function numToString(num) {
  var bin = num.toString(2)
  return new Array(9 - bin.length).join(0) + bin
}

//获取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)
}

//图片转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 += numToString(imgData[i])
  }

  bin = bin + stringToBin('$$' + imgWidth + ',' + imgHeight + '$$')
  return binToBase64(bin)
}

//绘图
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)
}

//base64转图片
function base642img(data) {
  var str = binToStr(base64ToBin(data))
  var imgWidth = str.match(/\$\$(\d+),(\d+)\$\$$/, '')[1]
  var imgHeight = str.match(/\$\$(\d+),(\d+)\$\$$/, '')[2]
  var imgData = base64ToBin(data).replace(
    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)
}

window.onload = function() {
  const base64 = img2Base64(document.getElementById('img1'))
  document.getElementById('txt1').value = base64
  paint(base642img(base64))
}