diff --git a/luametalatex-lateinit.lua b/luametalatex-lateinit.lua index 2af1370..70c37bf 100644 --- a/luametalatex-lateinit.lua +++ b/luametalatex-lateinit.lua @@ -11,9 +11,6 @@ status.safer_option = 0 -- compat status.shell_escape = 0 -- compat -- This is currently a lie. -- require'module' -- ??? pdf = { - getfontname = function(id) -- No font sharing yet (TODO) - return id - end, variable = {}, } require'luametalatex-font-resolve' -- Replace font.define. Must be loaded before callbacks diff --git a/luametalatex-nodewriter.lua b/luametalatex-nodewriter.lua index 67d78fe..92cdffd 100644 --- a/luametalatex-nodewriter.lua +++ b/luametalatex-nodewriter.lua @@ -31,6 +31,7 @@ local rangedimensions = direct.rangedimensions local traverse_id = direct.traverse_id local getdata = direct.getdata +local pdf_font_map = require'luametalatex-pdf-font-deduplicate' local get_whatsit_handler = require'luametalatex-whatsits'.handler local dir_id = node.id'dir' @@ -95,10 +96,10 @@ local function totext(p, fid) local f = font.getfont(fid) or font.fonts[fid] if last ~= text then p.strings[#p.strings+1] = "BT" p.pos.lx, p.pos.ly, p.pos.x, p.pos.y, p.font.exfactor, p.font.extend, p.font.squeeze, p.font.slant = 0, 0, 0, 0, 0, 1, 1, 0 end - if not f.parent then f.parent = pdf.getfontname(fid) end - p.resources.Font[fontnames[f.parent]] = p.fontdirs[f.parent] - p.strings[#p.strings+1] = format("/F%i %f Tf 0 Tr", f.parent, sp2bp(f.size)) -- TODO: Setting the mode, width, etc. - p.font.usedglyphs = p.usedglyphs[f.parent] + local pdf_fid = pdf_font_map[fid] + p.resources.Font[fontnames[pdf_fid]] = p.fontdirs[pdf_fid] + p.strings[#p.strings+1] = format("/F%i %f Tf 0 Tr", pdf_fid, sp2bp(f.size)) -- TODO: Setting the mode, width, etc. + p.font.usedglyphs = p.usedglyphs[pdf_fid] p.font.fid = fid p.font.font = f diff --git a/luametalatex-pdf-font-cff.lua b/luametalatex-pdf-font-cff.lua index 980de5b..f6db785 100644 --- a/luametalatex-pdf-font-cff.lua +++ b/luametalatex-pdf-font-cff.lua @@ -580,7 +580,7 @@ end -- local buf = file:read'a' -- file:close() -- io.open(arg[3], 'w'):write(myfunc(buf, 1, 1, nil, {{3}, {200}, {1000}, {1329}, {1330}, {1331}})):close() -return function(filename, encoding) return function(fontdir, usedcids) +return function(filename, fontid, encoding) return function(fontdir, usedcids) local file = io.open(filename) local buf = file:read'a' local i = 1 @@ -589,12 +589,12 @@ return function(filename, encoding) return function(fontdir, usedcids) if magic == "ttcf" or magic == "OTTO" then -- assert(not encoding) -- nil or false encoding = encoding or false - local magic, tables = sfnt.parse(buf, 1) -- TODO: Interpret widths etc, they might differ from the CFF ones. + local magic, tables = sfnt.parse(buf, fontid) -- TODO: Interpret widths etc, they might differ from the CFF ones. assert(magic == "OTTO") -- Also CFF2 would be nice to have i = tables['CFF '][1] end - local content, bbox = myfunc(buf, i, 1, usedcids, encoding) + local content, bbox = myfunc(buf, i, fontid, usedcids, encoding) fontdir.bbox = bbox return content end end diff --git a/luametalatex-pdf-font-deduplicate.lua b/luametalatex-pdf-font-deduplicate.lua new file mode 100644 index 0000000..4a08d20 --- /dev/null +++ b/luametalatex-pdf-font-deduplicate.lua @@ -0,0 +1,44 @@ +require'luametalatex-font-resolve' -- Ensure that font.fonts exists + +local keymap = {} + +-- There are multiple criteria for sharing backend fonts: +-- * Obviously encodingbytes have to be the same. +-- * The filename better is the same too. +-- * Similarly the index must be the same. +-- * Specifically in the PK font case *without* fixed DPI, +-- The size must be the same too. +-- * For fontmap based fonts, compare the name field instead, +-- of the normal filename, especially to capture encoding differences. +-- An alternative might be to only take the encoding into account. +-- This is also required for other fonts which might not be backed by +-- traditional files +local function build_sharekey(fontdir) + local encodingbytes = assert(fontdir.encodingbytes) + local key = string.format("%i:%s:", fontdir.encodingbytes, fontdir.format) + if encodingbytes == 1 then + if fontdir.format == "type3" then + return string.format("%s%i:%s", key, fontdir.size, fontdir.name) + end + key = string.format("%s%s:", key, fontdir.encoding or '') + end + key = string.format("%s%i:%s", key, fontdir.subfont or 1, fontdir.filename) + return key +end + +local fonts = font.fonts +local fontmap = setmetatable({}, { + __index = function(t, fid) + local key = build_sharekey(assert(fonts[fid])) + local mapped = keymap[key] + local share_parent = mapped and t[mapped] or fid + t[fid] = share_parent + return share_parent + end, +}) + +function pdf.getfontname(fid) + return fontmap[fid] +end + +return fontmap diff --git a/luametalatex-pdf-font.lua b/luametalatex-pdf-font.lua index 331873e..70f5ed3 100644 --- a/luametalatex-pdf-font.lua +++ b/luametalatex-pdf-font.lua @@ -181,7 +181,7 @@ local function buildfont0cff(pdf, fontdir, usedcids) if fontdir.format == "type1" then cff = require'luametalatex-pdf-font-t1'(fontdir.filename, fontdir.encoding)(fontdir, usedcids) elseif fontdir.format == "opentype" then - cff = require'luametalatex-pdf-font-cff'(fontdir.filename, fontdir.encodingbytes == 1 and (fontdir.encoding or true))(fontdir, usedcids) + cff = require'luametalatex-pdf-font-cff'(fontdir.filename, 1, fontdir.encodingbytes == 1 and (fontdir.encoding or true))(fontdir, usedcids) else error[[Unsupported format]] end diff --git a/luametalatex-pdf-image-pdf.lua b/luametalatex-pdf-image-pdf.lua index dcf57ac..2de3d67 100644 --- a/luametalatex-pdf-image-pdf.lua +++ b/luametalatex-pdf-image-pdf.lua @@ -74,7 +74,7 @@ function pdf_functions.write(pfile, img) local file = open_pdfe(img) local page = pdfe.getpage(file, img.page) local bbox = img.bbox - local dict = string.format("/Subtype/Form/BBox[%f %f %f %f]/Resources %s", bbox[1], bbox[2], bbox[3], bbox[4], pdfe_deepcopy(file, img.filepath, pfile, pdfe.getfromdictionary(page, 'Resources'))) + local dict = string.format("/Subtype/Form/BBox[%f %f %f %f]/Resources %s", to_bp(bbox[1]), to_bp(bbox[2]), to_bp(bbox[3]), to_bp(bbox[4]), pdfe_deepcopy(file, img.filepath, pfile, pdfe.getfromdictionary(page, 'Resources'))) local content, raw = page.Contents -- Three cases: Contents is a stream, so copy the stream (Remember to copy filter if necessary) -- Contents is an array of streams, so append all the streams as a new stream