lpdf-fnt.lmt /size: 6335 b    last modification: 2021-10-28 13:51
1if not modules then modules = { } end modules ['lpdf-fnt'] = {
2    version   = 1.001,
3    comment   = "companion to lpdf-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-- This is experimental code.
10
11local match, gmatch = string.match, string.gmatch
12local tonumber, rawget = tonumber, rawget
13
14local pdfe             = lpdf.epdf
15local pdfreference     = lpdf.reference
16local pdfreserveobject = lpdf.reserveobject
17
18local tobemerged   = { }
19local trace_merge  = false  trackers.register("graphics.fonts",function(v) trace_merge = v end)
20local report_merge = logs.reporter("graphics","fonts")
21
22local function register(usedname,cleanname)
23    local cleanname = cleanname or fonts.names.cleanname(usedname)
24    local fontid    = fonts.definers.internal { name = cleanname }
25    if fontid then
26        local objref = pdfreserveobject()
27        if trace_merge then
28            report_merge("registering %a with name %a, id %a and object %a",usedname,cleanname,fontid,objref)
29        end
30        return {
31            id        = fontid,
32            reference = objref,
33            indices   = { },
34            cleanname = cleanname,
35        }
36    end
37    return false
38end
39
40function lpdf.registerfont(usedname,cleanname)
41    local v = register(usedname,cleanname)
42    tobemerged[usedname] = v
43    return v
44end
45
46table.setmetatableindex(tobemerged,function(t,k)
47    return lpdf.registerfont(k)
48end)
49
50local function finalizefont(v)
51    local indextoslot = fonts.helpers.indextoslot
52    if v then
53        local id = v.id
54        local n  = 0
55        for i in next, v.indices do
56            local u = indextoslot(id,i)
57            n = n + 1
58        end
59        v.n = n
60    end
61end
62
63statistics.register("merged fonts", function()
64    if next(tobemerged) then
65        local t = { }
66        for k, v in table.sortedhash(tobemerged) do
67            t[#t+1] = string.formatters["%s (+%i)"](k,v.n)
68        end
69        return table.concat(t," ")
70    end
71end)
72
73function lpdf.finalizefonts()
74    for k, v in next, tobemerged do
75        finalizefont(v)
76    end
77end
78
79callback.register("font_descriptor_objnum_provider",function(name)
80    local m = rawget(tobemerged,name)
81    if m then
82     -- finalizefont(m)
83        local r = m.reference or 0
84        if trace_merge then
85            report_merge("using object %a for font descriptor of %a",r,name)
86        end
87        return r
88    end
89    return 0
90end)
91
92local function getunicodes1(str,indices)
93    for s in gmatch(str,"beginbfrange%s*(.-)%s*endbfrange") do
94        for first, last, offset in gmatch(s,"<([^>]+)>%s+<([^>]+)>%s+<([^>]+)>") do
95            for i=tonumber(first,16),tonumber(last,16) do
96                indices[i] = true
97            end
98        end
99    end
100    for s in gmatch(str,"beginbfchar%s*(.-)%s*endbfchar") do
101        for old, new in gmatch(s,"<([^>]+)>%s+<([^>]+)>") do
102            indices[tonumber(old,16)] = true
103        end
104    end
105end
106
107local function getunicodes2(widths,indices)
108    for i=1,#widths,2 do
109        local start =  widths[i]
110        local count = #widths[i+1]
111        if start and count then
112            for i=start,start+count-1 do
113                indices[i] = true
114            end
115        end
116    end
117end
118
119local function checkedfonts(pdfdoc,xref,copied,page)
120    local list = page.Resources.Font
121    local done = { }
122    for k, somefont in pdfe.expanded(list) do
123        if somefont.Subtype == "Type0" and somefont.Encoding == "Identity-H" then
124            local descendants = somefont.DescendantFonts
125            if descendants then
126                for i=1,#descendants do
127                    local d = descendants[i]
128                    if d then
129                        local subtype = d.Subtype
130                        if subtype == "CIDFontType0" or subtype == "CIDFontType2" then
131                            local basefont = somefont.BaseFont
132                            if basefont then
133                                local fontname = match(basefont,"^[A-Z]+%+(.+)$")
134                                local fontdata = tobemerged[fontname]
135                                if fontdata then
136                                    local descriptor = d.FontDescriptor
137                                    if descriptor then
138                                        local okay   = false
139                                        local widths = d.W
140                                        if widths then
141                                            getunicodes2(widths,fontdata.indices)
142                                            okay = true
143                                        else
144                                            local tounicode = somefont.ToUnicode
145                                            if tounicode then
146                                                getunicodes1(tounicode(),fontdata.indices)
147                                                okay = true
148                                            end
149                                        end
150                                        if okay then
151                                            local r = xref[descriptor]
152                                            done[r] = fontdata.reference
153                                        end
154                                    end
155                                end
156                            end
157                        end
158                    end
159                end
160            end
161        end
162    end
163    return next(done) and done
164end
165
166function lpdf.epdf.plugin(pdfdoc,xref,copied,page) -- needs checking
167    local done = checkedfonts(pdfdoc,xref,copied,page)
168    if done then
169        return {
170            FontDescriptor = function(xref,copied,object,key,value,copyobject)
171                local r = value[3]
172                local d = done[r]
173                if d then
174                    return pdfreference(d)
175                else
176                    return copyobject(xref,copied,object,key,value)
177                end
178            end
179        }
180    end
181end
182
183lpdf.registerdocumentfinalizer(lpdf.finalizefonts)
184
185-- already defined in font-ocl but the context variatn will go here
186--
187-- function lpdf.vfimage(wd,ht,dp,data,name)
188--     return { "image", { filename = name, width = wd, height = ht, depth = dp } }
189-- end
190