81 lines
2.5 KiB
JavaScript
81 lines
2.5 KiB
JavaScript
const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||
|
||
/**
|
||
* 把 SVG 文本编码成 UTF-8 字节。
|
||
* 说明:
|
||
* 1. 小程序运行时没有稳定可用的 Buffer,因此这里使用纯 JS 编码;
|
||
* 2. 需要显式处理代理对,避免非 ASCII 字符在 data URI 中损坏;
|
||
* 3. 非法代理项统一替换成 U+FFFD,保证输出始终可编码。
|
||
*/
|
||
function encodeUtf8Bytes(input) {
|
||
const source = String(input || "");
|
||
const bytes = [];
|
||
for (let index = 0; index < source.length; index += 1) {
|
||
const first = source.charCodeAt(index);
|
||
if (first < 0x80) {
|
||
bytes.push(first);
|
||
continue;
|
||
}
|
||
if (first < 0x800) {
|
||
bytes.push(0xc0 | (first >> 6), 0x80 | (first & 0x3f));
|
||
continue;
|
||
}
|
||
|
||
let codePoint = first;
|
||
if (first >= 0xd800 && first <= 0xdbff) {
|
||
const second = source.charCodeAt(index + 1);
|
||
if (second >= 0xdc00 && second <= 0xdfff) {
|
||
codePoint = ((first - 0xd800) << 10) + (second - 0xdc00) + 0x10000;
|
||
index += 1;
|
||
} else {
|
||
codePoint = 0xfffd;
|
||
}
|
||
} else if (first >= 0xdc00 && first <= 0xdfff) {
|
||
codePoint = 0xfffd;
|
||
}
|
||
|
||
if (codePoint < 0x10000) {
|
||
bytes.push(0xe0 | (codePoint >> 12), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
|
||
continue;
|
||
}
|
||
|
||
bytes.push(
|
||
0xf0 | (codePoint >> 18),
|
||
0x80 | ((codePoint >> 12) & 0x3f),
|
||
0x80 | ((codePoint >> 6) & 0x3f),
|
||
0x80 | (codePoint & 0x3f)
|
||
);
|
||
}
|
||
return bytes;
|
||
}
|
||
|
||
/**
|
||
* 把 UTF-8 字节数组转成 base64。
|
||
* 这样生成的 data URI 可以避开开发者工具对 `utf8,...` 形式 SVG URI 的兼容问题。
|
||
*/
|
||
function encodeBase64FromBytes(bytes) {
|
||
const output = [];
|
||
for (let index = 0; index < bytes.length; index += 3) {
|
||
const first = bytes[index];
|
||
const second = index + 1 < bytes.length ? bytes[index + 1] : null;
|
||
const third = index + 2 < bytes.length ? bytes[index + 2] : null;
|
||
const triplet = (first << 16) | ((second || 0) << 8) | (third || 0);
|
||
output.push(
|
||
BASE64_ALPHABET[(triplet >> 18) & 0x3f],
|
||
BASE64_ALPHABET[(triplet >> 12) & 0x3f],
|
||
second === null ? "=" : BASE64_ALPHABET[(triplet >> 6) & 0x3f],
|
||
third === null ? "=" : BASE64_ALPHABET[triplet & 0x3f]
|
||
);
|
||
}
|
||
return output.join("");
|
||
}
|
||
|
||
function toSvgDataUri(svg) {
|
||
const base64 = encodeBase64FromBytes(encodeUtf8Bytes(svg));
|
||
return `data:image/svg+xml;base64,${base64}`;
|
||
}
|
||
|
||
module.exports = {
|
||
toSvgDataUri
|
||
};
|