termtosvg 录制的 SVG 在有中文等字符输出时会挤压在一起 , 此脚本专门用于解决此问题
Usage: <svgfile> [options]
Options:
-o, --outDir <dir> 指定输出目录, 默认输出到当前目录
一行代码解决有问题的svg
npx https://gist.github.com/cnwhy/7cad3be853a188823c077df1182f6b1a /tmp/termtosvg_d4pd0f4p.svg
| { | |
| "name": "termtosvg-CN-fix", | |
| "version": "0.0.1", | |
| "bin": "./termtosvg-fix.js", | |
| "dependencies": { | |
| "commander": "^2.19.0" | |
| } | |
| } |
| #!/usr/bin/env node | |
| // 处理 termtosvg 录制的SVG 对中文显示不友好的问题 | |
| const program = require('commander'); | |
| const path = require('path'); | |
| const fs = require('fs'); | |
| //常见非标宽字符区间 | |
| const Ukuan = [ | |
| '2460-24FF', //括号字母数字 | |
| '27F0-27FF', //补充大箭头1 | |
| '2900-297F', //补充大箭头2 | |
| '2B00-2BFF', //补充大箭头3 | |
| '2E80-9FFF', //中日韩 | |
| 'F900-FAFF', //中日韩相容表意文字 | |
| 'FE10-FE1F', //竖式标点 | |
| 'FE30-FE4F', //中日韩相容形式 | |
| 'FF00-FFEF', //全角字符 | |
| ]; | |
| const Ukuan_rang = Ukuan.map(v=>v.split('-').map(i=>parseInt(i,16))); | |
| const Ukuan_reg = new RegExp('['+Ukuan.map(v=>v.split('-').map(i=>'\\u'+i).join('-')).join('')+']'); | |
| const reg_text = /<text[^>]*(textLength="\d+")[^>]*>(.*?)<\/text>/g; | |
| const hasKuang = function(str){ | |
| if(Ukuan_reg.test(str)){ | |
| return true | |
| }else{ | |
| var codes = str.match(/&(?:#[xX][\da-fA-F]+|#\d+);/g); | |
| if(codes){ | |
| for(let s of codes){ | |
| if (s.charAt(1) === '#') { | |
| let code; | |
| if (s.charAt(2) === 'X' || s.charAt(2) === 'x') { | |
| // return decodeCodePoint(parseInt(str.substr(3), 16)); | |
| code = parseInt(s.substr(3), 16) | |
| } | |
| code = parseInt(s.substr(2), 10); | |
| for(let i=0; i<Ukuan_rang.length; i++){ | |
| let range = Ukuan_rang[i]; | |
| if(code >= range[0] && code <= range[1]){ | |
| return true; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| const fixCN = function(xmlstr){ | |
| return xmlstr.replace(reg_text,function(str,attr,content){ | |
| if(hasKuang(content)){ | |
| str = str.replace(attr,''); | |
| } | |
| return str; | |
| }) | |
| } | |
| // const xml_map = { amp: '&', apos: "'", gt: '>', lt: '<', quot: '"' }; | |
| // const xmlReplace = function() { | |
| // if (str.charAt(1) === '#') { | |
| // if (str.charAt(2) === 'X' || str.charAt(2) === 'x') { | |
| // return decodeCodePoint(parseInt(str.substr(3), 16)); | |
| // } | |
| // return decodeCodePoint(parseInt(str.substr(2), 10)); | |
| // } | |
| // return xml_map[str.slice(1, -1)]; | |
| // }; | |
| // const xmlDecode = (function() { | |
| // var keys = Object.keys(map).join('|'); | |
| // keys += '|#[xX][\\da-fA-F]+|#\\d+'; | |
| // var re = new RegExp('&(?:' + keys + ');', 'g'); | |
| // return function(str) { | |
| // return String(str).replace(re, xmlReplace); | |
| // }; | |
| // })(); | |
| function main(files = [], outDir = './') { | |
| // const files = args._ || []; | |
| let filesPath = files.map(file => path.resolve(process.cwd(), file)); | |
| let outPath = files.map(p=>path.join(outDir, 'convert-' + path.parse(p).base)); | |
| let contents = filesPath.map(file => fs.readFileSync(file).toString()); | |
| contents.forEach((xml,index)=>{ | |
| fs.writeFileSync(outPath[index], fixCN(xml)); | |
| }) | |
| console.log('处理完成:') | |
| console.log(outPath.join('\n')); | |
| } | |
| program.usage('<file> [options]'); | |
| program.option('-o, --outDir <dir>', '指定输出目录'); | |
| program.parse(process.argv); | |
| if (program.args.length) { | |
| main(program.args, program.outDir); | |
| } |