Fix bugs and add node fonts
This commit is contained in:
parent
2eefb9a14b
commit
1195e0f201
@ -5,6 +5,7 @@ local writer = require'luametalatex-nodewriter'
|
|||||||
local newpdf = require'luametalatex-pdf'
|
local newpdf = require'luametalatex-pdf'
|
||||||
local nametree = require'luametalatex-pdf-nametree'
|
local nametree = require'luametalatex-pdf-nametree'
|
||||||
local build_fontdir = require'luametalatex-pdf-font'
|
local build_fontdir = require'luametalatex-pdf-font'
|
||||||
|
local prepare_node_font = require'luametalatex-pdf-font-node'.prepare
|
||||||
local fontmap = require'luametalatex-pdf-font-map'
|
local fontmap = require'luametalatex-pdf-font-map'
|
||||||
|
|
||||||
local utils = require'luametalatex-pdf-utils'
|
local utils = require'luametalatex-pdf-utils'
|
||||||
@ -13,7 +14,17 @@ local to_bp = utils.to_bp
|
|||||||
|
|
||||||
local pdfname, pfile
|
local pdfname, pfile
|
||||||
local fontdirs = setmetatable({}, {__index=function(t, k)t[k] = pfile:getobj() return t[k] end})
|
local fontdirs = setmetatable({}, {__index=function(t, k)t[k] = pfile:getobj() return t[k] end})
|
||||||
local usedglyphs = {}
|
local nodefont_meta = {}
|
||||||
|
local usedglyphs = setmetatable({}, {__index=function(t, fid)
|
||||||
|
local v
|
||||||
|
if font.fonts[fid].format == 'type3node' then
|
||||||
|
v = setmetatable({generation = 0, next_generation = 0}, nodefont_meta)
|
||||||
|
else
|
||||||
|
v = {}
|
||||||
|
end
|
||||||
|
t[fid] = v
|
||||||
|
return v
|
||||||
|
end})
|
||||||
local dests = {}
|
local dests = {}
|
||||||
local cur_page
|
local cur_page
|
||||||
local declare_whatsit = require'luametalatex-whatsits'.new
|
local declare_whatsit = require'luametalatex-whatsits'.new
|
||||||
@ -69,7 +80,7 @@ token.luacmd("shipout", function()
|
|||||||
local out, resources, annots = writer(pfile, list, fontdirs, usedglyphs, colorstacks)
|
local out, resources, annots = writer(pfile, list, fontdirs, usedglyphs, colorstacks)
|
||||||
cur_page = nil
|
cur_page = nil
|
||||||
local content = pfile:stream(nil, '', out)
|
local content = pfile:stream(nil, '', out)
|
||||||
pfile:indirect(page, string.format([[<</Type/Page/Parent %i 0 R/Contents %i 0 R/MediaBox[0 %i %i %i]/Resources<<%s%s>>%s%s>>]], parent, content, -math.ceil(to_bp(list.depth)), math.ceil(to_bp(list.width)), math.ceil(to_bp(list.height)), resources, pdfvariable.pageresources, annots, pdfvariable.pageattr))
|
pfile:indirect(page, string.format([[<</Type/Page/Parent %i 0 R/Contents %i 0 R/MediaBox[0 %i %i %i]/Resources%s%s%s>>]], parent, content, -math.ceil(to_bp(list.depth)), math.ceil(to_bp(list.width)), math.ceil(to_bp(list.height)), resources(pdfvariable.pageresources), annots, pdfvariable.pageattr))
|
||||||
node.flush_list(list)
|
node.flush_list(list)
|
||||||
token.put_next(reset_deadcycles)
|
token.put_next(reset_deadcycles)
|
||||||
token.scan_token()
|
token.scan_token()
|
||||||
@ -104,14 +115,36 @@ local pdf_escape = require'luametalatex-pdf-escape'
|
|||||||
local pdf_bytestring = pdf_escape.escape_bytes
|
local pdf_bytestring = pdf_escape.escape_bytes
|
||||||
local pdf_text = pdf_escape.escape_text
|
local pdf_text = pdf_escape.escape_text
|
||||||
|
|
||||||
|
local function nodefont_newindex(t, k, v)
|
||||||
|
t.generation = t.next_generation
|
||||||
|
return rawset(t, k, v)
|
||||||
|
end
|
||||||
|
|
||||||
callback.register("stop_run", function()
|
callback.register("stop_run", function()
|
||||||
if not pfile then
|
if not pfile then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
do
|
||||||
|
nodefont_meta.__newindex = nodefont_newindex -- Start recording generations
|
||||||
|
local need_new_run = true
|
||||||
|
while need_new_run do
|
||||||
|
need_new_run = nil
|
||||||
|
for fid, glyphs in pairs(usedglyphs) do
|
||||||
|
local next_gen = glyphs.next_generation
|
||||||
|
if next_gen and next_gen == glyphs.generation then
|
||||||
|
glyphs.next_generation = next_gen+1
|
||||||
|
need_new_run = true
|
||||||
|
local f = font.getfont(fid) or font.fonts[fid]
|
||||||
|
prepare_node_font(f, glyphs, pfile, fontdirs, usedglyphs) -- Might become fid, glyphs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
for fid, id in pairs(fontdirs) do
|
for fid, id in pairs(fontdirs) do
|
||||||
local f = font.getfont(fid) or font.fonts[fid]
|
local f = font.getfont(fid) or font.fonts[fid]
|
||||||
local psname = f.psname or f.fullname
|
|
||||||
local sorted = {}
|
local sorted = {}
|
||||||
|
local used = usedglyphs[fid]
|
||||||
|
used.generation, used.next_generation = nil, nil
|
||||||
for k,v in pairs(usedglyphs[fid]) do
|
for k,v in pairs(usedglyphs[fid]) do
|
||||||
sorted[#sorted+1] = v
|
sorted[#sorted+1] = v
|
||||||
end
|
end
|
||||||
@ -438,8 +471,8 @@ local refobj_whatsit = declare_whatsit('pdf_refobj', function(prop, p, n, x, y)
|
|||||||
end)
|
end)
|
||||||
local literal_whatsit = declare_whatsit('pdf_literal', function(prop, p, n, x, y)
|
local literal_whatsit = declare_whatsit('pdf_literal', function(prop, p, n, x, y)
|
||||||
if not prop then
|
if not prop then
|
||||||
tex.error('Invalid pdf_literal whatsit', {"A pdf_literal whatsit did not contain a literal to be inserted. \z
|
tex.error('Invalid pdf_literal whatsit', "A pdf_literal whatsit did not contain a literal to be inserted. \z
|
||||||
Maybe your code hasn't been adapted to LuaMetaLaTeX yet?"})
|
Maybe your code hasn't been adapted to LuaMetaLaTeX yet?")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
pdf.write(prop.mode, prop.data, x, y, p)
|
pdf.write(prop.mode, prop.data, x, y, p)
|
||||||
|
@ -55,7 +55,7 @@ function font.define(f)
|
|||||||
local format = f.format or "unknown"
|
local format = f.format or "unknown"
|
||||||
local encodingbytes = f.encodingbytes or (f.format:sub(5) == "type" and 2 or 1)
|
local encodingbytes = f.encodingbytes or (f.format:sub(5) == "type" and 2 or 1)
|
||||||
f.encodingbytes = encodingbytes
|
f.encodingbytes = encodingbytes
|
||||||
if encodingbytes == 1 and f.type ~= 'virtual' then
|
if encodingbytes == 1 and f.type ~= 'virtual' and f.format ~= 'type3node' then
|
||||||
-- map file lookup
|
-- map file lookup
|
||||||
local entry = fontmap[f.name]
|
local entry = fontmap[f.name]
|
||||||
if entry then
|
if entry then
|
||||||
@ -145,7 +145,7 @@ function font.addcharacters(fid, newdir)
|
|||||||
local existing = fontdir[cp]
|
local existing = fontdir[cp]
|
||||||
if existing ~= glyph then
|
if existing ~= glyph then
|
||||||
if existing then
|
if existing then
|
||||||
texio.write_nl'Overwriting existing character. Here be dragons'
|
-- texio.write_nl'Overwriting existing character. Here be dragons'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if glyph.commands then
|
if glyph.commands then
|
||||||
|
@ -35,6 +35,7 @@ local utils = require'luametalatex-pdf-utils'
|
|||||||
local strip_floats = utils.strip_floats
|
local strip_floats = utils.strip_floats
|
||||||
local to_bp = utils.to_bp
|
local to_bp = utils.to_bp
|
||||||
|
|
||||||
|
local make_resources = require'luametalatex-pdf-resources'
|
||||||
local pdf_font_map = require'luametalatex-pdf-font-deduplicate'
|
local pdf_font_map = require'luametalatex-pdf-font-deduplicate'
|
||||||
local get_whatsit_handler = require'luametalatex-whatsits'.handler
|
local get_whatsit_handler = require'luametalatex-whatsits'.handler
|
||||||
|
|
||||||
@ -382,6 +383,8 @@ local function do_commands(p, c, f, fid, x, y, outer, ...)
|
|||||||
for _, cmd in ipairs(c.commands) do
|
for _, cmd in ipairs(c.commands) do
|
||||||
if cmd[1] == "node" then
|
if cmd[1] == "node" then
|
||||||
local cmd = cmd[2]
|
local cmd = cmd[2]
|
||||||
|
assert(node.type(cmd))
|
||||||
|
cmd = todirect(cmd)
|
||||||
nodehandler[getid(cmd)](p, cmd, x, y, nil, ...)
|
nodehandler[getid(cmd)](p, cmd, x, y, nil, ...)
|
||||||
x = x + getwidth(cmd)
|
x = x + getwidth(cmd)
|
||||||
elseif cmd[1] == "font" then
|
elseif cmd[1] == "font" then
|
||||||
@ -397,17 +400,17 @@ local function do_commands(p, c, f, fid, x, y, outer, ...)
|
|||||||
current_font = assert(fonts[cmd[2]], "invalid font requested")
|
current_font = assert(fonts[cmd[2]], "invalid font requested")
|
||||||
local n = direct.new'glyph'
|
local n = direct.new'glyph'
|
||||||
setsubtype(n, 256)
|
setsubtype(n, 256)
|
||||||
setfont(n, current_font.id, cmd[2])
|
setfont(n, current_font.id, cmd[3])
|
||||||
nodehandler.glyph(p, n, x, y, outer, ...)
|
nodehandler.glyph(p, n, x, y, outer, ...)
|
||||||
direct.free(n)
|
|
||||||
x = x + getwidth(n)
|
x = x + getwidth(n)
|
||||||
|
direct.free(n)
|
||||||
elseif cmd[1] == "rule" then
|
elseif cmd[1] == "rule" then
|
||||||
local n = direct.new'rule'
|
local n = direct.new'rule'
|
||||||
setheight(n, cmd[2])
|
setheight(n, cmd[2])
|
||||||
setwidth(n, cmd[3])
|
setwidth(n, cmd[3])
|
||||||
nodehandler.rule(p, n, x, y, outer, ...)
|
nodehandler.rule(p, n, x, y, outer, ...)
|
||||||
direct.free(n)
|
|
||||||
x = x + getwidth(n)
|
x = x + getwidth(n)
|
||||||
|
direct.free(n)
|
||||||
elseif cmd[1] == "left" then
|
elseif cmd[1] == "left" then
|
||||||
x = x + cmd[2]
|
x = x + cmd[2]
|
||||||
elseif cmd[1] == "down" then
|
elseif cmd[1] == "down" then
|
||||||
@ -533,22 +536,9 @@ local ondemandmeta = {
|
|||||||
return t[k]
|
return t[k]
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
local function writeresources(p)
|
local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks, resources)
|
||||||
local resources = p.resources
|
|
||||||
local result = {}
|
|
||||||
for kind, t in pairs(resources) do if next(t) then
|
|
||||||
result[#result+1] = format("/%s<<", kind)
|
|
||||||
for name, value in pairs(t) do
|
|
||||||
result[#result+1] = format("/%s %i 0 R", name, value)
|
|
||||||
t[name] = nil
|
|
||||||
end
|
|
||||||
result[#result+1] = ">>"
|
|
||||||
end end
|
|
||||||
return concat(result)
|
|
||||||
end
|
|
||||||
local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks)
|
|
||||||
n = todirect(n)
|
n = todirect(n)
|
||||||
setmetatable(usedglyphs, ondemandmeta)
|
resources = resources or make_resources()
|
||||||
local p = {
|
local p = {
|
||||||
is_page = not not colorstacks,
|
is_page = not not colorstacks,
|
||||||
file = file,
|
file = file,
|
||||||
@ -560,7 +550,7 @@ local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks)
|
|||||||
vfont = {},
|
vfont = {},
|
||||||
matrix = {1, 0, 0, 1, 0, 0},
|
matrix = {1, 0, 0, 1, 0, 0},
|
||||||
pending_matrix = {},
|
pending_matrix = {},
|
||||||
resources = setmetatable({}, ondemandmeta),
|
resources = resources,
|
||||||
annots = {},
|
annots = {},
|
||||||
linkcontext = file.linkcontext,
|
linkcontext = file.linkcontext,
|
||||||
fontdirs = fontdirs,
|
fontdirs = fontdirs,
|
||||||
@ -580,7 +570,7 @@ local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks)
|
|||||||
nodehandler[getid(n)](p, n, 0, 0, n, nil, 0)
|
nodehandler[getid(n)](p, n, 0, 0, n, nil, 0)
|
||||||
-- nodehandler[getid(n)](p, n, 0, getdepth(n), n)
|
-- nodehandler[getid(n)](p, n, 0, getdepth(n), n)
|
||||||
topage(p)
|
topage(p)
|
||||||
return concat(p.strings, '\n'), writeresources(p), (p.annots[1] and string.format("/Annots[%s]", table.concat(p.annots, ' ')) or "")
|
return concat(p.strings, '\n'), resources, (p.annots[1] and string.format("/Annots[%s]", table.concat(p.annots, ' ')) or "")
|
||||||
end
|
end
|
||||||
require'luametalatex-pdf-savedbox':init_nodewriter(nodewriter)
|
require'luametalatex-pdf-savedbox':init_nodewriter(nodewriter)
|
||||||
return nodewriter
|
return nodewriter
|
||||||
|
@ -17,7 +17,7 @@ local function build_sharekey(fontdir)
|
|||||||
local encodingbytes = assert(fontdir.encodingbytes)
|
local encodingbytes = assert(fontdir.encodingbytes)
|
||||||
local key = string.format("%i:%s:", fontdir.encodingbytes, fontdir.format)
|
local key = string.format("%i:%s:", fontdir.encodingbytes, fontdir.format)
|
||||||
if encodingbytes == 1 then
|
if encodingbytes == 1 then
|
||||||
if fontdir.format == "type3" then
|
if fontdir.format:sub(1,5) == "type3" then
|
||||||
return string.format("%s%i:%s", key, fontdir.size, fontdir.name)
|
return string.format("%s%i:%s", key, fontdir.size, fontdir.name)
|
||||||
end
|
end
|
||||||
key = string.format("%s%s:", key, fontdir.encoding or '')
|
key = string.format("%s%s:", key, fontdir.encoding or '')
|
||||||
|
@ -250,27 +250,34 @@ local function buildfont0(pdf, fontdir, usedcids)
|
|||||||
cidfont)
|
cidfont)
|
||||||
end
|
end
|
||||||
local buildfontpk = require'luametalatex-pdf-font-pk'
|
local buildfontpk = require'luametalatex-pdf-font-pk'
|
||||||
|
local buildfontnode = require'luametalatex-pdf-font-node'.buildfont
|
||||||
local function buildfont3(pdf, fontdir, usedcids)
|
local function buildfont3(pdf, fontdir, usedcids)
|
||||||
|
local buildfont = fontdir.format == 'type3' and buildfontpk
|
||||||
|
or fontdir.format == 'type3node' and buildfontnode
|
||||||
|
or error[[Unsupported Type3 based font format]]
|
||||||
usedcids = usedcids or allcids(fontdir)
|
usedcids = usedcids or allcids(fontdir)
|
||||||
table.sort(usedcids, function(a,b) return a[1]<b[1] end)
|
table.sort(usedcids, function(a,b) return a[1]<b[1] end)
|
||||||
local enc = cidmap1byte(pdf)
|
local enc = cidmap1byte(pdf)
|
||||||
local bbox, matrix, widths, charprocs = buildfontpk(pdf, fontdir, usedcids) -- TOOD
|
local bbox, matrix, widths, charprocs = buildfont(pdf, fontdir, usedcids)
|
||||||
local touni = pdf:stream(nil, "", tounicode[1](fontdir, usedcids)) -- Done late to allow for defaults set from the font file
|
local touni = pdf:stream(nil, "", tounicode[1](fontdir, usedcids)) -- Done late to allow for defaults set from the font file
|
||||||
return strip_floats(string.format(
|
local matrices = strip_floats(string.format(
|
||||||
"<</Type/Font/Subtype/Type3/FontBBox[%f %f %f %f]/FontMatrix[%f %f %f %f %f %f]/CharProcs%s/Encoding%s/FirstChar %i/LastChar %i/Widths %i 0 R/ToUnicode %i 0 R>>",
|
"/FontBBox[%f %f %f %f]/FontMatrix[%f %f %f %f %f %f]",
|
||||||
-- "<</Type/Font/Subtype/Type3/FontBBox[%f %f %f %f]/FontMatrix[%f %f %f %f %f %f]/CharProcs%s/Encoding%s/FirstChar %i/LastChar %i/Widths[%s]/ToUnicode %i 0 R/FontDescriptor %i 0 R>>",
|
|
||||||
bbox[1], bbox[2], bbox[3], bbox[4],
|
bbox[1], bbox[2], bbox[3], bbox[4],
|
||||||
matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6],
|
matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]))
|
||||||
|
return string.format(
|
||||||
|
"<</Type/Font/Subtype/Type3%s/CharProcs%s/Encoding%s/FirstChar %i/LastChar %i/Widths %i 0 R/ToUnicode %i 0 R>>",
|
||||||
|
-- "<</Type/Font/Subtype/Type3/CharProcs%s/Encoding%s/FirstChar %i/LastChar %i/Widths %i 0 R/ToUnicode %i 0 R/FontDescriptor %i 0 R>>",
|
||||||
|
matrices,
|
||||||
charprocs,
|
charprocs,
|
||||||
encodingtype3(pdf),
|
encodingtype3(pdf),
|
||||||
usedcids[1][1],
|
usedcids[1][1],
|
||||||
usedcids[#usedcids][1],
|
usedcids[#usedcids][1],
|
||||||
widths,
|
widths,
|
||||||
touni
|
touni
|
||||||
)) -- , descriptor) -- TODO
|
) -- , descriptor) -- TODO
|
||||||
end
|
end
|
||||||
return function(pdf, fontdir, usedcids)
|
return function(pdf, fontdir, usedcids)
|
||||||
if fontdir.format == "type3" then
|
if fontdir.format:sub(1,5) == "type3" then
|
||||||
return buildfont3(pdf, fontdir, usedcids)
|
return buildfont3(pdf, fontdir, usedcids)
|
||||||
else
|
else
|
||||||
return buildfont0(pdf, fontdir, usedcids)
|
return buildfont0(pdf, fontdir, usedcids)
|
||||||
|
@ -19,7 +19,7 @@ local function shipout(pfile, xform, fontdirs, usedglyphs)
|
|||||||
texio.write_nl('term and log', 'WARNING (savedboxresource shipout): Ignoring unsupported PDF variables xformattr and xformresources. Specify resources and attributes for specific XForms instead.')
|
texio.write_nl('term and log', 'WARNING (savedboxresource shipout): Ignoring unsupported PDF variables xformattr and xformresources. Specify resources and attributes for specific XForms instead.')
|
||||||
end
|
end
|
||||||
local bbox = strip_floats(string.format('/BBox[%f %f %f %f]', -to_bp(margin), -to_bp(list.depth+margin), to_bp(list.width+margin), to_bp(list.height+margin)))
|
local bbox = strip_floats(string.format('/BBox[%f %f %f %f]', -to_bp(margin), -to_bp(list.depth+margin), to_bp(list.width+margin), to_bp(list.height+margin)))
|
||||||
local dict = string.format('/Subtype/Form%s/Resources<<%s%s>>%s', bbox, resources, xform.resources or '', xform.attributes or '')
|
local dict = string.format('/Subtype/Form%s/Resources%s%s', bbox, resources(xform.resources), xform.attributes or '')
|
||||||
node.flush_list(list)
|
node.flush_list(list)
|
||||||
xform.list = nil
|
xform.list = nil
|
||||||
local objnum = pfile:stream(xform.objnum, dict, out)
|
local objnum = pfile:stream(xform.objnum, dict, out)
|
||||||
|
Loading…
Reference in New Issue
Block a user