-
Notifications
You must be signed in to change notification settings - Fork 1
/
cmd.js
executable file
·212 lines (191 loc) · 6.27 KB
/
cmd.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/usr/bin/env node
var fs = require('fs')
var opentype = require('opentype.js')
var pack = require('./lib/pack.js')
var from = require('from2')
var pump = require('stream').pipeline
var varint = require('varint')
var uniq = require('uniq')
var minimist = require('minimist')
var argv = minimist(process.argv.slice(2), {
alias: {
h: 'help',
v: 'version',
i: 'infile',
o: 'outfile',
u: ['unicode','unicodes'],
c: ['char','chars'],
x: ['index','indexes'],
l: ['ls','list'],
m: ['meta'],
},
boolean: [ 'help', 'version', 'list', 'meta' ],
default: { outfile: '-' },
})
var magic = Buffer.from(require('./lib/magic.js').concat(0x0a))
var outstream = argv.outfile === '-' ? process.stdout : fs.createWriteStream(argv.outfile)
if (argv.meta) {
var compare = require('./lib/compare.js')
var infiles = [].concat(argv.infile || []).concat(argv._)
var index = 0
var QBZF = null
return pump(from(function (size, next) {
if (index >= infiles.length) return next(null, null)
var infile = infiles[index++]
fs.readFile(infile, function (err, buf) {
var data = buf.buffer
var fileType = compare(magic, buf.slice(0,magic.length)) === 0 ? 'qbzf' : 'ttf'
if (fileType === 'ttf') {
var font = opentype.parse(data)
var keys = Object.keys(font.glyphs.glyphs)
var unicodes = keys.map(k => font.glyphs.glyphs[k].unicodes)
.filter(u => u.length > 0).sort(cmpu)
} else {
if (!QBZF) QBZF = require('./')
var qbzf = QBZF(buf)
var unicodes = []
for (var k of qbzf._glyphs.keys()) {
var u = k.split(',').map(Number)
unicodes.push(u)
}
}
var ranges = [], range = [null,null]
var prev = []
for (var i = 0; i < unicodes.length; i++) {
var u = unicodes[i]
if (range[0] === null) {
range[0] = u.length === 1 ? u[0] : u
} else if (diffu(prev,u) > 1) {
range[1] = prev.length === 1 ? prev[0]+1 : [prev[0],prev[1]+1]
ranges.push(range[1]-range[0] === 1 ? range[0] : range)
range = [ u.length === 1 ? u[0] : u, null ]
}
prev = u
}
if (range[0] !== null) {
range[1] = prev.length === 1 ? prev[0] : prev
ranges.push(range[1]-range[0] === 1 ? range[0] : range)
}
next(null, JSON.stringify({
file: infile,
type: fileType,
unicodes: ranges,
})+'\n')
})
}), outstream, onerror)
return
}
var infile = argv.infile ?? argv._[0]
if (argv.version) return console.log(require('./package.json').version)
if (infile === undefined || argv.help) return usage()
var data = fs.readFileSync(infile).buffer
var font = opentype.parse(data)
var isHeader = true
var indexes = []
if (argv.unicodes !== undefined) {
var codes = new Set
var ucodes = [].concat(argv.unicodes)
.flatMap(c => String(c).split(','))
for (var i = 0; i < ucodes.length; i++) {
var u = ucodes[i]
var m = /^\\?u\+?([0-9A-Fa-f]+)/i.exec(u)
codes.add(m ? parseInt(m[1],16) : Number(u))
}
for (var [index,g] of Object.entries(font.glyphs.glyphs)) {
if (codes.has(g.unicode)) {
indexes.push(Number(index))
}
}
}
if (argv.chars !== undefined) {
var codes = new Set
var chars = [].concat(argv.chars)
.flatMap(c => c === ',' ? c : String(c).split(','))
for (var i = 0; i < chars.length; i++) {
codes.add(chars[i].charCodeAt(0))
}
for (var [index,g] of Object.entries(font.glyphs.glyphs)) {
if (codes.has(g.unicode)) {
indexes.push(Number(index))
}
}
}
if (argv.indexes !== undefined) {
indexes = indexes.concat(argv.indexes)
.flatMap(c => String(c).split(',').map(Number))
}
if (indexes.length === 0) {
indexes = Object.keys(font.glyphs.glyphs).map(Number)
}
uniq(indexes)
indexes.sort((a,b) => a < b ? -1 : +1)
var index = 0
if (argv.list) {
return pump(from(function (size, next) {
if (index >= indexes.length) return next(null, null)
while (true) {
if (index >= indexes.length) break
var g = font.glyphs.glyphs[indexes[index++]]
if (g.unicodes.length === 0) continue
return next(null, JSON.stringify(g)+'\n')
}
next(null, null)
}), outstream, onerror)
}
pump(from(function (size, next) {
if (isHeader) {
var header = Buffer.alloc(magic.length + varint.encodingLength(font.unitsPerEm))
magic.copy(header, 0)
varint.encode(font.unitsPerEm, header, magic.length)
isHeader = false
return next(null, header)
}
if (index >= indexes.length) return next(null, null)
while (true) {
if (index >= indexes.length) break
var g = font.glyphs.glyphs[indexes[index++]]
if (g.unicodes.length === 0) continue
return next(null, pack(g))
}
next(null, null)
}), outstream, onerror)
function usage() {
console.log(`
usage: qbzf (INFILE)
-i INFILE Read from this font file.
-o OUTFILE Write bezier text output to this file. Default: "-" (stdout)
-l --list List all codes from the input ttf font file.
-m --meta List unitsPerEm and glyph unicodes as ranges for each INFILE,
which can be a ttf or qbzf font file.
-u --unicode Only include glyphs with these unicode values.
-c --char Only include glyphs with these character values.
-x --index Only include glyphs with these indexes.
-h --help Show this message.
-v --version Print software version (${require('./package.json').version}).
Unicode and index lists can be specified with multiple flags (-u 97 -u 98 -u 99)
or with comma-separated lists (-u 97,98,99).
Char lists can be specified with multiple flags or comma-separated lists.
For a literal comma, use "-c,".
Unicodes can be specified in hexadecimal with a leading "u": (-u u0061).
`.trim().replace(/^ {4}/mg,'') + '\n')
}
function onerror(err) {
if (err && err.code !== 'EPIPE') {
console.error(err)
process.exit(1)
}
}
function cmpu(a,b) {
if (a[0] === b[0] && a.length === b.length) {
return a[1] < b[1] ? -1 : + 1
} else if (a[0] === b[0]) {
return a.length < b.length ? -1 : +1
}
return a[0] < b[0] ? -1 : +1
}
function diffu(a,b) {
if (a.length === 1 && b.length === 1) return b[0]-a[0]
if (a.length !== b.length) return 100
if (a[0] === b[0] && a[1]+1 === b[0]) return 0
return 100
}