font-ocm.lua /size: 29 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
font-ocm
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to font-ini.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
if
not
context
then
10
return
11
elseif
CONTEXTLMTXMODE
and
CONTEXTLMTXMODE
>
0
then
12
return
13
else
14
-- Maybe I'll also make a generic variant but for now I just test this in
15
-- MkIV. After all, color fonts are not that much used (and generic is for
16
-- serious looking articles and books and not for fancy documents using
17
-- emoji.) Below is a quick and dirty implementation. Also, it looks like
18
-- these features were never used outside context anyway (in spite of being
19
-- in generic).
20
end
21 22
local
tostring
,
tonumber
,
next
=
tostring
,
tonumber
,
next
23
local
round
,
max
=
math
.
round
,
math
.
round
24
local
sortedkeys
,
sortedhash
,
concat
=
table
.
sortedkeys
,
table
.
sortedhash
,
table
.
concat
25
local
setmetatableindex
=
table
.
setmetatableindex
26
local
formatters
=
string
.
formatters
27 28
local
otf
=
fonts
.
handlers
.
otf
29
local
otfregister
=
otf
.
features
.
register
30
local
bpfactor
=
number
.
dimenfactors
.
bp
31
local
typethree
=
{
}
32 33
callback
.
register
(
"
provide_charproc_data
"
,
function
(
action
,
f
,
...
)
34
local
registered
=
typethree
[
f
]
35
if
registered
then
36
return
registered
(
action
,
f
,
...
)
37
else
38
return
0
,
0
-- this will also disable further calls
39
end
40
end
)
41 42
local
defaults
=
{
43
[
1
]
=
function
(
)
return
0
,
0
end
,
44
[
2
]
=
function
(
)
return
0
,
0
end
,
45
[
3
]
=
function
(
)
return
0
.
001
,
"
"
end
,
46
}
47 48
local
function
registeractions
(
t
)
49
return
{
50
[
1
]
=
t
.
preroll
or
defaults
[
1
]
,
51
[
2
]
=
t
.
collect
or
defaults
[
2
]
,
52
[
3
]
=
t
.
wrapup
or
defaults
[
3
]
,
53
}
54
end
55 56
local
function
registertypethreeresource
(
specification
,
n
,
o
)
57
specification
.
usedobjects
[
"
X
"
.
.
n
]
=
lpdf
.
reference
(
o
)
58
end
59 60
local
function
registertypethreefont
(
specification
,
n
,
o
)
61
specification
.
usedfonts
[
"
F
"
.
.
n
]
=
lpdf
.
reference
(
o
)
62
end
63 64
local
function
typethreeresources
(
specification
)
65
local
usedobjects
=
specification
.
usedobjects
66
local
usedfonts
=
specification
.
usedfonts
67
local
resources
=
{
}
68
if
next
(
usedobjects
)
then
69
resources
[
#
resources
+
1
]
=
"
/XObject <<
"
.
.
usedobjects
(
)
.
.
"
>>
"
70
end
71
if
next
(
usedfonts
)
then
72
resources
[
#
resources
+
1
]
=
"
/Font <<
"
.
.
usedfonts
(
)
.
.
"
>>
"
73
end
74
-- resources[#resources+1] = lpdf.collectedresources()
75
specification
.
usedfonts
=
nil
76
specification
.
usedobjects
=
nil
77
return
concat
(
resources
,
"
"
)
78
end
79 80
local
function
registerfont
(
specification
,
actions
)
81
specification
.
usedfonts
=
lpdf
.
dictionary
(
)
82
specification
.
usedobjects
=
lpdf
.
dictionary
(
)
83
typethree
[
specification
.
id
]
=
function
(
action
,
f
,
c
)
84
return
actions
[
action
]
(
specification
,
f
,
c
)
85
end
86
end
87 88
fonts
.
handlers
.
typethree
=
{
89
register
=
function
(
id
,
handler
)
90
-- needed for manual
91
if
not
typethree
[
id
]
then
92
logs
.
report
(
"
fonts
"
,
"
low level Type3 handler registered for font with id %i
"
,
id
)
93
typethree
[
id
]
=
handler
94
end
95
end
96
}
97 98
local
initializeoverlay
do
99 100
local
f_color
=
formatters
[
"
%.3f %.3f %.3f rg
"
]
101
local
f_gray
=
formatters
[
"
%.3f g
"
]
102
local
sharedpalettes
=
{
}
103
local
colors
=
attributes
.
list
[
attributes
.
private
(
'
color
'
)
]
or
{
}
104
local
transparencies
=
attributes
.
list
[
attributes
.
private
(
'
transparency
'
)
]
or
{
}
105 106
function
otf
.
registerpalette
(
name
,
values
)
107
sharedpalettes
[
name
]
=
values
108
local
color
=
lpdf
.
color
109
local
transparency
=
lpdf
.
transparency
110
local
register
=
colors
.
register
111
for
i
=
1
,
#
values
do
112
local
v
=
values
[
i
]
113
if
v
=
=
"
textcolor
"
then
114
values
[
i
]
=
false
115
else
116
local
c
=
nil
117
local
t
=
nil
118
if
type
(
v
)
=
=
"
table
"
then
119
c
=
register
(
name
,
"
rgb
"
,
120
max
(
round
(
(
v
.
r
or
0
)
*
255
)
,
255
)
/
255
,
121
max
(
round
(
(
v
.
g
or
0
)
*
255
)
,
255
)
/
255
,
122
max
(
round
(
(
v
.
b
or
0
)
*
255
)
,
255
)
/
255
123
)
124
else
125
c
=
colors
[
v
]
126
t
=
transparencies
[
v
]
127
end
128
if
c
and
t
then
129
values
[
i
]
=
color
(
1
,
c
)
.
.
"
"
.
.
transparency
(
t
)
130
elseif
c
then
131
values
[
i
]
=
color
(
1
,
c
)
132
elseif
t
then
133
values
[
i
]
=
color
(
1
,
t
)
134
end
135
end
136
end
137
end
138 139
local
function
convert
(
t
,
k
)
140
local
v
=
{
}
141
for
i
=
1
,
#
k
do
142
local
p
=
k
[
i
]
143
local
r
,
g
,
b
=
p
[
1
]
,
p
[
2
]
,
p
[
3
]
144
if
r
=
=
g
and
g
=
=
b
then
145
v
[
i
]
=
f_gray
(
r
/
255
)
146
else
147
v
[
i
]
=
f_color
(
r
/
255
,
g
/
255
,
b
/
255
)
148
end
149
end
150
t
[
k
]
=
v
151
return
v
152
end
153 154
-- This is by no means watertight (the id mess) especially because we
155
-- don't know it yet. Instead we can just assemble here and avoid the
156
-- box approach. I might do that (so then we need to pass fonts and
157
-- extra resource entries.
158 159
local
f_stream
=
formatters
[
"
%s 0 d0 %s 0 0 %s 0 %s cm /X%i Do
"
]
160
local
fontorder
=
0
161
local
actions
=
registeractions
{
162 163
preroll
=
function
(
specification
,
f
,
c
)
164
local
data
=
specification
.
delegated
[
c
]
165
local
colorlist
=
data
.
colorlist
166
local
colorvalues
=
specification
.
colorvalues
167
local
default
=
specification
.
default
168
local
mainid
=
specification
.
mainid
169
local
t
=
{
"
\\typethreefont{
"
,
mainid
,
"
}
"
}
170
local
n
=
3
171
local
l
=
nil
172
local
m
=
#
colorlist
173
for
i
=
1
,
m
do
174
local
entry
=
colorlist
[
i
]
175
local
v
=
colorvalues
[
entry
.
class
]
or
default
176
if
v
and
l
~
=
v
then
177
n
=
n
+
1
;
t
[
n
]
=
"
\\typethreecode{
"
178
n
=
n
+
1
;
t
[
n
]
=
v
179
n
=
n
+
1
;
t
[
n
]
=
"
}
"
180
l
=
v
181
end
182
if
i
<
m
then
183
n
=
n
+
1
;
t
[
n
]
=
"
\\typethreechar{
"
184
else
185
n
=
n
+
1
;
t
[
n
]
=
"
\\typethreelast{
"
186
end
187
n
=
n
+
1
;
t
[
n
]
=
entry
.
slot
188
n
=
n
+
1
;
t
[
n
]
=
"
}
"
189
end
190
token
.
set_macro
(
"
typethreemacro
"
,
concat
(
t
)
)
191
tex
.
runtoks
(
"
typethreetoks
"
)
192
registertypethreeresource
(
specification
,
c
,
tex
.
saveboxresource
(
0
,
nil
,
lpdf
.
collectedresources
(
)
,
true
)
)
193
-- registertypethreefont(specification,mainid,lpdf.reference(lpdf.getfontobjnumber(mainid)))
194
return
0
,
0
195
end
,
196 197
collect
=
function
(
specification
,
f
,
c
)
198
local
parameters
=
specification
.
parameters
199
local
data
=
specification
.
delegated
[
c
]
200
local
factor
=
parameters
.
hfactor
201
local
units
=
parameters
.
units
202
local
width
=
(
data
.
width
or
0
)
/
factor
203
local
scale
=
100
204
local
factor
=
units
*
bpfactor
-- / scale
205
local
depth
=
(
data
.
depth
or
0
)
*
factor
206
local
shift
=
-
depth
/
(
10
*
units
/
1000
)
207
local
object
=
pdf
.
immediateobj
(
"
stream
"
,
f_stream
(
width
,
scale
,
scale
,
shift
,
c
)
)
208
return
object
,
width
209
end
,
210 211
wrapup
=
function
(
specification
,
f
)
212
return
0
.
001
,
typethreeresources
(
specification
)
213
end
,
214 215
}
216 217
local
function
register
(
specification
)
218
registerfont
(
specification
,
actions
)
219
end
220 221
initializeoverlay
=
function
(
tfmdata
,
kind
,
value
)
222
if
value
then
223
local
resources
=
tfmdata
.
resources
224
local
palettes
=
resources
.
colorpalettes
225
if
palettes
then
226
local
converted
=
resources
.
converted
227
if
not
converted
then
228
converted
=
setmetatableindex
(
convert
)
229
resources
.
converted
=
converted
230
end
231
local
colorvalues
=
sharedpalettes
[
value
]
232
local
default
=
false
-- so the text color (bad for icon overloads)
233
if
colorvalues
then
234
default
=
colorvalues
[
#
colorvalues
]
235
else
236
colorvalues
=
converted
[
palettes
[
tonumber
(
value
)
or
1
]
or
palettes
[
1
]
]
or
{
}
237
end
238
local
classes
=
#
colorvalues
239
if
classes
=
=
0
then
240
return
241
end
242
--
243
local
characters
=
tfmdata
.
characters
244
local
descriptions
=
tfmdata
.
descriptions
245
local
properties
=
tfmdata
.
properties
246
local
parameters
=
tfmdata
.
parameters
247
--
248
properties
.
virtualized
=
true
249
--
250
local
delegated
=
{
}
251
local
index
=
0
252
local
fonts
=
tfmdata
.
fonts
or
{
}
253
local
fontindex
=
#
fonts
+
1
254
tfmdata
.
fonts
=
fonts
255 256
local
function
flush
(
)
257
if
index
>
0
then
258
fontorder
=
fontorder
+
1
259
local
f
=
{
260
characters
=
delegated
,
261
parameters
=
parameters
,
262
tounicode
=
true
,
263
format
=
"
type3
"
,
264
name
=
"
InternalTypeThreeFont
"
,
-- .. fontorder,
265
psname
=
"
none
"
,
266
}
267
fonts
[
fontindex
]
=
{
268
id
=
font
.
define
(
f
)
,
269
delegated
=
delegated
,
270
parameters
=
parameters
,
271
colorvalues
=
colorvalues
,
272
default
=
default
,
273
}
274
end
275
fontindex
=
fontindex
+
1
276
index
=
0
277
delegated
=
{
}
278
end
279 280
for
unicode
,
character
in
sortedhash
(
characters
)
do
281
local
description
=
descriptions
[
unicode
]
282
if
description
then
283
local
colorlist
=
description
.
colors
284
if
colorlist
then
285
if
index
=
=
255
then
286
flush
(
)
287
end
288
index
=
index
+
1
289
delegated
[
index
]
=
{
290
width
=
character
.
width
,
291
height
=
character
.
height
,
292
depth
=
character
.
depth
,
293
tounicode
=
character
.
tounicode
,
294
colorlist
=
colorlist
,
295
}
296
character
.
commands
=
{
297
{
"
slot
"
,
fontindex
,
index
}
,
298
}
299
end
300
end
301
end
302 303
flush
(
)
304
local
mainid
=
font
.
nextid
(
)
305
for
i
=
1
,
#
fonts
do
306
local
f
=
fonts
[
i
]
307
if
f
.
delegated
then
308
f
.
mainid
=
mainid
309
register
(
f
)
310
end
311
end
312 313
return
true
314
end
315
end
316
end
317 318
otfregister
{
319
name
=
"
colr
"
,
320
description
=
"
color glyphs
"
,
321
manipulators
=
{
322
base
=
initializeoverlay
,
323
node
=
initializeoverlay
,
324
}
325
}
326 327
end
328 329
do
330 331
local
nofstreams
=
0
332
local
f_name
=
formatters
[
[[
pdf-glyph-%05i
]]
]
333
local
f_used
=
context
and
formatters
[
[[
original:///%s
]]
]
or
formatters
[
[[
%s
]]
]
334
local
hashed
=
{
}
335
local
cache
=
{
}
336 337
local
openpdf
=
pdfe
.
new
338 339
function
otf
.
storepdfdata
(
pdf
)
340
if
pdf
then
341
local
done
=
hashed
[
pdf
]
342
if
not
done
then
343
nofstreams
=
nofstreams
+
1
344
local
f
=
f_name
(
nofstreams
)
345
local
n
=
openpdf
(
pdf
,
#
pdf
,
f
)
346
done
=
f_used
(
n
)
347
hashed
[
pdf
]
=
done
348
end
349
return
done
350
end
351
end
352 353
end
354 355
local
pdftovirtual
do
356 357
local
f_stream
=
formatters
[
"
%s 0 d0 %s 0 0 %s %s %s cm /X%i Do
"
]
358
local
fontorder
=
0
359
local
shared
=
{
}
360
local
actions
=
registeractions
{
361 362
preroll
=
function
(
specification
,
f
,
c
)
363
return
0
,
0
364
end
,
365 366
collect
=
function
(
specification
,
f
,
c
)
367
local
parameters
=
specification
.
parameters
368
local
data
=
specification
.
delegated
[
c
]
369
local
desdata
=
data
.
desdata
370
local
pdfdata
=
data
.
pdfdata
371
local
width
=
desdata
.
width
or
0
372
local
height
=
desdata
.
height
or
0
373
local
depth
=
desdata
.
depth
or
0
374
local
factor
=
parameters
.
hfactor
375
local
units
=
parameters
.
units
376
local
typ
=
type
(
pdfdata
)
377 378
local
dx
=
0
379
local
dy
=
0
380
local
scale
=
1
381 382
if
typ
=
=
"
table
"
then
383
data
=
pdfdata
.
data
384
dx
=
pdfdata
.
x
or
pdfdata
.
dx
or
0
385
dy
=
pdfdata
.
y
or
pdfdata
.
dy
or
0
386
scale
=
pdfdata
.
scale
or
1
387
elseif
typ
=
=
"
string
"
then
388
data
=
pdfdata
389
dx
=
0
390
dy
=
0
391
else
392
return
0
,
0
393
end
394 395
if
not
data
then
396
return
0
,
0
397
end
398 399
local
name
=
otf
.
storepdfdata
(
data
)
400
local
xform
=
shared
[
name
]
401 402
if
not
xform
then
403
xform
=
images
.
embed
(
images
.
create
{
filename
=
name
}
)
404
shared
[
name
]
=
xform
405
end
406 407
registertypethreeresource
(
specification
,
c
,
xform
.
objnum
)
408 409
scale
=
scale
*
(
width
/
(
xform
.
width
*
bpfactor
)
)
410
dy
=
-
depth
+
dy
411
-- dx = 0
412
-- dy = 0
413
local
object
=
pdf
.
immediateobj
(
"
stream
"
,
f_stream
(
width
,
scale
,
scale
,
dx
,
dy
,
c
)
)
,
width
414 415
return
object
,
width
416
end
,
417 418
wrapup
=
function
(
specification
,
f
)
419
return
1
/
specification
.
parameters
.
units
,
typethreeresources
(
specification
)
420
end
,
421 422
}
423 424
local
function
register
(
specification
)
425
registerfont
(
specification
,
actions
)
426
end
427 428
pdftovirtual
=
function
(
tfmdata
,
pdfshapes
,
kind
)
-- kind = png|svg
429
if
not
tfmdata
or
not
pdfshapes
or
not
kind
then
430
return
431
end
432
--
433
local
characters
=
tfmdata
.
characters
434
local
descriptions
=
tfmdata
.
descriptions
435
local
properties
=
tfmdata
.
properties
436
local
parameters
=
tfmdata
.
parameters
437
local
hfactor
=
parameters
.
hfactor
438
--
439
properties
.
virtualized
=
true
440
--
441
local
storepdfdata
=
otf
.
storepdfdata
442
--
443
local
delegated
=
{
}
444
local
index
=
0
445
local
fonts
=
tfmdata
.
fonts
or
{
}
446
local
fontindex
=
#
fonts
+
1
447
tfmdata
.
fonts
=
fonts
448 449
local
function
flush
(
)
450
if
index
>
0
then
451
fontorder
=
fontorder
+
1
452
local
f
=
{
453
characters
=
delegated
,
454
parameters
=
parameters
,
455
tounicode
=
true
,
456
format
=
"
type3
"
,
457
name
=
"
InternalTypeThreeFont
"
.
.
fontorder
,
458
psname
=
"
none
"
,
459
size
=
parameters
.
size
,
460
}
461
fonts
[
fontindex
]
=
{
462
id
=
font
.
define
(
f
)
,
463
delegated
=
delegated
,
464
parameters
=
parameters
,
465
}
466
end
467
fontindex
=
fontindex
+
1
468
index
=
0
469
delegated
=
{
}
470
end
471 472
for
unicode
,
character
in
sortedhash
(
characters
)
do
473
local
idx
=
character
.
index
474
if
idx
then
475
local
pdfdata
=
pdfshapes
[
idx
]
476
local
description
=
descriptions
[
unicode
]
477
if
pdfdata
and
description
then
478
if
index
=
=
255
then
479
flush
(
)
480
end
481
index
=
index
+
1
482
delegated
[
index
]
=
{
483
desdata
=
description
,
484
width
=
character
.
width
,
485
height
=
character
.
width
,
486
depth
=
character
.
width
,
487
tounicode
=
character
.
tounicode
,
488
pdfdata
=
pdfdata
,
489
}
490
character
.
commands
=
{
491
{
"
slot
"
,
fontindex
,
index
}
,
492
}
493
end
494
end
495
end
496
--
497
flush
(
)
498
local
mainid
=
font
.
nextid
(
)
499
for
i
=
1
,
#
fonts
do
500
local
f
=
fonts
[
i
]
501
if
f
.
delegated
then
502
f
.
mainid
=
mainid
503
register
(
f
)
504
end
505
end
506
--
507
end
508 509
end
510 511
local
initializesvg
do
512 513
local
otfsvg
=
otf
.
svg
or
{
}
514
otf
.
svg
=
otfsvg
515
otf
.
svgenabled
=
true
516 517
local
report_svg
=
logs
.
reporter
(
"
fonts
"
,
"
svg conversion
"
)
518 519
local
loaddata
=
io
.
loaddata
520
local
savedata
=
io
.
savedata
521
local
remove
=
os
.
remove
522 523
local
xmlconvert
=
xml
.
convert
524
local
xmlfirst
=
xml
.
first
525 526
function
otfsvg
.
filterglyph
(
entry
,
index
)
527
local
d
=
entry
.
data
528
if
gzip
.
compressed
(
d
)
then
529
d
=
gzip
.
decompress
(
d
)
or
d
530
end
531
local
svg
=
xmlconvert
(
d
)
532
local
root
=
svg
and
xmlfirst
(
svg
,
"
/svg[@id='glyph
"
.
.
index
.
.
"
']
"
)
533
local
data
=
root
and
tostring
(
root
)
534
return
data
535
end
536 537
local
runner
=
sandbox
and
sandbox
.
registerrunner
{
538
name
=
"
otfsvg
"
,
539
program
=
"
inkscape
"
,
540
method
=
"
pipeto
"
,
541
template
=
"
--export-area-drawing --shell > temp-otf-svg-shape.log
"
,
542
reporter
=
report_svg
,
543
}
544 545
if
not
runner
then
546
--
547
-- poor mans variant for generic:
548
--
549
runner
=
function
(
)
550
return
io
.
popen
(
"
inkscape --export-area-drawing --shell > temp-otf-svg-shape.log
"
,
"
w
"
)
551
end
552
end
553 554
-- There are svg out there with bad viewBox specifications where shapes lay outside that area,
555
-- but trying to correct that didn't work out well enough so I discarded that code. BTW, we
556
-- decouple the inskape run and the loading run because inkscape is working in the background
557
-- in the files so we need to have unique files.
558
--
559
-- Because a generic setup can be flawed we need to catch bad inkscape runs which add a bit of
560
-- ugly overhead. Bah.
561 562
local
new
=
nil
563 564
local
function
inkscapeformat
(
suffix
)
565
if
new
=
=
nil
then
566
new
=
os
.
resultof
(
"
inkscape --version
"
)
or
"
"
567
new
=
new
=
=
"
"
or
not
find
(
new
,
"
Inkscape%s*0
"
)
568
end
569
return
new
and
"
filename
"
or
suffix
570
end
571 572
function
otfsvg
.
topdf
(
svgshapes
,
tfmdata
)
573
local
pdfshapes
=
{
}
574
local
inkscape
=
runner
(
)
575
if
inkscape
then
576
-- local indices = fonts.getindices(tfmdata)
577
local
descriptions
=
tfmdata
.
descriptions
578
local
nofshapes
=
#
svgshapes
579
local
f_svgfile
=
formatters
[
"
temp-otf-svg-shape-%i.svg
"
]
580
local
f_pdffile
=
formatters
[
"
temp-otf-svg-shape-%i.pdf
"
]
581
local
f_convert
=
formatters
[
"
%s --export-%s=%s\n
"
]
582
local
filterglyph
=
otfsvg
.
filterglyph
583
local
nofdone
=
0
584
local
processed
=
{
}
585
report_svg
(
"
processing %i svg containers
"
,
nofshapes
)
586
statistics
.
starttiming
(
)
587
for
i
=
1
,
nofshapes
do
588
local
entry
=
svgshapes
[
i
]
589
for
index
=
entry
.
first
,
entry
.
last
do
590
local
data
=
filterglyph
(
entry
,
index
)
591
if
data
and
data
~
=
"
"
then
592
local
svgfile
=
f_svgfile
(
index
)
593
local
pdffile
=
f_pdffile
(
index
)
594
savedata
(
svgfile
,
data
)
595
inkscape
:
write
(
f_convert
(
svgfile
,
inkscapeformat
(
"
pdf
"
)
,
pdffile
)
)
596
processed
[
index
]
=
true
597
nofdone
=
nofdone
+
1
598
if
nofdone
%
25
=
=
0
then
599
report_svg
(
"
%i shapes submitted
"
,
nofdone
)
600
end
601
end
602
end
603
end
604
if
nofdone
%
25
~
=
0
then
605
report_svg
(
"
%i shapes submitted
"
,
nofdone
)
606
end
607
report_svg
(
"
processing can be going on for a while
"
)
608
inkscape
:
write
(
"
quit\n
"
)
609
inkscape
:
close
(
)
610
report_svg
(
"
processing %i pdf results
"
,
nofshapes
)
611
for
index
in
next
,
processed
do
612
local
svgfile
=
f_svgfile
(
index
)
613
local
pdffile
=
f_pdffile
(
index
)
614
-- local fntdata = descriptions[indices[index]]
615
-- local bounds = fntdata and fntdata.boundingbox
616
local
pdfdata
=
loaddata
(
pdffile
)
617
if
pdfdata
and
pdfdata
~
=
"
"
then
618
pdfshapes
[
index
]
=
{
619
data
=
pdfdata
,
620
-- x = bounds and bounds[1] or 0,
621
-- y = bounds and bounds[2] or 0,
622
}
623
end
624
remove
(
svgfile
)
625
remove
(
pdffile
)
626
end
627
local
characters
=
tfmdata
.
characters
628
for
k
,
v
in
next
,
characters
do
629
local
d
=
descriptions
[
k
]
630
local
i
=
d
.
index
631
if
i
then
632
local
p
=
pdfshapes
[
i
]
633
if
p
then
634
local
w
=
d
.
width
635
local
l
=
d
.
boundingbox
[
1
]
636
local
r
=
d
.
boundingbox
[
3
]
637
p
.
scale
=
(
r
-
l
)
/
w
638
p
.
x
=
l
639
end
640
end
641
end
642
if
not
next
(
pdfshapes
)
then
643
report_svg
(
"
there are no converted shapes, fix your setup
"
)
644
end
645
statistics
.
stoptiming
(
)
646
if
statistics
.
elapsedseconds
then
647
report_svg
(
"
svg conversion time %s
"
,
statistics
.
elapsedseconds
(
)
or
"
-
"
)
648
end
649
end
650
return
pdfshapes
651
end
652 653
initializesvg
=
function
(
tfmdata
,
kind
,
value
)
-- hm, always value
654
if
value
and
otf
.
svgenabled
then
655
local
svg
=
tfmdata
.
properties
.
svg
656
local
hash
=
svg
and
svg
.
hash
657
local
timestamp
=
svg
and
svg
.
timestamp
658
if
not
hash
then
659
return
660
end
661
local
pdffile
=
containers
.
read
(
otf
.
pdfcache
,
hash
)
662
local
pdfshapes
=
pdffile
and
pdffile
.
pdfshapes
663
if
not
pdfshapes
or
pdffile
.
timestamp
~
=
timestamp
or
not
next
(
pdfshapes
)
then
664
-- the next test tries to catch errors in generic usage but of course can result
665
-- in running again and again
666
local
svgfile
=
containers
.
read
(
otf
.
svgcache
,
hash
)
667
local
svgshapes
=
svgfile
and
svgfile
.
svgshapes
668
pdfshapes
=
svgshapes
and
otfsvg
.
topdf
(
svgshapes
,
tfmdata
,
otf
.
pdfcache
.
writable
,
hash
)
or
{
}
669
containers
.
write
(
otf
.
pdfcache
,
hash
,
{
670
pdfshapes
=
pdfshapes
,
671
timestamp
=
timestamp
,
672
}
)
673
end
674
pdftovirtual
(
tfmdata
,
pdfshapes
,
"
svg
"
)
675
return
true
676
end
677
end
678 679
otfregister
{
680
name
=
"
svg
"
,
681
description
=
"
svg glyphs
"
,
682
manipulators
=
{
683
base
=
initializesvg
,
684
node
=
initializesvg
,
685
}
686
}
687 688
end
689 690
-- This can be done differently e.g. with ffi and gm and we can share code anway. Using
691
-- batchmode in gm is not faster and as it accumulates we would need to flush all
692
-- individual shapes. But ... in context lmtx (and maybe the backport) we will use
693
-- a different and more efficient method anyway. I'm still wondering if I should
694
-- keep color code in generic. Maybe it should be optional.
695 696
local
initializepng
do
697 698
local
otfpng
=
otf
.
png
or
{
}
699
otf
.
png
=
otfpng
700
otf
.
pngenabled
=
true
701 702
local
report_png
=
logs
.
reporter
(
"
fonts
"
,
"
png conversion
"
)
703 704
local
loaddata
=
io
.
loaddata
705
local
savedata
=
io
.
savedata
706
local
remove
=
os
.
remove
707 708
local
runner
=
sandbox
and
sandbox
.
registerrunner
{
709
name
=
"
otfpng
"
,
710
program
=
"
gm
"
,
711
template
=
"
convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log
"
,
712
-- reporter = report_png,
713
}
714 715
if
not
runner
then
716
--
717
-- poor mans variant for generic:
718
--
719
runner
=
function
(
)
720
return
os
.
execute
(
"
gm convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log
"
)
721
end
722
end
723 724
-- Alternatively we can create a single pdf file with -adjoin and then pick up pages from
725
-- that file but creating thousands of small files is no fun either.
726 727
local
files
=
utilities
.
files
728
local
openfile
=
files
.
open
729
local
closefile
=
files
.
close
730
local
setposition
=
files
.
setposition
731
local
readstring
=
files
.
readstring
732 733
function
otfpng
.
topdf
(
pngshapes
,
filename
)
734
if
pngshapes
and
filename
then
735
local
pdfshapes
=
{
}
736
local
pngfile
=
"
temp-otf-png-shape.png
"
737
local
pdffile
=
"
temp-otf-png-shape.pdf
"
738
local
nofdone
=
0
739
local
indices
=
sortedkeys
(
pngshapes
)
-- can be sparse
740
local
nofindices
=
#
indices
741
report_png
(
"
processing %i png containers
"
,
nofindices
)
742
statistics
.
starttiming
(
)
743
local
filehandle
=
openfile
(
filename
)
744
for
i
=
1
,
nofindices
do
745
local
index
=
indices
[
i
]
746
local
entry
=
pngshapes
[
index
]
747
-- local data = entry.data -- or placeholder
748
local
offset
=
entry
.
o
749
local
size
=
entry
.
s
750
local
x
=
entry
.
x
751
local
y
=
entry
.
y
752
local
data
=
nil
753
if
offset
and
size
then
754
setposition
(
filehandle
,
offset
)
755
data
=
readstring
(
filehandle
,
size
)
756
savedata
(
pngfile
,
data
)
757
runner
(
)
758
data
=
loaddata
(
pdffile
)
759
end
760
pdfshapes
[
index
]
=
{
761
-- x = x ~= 0 and x or nil,
762
-- y = y ~= 0 and y or nil,
763
data
=
data
,
764
}
765
nofdone
=
nofdone
+
1
766
if
nofdone
%
100
=
=
0
then
767
report_png
(
"
%i shapes processed
"
,
nofdone
)
768
end
769
end
770
closefile
(
filehandle
)
771
report_png
(
"
processing %i pdf results
"
,
nofindices
)
772
remove
(
pngfile
)
773
remove
(
pdffile
)
774
statistics
.
stoptiming
(
)
775
if
statistics
.
elapsedseconds
then
776
report_png
(
"
png conversion time %s
"
,
statistics
.
elapsedseconds
(
)
or
"
-
"
)
777
end
778
return
pdfshapes
779
end
780
end
781 782
initializepng
=
function
(
tfmdata
,
kind
,
value
)
-- hm, always value
783
if
value
and
otf
.
pngenabled
then
784
local
png
=
tfmdata
.
properties
.
png
785
local
hash
=
png
and
png
.
hash
786
local
timestamp
=
png
and
png
.
timestamp
787
if
not
hash
then
788
return
789
end
790
local
pdffile
=
containers
.
read
(
otf
.
pdfcache
,
hash
)
791
local
pdfshapes
=
pdffile
and
pdffile
.
pdfshapes
792
if
not
pdfshapes
or
pdffile
.
timestamp
~
=
timestamp
then
793
local
pngfile
=
containers
.
read
(
otf
.
pngcache
,
hash
)
794
local
filename
=
tfmdata
.
resources
.
filename
795
local
pngshapes
=
pngfile
and
pngfile
.
pngshapes
796
pdfshapes
=
pngshapes
and
otfpng
.
topdf
(
pngshapes
,
filename
)
or
{
}
797
containers
.
write
(
otf
.
pdfcache
,
hash
,
{
798
pdfshapes
=
pdfshapes
,
799
timestamp
=
timestamp
,
800
}
)
801
end
802
--
803
pdftovirtual
(
tfmdata
,
pdfshapes
,
"
png
"
)
804
return
true
805
end
806
end
807 808
otfregister
{
809
name
=
"
sbix
"
,
810
description
=
"
sbix glyphs
"
,
811
manipulators
=
{
812
base
=
initializepng
,
813
node
=
initializepng
,
814
}
815
}
816 817
otfregister
{
818
name
=
"
cblc
"
,
819
description
=
"
cblc glyphs
"
,
820
manipulators
=
{
821
base
=
initializepng
,
822
node
=
initializepng
,
823
}
824
}
825 826
end
827 828
do
829 830
local
function
initializecolor
(
tfmdata
,
kind
,
value
)
831
if
value
=
=
"
auto
"
then
832
return
833
initializeoverlay
(
tfmdata
,
kind
,
value
)
or
834
initializesvg
(
tfmdata
,
kind
,
value
)
or
835
initializepng
(
tfmdata
,
kind
,
value
)
836
elseif
value
=
=
"
overlay
"
then
837
return
initializeoverlay
(
tfmdata
,
kind
,
value
)
838
elseif
value
=
=
"
svg
"
then
839
return
initializesvg
(
tfmdata
,
kind
,
value
)
840
elseif
value
=
=
"
png
"
or
value
=
=
"
bitmap
"
then
841
return
initializepng
(
tfmdata
,
kind
,
value
)
842
else
843
-- forget about it
844
end
845
end
846 847
otfregister
{
848
name
=
"
color
"
,
849
description
=
"
color glyphs
"
,
850
manipulators
=
{
851
base
=
initializecolor
,
852
node
=
initializecolor
,
853
}
854
}
855 856
end
857 858
-- Old stuff:
859 860
do
861 862
local
startactualtext
=
nil
863
local
stopactualtext
=
nil
864 865
function
otf
.
getactualtext
(
s
)
866
if
not
startactualtext
then
867
startactualtext
=
backends
.
codeinjections
.
startunicodetoactualtextdirect
868
stopactualtext
=
backends
.
codeinjections
.
stopunicodetoactualtextdirect
869
end
870
return
startactualtext
(
s
)
,
stopactualtext
(
)
871
end
872 873
end
874 875