2019-07-17 21:14:34 +02:00
local format = string.format
local concat = table.concat
local write = texio.write_nl
2020-01-02 04:14:39 +01:00
local direct = node.direct
2020-05-31 09:30:49 +02:00
local properties = direct.properties
2020-01-02 04:14:39 +01:00
local tonode = direct.tonode
local todirect = direct.todirect
local getid = direct.getid
local traverse = direct.traverse
local getsubtype = direct.getsubtype
2020-05-31 09:30:49 +02:00
local getdirection = direct.getdirection
2020-01-02 04:14:39 +01:00
local setsubtype = direct.setsubtype
local getdepth = direct.getdepth
local getheight = direct.getheight
local getwidth = direct.getwidth
local setdepth = direct.setdepth
local setheight = direct.setheight
local setwidth = direct.setwidth
local getshift = direct.getshift
local getlist = direct.getlist
local getkern = direct.getkern
local getreplace = direct.getreplace
local getleader = direct.getleader
local setfont = direct.setfont
local getfont = direct.getfont
local getoffsets = direct.getoffsets
local getnext = direct.getnext
local getexpansion = direct.getexpansion
local getchar = direct.getchar
local rangedimensions = direct.rangedimensions
2020-05-31 09:30:49 +02:00
local traverse_id = direct.traverse_id
2020-06-11 01:16:42 +02:00
local getdata = direct.getdata
2020-05-31 09:30:49 +02:00
local dir_id = node.id ' dir '
2019-07-17 21:14:34 +02:00
local function doublekeyed ( t , id2name , name2id , index )
return setmetatable ( t , {
__index = index ,
__newindex = function ( t , k , v )
rawset ( t , k , v )
if type ( k ) == ' string ' then
rawset ( t , name2id ( k ) , v )
else
rawset ( t , id2name ( k ) , v )
end
end ,
} )
end
local nodehandler = ( function ( )
local function unknown_handler ( _ , n , x , y )
2020-05-31 09:30:49 +02:00
print ( node.type ( 10 ) )
write ( format ( " Sorry, but the PDF backend does not support %q (id = %i) nodes right now. The supplied node will be dropped at coordinates (%i, %i). " , node.type ( getid ( n ) ) , getid ( n ) , x // 1 , y // 1 ) )
2019-07-17 21:14:34 +02:00
end
return doublekeyed ( { } , node.type , node.id , function ( )
return unknown_handler
end )
end ) ( )
local whatsithandler = ( function ( )
local whatsits = node.whatsits ( )
local function unknown_handler ( p , n , x , y , ... )
2020-01-02 04:14:39 +01:00
local prop = properties [ n ] -- or node.getproperty(n)
2019-07-17 21:14:34 +02:00
if prop and prop.handle then
prop : handle ( p , n , x , y , ... )
else
2020-05-31 09:30:49 +02:00
write ( format ( " Sorry, but the PDF backend does not support %q (id = %i) whatsits right now. The supplied node will be dropped at coordinates (%i, %i). " , whatsits [ getsubtype ( n ) ] , getsubtype ( n ) , x // 1 , y // 1 ) )
2019-07-17 21:14:34 +02:00
end
end
return doublekeyed ( { } , function ( n ) return whatsits [ n ] end , function ( n ) return whatsits [ n ] end , function ( )
return unknown_handler
end )
end ) ( )
local glyph , text , page , cm_pending = 1 , 2 , 3 , 4
local gsub = string.gsub
local function projected_point ( m , x , y , w )
w = w or 1
return x * m [ 1 ] + y * m [ 3 ] + w * m [ 5 ] , x * m [ 2 ] + y * m [ 4 ] + w * m [ 6 ]
end
local function sp2bp ( sp )
return sp / 65781.76
end
local topage
local function totext ( p , fid )
local last = p.mode
if last == glyph then
p.pending [ # p.pending + 1 ] = " )]TJ "
p.strings [ # p.strings + 1 ] = concat ( p.pending )
for i = 1 , # p.pending do p.pending [ i ] = nil end
last = text
end
if last == cm_pending then topage ( p ) end
p.mode = text
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 = 0 , 0 , 0 , 0 , 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.
p.font . fid = fid
p.font . font = f
return false -- Return true if we need a new textmatrix
end
2019-07-20 14:53:24 +02:00
function topage ( p )
2019-07-17 21:14:34 +02:00
local last = p.mode
if last == page then return end
if last <= text then
totext ( p , p.font . fid ) -- First make sure we are really in text mode
p.strings [ # p.strings + 1 ] = " ET "
elseif last == cm_pending then
local pending = p.pending_matrix
if pending [ 1 ] ~= 1 or pending [ 2 ] ~= 0 or pending [ 3 ] ~= 0 or pending [ 4 ] ~= 1 or pending [ 5 ] ~= 0 or pending [ 6 ] ~= 0 then
p.strings [ # p.strings + 1 ] = format ( " %f %f %f %f %f %f cm " , pending [ 1 ] , pending [ 2 ] , pending [ 3 ] , pending [ 4 ] , sp2bp ( pending [ 5 ] ) , sp2bp ( pending [ 6 ] ) )
end
else
error [[Unknown mode]]
end
p.mode = page
end
local function toglyph ( p , fid , x , y , exfactor )
local last = p.mode
if last == glyph and p.font . fid == fid and p.pos . y == y and p.font . exfactor == exfactor then
if x == p.pos . x then return end
local xoffset = ( x - p.pos . x ) / p.font . font.size * 1000 / ( 1 + exfactor / 1000000 )
if math.abs ( xoffset ) < 1000000 then -- 1000000 is arbitrary
p.pending [ # p.pending + 1 ] = format ( " )%i( " , math.floor ( - xoffset ) )
p.pos . x = x
return
end
end
if totext ( p , fid ) or exfactor ~= p.font . exfactor then
p.font . exfactor = exfactor
p.strings [ # p.strings + 1 ] = gsub ( format ( " %f 0.0 %f %f %f %f Tm " , 1 + exfactor / 1000000 , 0 , 1 , sp2bp ( x ) , sp2bp ( y ) ) , ' %.?0+ ' , ' ' )
else
p.strings [ # p.strings + 1 ] = gsub ( format ( " %f %f Td " , sp2bp ( ( x - p.pos . lx ) / ( 1 + exfactor / 1000000 ) ) , sp2bp ( y - p.pos . ly ) ) , ' %.?0+ ' , ' ' )
end
p.pos . lx , p.pos . ly , p.pos . x , p.pos . y = x , y , x , y
p.mode = glyph
p.pending [ 1 ] = " [( "
end
function nodehandler . hlist ( p , list , x0 , y , outerlist , origin , level )
if outerlist then
2020-01-02 04:14:39 +01:00
if getid ( outerlist ) == 0 then
y = y - getshift ( list )
2019-07-17 21:14:34 +02:00
else
2020-01-02 04:14:39 +01:00
x0 = x0 + getshift ( list )
2019-07-17 21:14:34 +02:00
end
end
2020-05-31 09:30:49 +02:00
local direction = getdirection ( list )
if direction == 1 then
x0 = x0 + getwidth ( list )
end
local dirstack = { }
local dirnodes = { }
for n , sub in traverse_id ( dir_id , getlist ( list ) ) do
if sub == 0 then
dirstack [ # dirstack + 1 ] = n
else
local m = dirstack [ # dirstack ]
dirnodes [ m ] = n
dirstack [ # dirstack ] = nil
end
end
for i = 1 , # dirstack do
dirnodes [ dirstack [ i ] ] = rangedimensions ( list , dirstack [ i ] )
end
2019-07-17 21:14:34 +02:00
local x = x0
2020-06-05 04:12:29 +02:00
local linkcontext = p.linkcontext
if linkcontext then
linkcontext : set ( p , x , y , list , level + 1 , ' start ' )
end
2020-05-31 09:30:49 +02:00
for n , id , sub in traverse ( getlist ( list ) ) do
if id == dir_id then
if sub == 0 then
local newdir = getdirection ( n )
if newdir ~= direction then
local close = dirnodes [ n ]
local dim = rangedimensions ( list , n , close )
if close then dirnodes [ close ] = dim end
x = x + ( 2 * newdir - 1 ) * dim
direction = newdir
end
else
local dim = dirnodes [ n ]
if dim then
2020-06-02 01:22:59 +02:00
x = x + ( 2 * direction - 1 ) * dim
2020-05-31 09:30:49 +02:00
direction = 1 - direction
end
end
else
local next = getnext ( n )
local w = next and rangedimensions ( list , n , next ) or rangedimensions ( list , n )
if direction == 1 then x = x - w end
nodehandler [ id ] ( p , n , x , y , list , x0 , level + 1 )
if direction == 0 then x = w + x end
end
2019-07-17 21:14:34 +02:00
end
2020-06-05 04:12:29 +02:00
linkcontext = p.linkcontext
if linkcontext then
linkcontext : set ( p , x , y , list , level + 1 , ' end ' )
end
2019-07-17 21:14:34 +02:00
end
function nodehandler . vlist ( p , list , x , y0 , outerlist , origin , level )
if outerlist then
2020-01-02 04:14:39 +01:00
if getid ( outerlist ) == 0 then
y0 = y0 - getshift ( list )
2019-07-17 21:14:34 +02:00
else
2020-01-02 04:14:39 +01:00
x = x + getshift ( list )
2019-07-17 21:14:34 +02:00
end
end
2020-01-02 04:14:39 +01:00
y0 = y0 + getheight ( list )
2019-07-17 21:14:34 +02:00
local y = y0
2020-01-02 04:14:39 +01:00
for n in traverse ( getlist ( list ) ) do
local d , h , _ = 0 , direct.effective_glue ( n , list ) or math.tointeger ( getkern ( n ) )
2019-07-17 21:14:34 +02:00
if not h then
2020-01-02 04:14:39 +01:00
_ , h , d = direct.getwhd ( n )
2019-07-17 21:14:34 +02:00
end
y = y - ( h or 0 )
2020-01-02 04:14:39 +01:00
nodehandler [ getid ( n ) ] ( p , n , x , y , list , y0 , level + 1 )
2019-07-17 21:14:34 +02:00
y = y - ( d or 0 )
end
end
2020-06-11 01:16:42 +02:00
do
local rulesubtypes = { }
for i , n in next , node.subtypes ' rule ' do
rulesubtypes [ n ] = i
end
local box_rule = rulesubtypes.box
local image_rule = rulesubtypes.image
local user_rule = rulesubtypes.user
local empty_rule = rulesubtypes.empty
local outline_rule = rulesubtypes.outline
local ship_img = require ' luametalatex-pdf-image ' . ship
2019-07-17 21:14:34 +02:00
function nodehandler . rule ( p , n , x , y , outer )
2020-01-02 04:14:39 +01:00
if getwidth ( n ) == - 1073741824 then setwidth ( n , getwidth ( outer ) ) end
if getheight ( n ) == - 1073741824 then setheight ( n , getheight ( outer ) ) end
if getdepth ( n ) == - 1073741824 then setdepth ( n , getdepth ( outer ) ) end
local sub = getsubtype ( n )
2020-06-11 01:16:42 +02:00
if sub == box_rule then
2019-07-17 21:14:34 +02:00
error [[We can't handle boxes yet]]
2020-06-11 01:16:42 +02:00
elseif sub == image_rule then
if getwidth ( n ) <= 0 or getdepth ( n ) + getheight ( n ) <= 0 then return end
ship_img ( getdata ( n ) , p , n , x , y )
elseif sub == empty_rule then
elseif sub == user_rule then
2019-07-17 21:14:34 +02:00
error [[We can't handle user rules yet]]
2020-06-11 01:16:42 +02:00
elseif sub == outline_rule then
2019-07-17 21:14:34 +02:00
error [[We can't handle outline rules yet]]
else
2020-01-02 04:14:39 +01:00
if getwidth ( n ) <= 0 or getdepth ( n ) + getheight ( n ) <= 0 then return end
2019-07-17 21:14:34 +02:00
topage ( p )
2020-01-02 04:14:39 +01:00
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+ ' , ' ' )
2019-07-17 21:14:34 +02:00
end
end
2020-06-11 01:16:42 +02:00
end
2019-07-17 21:14:34 +02:00
function nodehandler . boundary ( ) end
function nodehandler . disc ( p , n , x , y , list , ... ) -- FIXME: I am not sure why this can happen, let's assume we can use .replace
2020-01-02 04:14:39 +01:00
for n in traverse ( getreplace ( n ) ) do
local next = getnext ( n )
local w = next and rangedimensions ( list , n , next ) or rangedimensions ( list , n )
nodehandler [ getid ( n ) ] ( p , n , x , y , list , ... )
2019-07-17 21:14:34 +02:00
x = w + x
end
end
function nodehandler . local_par ( ) end
function nodehandler . math ( ) end
function nodehandler . glue ( p , n , x , y , outer , origin , level ) -- Naturally this is an interesting one.
2020-01-02 04:14:39 +01:00
local subtype = getsubtype ( n )
2019-07-17 21:14:34 +02:00
if subtype < 100 then return end -- We only really care about leaders
2020-01-02 04:14:39 +01:00
local leader = getleader ( n )
local w = direct.effective_glue ( n , outer )
if getid ( leader ) == 2 then -- We got a rule, this should be easy
if getid ( outer ) == 0 then
setwidth ( leader , w )
2019-07-17 21:14:34 +02:00
else
2020-01-02 04:14:39 +01:00
setheight ( leader , w )
setdepth ( leader , 0 )
2019-07-17 21:14:34 +02:00
end
return nodehandler.rule ( p , leader , x , y , outer )
end
2020-01-02 04:14:39 +01:00
local lwidth = getid ( outer ) == 0 and getwidth ( leader ) or getheight ( leader ) + getdepth ( leader )
if getid ( outer ) ~= 0 then
2019-07-17 21:14:34 +02:00
y = y + w
end
if subtype == 100 then
2020-01-02 04:14:39 +01:00
if getid ( outer ) == 0 then
2019-07-17 21:14:34 +02:00
local newx = ( ( x - origin - 1 ) // lwidth + 1 ) * lwidth + origin
-- local newx = -(origin-x)//lwidth * lwidth + origin
w = w + x - newx
x = newx
else
-- local newy = -(origin-y)//lwidth * lwidth + origin
local newy = ( y - origin ) // lwidth * lwidth + origin
w = w + newy - y
y = newy
end
elseif subtype == 101 then
local inner = w - ( w // lwidth ) * lwidth
2020-01-02 04:14:39 +01:00
if getid ( outer ) == 0 then
2019-07-17 21:14:34 +02:00
x = x + inner / 2
else
y = y - inner / 2
end
elseif subtype == 102 then
local count = w // lwidth
local skip = ( w - count * lwidth ) / ( count + 1 )
2020-01-02 04:14:39 +01:00
if getid ( outer ) == 0 then
2019-07-17 21:14:34 +02:00
x = x + skip
else
y = y - skip
end
lwidth = lwidth + skip
elseif subtype == 103 then
2020-01-02 04:14:39 +01:00
if getid ( outer ) == 0 then
2019-07-17 21:14:34 +02:00
local newx = ( ( x - 1 ) // lwidth + 1 ) * lwidth
w = w + x - newx
x = newx
else
local newy = y // lwidth * lwidth
w = w + newy - y
y = newy
end
end
2020-01-02 04:14:39 +01:00
local handler = nodehandler [ getid ( leader ) ]
if getid ( outer ) == 0 then
2019-07-17 21:14:34 +02:00
while w >= lwidth do
handler ( p , leader , x , y , outer , origin , level + 1 )
w = w - lwidth
x = x + lwidth
end
else
2020-01-02 04:14:39 +01:00
y = y - getheight ( leader )
2019-07-17 21:14:34 +02:00
while w >= lwidth do
handler ( p , leader , x , y , outer , origin , level + 1 )
w = w - lwidth
y = y - lwidth
end
end
end
function nodehandler . kern ( ) end
function nodehandler . penalty ( ) end
2020-06-07 22:42:53 +02:00
local pdf_escape = require ' luametalatex-pdf-escape ' . escape_raw
2019-07-17 21:14:34 +02:00
local match = lpeg.match
local function do_commands ( p , c , f , fid , x , y , outer , ... )
local fonts = f.fonts
local stack , current_font = { } , fonts [ 1 ]
for _ , cmd in ipairs ( c.commands ) do
if cmd [ 1 ] == " node " then
local cmd = cmd [ 2 ]
2020-01-02 04:14:39 +01:00
nodehandler [ getid ( cmd ) ] ( p , cmd , x , y , nil , ... )
x = x + getwidth ( cmd )
2019-07-17 21:14:34 +02:00
elseif cmd [ 1 ] == " font " then
current_font = fonts [ cmd [ 2 ] ]
elseif cmd [ 1 ] == " char " then
2020-01-02 04:14:39 +01:00
local n = direct.new ' glyph '
setsubtype ( n , 256 )
setfont ( n , current_font.id , cmd [ 2 ] )
2019-07-17 21:14:34 +02:00
nodehandler.glyph ( p , n , x , y , outer , ... )
2020-01-02 04:14:39 +01:00
direct.free ( n )
x = x + getwidth ( n )
2019-07-17 21:14:34 +02:00
elseif cmd [ 1 ] == " slot " then
2020-01-02 04:14:39 +01:00
local n = direct.new ' glyph '
setsubtype ( n , 256 )
setfont ( n , cmd [ 2 ] , cmd [ 3 ] )
2019-07-17 21:14:34 +02:00
nodehandler.glyph ( p , n , x , y , outer , ... )
2020-01-02 04:14:39 +01:00
direct.free ( n )
x = x + getwidth ( n )
2019-07-17 21:14:34 +02:00
elseif cmd [ 1 ] == " rule " then
2020-01-02 04:14:39 +01:00
local n = direct.new ' rule '
setheight ( n , cmd [ 2 ] )
setwidth ( n , cmd [ 3 ] )
2019-07-17 21:14:34 +02:00
nodehandler.rule ( p , n , x , y , outer , ... )
2020-01-02 04:14:39 +01:00
direct.free ( n )
x = x + getwidth ( n )
2019-07-17 21:14:34 +02:00
elseif cmd [ 1 ] == " left " then
x = x + cmd [ 2 ]
elseif cmd [ 1 ] == " down " then
y = y + cmd [ 2 ]
elseif cmd [ 1 ] == " push " then
stack [ # stack + 1 ] = { x , y }
elseif cmd [ 1 ] == " pop " then
local top = stack [ # stack ]
stack [ # stack ] = nil
x , y = top [ 1 ] , top [ 2 ]
elseif cmd [ 1 ] == " special " then
2019-07-20 14:53:24 +02:00
error [[specials aren't supported yet]] -- TODO
2019-07-17 21:14:34 +02:00
elseif cmd [ 1 ] == " pdf " then
2019-07-20 14:53:24 +02:00
pdf.write ( cmd [ 3 ] and cmd [ 2 ] or " origin " , cmd [ 3 ] , x , y , p )
2019-07-17 21:14:34 +02:00
elseif cmd [ 1 ] == " lua " then
cmd = cmd [ 2 ]
if type ( cmd ) == " string " then cmd = load ( cmd ) end
assert ( type ( cmd ) == " function " )
2019-07-20 14:53:24 +02:00
pdf._latelua ( p , x , y , cmd , fid , c )
2019-07-17 21:14:34 +02:00
elseif cmd [ 1 ] == " image " then
2019-07-20 14:53:24 +02:00
error [[images aren't supported yet]] -- TODO
2019-07-17 21:14:34 +02:00
-- ???
-- else
-- NOP, comment and invalid commands ignored
end
if # commands ~= 1 then error [[Unsupported command number]] end
if commands [ 1 ] [ 1 ] ~= " node " then error [[Unsupported command name]] end
commands = commands [ 1 ] [ 2 ]
2020-01-02 04:14:39 +01:00
nodehandler [ getid ( commands ) ] ( p , commands , x , y , nil , ... )
2019-07-17 21:14:34 +02:00
end
end
function nodehandler . glyph ( p , n , x , y , ... )
2020-01-02 04:14:39 +01:00
if getfont ( n ) ~= p.vfont . fid then
p.vfont . fid = getfont ( n )
p.vfont . font = font.getfont ( getfont ( n ) ) or font.fonts [ getfont ( n ) ]
2019-07-17 21:14:34 +02:00
end
local f , fid = p.vfont . font , p.vfont . fid
2020-01-02 04:14:39 +01:00
local c = f.characters [ getchar ( n ) ]
2019-07-17 21:14:34 +02:00
if not c then
2019-07-18 20:02:58 +02:00
texio.write_nl ( " Missing character " )
return
2019-07-17 21:14:34 +02:00
end
if c.commands then return do_commands ( p , c , f , fid , x , y , ... ) end
2020-01-02 04:14:39 +01:00
local xoffset , yoffset = getoffsets ( n )
toglyph ( p , getfont ( n ) , x + xoffset , y + yoffset , getexpansion ( n ) )
2019-07-17 21:14:34 +02:00
local index = c.index
if index then
-- if f.encodingbytes == -3 then
2020-01-02 04:14:39 +01:00
if false then
2019-07-17 21:14:34 +02:00
if index < 0x80 then
2020-06-07 22:42:53 +02:00
p.pending [ # p.pending + 1 ] = pdf_escape ( string.pack ( ' >B ' , index ) )
2019-07-17 21:14:34 +02:00
elseif index < 0x7F80 then
2020-06-07 22:42:53 +02:00
p.pending [ # p.pending + 1 ] = pdf_escape ( string.pack ( ' >H ' , index + 0x7F80 ) )
2019-07-17 21:14:34 +02:00
else
2020-06-07 22:42:53 +02:00
p.pending [ # p.pending + 1 ] = pdf_escape ( string.pack ( ' >BH ' , 0xFF , index - 0x7F80 ) )
2019-07-17 21:14:34 +02:00
end
else
2020-06-07 22:42:53 +02:00
p.pending [ # p.pending + 1 ] = pdf_escape ( string.pack ( ' >H ' , index ) )
2019-07-17 21:14:34 +02:00
end
if not p.usedglyphs [ index ] then
p.usedglyphs [ index ] = { index , math.floor ( c.width * 1000 / f.size + .5 ) , c.tounicode }
end
else
2020-06-07 22:42:53 +02:00
p.pending [ # p.pending + 1 ] = pdf_escape ( string.char ( getchar ( n ) ) )
2020-01-02 04:14:39 +01:00
if not p.usedglyphs [ getchar ( n ) ] then
p.usedglyphs [ getchar ( n ) ] = { getchar ( n ) , math.floor ( c.width * 1000 / f.size + .5 ) , c.tounicode }
2019-07-17 21:14:34 +02:00
end
end
2020-01-02 04:14:39 +01:00
p.pos . x = p.pos . x + math.floor ( getwidth ( n ) * ( 1 + getexpansion ( n ) / 1000000 ) + .5 )
2019-07-17 21:14:34 +02:00
end
function nodehandler . whatsit ( p , n , ... ) -- Whatsit?
2020-06-06 00:36:05 +02:00
local prop = properties [ n ] -- or node.getproperty(n)
if prop and prop.handle then
prop : handle ( p , n , ... )
else
write ( " Invalid whatsit found (missing handler). " )
end
2019-07-17 21:14:34 +02:00
end
2019-07-18 20:02:58 +02:00
local global_p , global_x , global_y
function pdf . _latelua ( p , x , y , func , ... )
global_p , global_x , global_y = p , x , y
return func ( ... )
end
2020-06-04 23:30:46 +02:00
function pdf . write_matrix ( a , b , c , d , e , f , p )
e , f , p = e or 0 , f or 0 , p or global_p
local pending = p.pending_matrix
if p.mode ~= cm_pending then
topage ( p )
p.mode = cm_pending
else
a , b = projected_point ( pending , a , b , 0 )
c , d = projected_point ( pending , c , d , 0 )
e , f = projected_point ( pending , e , f , 1 )
end
pending [ 1 ] , pending [ 2 ] , pending [ 3 ] , pending [ 4 ] , pending [ 5 ] , pending [ 6 ] = a , b , c , d , e , f
end
local write_matrix = pdf.write_matrix
2019-07-18 20:02:58 +02:00
function pdf . write ( mode , text , x , y , p )
x , y , p = x or global_x , y or global_y , p or global_p
2019-07-20 14:53:24 +02:00
if mode == " page " then
topage ( p )
p.strings [ # p.strings + 1 ] = text
elseif mode == " text " then
2019-07-18 20:02:58 +02:00
topage ( p )
p.strings [ # p.strings + 1 ] = text
2019-07-20 14:53:24 +02:00
elseif mode == " direct " then
if p.mode ~= page then
totext ( p , p.font . fid )
end
p.strings [ # p.strings + 1 ] = text
2019-07-18 20:02:58 +02:00
elseif mode == " origin " then
2020-06-04 23:30:46 +02:00
write_matrix ( 1 , 0 , 0 , 1 , x , y , p )
2019-07-18 20:02:58 +02:00
topage ( p )
p.strings [ # p.strings + 1 ] = text
2020-06-04 23:30:46 +02:00
write_matrix ( 1 , 0 , 0 , 1 , - x , - y , p )
2019-07-18 20:02:58 +02:00
else
write ( format ( ' Literal type %s unsupported ' , mode ) )
end
end
2019-07-17 21:14:34 +02:00
local ondemandmeta = {
__index = function ( t , k )
t [ k ] = { }
return t [ k ]
end
}
local function writeresources ( p )
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
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 } )
2019-07-18 20:02:58 +02:00
return function ( file , n , fontdirs , usedglyphs , colorstacks )
2020-01-02 04:14:39 +01:00
n = todirect ( n )
2019-07-17 21:14:34 +02:00
setmetatable ( usedglyphs , ondemandmeta )
local p = {
2019-07-18 20:02:58 +02:00
is_page = not not colorstacks ,
2019-07-17 21:14:34 +02:00
file = file ,
mode = 3 ,
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 } ,
pending_matrix = { } ,
resources = setmetatable ( { } , ondemandmeta ) ,
annots = { } ,
linkcontext = file.linkcontext ,
}
2019-07-18 20:02:58 +02:00
if colorstacks then
for i = 1 , # colorstacks do
local colorstack = colorstacks [ i ]
if colorstack.page then
local stack = colorstack.page_stack
if colorstack.default ~= stack [ # stack ] then
pdf.write ( colorstack.mode , stack [ # stack ] , 0 , 0 , p )
end
end
end
end
2020-01-02 04:14:39 +01:00
nodehandler [ getid ( n ) ] ( p , n , 0 , 0 , n , nil , 0 )
-- nodehandler[getid(n)](p, n, 0, getdepth(n), n)
2019-07-17 21:14:34 +02:00
topage ( p )
return concat ( p.strings , ' \n ' ) , writeresources ( p ) , ( p.annots [ 1 ] and string.format ( " /Annots[%s] " , table.concat ( p.annots , ' ' ) ) or " " )
end