atob与btoa可逆性问题及Base64压缩函数优化问询
Base64可逆转换与DataURI压缩问题及解决
1. btoa无法还原Base64字符串的问题
示例代码:
let b64 = "abc123" console.log(btoa(atob(b64))); //abc12w==
字符串末尾变化:原字符串abc123变为abc12w==,新增了w==的填充内容。
2. DataURI转16位字符串压缩的异常函数
将图片DataURI存储到localStorage时,为把8位字符串转成16位实现长度减半,编写了以下函数,但btoa执行异常:
function compress(dataURI_or_base64) { // 8-bit to 16-bit string (get half length) var bin = atob(dataURI_or_base64.substr(dataURI_or_base64.indexOf(',')+1)); //remove header var len = bin.length; var arr = new Uint8Array(new ArrayBuffer(len)); for (var i = 0; i < len; i++) arr[i] = bin.charCodeAt(i); return new TextDecoder('utf-16').decode(arr); } function decompress(str, mimeType) { // 16-bit to 8-bit string (get back) var arr = new Uint8Array(str.length * 2), i = 0, j = 0; while (i < str.length) { var cc = str.charCodeAt(i++) arr[j++] = cc & 0xff; arr[j++] = cc >> 8; } var bin = '', i = 0; while (i < arr.byteLength) bin += String.fromCharCode(arr[i++]); let dataURI = 'data:' + mimeType + ';base64,' return (mimeType? dataURI: "") + window.btoa(bin); }
3. btoa(atob(b64))的异常点与可逆转换实现
- 异常点:
atob要求输入必须是合法Base64字符串,长度需能被4整除。示例中abc123长度为6,不符合规范,atob会自动处理但导致后续btoa生成的字符串与原输入不一致。 - 可逆转换可行性:可以实现,但需保证输入是合法Base64字符串,或在处理时自动补全填充字符、还原时去除填充。
- atob_rev函数实现思路:需要记录原Base64字符串的填充情况,或在
atob处理前补全合法填充,atob_rev时根据原长度还原对应的Base64字符串(包括正确的填充字符)。
4. 问题解决与更新方案
2023.08.01找到有效解决方案:
- 原示例中的
abc123不是合法Base64字符串,因为Base64字符串长度必须能被4整除。 - 移除
TextDecoder后函数正常工作,修改后的compress函数如下:
function compress(dataURI_or_base64) { let i = 0, a = dataURI_or_base64; //6-bit ascii a = a.slice(a.indexOf(',') + 1) //remove header if (a.length % 4) alert("Padding error\n" + a) let bin = window.atob(a), str16bit = "" while (i < bin.length) { let lo = bin.charCodeAt(i++); let hi = bin.charCodeAt(i++); str16bit += String.fromCharCode(lo | hi << 8) } return str16bit }
该方案实现无损压缩,压缩率超50%。新增的a.length % 4 === 0检查会触发错误提示,避免非法Base64输入。另一种可选方案是在函数内部自动为输入补全填充字符,在decompress时再去除填充,适用于6位ASCII文本消息的编解码。
内容的提问来源于stack exchange,提问作者Dan Froberg
相关产品推荐
相关产品推荐

