diff --git a/silex/outputters/base.lua b/silex/outputters/base.lua
index 2d5042d..ee6cd33 100644
--- a/silex/outputters/base.lua
+++ b/silex/outputters/base.lua
@@ -1,3 +1,6 @@
+--- SILE outputter class.
+-- @interfaces outputters
+
local outputter = pl.class()
outputter.type = "outputter"
outputter._name = "base"
@@ -8,22 +11,30 @@ function outputter:_init ()
end
function outputter:registerHook (category, func)
- if not self.hooks[category] then self.hooks[category] = {} end
+ if not self.hooks[category] then
+ self.hooks[category] = {}
+ end
table.insert(self.hooks[category], func)
end
function outputter:runHooks (category, data)
- if not self.hooks[category] then return nil end
- for _, func in ipairs(self.hooks[category]) do
- data = func(self, data)
- end
- return data
+ if not self.hooks[category] then
+ return nil
+ end
+ for _, func in ipairs(self.hooks[category]) do
+ data = func(self, data)
+ end
+ return data
end
function outputter.newPage () end
+function outputter:abort ()
+ return self:finish() -- unless otherwise defined
+end
+
function outputter:finish ()
- self:runHooks("prefinish")
+ self:runHooks("prefinish")
end
function outputter.getCursor () end
@@ -65,19 +76,19 @@ function outputter.setBookmark (_, _, _) end
function outputter.drawRaw (_) end
function outputter:getOutputFilename ()
- local fname
- if SILE.outputFilename then
- fname = SILE.outputFilename
- elseif SILE.input.filenames[1] then
- fname = pl.path.splitext(SILE.input.filenames[1])
- if self.extension then
- fname = fname .. "." .. self.extension
- end
- end
- if not fname then
- SU.error("Cannot guess output filename without an input name")
- end
- return fname
+ local fname
+ if SILE.outputFilename then
+ fname = SILE.outputFilename
+ elseif SILE.input.filenames[1] then
+ fname = pl.path.splitext(SILE.input.filenames[1])
+ if self.extension then
+ fname = fname .. "." .. self.extension
+ end
+ end
+ if not fname then
+ SU.error("Cannot guess output filename without an input name")
+ end
+ return fname
end
return outputter
diff --git a/silex/outputters/debug.lua b/silex/outputters/debug.lua
index fa08e71..f102da7 100644
--- a/silex/outputters/debug.lua
+++ b/silex/outputters/debug.lua
@@ -31,147 +31,172 @@ outputter.extension = "debug"
-- function outputter:_init () end
function outputter:_ensureInit ()
- if not started then
- started = true -- keep this before self:_writeline or it will be a race condition!
- local fname = self:getOutputFilename()
- outfile = fname == "-" and io.stdout or io.open(fname, "w+")
- if SILE.documentState.paperSize then
- self:_writeline("Set paper size ", SILE.documentState.paperSize[1], SILE.documentState.paperSize[2])
- end
- self:_writeline("Begin page")
- end
+ if not started then
+ started = true -- keep this before self:_writeline or it will be a race condition!
+ local fname = self:getOutputFilename()
+ outfile = fname == "-" and io.stdout or io.open(fname, "w+")
+ if SILE.documentState.paperSize then
+ self:_writeline("Set paper size ", SILE.documentState.paperSize[1], SILE.documentState.paperSize[2])
+ end
+ self:_writeline("Begin page")
+ end
end
function outputter:_writeline (...)
- self:_ensureInit()
- local args = pl.utils.pack(...)
- for i = 1, #args do
- outfile:write(args[i])
- if i < #args then outfile:write("\t") end
- end
- outfile:write("\n")
+ self:_ensureInit()
+ local args = pl.utils.pack(...)
+ for i = 1, #args do
+ outfile:write(args[i])
+ if i < #args then
+ outfile:write("\t")
+ end
+ end
+ outfile:write("\n")
end
function outputter:newPage ()
- self:_writeline("New page")
+ self:_writeline("New page")
+end
+
+function outputter:abort ()
+ if started then
+ self:_writeline("Aborted")
+ outfile:close()
+ started = false
+ end
end
function outputter:finish ()
- if SILE.status.unsupported then self:_writeline("UNSUPPORTED") end
- self:_writeline("End page")
- self:runHooks("prefinish")
- self:_writeline("Finish")
- outfile:close()
+ if SILE.status.unsupported then
+ self:_writeline("UNSUPPORTED")
+ end
+ self:_writeline("End page")
+ self:runHooks("prefinish")
+ self:_writeline("Finish")
+ outfile:close()
+ started = false
end
function outputter.getCursor (_)
- return cursorX, cursorY
+ return cursorX, cursorY
end
function outputter:setCursor (x, y, relative)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- local oldx, oldy = self:getCursor()
- local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 }
- cursorX = offset.x + x
- cursorY = offset.y - y
- if _round(oldx) ~= _round(cursorX) then self:_writeline("Mx ", _round(x)) end
- if _round(oldy) ~= _round(cursorY) then self:_writeline("My ", _round(y)) end
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ local oldx, oldy = self:getCursor()
+ local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 }
+ cursorX = offset.x + x
+ cursorY = offset.y - y
+ if _round(oldx) ~= _round(cursorX) then
+ self:_writeline("Mx ", _round(x))
+ end
+ if _round(oldy) ~= _round(cursorY) then
+ self:_writeline("My ", _round(y))
+ end
end
function outputter:setColor (color)
- if color.r then
- self:_writeline("Set color", _round(color.r), _round(color.g), _round(color.b))
- elseif color.c then
- self:_writeline("Set color", _round(color.c), _round(color.m), _round(color.y), _round(color.k))
- elseif color.l then
- self:_writeline("Set color", _round(color.l))
- end
+ if color.r then
+ self:_writeline("Set color", _round(color.r), _round(color.g), _round(color.b))
+ elseif color.c then
+ self:_writeline("Set color", _round(color.c), _round(color.m), _round(color.y), _round(color.k))
+ elseif color.l then
+ self:_writeline("Set color", _round(color.l))
+ end
end
function outputter:pushColor (color)
- if color.r then
- self:_writeline("Push color", _round(color.r), _round(color.g), _round(color.b))
- elseif color.c then
- self:_writeline("Push color (CMYK)", _round(color.c), _round(color.m), _round(color.y), _round(color.k))
- elseif color.l then
- self:_writeline("Push color (grayscale)", _round(color.l))
- end
+ if color.r then
+ self:_writeline("Push color", _round(color.r), _round(color.g), _round(color.b))
+ elseif color.c then
+ self:_writeline("Push color (CMYK)", _round(color.c), _round(color.m), _round(color.y), _round(color.k))
+ elseif color.l then
+ self:_writeline("Push color (grayscale)", _round(color.l))
+ end
end
function outputter:popColor ()
- self:_writeline("Pop color")
+ self:_writeline("Pop color")
end
function outputter:drawHbox (value, width)
- if not value.glyphString then return end
- width = SU.cast("number", width)
- local buf
- if value.complex then
- local cluster = {}
- for i = 1, #value.items do
- local item = value.items[i]
- cluster[#cluster+1] = item.gid
- -- For the sake of terseness we're only dumping non-zero values
- if item.glyphAdvance ~= 0 then cluster[#cluster+1] = "a=".._round(item.glyphAdvance) end
- if item.x_offset then cluster[#cluster+1] = "x=".._round(item.x_offset) end
- if item.y_offset then cluster[#cluster+1] = "y=".._round(item.y_offset) end
- self:setCursor(item.width, 0, true)
- end
- buf = table.concat(cluster, " ")
- else
- buf = table.concat(value.glyphString, " ") .. " w=" .. _round(width)
- end
- self:_writeline("T", buf, "(" .. tostring(value.text) .. ")")
+ if not value.glyphString
+ then return
+ end
+ width = SU.cast("number", width)
+ local buf
+ if value.complex then
+ local cluster = {}
+ for i = 1, #value.items do
+ local item = value.items[i]
+ cluster[#cluster + 1] = item.gid
+ -- For the sake of terseness we're only dumping non-zero values
+ if item.glyphAdvance ~= 0 then
+ cluster[#cluster + 1] = "a=" .. _round(item.glyphAdvance)
+ end
+ if item.x_offset then
+ cluster[#cluster + 1] = "x=" .. _round(item.x_offset)
+ end
+ if item.y_offset then
+ cluster[#cluster + 1] = "y=" .. _round(item.y_offset)
+ end
+ self:setCursor(item.width, 0, true)
+ end
+ buf = table.concat(cluster, " ")
+ else
+ buf = table.concat(value.glyphString, " ") .. " w=" .. _round(width)
+ end
+ self:_writeline("T", buf, "(" .. tostring(value.text) .. ")")
end
function outputter:setFont (options)
- local font = SILE.font._key(options)
- if lastFont ~= font then
- self:_writeline("Set font ", font)
- lastFont = font
- end
+ local font = SILE.font._key(options)
+ if lastFont ~= font then
+ self:_writeline("Set font ", font)
+ lastFont = font
+ end
end
function outputter:drawImage (src, x, y, width, height)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- width = SU.cast("number", width)
- height = SU.cast("number", height)
- self:_writeline("Draw image", src, _round(x), _round(y), _round(width), _round(height))
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ width = SU.cast("number", width)
+ height = SU.cast("number", height)
+ self:_writeline("Draw image", src, _round(x), _round(y), _round(width), _round(height))
end
function outputter.getImageSize (_, src, pageno)
- local pdf = require("justenoughlibtexpdf")
- local llx, lly, urx, ury, xresol, yresol = pdf.imagebbox(src, pageno)
- return (urx-llx), (ury-lly), xresol, yresol
+ local pdf = require("justenoughlibtexpdf")
+ local llx, lly, urx, ury, xresol, yresol = pdf.imagebbox(src, pageno)
+ return (urx - llx), (ury - lly), xresol, yresol
end
function outputter:drawSVG (figure, _, x, y, width, height, scalefactor)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- width = SU.cast("number", width)
- height = SU.cast("number", height)
- self:_writeline("Draw SVG", _round(x), _round(y), _round(width), _round(height), figure, scalefactor)
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ width = SU.cast("number", width)
+ height = SU.cast("number", height)
+ self:_writeline("Draw SVG", _round(x), _round(y), _round(width), _round(height), figure, scalefactor)
end
function outputter:drawRule (x, y, width, depth)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- width = SU.cast("number", width)
- depth = SU.cast("number", depth)
- self:_writeline("Draw line", _round(x), _round(y), _round(width), _round(depth))
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ width = SU.cast("number", width)
+ depth = SU.cast("number", depth)
+ self:_writeline("Draw line", _round(x), _round(y), _round(width), _round(depth))
end
function outputter:setLinkAnchor (name, x, y)
- self:_writeline("Setting link anchor", name, x, y)
+ self:_writeline("Setting link anchor", name, x, y)
end
function outputter:beginLink (dest, opts)
- self:_writeline("Begining a link", dest, opts)
+ self:_writeline("Beginning a link", dest, opts)
end
-function outputter:endLink(dest, opts, x0, y0, x1, y1)
+function outputter:endLink (dest, opts, x0, y0, x1, y1)
self:_writeline("Ending a link", dest, opts, x0, y0, x1, y1)
end
diff --git a/silex/outputters/libtexpdf.lua b/silex/outputters/libtexpdf.lua
index 74fcc1c..779ab34 100644
--- a/silex/outputters/libtexpdf.lua
+++ b/silex/outputters/libtexpdf.lua
@@ -10,7 +10,7 @@ local lastkey = false
local debugfont = SILE.font.loadDefaults({ family = "Gentium Plus", language = "en", size = 10 })
local glyph2string = function (glyph)
- return string.char(math.floor(glyph % 2^32 / 2^8)) .. string.char(glyph % 0x100)
+ return string.char(math.floor(glyph % 2 ^ 32 / 2 ^ 8)) .. string.char(glyph % 0x100)
end
local _dl = 0.5
@@ -27,18 +27,18 @@ outputter.extension = "pdf"
local deltaX
local deltaY
local function trueXCoord (x)
- if not deltaX then
- local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
- deltaX = (sheetSize[1] - SILE.documentState.paperSize[1]) / 2
- end
- return x + deltaX
+ if not deltaX then
+ local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
+ deltaX = (sheetSize[1] - SILE.documentState.paperSize[1]) / 2
+ end
+ return x + deltaX
end
local function trueYCoord (y)
- if not deltaY then
- local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
- deltaY = (sheetSize[2] - SILE.documentState.paperSize[2]) / 2
- end
- return y + deltaY
+ if not deltaY then
+ local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
+ deltaY = (sheetSize[2] - SILE.documentState.paperSize[2]) / 2
+ end
+ return y + deltaY
end
-- The outputter init can't actually initialize output (as logical as it might
@@ -46,209 +46,236 @@ end
-- function outputter:_init () end
function outputter:_ensureInit ()
- if not started then
- local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
- local w, h = sheetSize[1], sheetSize[2]
- local fname = self:getOutputFilename()
- -- Ideally we could want to set the PDF CropBox, BleedBox, TrimBox...
- -- Our wrapper only manages the MediaBox at this point.
- pdf.init(fname == "-" and "/dev/stdout" or fname, w, h, SILE.full_version)
- pdf.beginpage()
- started = true
- end
+ if not started then
+ local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
+ local w, h = sheetSize[1], sheetSize[2]
+ local fname = self:getOutputFilename()
+ -- Ideally we could want to set the PDF CropBox, BleedBox, TrimBox...
+ -- Our wrapper only manages the MediaBox at this point.
+ pdf.init(fname == "-" and "/dev/stdout" or fname, w, h, SILE.full_version)
+ pdf.beginpage()
+ started = true
+ end
end
function outputter:newPage ()
- self:_ensureInit()
- pdf.endpage()
- pdf.beginpage()
+ self:_ensureInit()
+ pdf.endpage()
+ pdf.beginpage()
end
-- pdf structure package needs a tie in here
-function outputter._endHook (_)
+function outputter._endHook (_) end
+
+function outputter.abort ()
+ if started then
+ pdf.endpage()
+ pdf.finish()
+ started = false
+ lastkey = false
+ end
end
function outputter:finish ()
- self:_ensureInit()
- pdf.endpage()
- self:runHooks("prefinish")
- pdf.finish()
- started = false
- lastkey = nil
+ -- allows generation of empty PDFs
+ self:_ensureInit()
+ pdf.endpage()
+ self:runHooks("prefinish")
+ pdf.finish()
+ started = false
+ lastkey = false
end
function outputter.getCursor (_)
- return cursorX, cursorY
+ return cursorX, cursorY
end
function outputter.setCursor (_, x, y, relative)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 }
- cursorX = offset.x + x
- cursorY = offset.y + (relative and 0 or SILE.documentState.paperSize[2]) - y
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 }
+ cursorX = offset.x + x
+ cursorY = offset.y + (relative and 0 or SILE.documentState.paperSize[2]) - y
end
function outputter:setColor (color)
- self:_ensureInit()
- if color.r then pdf.setcolor_rgb(color.r, color.g, color.b) end
- if color.c then pdf.setcolor_cmyk(color.c, color.m, color.y, color.k) end
- if color.l then pdf.setcolor_gray(color.l) end
+ self:_ensureInit()
+ if color.r then
+ pdf.setcolor_rgb(color.r, color.g, color.b)
+ end
+ if color.c then
+ pdf.setcolor_cmyk(color.c, color.m, color.y, color.k)
+ end
+ if color.l then
+ pdf.setcolor_gray(color.l)
+ end
end
function outputter:pushColor (color)
- self:_ensureInit()
- if color.r then pdf.colorpush_rgb(color.r, color.g, color.b) end
- if color.c then pdf.colorpush_cmyk(color.c, color.m, color.y, color.k) end
- if color.l then pdf.colorpush_gray(color.l) end
+ self:_ensureInit()
+ if color.r then
+ pdf.colorpush_rgb(color.r, color.g, color.b)
+ end
+ if color.c then
+ pdf.colorpush_cmyk(color.c, color.m, color.y, color.k)
+ end
+ if color.l then
+ pdf.colorpush_gray(color.l)
+ end
end
function outputter:popColor ()
- self:_ensureInit()
- pdf.colorpop()
+ self:_ensureInit()
+ pdf.colorpop()
end
function outputter:_drawString (str, width, x_offset, y_offset)
- local x, y = self:getCursor()
- pdf.colorpush_rgb(0,0,0)
- pdf.colorpop()
- pdf.setstring(trueXCoord(x+x_offset), trueYCoord(y+y_offset), str, string.len(str), _font, width)
+ local x, y = self:getCursor()
+ pdf.colorpush_rgb(0, 0, 0)
+ pdf.colorpop()
+ pdf.setstring(trueXCoord(x + x_offset), trueYCoord(y + y_offset), str, string.len(str), _font, width)
end
function outputter:drawHbox (value, width)
- width = SU.cast("number", width)
- self:_ensureInit()
- if not value.glyphString then return end
- -- Nodes which require kerning or have offsets to the glyph
- -- position should be output a glyph at a time. We pass the
- -- glyph advance from the htmx table, so that libtexpdf knows
- -- how wide each glyph is. It uses this to then compute the
- -- relative position between the pen after the glyph has been
- -- painted (cursorX + glyphAdvance) and the next painting
- -- position (cursorX + width - remember that the box's "width"
- -- is actually the shaped x_advance).
- if value.complex then
- for i = 1, #value.items do
- local item = value.items[i]
- local buf = glyph2string(item.gid)
- self:_drawString(buf, item.glyphAdvance, item.x_offset or 0, item.y_offset or 0)
- self:setCursor(item.width, 0, true)
- end
- else
- local buf = {}
- for i = 1, #value.glyphString do
- buf[i] = glyph2string(value.glyphString[i])
- end
- buf = table.concat(buf, "")
- self:_drawString(buf, width, 0, 0)
- end
+ width = SU.cast("number", width)
+ self:_ensureInit()
+ if not value.glyphString then
+ return
+ end
+ -- Nodes which require kerning or have offsets to the glyph
+ -- position should be output a glyph at a time. We pass the
+ -- glyph advance from the htmx table, so that libtexpdf knows
+ -- how wide each glyph is. It uses this to then compute the
+ -- relative position between the pen after the glyph has been
+ -- painted (cursorX + glyphAdvance) and the next painting
+ -- position (cursorX + width - remember that the box's "width"
+ -- is actually the shaped x_advance).
+ if value.complex then
+ for i = 1, #value.items do
+ local item = value.items[i]
+ local buf = glyph2string(item.gid)
+ self:_drawString(buf, item.glyphAdvance, item.x_offset or 0, item.y_offset or 0)
+ self:setCursor(item.width, 0, true)
+ end
+ else
+ local buf = {}
+ for i = 1, #value.glyphString do
+ buf[i] = glyph2string(value.glyphString[i])
+ end
+ buf = table.concat(buf, "")
+ self:_drawString(buf, width, 0, 0)
+ end
end
function outputter:_withDebugFont (callback)
- if not _debugfont then
- _debugfont = self:setFont(debugfont)
- end
- local oldfont = _font
- _font = _debugfont
- callback()
- _font = oldfont
+ if not _debugfont then
+ _debugfont = self:setFont(debugfont)
+ end
+ local oldfont = _font
+ _font = _debugfont
+ callback()
+ _font = oldfont
end
function outputter:setFont (options)
- self:_ensureInit()
- local key = SILE.font._key(options)
- if lastkey and key == lastkey then return _font end
- local font = SILE.font.cache(options, SILE.shaper.getFace)
- if options.direction == "TTB" then
- font.layout_dir = 1
- end
- if SILE.typesetter.frame and SILE.typesetter.frame:writingDirection() == "TTB" then
- pdf.setdirmode(1)
- else
- pdf.setdirmode(0)
- end
- _font = pdf.loadfont(font)
- if _font < 0 then SU.error("Font loading error for " .. pl.pretty.write(options, "")) end
- lastkey = key
- return _font
+ self:_ensureInit()
+ local key = SILE.font._key(options)
+ if lastkey and key == lastkey then
+ return _font
+ end
+ local font = SILE.font.cache(options, SILE.shaper.getFace)
+ if options.direction == "TTB" then
+ font.layout_dir = 1
+ end
+ if SILE.typesetter.frame and SILE.typesetter.frame:writingDirection() == "TTB" then
+ pdf.setdirmode(1)
+ else
+ pdf.setdirmode(0)
+ end
+ _font = pdf.loadfont(font)
+ if _font < 0 then
+ SU.error("Font loading error for " .. pl.pretty.write(options, ""))
+ end
+ lastkey = key
+ return _font
end
function outputter:drawImage (src, x, y, width, height, pageno)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- width = SU.cast("number", width)
- height = SU.cast("number", height)
- self:_ensureInit()
- pdf.drawimage(src, trueXCoord(x), trueYCoord(y), width, height, pageno or 1)
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ width = SU.cast("number", width)
+ height = SU.cast("number", height)
+ self:_ensureInit()
+ pdf.drawimage(src, trueXCoord(x), trueYCoord(y), width, height, pageno or 1)
end
function outputter:getImageSize (src, pageno)
- self:_ensureInit() -- in case it's a PDF file
- local llx, lly, urx, ury, xresol, yresol = pdf.imagebbox(src, pageno or 1)
- return (urx-llx), (ury-lly), xresol, yresol
+ self:_ensureInit() -- in case it's a PDF file
+ local llx, lly, urx, ury, xresol, yresol = pdf.imagebbox(src, pageno or 1)
+ return (urx - llx), (ury - lly), xresol, yresol
end
function outputter:drawSVG (figure, x, y, _, height, scalefactor)
- self:_ensureInit()
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- height = SU.cast("number", height)
- pdf.add_content("q")
- self:setCursor(x, y)
- x, y = self:getCursor()
- local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
- local newy = y - SILE.documentState.paperSize[2] / 2 + height - sheetSize[2] / 2
- pdf.add_content(table.concat({ scalefactor, 0, 0, -scalefactor, trueXCoord(x), newy, "cm" }, " "))
- pdf.add_content(figure)
- pdf.add_content("Q")
+ self:_ensureInit()
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ height = SU.cast("number", height)
+ pdf.add_content("q")
+ self:setCursor(x, y)
+ x, y = self:getCursor()
+ local sheetSize = SILE.documentState.sheetSize or SILE.documentState.paperSize
+ local newy = y - SILE.documentState.paperSize[2] / 2 + height - sheetSize[2] / 2
+ pdf.add_content(table.concat({ scalefactor, 0, 0, -scalefactor, trueXCoord(x), newy, "cm" }, " "))
+ pdf.add_content(figure)
+ pdf.add_content("Q")
end
function outputter:drawRule (x, y, width, height)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- width = SU.cast("number", width)
- height = SU.cast("number", height)
- self:_ensureInit()
- local paperY = SILE.documentState.paperSize[2]
- pdf.setrule(trueXCoord(x), trueYCoord(paperY - y - height), width, height)
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ width = SU.cast("number", width)
+ height = SU.cast("number", height)
+ self:_ensureInit()
+ local paperY = SILE.documentState.paperSize[2]
+ pdf.setrule(trueXCoord(x), trueYCoord(paperY - y - height), width, height)
end
function outputter:debugFrame (frame)
- self:_ensureInit()
- self:pushColor({ r = 0.8, g = 0, b = 0 })
- self:drawRule(frame:left()-_dl/2, frame:top()-_dl/2, frame:width()+_dl, _dl)
- self:drawRule(frame:left()-_dl/2, frame:top()-_dl/2, _dl, frame:height()+_dl)
- self:drawRule(frame:right()-_dl/2, frame:top()-_dl/2, _dl, frame:height()+_dl)
- self:drawRule(frame:left()-_dl/2, frame:bottom()-_dl/2, frame:width()+_dl, _dl)
- -- self:drawRule(frame:left() + frame:width()/2 - 5, (frame:top() + frame:bottom())/2+5, 10, 10)
- local stuff = SILE.shaper:createNnodes(frame.id, debugfont)
- stuff = stuff[1].nodes[1].value.glyphString -- Horrible hack
- local buf = {}
- for i = 1, #stuff do
- buf[i] = glyph2string(stuff[i])
- end
- buf = table.concat(buf, "")
- self:_withDebugFont(function ()
- self:setCursor(frame:left():tonumber() - _dl/2, frame:top():tonumber() + _dl/2)
- self:_drawString(buf, 0, 0, 0)
- end)
- self:popColor()
+ self:_ensureInit()
+ self:pushColor({ r = 0.8, g = 0, b = 0 })
+ self:drawRule(frame:left() - _dl / 2, frame:top() - _dl / 2, frame:width() + _dl, _dl)
+ self:drawRule(frame:left() - _dl / 2, frame:top() - _dl / 2, _dl, frame:height() + _dl)
+ self:drawRule(frame:right() - _dl / 2, frame:top() - _dl / 2, _dl, frame:height() + _dl)
+ self:drawRule(frame:left() - _dl / 2, frame:bottom() - _dl / 2, frame:width() + _dl, _dl)
+ -- self:drawRule(frame:left() + frame:width()/2 - 5, (frame:top() + frame:bottom())/2+5, 10, 10)
+ local stuff = SILE.shaper:createNnodes(frame.id, debugfont)
+ stuff = stuff[1].nodes[1].value.glyphString -- Horrible hack
+ local buf = {}
+ for i = 1, #stuff do
+ buf[i] = glyph2string(stuff[i])
+ end
+ buf = table.concat(buf, "")
+ self:_withDebugFont(function ()
+ self:setCursor(frame:left():tonumber() - _dl / 2, frame:top():tonumber() + _dl / 2)
+ self:_drawString(buf, 0, 0, 0)
+ end)
+ self:popColor()
end
function outputter:debugHbox (hbox, scaledWidth)
- self:_ensureInit()
- self:pushColor({ r = 0.8, g = 0.3, b = 0.3 })
- local paperY = SILE.documentState.paperSize[2]
- local x, y = self:getCursor()
- y = paperY - y
- self:drawRule(x-_dl/2, y-_dl/2-hbox.height, scaledWidth+_dl, _dl)
- self:drawRule(x-_dl/2, y-hbox.height-_dl/2, _dl, hbox.height+hbox.depth+_dl)
- self:drawRule(x-_dl/2, y-_dl/2, scaledWidth+_dl, _dl)
- self:drawRule(x+scaledWidth-_dl/2, y-hbox.height-_dl/2, _dl, hbox.height+hbox.depth+_dl)
- if hbox.depth > SILE.types.length(0) then
- self:drawRule(x-_dl/2, y+hbox.depth-_dl/2, scaledWidth+_dl, _dl)
- end
- self:popColor()
+ self:_ensureInit()
+ self:pushColor({ r = 0.8, g = 0.3, b = 0.3 })
+ local paperY = SILE.documentState.paperSize[2]
+ local x, y = self:getCursor()
+ y = paperY - y
+ self:drawRule(x - _dl / 2, y - _dl / 2 - hbox.height, scaledWidth + _dl, _dl)
+ self:drawRule(x - _dl / 2, y - hbox.height - _dl / 2, _dl, hbox.height + hbox.depth + _dl)
+ self:drawRule(x - _dl / 2, y - _dl / 2, scaledWidth + _dl, _dl)
+ self:drawRule(x + scaledWidth - _dl / 2, y - hbox.height - _dl / 2, _dl, hbox.height + hbox.depth + _dl)
+ if hbox.depth > SILE.types.length(0) then
+ self:drawRule(x - _dl / 2, y + hbox.depth - _dl / 2, scaledWidth + _dl, _dl)
+ end
+ self:popColor()
end
-- The methods below are only implemented on outputters supporting these features.
@@ -257,133 +284,147 @@ end
-- ! The API is unstable and subject to change. !
function outputter:scaleFn (xorigin, yorigin, xratio, yratio, callback)
- xorigin = SU.cast("number", xorigin)
- yorigin = SU.cast("number", yorigin)
- local x0 = trueXCoord(xorigin)
- local y0 = -trueYCoord(yorigin)
- self:_ensureInit()
- pdf:gsave()
- pdf.setmatrix(1, 0, 0, 1, x0, y0)
- pdf.setmatrix(xratio, 0, 0, yratio, 0, 0)
- pdf.setmatrix(1, 0, 0, 1, -x0, -y0)
- callback()
- pdf:grestore()
+ xorigin = SU.cast("number", xorigin)
+ yorigin = SU.cast("number", yorigin)
+ local x0 = trueXCoord(xorigin)
+ local y0 = -trueYCoord(yorigin)
+ self:_ensureInit()
+ pdf:gsave()
+ pdf.setmatrix(1, 0, 0, 1, x0, y0)
+ pdf.setmatrix(xratio, 0, 0, yratio, 0, 0)
+ pdf.setmatrix(1, 0, 0, 1, -x0, -y0)
+ callback()
+ pdf:grestore()
end
function outputter:rotateFn (xorigin, yorigin, theta, callback)
- xorigin = SU.cast("number", xorigin)
- yorigin = SU.cast("number", yorigin)
- local x0 = trueXCoord(xorigin)
- local y0 = -trueYCoord(yorigin)
- self:_ensureInit()
- pdf:gsave()
- pdf.setmatrix(1, 0, 0, 1, x0, y0)
- pdf.setmatrix(math.cos(theta), math.sin(theta), -math.sin(theta), math.cos(theta), 0, 0)
- pdf.setmatrix(1, 0, 0, 1, -x0, -y0)
- callback()
- pdf:grestore()
+ xorigin = SU.cast("number", xorigin)
+ yorigin = SU.cast("number", yorigin)
+ local x0 = trueXCoord(xorigin)
+ local y0 = -trueYCoord(yorigin)
+ self:_ensureInit()
+ pdf:gsave()
+ pdf.setmatrix(1, 0, 0, 1, x0, y0)
+ pdf.setmatrix(math.cos(theta), math.sin(theta), -math.sin(theta), math.cos(theta), 0, 0)
+ pdf.setmatrix(1, 0, 0, 1, -x0, -y0)
+ callback()
+ pdf:grestore()
end
-- Other rotation unstable APIs
function outputter:enterFrameRotate (xa, xb, y, theta) -- Unstable API see rotate package
- xa = SU.cast("number", xa)
- xb = SU.cast("number", xb)
- y = SU.cast("number", y)
- -- Keep center point the same?
- local cx0 = trueXCoord(xa)
- local cx1 = trueXCoord(xb)
- local cy = -trueYCoord(y)
- self:_ensureInit()
- pdf:gsave()
- pdf.setmatrix(1, 0, 0, 1, cx1, cy)
- pdf.setmatrix(math.cos(theta), math.sin(theta), -math.sin(theta), math.cos(theta), 0, 0)
- pdf.setmatrix(1, 0, 0, 1, -cx0, -cy)
+ xa = SU.cast("number", xa)
+ xb = SU.cast("number", xb)
+ y = SU.cast("number", y)
+ -- Keep center point the same?
+ local cx0 = trueXCoord(xa)
+ local cx1 = trueXCoord(xb)
+ local cy = -trueYCoord(y)
+ self:_ensureInit()
+ pdf:gsave()
+ pdf.setmatrix(1, 0, 0, 1, cx1, cy)
+ pdf.setmatrix(math.cos(theta), math.sin(theta), -math.sin(theta), math.cos(theta), 0, 0)
+ pdf.setmatrix(1, 0, 0, 1, -cx0, -cy)
end
function outputter.leaveFrameRotate (_)
- pdf:grestore()
+ pdf:grestore()
end
-- Unstable link APIs
function outputter:setLinkAnchor (name, x, y)
- x = SU.cast("number", x)
- y = SU.cast("number", y)
- self:_ensureInit()
- pdf.destination(name, trueXCoord(x), trueYCoord(y))
+ x = SU.cast("number", x)
+ y = SU.cast("number", y)
+ self:_ensureInit()
+ pdf.destination(name, trueXCoord(x), trueYCoord(y))
end
local function borderColor (color)
- if color then
- if color.r then return "/C [" .. color.r .. " " .. color.g .. " " .. color.b .. "]" end
- if color.c then return "/C [" .. color.c .. " " .. color.m .. " " .. color.y .. " " .. color.k .. "]" end
- if color.l then return "/C [" .. color.l .. "]" end
- end
- return ""
+ if color then
+ if color.r then
+ return "/C [" .. color.r .. " " .. color.g .. " " .. color.b .. "]"
+ end
+ if color.c then
+ return "/C [" .. color.c .. " " .. color.m .. " " .. color.y .. " " .. color.k .. "]"
+ end
+ if color.l then
+ return "/C [" .. color.l .. "]"
+ end
+ end
+ return ""
end
local function borderStyle (style, width)
- if style == "underline" then return "/BS<>" end
- if style == "dashed" then return "/BS<>" end
- return "/Border[0 0 " .. width .. "]"
+ if style == "underline" then
+ return "/BS<>"
+ end
+ if style == "dashed" then
+ return "/BS<>"
+ end
+ return "/Border[0 0 " .. width .. "]"
end
-function outputter:beginLink (_, _) -- destination, options as argument
- self:_ensureInit()
- -- HACK:
- -- Looking at the code, pdf.begin_annotation does nothing, and Simon wrote a comment
- -- about tracking boxes. Unsure what he implied with this obscure statement.
- -- Sure thing is that some backends may need the destination here, e.g. an HTML backend
- -- would generate a , as well as the options possibly for styling
- -- on the link opening?
- pdf.begin_annotation()
+function outputter:startLink (_, _) -- destination, options as argument
+ self:_ensureInit()
+ -- HACK:
+ -- Looking at the code, pdf.begin_annotation does nothing, and Simon wrote a comment
+ -- about tracking boxes. Unsure what he implied with this obscure statement.
+ -- Sure thing is that some backends may need the destination here, e.g. an HTML backend
+ -- would generate a , as well as the options possibly for styling
+ -- on the link opening?
+ pdf.begin_annotation()
end
function outputter.endLink (_, dest, opts, x0, y0, x1, y1)
- local bordercolor = borderColor(opts.bordercolor)
- local borderwidth = SU.cast("integer", opts.borderwidth)
- local borderstyle = borderStyle(opts.borderstyle, borderwidth)
- local target = opts.external and "/Type/Action/S/URI/URI" or "/S/GoTo/D"
- local d = "<>>>"
- pdf.end_annotation(d,
- trueXCoord(x0) , trueYCoord(y0 - opts.borderoffset),
- trueXCoord(x1), trueYCoord(y1 + opts.borderoffset))
+ local bordercolor = borderColor(opts.bordercolor)
+ local borderwidth = SU.cast("integer", opts.borderwidth)
+ local borderstyle = borderStyle(opts.borderstyle, borderwidth)
+ local target = opts.external and "/Type/Action/S/URI/URI" or "/S/GoTo/D"
+ local d = "<>>>"
+ pdf.end_annotation(
+ d,
+ trueXCoord(x0),
+ trueYCoord(y0 - opts.borderoffset),
+ trueXCoord(x1),
+ trueYCoord(y1 + opts.borderoffset)
+ )
end
-- Bookmarks and metadata
local function validate_date (date)
- return string.match(date, [[^D:%d+%s*-%s*%d%d%s*'%s*%d%d%s*'?$]]) ~= nil
+ return string.match(date, [[^D:%d+%s*-%s*%d%d%s*'%s*%d%d%s*'?$]]) ~= nil
end
function outputter:setMetadata (key, value)
- if key == "Trapped" then
- SU.warn("Skipping special metadata key \\Trapped")
- return
- end
-
- if key == "ModDate" or key == "CreationDate" then
- if not validate_date(value) then
- SU.warn("Invalid date: " .. value)
+ if key == "Trapped" then
+ SU.warn("Skipping special metadata key \\Trapped")
return
- end
- else
- -- see comment in on bookmark
- value = SU.utf8_to_utf16be(value)
- end
- self:_ensureInit()
- pdf.metadata(key, value)
+ end
+
+ if key == "ModDate" or key == "CreationDate" then
+ if not validate_date(value) then
+ SU.warn("Invalid date: " .. value)
+ return
+ end
+ else
+ -- see comment in on bookmark
+ value = SU.utf8_to_utf16be(value)
+ end
+ self:_ensureInit()
+ pdf.metadata(key, value)
end
function outputter:setBookmark (dest, title, level)
- -- For annotations and bookmarks, text strings must be encoded using
- -- either PDFDocEncoding or UTF16-BE with a leading byte-order marker.
- -- As PDFDocEncoding supports only limited character repertoire for
- -- European languages, we use UTF-16BE for internationalization.
- local ustr = SU.utf8_to_utf16be_hexencoded(title)
- local d = "</A<>>>"
- self:_ensureInit()
- pdf.bookmark(d, level)
+ -- For annotations and bookmarks, text strings must be encoded using
+ -- either PDFDocEncoding or UTF16-BE with a leading byte-order marker.
+ -- As PDFDocEncoding supports only limited character repertoire for
+ -- European languages, we use UTF-16BE for internationalization.
+ local ustr = SU.utf8_to_utf16be_hexencoded(title)
+ local d = "</A<>>>"
+ self:_ensureInit()
+ pdf.bookmark(d, level)
end
-- Assumes the caller known what they want to stuff in raw PDF format