从svg转base64 再到字符串编码

svg转base64

昨天研究水印生产,其中使用到svg转base64,要用到 btoa 时,但是发现调用 btoa 之前都会再执行一个转码的api (注:有个跟它相反的** atob,两者功能正好相反)

window.btoa(unescape(encodeURIComponent(svgStr)))

我测试了一个例子,发现 unescape(encodeURIComponent(svgStr)) 貌似会对字符串里面的中文进行转码,后面查了一下 btoa 发现它接收的参数必须ASCII 码,如果里面有中文或者特殊字符会报错

btoa('我') 
// Uncaught DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.

如果是普通的字符串转base64,直接调用 encodeURIComponent 即可,但是像转svg这种就不能用这个方法,因为这样就无法显示图片了,所以需要对svg字符串里面的特殊字符转 ASCII 码,注意是只针对特殊字符
encodeURIComponent 针对非ASCII码返回的是utf-8 转义序列与%拼接的字符串,ASCII码则返回%与16进制数字,在编码ASCII时encodeURIComponentescape 返回是一样的
escape 编码非ASCII码时,返回的 %u与16进制的数据,这是它跟 encodeURIComponent 最大的区别。当前二者编码范围也不一样:
encodeURIComponent 不编码范围 A-Z a-z 0-9 - _ . ! ~ * ’ ( )
escape 不编码范围 A-Z a-z 0-9 @*_±./

encodeURIComponent('<') === escape('<') === '%3c'
encodeURIComponent('我') //  "%E6%88%91",由此可以看出utf-8编码中一个汉字占了三个字节(有些汉字占4个字节)
escape('我') // '%u6211'

看了上面编码的对比以及svg里面的字符串的格式(svg标签以及标签内的属性都是ASCII码)。现在只需要解决非ASCII码的编码问题,最简单的方式:

unescape(encodeURIComponent(svgStr))

通过正则的方式:

// 过滤ASCII码外的字符,并转成浏览器可识别的转义序列,16进制的转义序列前缀是 &#x
// ASCII编码范围是 0-255,用16进制表示就是 00-ff
// 16进制转10进制 parseInt('ff', 16) // 255
 function filterUnicodeToAscii(string) {
     return string.replace(/[^\x00-\xff]/g, function (str) {
       return '&#x' + str.charCodeAt().toString(16) + ';'
     })
 }
 filterUnicodeToAscii(svgStr)

以上就是全部内容了,其实关于字符串还有很多知识,但是文章有点乱,就不补充了。ps:本篇文章断断续续写了一周


以下是常用的字符串转码方法:

中文字符转Unicode码

function toUnicode(str){
    return str.replace(/[^\u0000-\u00FF]/g,function($0){
        return escape($0).replace(/(%u)(\w{4})/gi,"\\u$2");
    });
}

//escape 已经从标准中删除,但是Unicode主要是获取字符的16进制,可以用 charCodeAt().toString(16) 来获取
//'我'.charCodeAt().toString(16) // 6211
//如果获取的16进制小于4位,则需要补0,下面这种情况就要补0
//'?'.charCodeAt().toString(16) // 3f
// 下面是完整的代码
function toUnicode(str){
	if(!str && typeof str === string) {
		throw('请传入长度大于1的字符串')
	}
	const prefixed = '\u';
	const codes = '';
    for(let s of str) {
    	codes += prefixed + s.charCodeAt().toString(16).padStart(4, '0');
    }
    return codes;
}


10进制与16进制互转

// 数字转16进制
const n = 233;
n.toString(16) // e9

// 16进制转数字
const s = 'e9'
parseInt(s, 16) // 233

回忆一下encodeURIComponent 和 encodeURI

encodeURIComponentencodeURI 区别在于前者会额外对特殊字符进行编码,比如下面这种情况就只能用encodeURIComponent,如果没有对这部分进行编码,则查询的时候后面的部分就无法查询到

const value = 'test&a=1'
'http://www.baidu.com/s?word=' + encodeURIComponent(value)
encodeURIComponent(value) // "test%26a%3D1"
encodeURI(value) // "test&a=1"
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值