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