[use/save]boxresource, the Lua part
This commit is contained in:
parent
f7a76b69d8
commit
efedcba3e1
@ -47,11 +47,29 @@ token.luacmd("shipout", function()
|
||||
local out, resources, annots = writer(pfile, list, fontdirs, usedglyphs, colorstacks)
|
||||
cur_page = nil
|
||||
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>>]], parent, content, -math.ceil(list.depth/65781.76), math.ceil(list.width/65781.76), math.ceil(list.height/65781.76), resources, annots))
|
||||
pfile:indirect(page, string.format([[<</Type/Page/Parent %i 0 R/Contents %i 0 R/MediaBox[0 %i %i %i]/Resources<<%s>>%s>>]], parent, content, -math.ceil(list.depth/65781.76), math.ceil(list.width/65781.76), math.ceil(list.height/65781.76), resources, annots))
|
||||
node.flush_list(list)
|
||||
token.put_next(token.create'immediateassignment', token.create'global', token.create'deadcycles', token.create(0x30), token.create'relax')
|
||||
token.scan_token()
|
||||
end, 'force', 'protected')
|
||||
|
||||
local savedbox = require'luametalatex-pdf-savedbox'
|
||||
local savedbox_save = savedbox.save
|
||||
function tex.saveboxresource(n, attr, resources, immediate, type, margin, pfile)
|
||||
if not node.type(n) then
|
||||
n = tonumber(n)
|
||||
if not n then
|
||||
error[[Invalid argument to saveboxresource]]
|
||||
end
|
||||
token.put_next(token.create'box', token.new(n, token.command_id'char_given'))
|
||||
n = token.scan_list()
|
||||
end
|
||||
margin = margin or tex.sp'1bp' -- FIXME: default margin variable
|
||||
return savedbox_save(pfile or get_pfile(), n, attr, resources, immediate, type, margin, fontdirs, usedglyphs)
|
||||
end
|
||||
tex.useboxresource = savedbox.use
|
||||
-- TODO: savedbox TeX interface
|
||||
|
||||
local infodir = ""
|
||||
local namesdir = ""
|
||||
local catalogdir = ""
|
||||
@ -257,12 +275,16 @@ local function addlinkpoint(p, link, x, y, list, kind)
|
||||
end
|
||||
end
|
||||
local function linkcontext_set(linkcontext, p, x, y, list, level, kind)
|
||||
if not p.is_page then return end
|
||||
for _,l in ipairs(linkcontext) do if l.level == level then
|
||||
addlinkpoint(p, l, x, y, list, level, kind)
|
||||
end end
|
||||
end
|
||||
|
||||
function do_start_link(prop, p, n, x, y, outer, _, level)
|
||||
if not p.is_page then
|
||||
error[[No link allowed here]]
|
||||
end
|
||||
local links = p.linkcontext
|
||||
if not links then
|
||||
links = {set = linkcontext_set}
|
||||
@ -273,10 +295,14 @@ function do_start_link(prop, p, n, x, y, outer, _, level)
|
||||
addlinkpoint(p, link, x, y, outer, 'start')
|
||||
end
|
||||
function do_end_link(prop, p, n, x, y, outer, _, level)
|
||||
if not p.is_page then
|
||||
error[[No link allowed here]]
|
||||
end
|
||||
local links = p.linkcontext
|
||||
if not links then error"No link here to end" end
|
||||
local link = links[#links]
|
||||
links[#links] = nil
|
||||
if not links[1] then p.linkcontext = nil end
|
||||
if link.level ~= level then error"Wrong link level" end
|
||||
addlinkpoint(p, link, x, y, outer, 'final')
|
||||
end
|
||||
@ -367,9 +393,10 @@ local function do_colorstack(prop, p, n, x, y)
|
||||
local stack
|
||||
if p.is_page then
|
||||
stack = colorstack.page_stack
|
||||
elseif prop.last_form == resources then
|
||||
elseif colorstack.last_form == p.resources then
|
||||
stack = colorstack.form_stack
|
||||
else
|
||||
colorstack.last_form = p.resources
|
||||
stack = {prop.default}
|
||||
colorstack.form_stack = stack
|
||||
end
|
||||
|
@ -77,6 +77,7 @@ end
|
||||
local function sp2bp(sp)
|
||||
return sp/65781.76
|
||||
end
|
||||
local fontnames = setmetatable({}, {__index = function(t, k) local res = format("F%i", k) t[k] = res return res end})
|
||||
local topage
|
||||
local function totext(p, fid)
|
||||
local last = p.mode
|
||||
@ -91,8 +92,12 @@ local function totext(p, fid)
|
||||
if last == text and p.font.fid == fid then return end
|
||||
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
|
||||
p:fontprovider(f, fid)
|
||||
-- p.strings[#p.strings+1] = format("/F%i %f Tf 0 Tr", f.parent, sp2bp(f.size)) -- TODO: Setting the mode, expansion, etc.
|
||||
|
||||
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]
|
||||
|
||||
p.font.fid = fid
|
||||
p.font.font = f
|
||||
local need_tm = false
|
||||
@ -257,6 +262,7 @@ local user_rule = rulesubtypes.user
|
||||
local empty_rule = rulesubtypes.empty
|
||||
local outline_rule = rulesubtypes.outline
|
||||
local ship_img = require'luametalatex-pdf-image'.ship
|
||||
local ship_box = require'luametalatex-pdf-savedbox'.ship
|
||||
-- print(require'inspect'(node.subtypes('glue')))
|
||||
-- print(require'inspect'(node.fields('glue')))
|
||||
-- print(require'inspect'(node.fields('rule')))
|
||||
@ -266,10 +272,10 @@ function nodehandler.rule(p, n, x, y, outer)
|
||||
if getheight(n) == -1073741824 then setheight(n, getheight(outer)) end
|
||||
if getdepth(n) == -1073741824 then setdepth(n, getdepth(outer)) end
|
||||
local sub = getsubtype(n)
|
||||
if sub == box_rule then
|
||||
error[[We can't handle boxes yet]]
|
||||
elseif sub == image_rule then
|
||||
if getwidth(n) <= 0 or getdepth(n) + getheight(n) <= 0 then return end
|
||||
if sub == box_rule then
|
||||
ship_box(getdata(n), p, n, x, y)
|
||||
elseif sub == image_rule then
|
||||
ship_img(getdata(n), p, n, x, y)
|
||||
elseif sub == empty_rule then
|
||||
elseif sub == user_rule then
|
||||
@ -277,7 +283,6 @@ function nodehandler.rule(p, n, x, y, outer)
|
||||
elseif sub == outline_rule then
|
||||
error[[We can't handle outline rules yet]]
|
||||
else
|
||||
if getwidth(n) <= 0 or getdepth(n) + getheight(n) <= 0 then return end
|
||||
topage(p)
|
||||
p.strings[#p.strings+1] = gsub(format("%f %f %f %f re f", sp2bp(x), sp2bp(y - getdepth(n)), sp2bp(getwidth(n)), sp2bp(getdepth(n) + getheight(n))), '%.?0+ ', ' ')
|
||||
end
|
||||
@ -453,13 +458,13 @@ function nodehandler.glyph(p, n, x, y, ...)
|
||||
else
|
||||
p.pending[#p.pending+1] = pdf_escape(string.pack('>H', index))
|
||||
end
|
||||
if not p.usedglyphs[index] then
|
||||
p.usedglyphs[index] = {index, math.floor(c.width * 1000 / f.size / p.font.extend + .5), c.tounicode}
|
||||
if not p.font.usedglyphs[index] then
|
||||
p.font.usedglyphs[index] = {index, math.floor(c.width * 1000 / f.size / p.font.extend + .5), c.tounicode}
|
||||
end
|
||||
else
|
||||
p.pending[#p.pending+1] = pdf_escape(string.char(getchar(n)))
|
||||
if not p.usedglyphs[getchar(n)] then
|
||||
p.usedglyphs[getchar(n)] = {getchar(n), math.floor(c.width * 1000 / f.size / p.font.extend + .5), c.tounicode}
|
||||
if not p.font.usedglyphs[getchar(n)] then
|
||||
p.font.usedglyphs[getchar(n)] = {getchar(n), math.floor(c.width * 1000 / f.size / p.font.extend + .5), c.tounicode}
|
||||
end
|
||||
end
|
||||
p.pos.x = p.pos.x + math.floor(getwidth(n)*(1+getexpansion(n)/1000000)+.5)
|
||||
@ -521,7 +526,7 @@ local ondemandmeta = {
|
||||
}
|
||||
local function writeresources(p)
|
||||
local resources = p.resources
|
||||
local result = {"<<"}
|
||||
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
|
||||
@ -530,11 +535,9 @@ local function writeresources(p)
|
||||
end
|
||||
result[#result+1] = ">>"
|
||||
end end
|
||||
result[#result+1] = ">>"
|
||||
return concat(result)
|
||||
end
|
||||
local fontnames = setmetatable({}, {__index = function(t, k) local res = format("F%i", k) t[k] = res return res end})
|
||||
return function(file, n, fontdirs, usedglyphs, colorstacks)
|
||||
local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks)
|
||||
n = todirect(n)
|
||||
setmetatable(usedglyphs, ondemandmeta)
|
||||
local p = {
|
||||
@ -544,12 +547,6 @@ return function(file, n, fontdirs, usedglyphs, colorstacks)
|
||||
strings = {},
|
||||
pending = {},
|
||||
pos = {},
|
||||
fontprovider = function(p, f, fid)
|
||||
if not f.parent then f.parent = pdf.getfontname(fid) end
|
||||
p.resources.Font[fontnames[f.parent]] = fontdirs[f.parent]
|
||||
p.strings[#p.strings+1] = format("/F%i %f Tf 0 Tr", f.parent, sp2bp(f.size)) -- TODO: Setting the mode, expansion, etc.
|
||||
p.usedglyphs = usedglyphs[f.parent]
|
||||
end,
|
||||
font = {},
|
||||
vfont = {},
|
||||
matrix = {1, 0, 0, 1, 0, 0},
|
||||
@ -557,6 +554,8 @@ return function(file, n, fontdirs, usedglyphs, colorstacks)
|
||||
resources = setmetatable({}, ondemandmeta),
|
||||
annots = {},
|
||||
linkcontext = file.linkcontext,
|
||||
fontdirs = fontdirs,
|
||||
usedglyphs = usedglyphs,
|
||||
}
|
||||
if colorstacks then
|
||||
for i=1, #colorstacks do
|
||||
@ -574,3 +573,5 @@ return function(file, n, fontdirs, usedglyphs, colorstacks)
|
||||
topage(p)
|
||||
return concat(p.strings, '\n'), writeresources(p), (p.annots[1] and string.format("/Annots[%s]", table.concat(p.annots, ' ')) or "")
|
||||
end
|
||||
require'luametalatex-pdf-savedbox':init_nodewriter(nodewriter)
|
||||
return nodewriter
|
||||
|
99
luametalatex-pdf-savedbox.lua
Normal file
99
luametalatex-pdf-savedbox.lua
Normal file
@ -0,0 +1,99 @@
|
||||
local writer -- = require'luametalatex-nodewriter' -- This would introduce some cyclic dependency
|
||||
|
||||
-- XForms currently have the form {width, height, depth, objnum, attributes, list, margin}
|
||||
local xforms = {}
|
||||
|
||||
local function to_bp(sp) return sp/65781.76 end
|
||||
|
||||
local function shipout(pfile, xform, fontdirs, usedglyphs)
|
||||
local list, margin = xform.list, xform.margin
|
||||
if not list then return xform.objnum end -- Already shipped out
|
||||
local last_page = cur_page cur_page = nil
|
||||
local out, resources, annots = writer(pfile, list, fontdirs, usedglyphs)
|
||||
cur_page = last_page
|
||||
assert(annots == '')
|
||||
local dict = string.format('/Subtype/Form/BBox[%f %f %f %f]/Resources<<%s%s>>%s', -to_bp(margin), -to_bp(list.depth+margin), to_bp(list.width+margin), to_bp(list.height+margin), resources, xform.resources or '', xform.attributes or '')
|
||||
node.flush_list(list)
|
||||
xform.list = nil
|
||||
local objnum = pfile:stream(xform.objnum, dict, out)
|
||||
xform.objnum = objnum
|
||||
return objnum
|
||||
end
|
||||
|
||||
local function save(pfile, n, attr, resources, immediate, type, margin, fontdirs, usedglyphs)
|
||||
local index = #xforms+1
|
||||
local xform = {
|
||||
list = assert(n, 'List required for saveboxresource'),
|
||||
width = n.width,
|
||||
height = n.height,
|
||||
depth = n.depth,
|
||||
attributes = attr,
|
||||
resources = resources,
|
||||
margin = margin,
|
||||
-- type = type, -- TODO: Not yet used. Do we need this at all?
|
||||
}
|
||||
xforms[index] = xform
|
||||
if immediate then
|
||||
shipout(pfile, xform, fontdirs, usedglyphs)
|
||||
end
|
||||
return index
|
||||
end
|
||||
|
||||
local function adjust_sizes(width, height, depth, real_width, real_height, real_depth)
|
||||
if not depth then
|
||||
if height then
|
||||
local scale = height/real_height
|
||||
depth = (real_depth*scale + .5)//1
|
||||
width = width or (real_width*scale + .5)//1
|
||||
elseif width then
|
||||
local scale = width/real_width
|
||||
depth = (real_depth*scale + .5)//1
|
||||
height = (real_height*scale + .5)//1
|
||||
else
|
||||
width, height, depth = real_width, real_height, real_depth
|
||||
end
|
||||
elseif height then
|
||||
width = width or (real_width*(height+depth)/(real_height+real_depth) + .5)//1
|
||||
else
|
||||
width = width or real_width
|
||||
local scale = width/real_width
|
||||
height = ((real_depth+real_height)*scale + .5)//1 - depth
|
||||
end
|
||||
return width, height, depth
|
||||
end
|
||||
|
||||
local ruleid = node.id'rule'
|
||||
local ruletypes = node.subtypes'rule'
|
||||
local boxrule
|
||||
for n, name in next, ruletypes do
|
||||
if name == 'box' then boxrule = n break end
|
||||
end
|
||||
|
||||
local function use(index, width, height, depth)
|
||||
local xform = xforms[index]
|
||||
if not xform then return nil, nil, nil, nil end
|
||||
width, height, depth = adjust_sizes(width, height, depth, xform.width, xform.height, xform.depth)
|
||||
local n = node.direct.new(ruleid, boxrule)
|
||||
node.direct.setdata(n, index)
|
||||
node.direct.setwhd(n, width, height, depth)
|
||||
return node.direct.tonode(n), width, height, depth
|
||||
end
|
||||
|
||||
local function do_box(data, p, n, x, y)
|
||||
local xform = assert(xforms[data], 'Invalid XForm')
|
||||
local objnum = shipout(p.file, xform, p.fontdirs, p.usedglyphs)
|
||||
local width, height, depth = node.direct.getwhd(n)
|
||||
local xscale, yscale = width / xform.width, (height+depth) / (xform.height+xform.depth)
|
||||
p.resources.XObject['Fm' .. tostring(data)] = objnum
|
||||
pdf.write('page', string.format('q %f 0 0 %f %f %f cm /Fm%i Do Q',
|
||||
xscale, yscale,
|
||||
to_bp(x), to_bp(y-depth+yscale*xform.depth),
|
||||
data), nil, nil, p)
|
||||
end
|
||||
|
||||
return {
|
||||
save = save,
|
||||
use = use,
|
||||
ship = do_box,
|
||||
init_nodewriter = function(t, nodewriter) writer, t.init_nodewriter = nodewriter, nil end,
|
||||
}
|
Loading…
Reference in New Issue
Block a user