summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/barracuda/lib-driver
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2019-12-05 21:23:07 +0000
committerKarl Berry <karl@freefriends.org>2019-12-05 21:23:07 +0000
commit0ed7b2cd92f7a81334f612df3e37211f8333ae75 (patch)
tree2bcbe01d8e86cbf57d64069a153346da4936b00a /Master/texmf-dist/scripts/barracuda/lib-driver
parent7f43f3692e1354166c0623faf83c84b23d041ea3 (diff)
barracuda (5dec19)
git-svn-id: svn://tug.org/texlive/trunk@53034 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/barracuda/lib-driver')
-rw-r--r--Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua399
-rw-r--r--Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua284
-rw-r--r--Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua260
3 files changed, 943 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua
new file mode 100644
index 00000000000..4827a190c57
--- /dev/null
+++ b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua
@@ -0,0 +1,399 @@
+--
+-- ga Intermediate Graphic Language for barcode drawing
+-- Copyright (C) 2019 Roberto Giacomelli
+--
+-- Basic driver interface
+-- drawing elementary vector shape
+-- All dimensions are in scaled point (sp)
+
+local Driver = {
+ _VERSION = "Driver v0.0.9",
+ _NAME = "Driver",
+ _DESCRIPTION = "Driver for ga graphic assembler stream",
+}
+
+Driver.__index = Driver
+Driver._drv_instance = {} -- driver instances repository
+
+-- driver_type/submodule name
+Driver._drv_available_drv = { -- lowercase keys please
+ native = "lib-driver.brcd-drv-pdfliteral", -- only LuaTeX driver
+ svg = "lib-driver.brcd-drv-svg",
+}
+
+function Driver:_get_driver(id_drv) --> object, err
+ if type(id_drv) ~= "string" then
+ return nil, "[ArgErr] 'id_drv' is not a string"
+ end
+ if not self._drv_available_drv[id_drv] then
+ return nil, "[ArgErr] driver '"..id_drv.."' not found"
+ end
+ local t_drv = self._drv_instance
+ if t_drv[id_drv] then -- is the repo already loaded?
+ return t_drv[id_drv], nil
+ else -- loading driver
+ local module = self._drv_available_drv[id_drv]
+ local channel = require(module)
+ t_drv[id_drv] = channel
+ return channel, nil
+ end
+end
+
+function Driver:_new_state() --> a new state
+ return {
+ line_width = 65781.76, -- line width 1bp (in scaled point sp)
+ line_cap = 0, -- line cap style
+ line_join = 0, -- line join style
+ gtext = false, -- text group off
+ bb_on = true, -- bounding box checking activation
+ bb_x1 = nil, -- bounding box coordinates in sp (nil means no data)
+ bb_y1 = nil,
+ bb_x2 = nil,
+ bb_y2 = nil,
+ mm = 186467.98110236, -- conversion factor sp -> mm (millimeter)
+ bp = 65781.76, -- conversion factor sp -> bp (big point)
+ }
+end
+
+function Driver:_ga_process(drv, ga, st, bf, xt)
+ local op_fn = self._opcode_v001
+ local pc = 1 -- program counter
+ local data = ga._data
+ while data[pc] do -- stream processing
+ local opcode = data[pc]
+ local fn = assert(op_fn[opcode], "[InternalErr] unimpl opcode ".. opcode)
+ pc = fn(drv, st, pc + 1, data, bf, xt)
+ end
+end
+
+-- save graphic data in an external file with the 'id_drv' format
+-- id_drv: specific driver output
+-- ga: ga object
+-- filename: file name
+-- ext: file extension (optional)
+function Driver:save(id_drv, ga, filename, ext) --> ok, err
+ -- retrive the output library
+ local drv, err = self:_get_driver(id_drv)
+ if err then return false, err end
+ -- init
+ local state = self:_new_state()
+ local buf, txt_buf = drv.init_buffer(state) -- a new buffer and text_buffer
+ -- processing
+ self:_ga_process(drv, ga, state, buf, txt_buf)
+ -- buffer finalizing
+ drv.close_buffer(state, buf, txt_buf) -- finalize the istruction
+ -- file saving
+ local sep = drv.buf_sep
+ ext = ext or drv.ext
+ local fn = io.open(filename.."."..ext, "w") -- output the file
+ fn:write(table.concat(buf, sep)) -- concat the buffer
+ fn:close()
+ return true, nil
+end
+
+-- insert a ga drawing in a TeX box
+-- PDFnative only function
+function Driver:ga_to_hbox(ga, boxname) --> ok, err
+ -- retrive the output library
+ local id_drv = "native"
+ local drv, err = self:_get_driver(id_drv)
+ if err then return false, err end
+ -- init process
+ local state = self:_new_state()
+ local buf, txt_buf = drv.init_buffer(state) -- a new buffer and text_buffer
+ -- processing
+ self:_ga_process(drv, ga, state, buf, txt_buf)
+ -- finalizing
+ drv.close_buffer(state, buf, txt_buf) -- finalize the istruction sequence
+ -- build hbox
+ local ok, err = drv.hboxcreate(boxname, state, buf, txt_buf)
+ return ok, err
+end
+
+
+-- operational functions
+-- _op_v001 corresponds to the version 1 of ga graphic assembler specification.
+-- The table indexes every opcode to a function that takes these arguments and
+-- return the updated program counter pointed to the next operation:
+-- fn: format specific driver library
+-- st: state
+-- pc: program counter
+-- ga: read only ga stream
+-- bf: the output buffer
+-- xt: the output text object buffer
+Driver._opcode_v001 = {
+ [1] = function (drv, st, pc, ga, bf, xt) -- 1 <W: dim>; set line width
+ local w = ga[pc]
+ st.line_width = w
+ if not drv.append_001 then
+ error("[InternalErr] unimplemented opcode 1 for "..drv._NAME)
+ end
+ drv.append_001(st, bf, xt, w)
+ return pc + 1
+ end,
+ [2] = function (drv, st, pc, ga, bf, xt) -- 2 <e: u8>; set line cap style
+ local style = ga[pc]
+ st.line_cap = style
+ if not drv.append_002 then
+ error("[InternalErr] unimplemented opcode 2 for "..drv._NAME)
+ end
+ drv.append_002(st, bf, xt, style)
+ return pc + 1
+ end,
+ [3] = function (drv, st, pc, ga, bf, xt) -- 3 <e: u8>; set line join style
+ local join = ga[pc]
+ if not drv.append_003 then
+ error("[InternalErr] unimplemented opcode 3 for "..drv._NAME)
+ end
+ drv.append_003(st, bf, xt, join)
+ return pc + 1
+ end,
+ [30] = function (drv, st, pc, ga, bf, xt) -- start_bbox_group
+ assert(st.bb_on)
+ st.bb_on = false
+ return pc
+ end,
+ [31] = function (drv, st, pc, ga, bf, xt) -- end_bbox_group
+ assert(st.bb_on == false)
+ st.bb_on = true
+ local x1 = ga[pc]; pc = pc + 1
+ local y1 = ga[pc]; pc = pc + 1
+ local x2 = ga[pc]; pc = pc + 1
+ local y2 = ga[pc]; pc = pc + 1
+ if st.bb_x1 == nil then
+ st.bb_x1 = x1
+ st.bb_y1 = y1
+ st.bb_x2 = x2
+ st.bb_y2 = y2
+ else
+ if x1 < st.bb_x1 then st.bb_x1 = x1 end
+ if x2 > st.bb_x2 then st.bb_x2 = x2 end
+ if y1 < st.bb_y1 then st.bb_y1 = y1 end
+ if y2 > st.bb_y2 then st.bb_y2 = y2 end
+ end
+ return pc
+ end,
+ -- draw an horizontal line
+ -- 33 <x1: DIM> <x2: DIM> <y: DIM>
+ [33] = function (drv, st, pc, ga, bf, xt)
+ local x1 = ga[pc]; pc = pc + 1
+ local x2 = ga[pc]; pc = pc + 1
+ local y = ga[pc]; pc = pc + 1
+ if st.bb_on then -- eventually update bbox
+ local hw = st.line_width/2
+ local by1 = y - hw
+ local by2 = y + hw
+ if st.bb_x1 == nil then
+ st.bb_x1 = x1
+ st.bb_x2 = x2
+ st.bb_y1 = by1
+ st.bb_y2 = by2
+ else
+ if x1 < st.bb_x1 then st.bb_x1 = x1 end
+ if x2 > st.bb_x2 then st.bb_x2 = x2 end
+ if by1 < st.bb_y1 then st.bb_y1 = by1 end
+ if by2 > st.bb_y2 then st.bb_y2 = by2 end
+ end
+ end
+ if not drv.append_033 then
+ error("[InternalErr] unimplemented opcode 33 for "..drv._NAME)
+ end
+ drv.append_033(st, bf, xt, x1, x2, y)
+ return pc
+ end,
+ -- draw a vertical line
+ [34] = function (drv, st, pc, ga, bf, xt) -- 34 <y1: DIM> <y2: DIM> <x: DIM>
+ local y1 = ga[pc]; pc = pc + 1
+ local y2 = ga[pc]; pc = pc + 1
+ local x = ga[pc]; pc = pc + 1
+ if st.bb_on then -- eventually update the figure bounding box
+ local hw = st.line_width/2
+ local bx1 = x - hw
+ local bx2 = x + hw
+ if st.bb_x1 == nil then
+ st.bb_x1 = bx1
+ st.bb_x2 = bx2
+ st.bb_y1 = y1
+ st.bb_y2 = y2
+ else
+ if bx1 < st.bb_x1 then st.bb_x1 = bx1 end
+ if bx2 > st.bb_x2 then st.bb_x2 = bx2 end
+ if y1 < st.bb_y1 then st.bb_y1 = y1 end
+ if y2 > st.bb_y2 then st.bb_y2 = y2 end
+ end
+ end
+ if not drv.append_034 then
+ error("[InternalErr] unimplemented opcode 34 for "..drv._NAME)
+ end
+ drv.append_034(st, bf, xt, y1, y2, x)
+ return pc
+ end,
+ -- draw a group of vertical lines (vbar)
+ -- 36 <y1: DIM> <y2: DIM> <b: UINT> <x1: DIM> <t1: DIM>
+ [36] = function(drv, st, pc, ga, bf, xt) -- vbar
+ local y1 = ga[pc]; pc = pc + 1
+ local y2 = ga[pc]; pc = pc + 1
+ local nbar = ga[pc]; pc = pc + 1
+ assert(nbar > 0)
+ local h = y2 - y1 -- height common to every rectangle
+ assert(h > 0)
+ local pc_next = pc + 2 * nbar
+ if drv.append_036_start then
+ drv.append_036_start(st, bf, xt, nbar, y1, y2)
+ end
+ local bx1, bx2
+ for i = pc, pc_next - 1, 2 do -- reading coordinates <x axis> <width>
+ local x = assert(ga[i], "[InternalErr] ga prematurely reached the end")
+ local w = assert(ga[i+1], "[InternalErr] ga prematurely reached the end")
+ drv.append_036_bar(st, bf, xt, x, w, y1, y2)
+ -- check the bounding box only if the corresponding flag is true
+ local x1 = x - w/2
+ local x2 = x + w/2
+ if st.bb_on then
+ if bx1 == nil then
+ bx1 = x1
+ bx2 = x2
+ else
+ if x1 < bx1 then bx1 = x1 end
+ if x2 > bx2 then bx2 = x2 end
+ end
+ end
+ end
+ if drv.append_036_stop then
+ drv.append_036_stop(st, bf, xt, nbar, y1, y2)
+ end
+ if st.bb_on then -- eventually update bbox
+ if st.bb_x1 == nil then
+ st.bb_x1 = bx1
+ st.bb_x2 = bx2
+ st.bb_y1 = y1
+ st.bb_y2 = y2
+ else
+ if bx1 < st.bb_x1 then st.bb_x1 = bx1 end
+ if bx2 > st.bb_x2 then st.bb_x2 = bx2 end
+ if y1 < st.bb_y1 then st.bb_y1 = y1 end
+ if y2 > st.bb_y2 then st.bb_y2 = y2 end
+ end
+ end
+ return pc_next
+ end,
+ -- draw a rectangle
+ -- 48 <x1: DIM> <y1: DIM> <x2: DIM> <y2: DIM>
+ [48] = function(drv, st, pc, ga, bf, xt)
+ local x1 = ga[pc]; pc = pc + 1
+ local y1 = ga[pc]; pc = pc + 1
+ local x2 = ga[pc]; pc = pc + 1
+ local y2 = ga[pc]; pc = pc + 1
+ -- check the bounding box only if the flag is true
+ if st.bb_on then
+ local hw = st.line_width/2
+ local bx1, bx2 = x1 - hw, x2 + hw
+ local by1, by2 = y1 - hw, y2 + hw
+ if st.bb_x1 == nil then
+ st.bb_x1 = bx1
+ st.bb_x2 = bx2
+ st.bb_y1 = by1
+ st.bb_y2 = by2
+ else
+ if bx1 < st.bb_x1 then st.bb_x1 = bx1 end
+ if bx2 > st.bb_x2 then st.bb_x2 = bx2 end
+ if by1 < st.bb_y1 then st.bb_y1 = by1 end
+ if by2 > st.bb_y2 then st.bb_y2 = by2 end
+ end
+ end
+ if not drv.append_048 then
+ error("[InternalErr] unimplemented opcode 48 for "..drv._NAME)
+ end
+ drv.append_048(st, bf, xt, x1, y1, x2, y2)
+ return pc
+ end,
+ -- text
+ [130] = function(drv, st, pc, ga, bf, xt) -- text: ax ay xpos ypos string
+ local ax = ga[pc]; pc = pc + 1
+ local ay = ga[pc]; pc = pc + 1
+ local xpos = ga[pc]; pc = pc + 1
+ local ypos = ga[pc]; pc = pc + 1
+ assert(ga[pc] ~= 0, "[InternalErr] empty chars sequence")
+ while ga[pc] ~= 0 do
+ local c = ga[pc]; pc = pc + 1
+ drv.append_130_char(st, bf, xt, c)
+ end
+ local x1, y1, x2, y2 = drv.append_130_stop(st, bf, xt, xpos, ypos, ax, ay)
+ -- bounding box checking
+ if st.bb_on then
+ if st.bb_x1 == nil then
+ st.bb_x1 = x1
+ st.bb_x2 = x2
+ st.bb_y1 = y1
+ st.bb_y2 = y2
+ else
+ if x1 < st.bb_x1 then st.bb_x1 = x1 end
+ if x2 > st.bb_x2 then st.bb_x2 = x2 end
+ if y1 < st.bb_y1 then st.bb_y1 = y1 end
+ if y2 > st.bb_y2 then st.bb_y2 = y2 end
+ end
+ end
+ return pc + 1
+ end,
+ [131] = function(drv, st, pc, ga, bf, xt) -- text_xspaced x1 xgap ay ypos chars
+ local x1 = ga[pc]; pc = pc + 1
+ local xgap = ga[pc]; pc = pc + 1
+ local ay = ga[pc]; pc = pc + 1
+ local ypos = ga[pc]; pc = pc + 1
+ assert(ga[pc] ~= 0, "[InternalErr] empty chars sequence")
+ while ga[pc] ~= 0 do
+ local c = ga[pc]; pc = pc + 1
+ drv.append_131_char(st, bf, xt, c, xgap)
+ end
+ local bx1, by1, bx2, by2 = drv.append_131_stop(st, bf, xt, x1, xgap, ypos, ay)
+ -- bounding box checking
+ if st.bb_on then -- eventually update bbox
+ if st.bb_x1 == nil then
+ st.bb_x1 = bx1
+ st.bb_x2 = bx2
+ st.bb_y1 = by1 -- no depth
+ st.bb_y2 = by2
+ else
+ if bx1 < st.bb_x1 then st.bb_x1 = bx1 end
+ if bx2 > st.bb_x2 then st.bb_x2 = bx2 end
+ if by1 < st.bb_y1 then st.bb_y1 = by1 end
+ if by2 > st.bb_y2 then st.bb_y2 = by2 end
+ end
+ end
+ return pc + 1
+ end,
+ -- text_xwidth
+ -- <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS>
+ [132] = function (drv, st, pc, ga, bf, xt)
+ local ay = ga[pc]; pc = pc + 1 -- y anchor
+ local x1 = ga[pc]; pc = pc + 1 -- left limit
+ local x2 = ga[pc]; pc = pc + 1 -- right limit
+ assert (x1 ~= x2, "[InternalErr] x coordinate are equal")
+ assert (x1 < x2, "[InternalErr] not ordered x1, x2 limits")
+ local ypos = ga[pc]; pc = pc + 1 -- y coordinate of anchor point
+ assert(ga[pc] ~= 0, "[InternalErr] empty chars sequence")
+ while ga[pc] ~= 0 do
+ local c = ga[pc]; pc = pc + 1
+ drv.append_132_char(st, bf, xt, c)
+ end
+ local bx1, by1, bx2, by2 = drv.append_132_stop(st, bf, xt, x1, x2, ypos, ay)
+ -- bounding box checking
+ if st.bb_on then -- eventually update bbox
+ if st.bb_x1 == nil then
+ st.bb_x1 = bx1
+ st.bb_x2 = bx2
+ st.bb_y1 = by1 -- no depth
+ st.bb_y2 = by2
+ else
+ if bx1 < st.bb_x1 then st.bb_x1 = bx1 end
+ if bx2 > st.bb_x2 then st.bb_x2 = bx2 end
+ if by1 < st.bb_y1 then st.bb_y1 = by1 end
+ if by2 > st.bb_y2 then st.bb_y2 = by2 end
+ end
+ end
+ return pc + 1
+ end,
+}
+
+return Driver
+
diff --git a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua
new file mode 100644
index 00000000000..50baea1472c
--- /dev/null
+++ b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua
@@ -0,0 +1,284 @@
+--
+-- ga graphic assembler or
+-- Intermediate Graphic Language for barcode drawing
+-- Copyright (C) 2019 Roberto Giacomelli
+--
+-- All dimensions are in scaled point (sp)
+-- ga LuaTeX Driver (native implementation node+pdfliteral)
+
+-- class for drawing elementary geometric elements
+local PDFnative = {
+ _VERSION = "PDFnative v0.0.4",
+ _NAME = "PDFnative",
+ _DESCRIPTION = "A LuaTeX native pdfliteral driver for ga graphic stream",
+}
+
+PDFnative.ext = "txt" -- file extension
+PDFnative.buf_sep = "\n" -- separation string for buffer concat
+
+function PDFnative.init_buffer(st) --> buffer, text buffer
+ st.head = nil -- addition for text processing (to remember purpose)
+ st.last = nil
+ st.hbox = nil
+ st.cw = nil
+ st.x_hbox = nil
+ st.char_counter = nil
+ local bf = {"q"} -- create a new graphic stack
+ local xt = {} -- text buffer
+ return bf, xt
+end
+
+function PDFnative.close_buffer(st, bf, xt)
+ bf[#bf + 1] = "Q" -- stack restoring
+end
+
+-- text utility special functions
+
+local function newglue(w) --> node
+ local n = node.new("glue")
+ n.width = w
+ return n
+end
+
+local function newglyph(c) --> node -- ? U+2423 ␣ for whitespace?
+ if c == 32 then
+ return newglue(tex.sp "3.5pt")
+ end
+ local n = node.new("glyph")
+ n.char = c
+ n.font = font.current()
+ return n
+end
+
+local function newpdfliteral(buf) --> node
+ local npdf = node.new("whatsit", "pdf_literal")
+ npdf.mode = 0
+ npdf.data = table.concat(buf, "\n")
+ return npdf
+end
+
+local function append_glyph(head, last, c) --> head, last, xdim
+ if c == 32 then -- space
+ local space = tex.sp "3.5pt"
+ head, last = node.insert_after(head, last, newglue(space))
+ return head, last, space
+ else
+ local g = newglyph(c)
+ local xdim = g.width
+ head, last = node.insert_after(head, last, g)
+ return head, last, xdim
+ end
+end
+
+-- special drawing function
+function PDFnative.hboxcreate(hboxname, st, buf, txt) --> ok, err
+ local node = assert(node, "This is not LuaTeX!")
+ local tex = assert(tex)
+ local font = assert(font)
+ if not tex.isbox(hboxname) then
+ return nil, string.format("Box register [%s] doesn’t exist", hboxname)
+ end
+ local bb_x1, bb_y1, bb_x2, bb_y2 = st.bb_x1, st.bb_y1, st.bb_x2, st.bb_y2
+ local npdf = newpdfliteral(buf) -- node whatsit pdfliteral
+ -- vboxing, vertical correction
+ local vpdf = node.vpack(npdf)
+ vpdf.height = -bb_y1
+ -- glue, for horizontal correction
+ local ng = newglue(-bb_x1)
+ local head, last = node.insert_after(ng, ng, vpdf)
+ local xprev = 0.0
+ for _, t in ipairs(txt) do -- text processing
+ local gy = newglue(t[3] - bb_y1) -- n, x, y, w, h -- t[3] -t[5] - bb_y1
+ local nvtxt = node.insert_after(t[1], t[1], gy)
+ local vtxt = node.vpack(nvtxt)
+ local gx = newglue(t[2]-xprev)
+ head, last = node.insert_after(head, last, gx)
+ head, last = node.insert_after(head, last, vtxt)
+ xprev = t[2] + t[4]
+ end
+ -- hboxing
+ local hbox = node.hpack(head)
+ hbox.width = bb_x2 - bb_x1
+ hbox.height = bb_y2 - bb_y1
+ tex.box[hboxname] = hbox
+ return true, nil
+end
+
+-- PDF literal encoding functions
+
+-- 1 <W: dim>; set line width
+function PDFnative.append_001(st, bf, xt, w)
+ local bp = st.bp -- 1bp (sp)
+ bf[#bf + 1] = string.format("%0.6f w", w/bp)
+end
+
+-- 2 <enum: u8>; set line cap style
+function PDFnative.append_002(st, bf, xt, cap)
+ bf[#bf + 1] = string.format("%d J", cap)
+end
+
+-- 3 <enum: u8>; set line join style
+function PDFnative.append_003(st, bf, xt, j)
+ bf[#bf + 1] = string.format("%d j", j)
+end
+
+-- draw an horizontal line
+-- 33 <x1: DIM> <x2: DIM> <y: DIM>
+function PDFnative.append_033(st, bf, xt, x1, x2, y)
+ local bp = st.bp -- conversion factor bp -> sp
+ bf[#bf + 1] = string.format("% 0.6f %0.6f m", x1/bp, y/bp)
+ bf[#bf + 1] = string.format("% 0.6f %0.6f l", x2/bp, y/bp)
+ bf[#bf + 1] = "S" -- stroke
+end
+
+-- vline
+-- draw a vertical line
+-- 34 <y1: DIM> <y2: DIM> <x: DIM>
+function PDFnative.append_034(st, bf, xt, y1, y2, x)
+ local bp = st.bp -- conversion factor bp -> sp
+ bf[#bf + 1] = string.format("% 0.6f %0.6f m", x/bp, y1/bp)
+ bf[#bf + 1] = string.format("% 0.6f %0.6f l", x/bp, y2/bp)
+ bf[#bf + 1] = "S" -- stroke
+end
+
+-- Vbar
+-- draw a group of vertical lines
+-- 36 <y1: DIM> <y2: DIM> <b: UINT> <x1: DIM> <t1: DIM> ...
+function PDFnative.append_036_bar(st, bf, xt, x, w, y1, y2)
+ local bp = st.bp -- conversion factor bp -> sp
+ local fmt = "%0.6f %0.6f %0.6f %0.6f re"
+ local x1 = x - w/2
+ local h = y2 - y1
+ -- pdf literal insertion <x y w h re>
+ bf[#bf + 1] = string.format(fmt, x1/bp, y1/bp, w/bp, h/bp)
+end
+function PDFnative.append_036_stop(st, bf, xt, nbar, y1, y2)
+ bf[#bf + 1] = "f" -- fill
+ bf[#bf + 1] = "S" -- stroke
+end
+
+-- draw a rectangle
+-- 48 <x1: DIM> <y1: DIM> <x2: DIM> <y2: DIM>
+function PDFnative.append_048(st, bf, xt, x1, y1, x2, y2)
+ local w = x2 - x1 -- rectangle width
+ assert(w > 0)
+ local h = y2 - y1 -- rectangle height
+ assert(h > 0)
+ local bp = st.bp -- conversion factor
+ local fmt = "%0.6f %0.6f %0.6f %0.6f re S"
+ -- pdf literal string <x y w h re>
+ bf[#bf + 1] = string.format(fmt, x1/bp, y1/bp, w/bp, h/bp)
+end
+
+-- 130 <text> Text with several glyphs
+-- 130 <ax: FLOAT> <ay: FLOAT> <xpos: DIM> <ypos: DIM> <c: CHARS>
+function PDFnative.append_130_char(st, bf, xt, c)
+ local head, last = st.head, st.last
+ head, last = append_glyph(head, last, c)
+ st.head = head
+ st.last = last
+end
+-- return bounding box of the text object without deep
+function PDFnative.append_130_stop(st, bf, xt, xpos, ypos, ax, ay)
+ local head = assert(st.head)
+ st.head = nil -- reset temporary reference
+ st.last = nil
+ local hbox = node.hpack(head)
+ local w, h, d = node.dimensions(hbox)
+ local x1 = xpos - ax*w -- text position
+ local y1; if ay > 0 then
+ y1 = ypos - h*ay
+ else
+ y1 = ypos - d*ay
+ end
+ xt[#xt + 1] = {hbox, x1, y1 - d, w, h}
+ return x1, y1, x1 + w, y1 + h
+end
+
+-- 131 <text_xspaced>, Text with glyphs equally spaced on its vertical axis
+-- 131 <x1: DIM> <xgap: DIM> <ay: FLOAT> <ypos: DIM> <c: CHARS>
+function PDFnative.append_131_char(st, bf, xt, c, xgap)
+ local head, last, prec_cw = st.head, st.last, st.cw
+ local cw
+ if prec_cw then
+ local g = newglyph(c)
+ cw = g.width
+ local isp = xgap - (cw + prec_cw)/2
+ local s = newglue(isp)
+ head, last = node.insert_after(head, last, s)
+ head, last = node.insert_after(head, last, g)
+ else -- first char
+ head, last, cw = append_glyph(head, last, c)
+ st.x_hbox = cw/2
+ end
+ st.cw = cw
+ st.head = head
+ st.last = last
+end
+function PDFnative.append_131_stop(st, bf, xt, x1, xgap, ypos, ay) --> bb
+ local head = assert(st.head)
+ st.head = nil -- reset temporary reference
+ st.last = nil
+ st.cw = nil
+ local hbox = node.hpack(head)
+ local w, h, d = node.dimensions(hbox)
+ local bx1 = x1 - st.x_hbox
+ st.x_hbox = nil -- reset temporary references
+ local y1; if ay > 0 then
+ y1 = ypos - h*ay
+ else
+ y1 = ypos - d*ay
+ end
+ xt[#xt + 1] = {hbox, bx1, y1 - d, w, h}
+ return bx1, y1, bx1 + w, y1 + h
+end
+
+-- 132 <text_xwidth> Glyphs equally spaced on vertical axis between two x coordinates
+-- 132 <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS>
+function PDFnative.append_132_char(st, bf, xt, c)
+ local head, last = st.head, st.last
+ if head then
+ local g = newglyph(c)
+ local s = newglue(1)
+ head, last = node.insert_after(head, last, s)
+ head, last = node.insert_after(head, last, g)
+ st.char_counter = st.char_counter + 1
+ else -- first char
+ head, last, cw = append_glyph(head, last, c)
+ st.cw = cw
+ st.char_counter = 1
+ end
+ st.head = head
+ st.last = last
+end
+function PDFnative.append_132_stop(st, bf, xt, x1, x2, ypos, ay) --> p1, p2
+ local head, last = st.head, st.last
+ st.head = nil -- reset temporary registry
+ st.last = nil
+ local w_1 = st.cw
+ st.cw = nil
+ local i = st.char_counter
+ st.char_counter = nil
+ local w_n = last.width
+ local xgap = (x2 - x1 - (w_1 + w_n)/2)/(i - 1)
+ local c_curr = head
+ for _ = 1, i - 1 do
+ local g = c_curr.next
+ local c_next = g.next
+ local w_2
+ w_1, w_2 = c_curr.width, c_next.width
+ g.width = xgap - (w_1 + w_2)/2
+ c_curr = c_next
+ end
+ local hbox = node.hpack(head)
+ local w, h, d = node.dimensions(hbox)
+ local y; if ay > 0 then
+ y = ypos - h*ay
+ else
+ y = ypos - d*ay
+ end
+ xt[#xt + 1] = {hbox, x1, y - d, w, h}
+ return x1, y, x2, y + h
+end
+
+return PDFnative
diff --git a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua
new file mode 100644
index 00000000000..7a2c5ab1128
--- /dev/null
+++ b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua
@@ -0,0 +1,260 @@
+--
+-- ga Intermediate Graphic Language for barcode drawing
+-- SVG library
+-- Copyright (C) 2019 Roberto Giacomelli
+--
+-- All dimension in the ga stream are scaled point (sp)
+-- 1 pt = 65536 sp
+
+-- class for drawing elementary geometric elements
+local SVG = {
+ _VERSION = "SVGdriver v0.0.1",
+ _NAME = "SVGdriver",
+ _DESCRIPTION = "A SVG driver for the ga graphic stream",
+}
+
+SVG.ext = "svg" -- file extension
+SVG.buf_sep = nil -- separation string for buffer concat
+
+function SVG.init_buffer(st) --> buffer, text buffer
+ local bf = {
+ '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n',
+ '<!-- Created with Barracuda package (https://github.com/robitex/barracuda) -->\n',
+ '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n',
+ ' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n',
+ '<svg xmlns="http://www.w3.org/2000/svg"\n',
+ ' version="1.1"\n',
+ ' width="%0.6fmm" height="%0.6fmm"\n', -- line 7
+ ' viewBox="%0.6f %0.6f %0.6f %0.6f"\n', -- line 8
+ '>\n',
+ }
+ -- additions for SVG driver to 'state'
+ st.ident_lvl = 1 -- identation level
+ st.char_buf = nil
+ local mm = st.mm
+ st.h_char = 2.1 * mm -- char height (mm)
+ st.w_char = st.h_char / 1.303 -- avg char width (mm)
+ st.d_char = st.h_char / 3.7 -- char deep (mm)
+ return bf, {}
+end
+
+function SVG.close_buffer(st, bf, xt)
+ bf[#bf + 1] = '</svg>\n' -- close svg xml element
+ bf[#bf + 1] = '\n' -- a last empty line
+ local mm = st.mm
+ local x1, y1, x2, y2 = st.bb_x1, st.bb_y1, st.bb_x2, st.bb_y2
+ local w = (x2 - x1)/mm
+ local h = (y2 - y1)/mm
+ local fmt_wh = bf[7]
+ bf[7] = string.format(fmt_wh, w, h) -- line 7
+ local x, y = x1/mm, -y2/mm
+ local fmt_vw = bf[8]
+ bf[8] = string.format(fmt_vw, x, y, w, h)
+end
+
+-- SVG encoding functions
+
+-- 1 <W: dim>; set line width
+function SVG.append_001(st, bf, xt, w)
+ -- nothing to do
+end
+
+-- draw an horizontal line
+-- 33 <x1: DIM> <x2: DIM> <y: DIM>
+function SVG.append_033(st, bf, xt, x1, x2, y)
+ local lvl = st.ident_lvl
+ local ident = string.rep(" ", lvl) -- a couple of spaces as indentation
+ local mm = st.mm -- conversion ratio sp -> bp
+ bf[#bf + 1] = string.format( -- <path> element
+ '%s<path d="M%0.6f %0.6fH%0.6f"\n',
+ ident, x1/mm, -y/mm, x2/mm
+ )
+ local lw = st.line_width
+ bf[#bf + 1] = string.format(
+ '%s style="stroke:#000000;stroke-width:%0.6f"\n',
+ ident, lw/mm
+ )
+ bf[#bf + 1] = ident..'/>\n'
+end
+
+-- Vertical line: 34 <y1: DIM> <y2: DIM> <x: DIM>
+function SVG.append_034(st, bf, xt, y1, y2, x)
+ local lvl = st.ident_lvl
+ local ident = string.rep(" ", lvl) -- a couple of spaces as indentation
+ local mm = st.mm -- conversion ratio sp -> mm
+ bf[#bf + 1] = string.format( -- <path> element
+ '%s<path d="M%0.6f %0.6fV%0.6f"\n',
+ ident, x/mm, -y2/mm, -y1/mm
+ )
+ local lw = st.line_width
+ bf[#bf + 1] = string.format(
+ '%s style="stroke:#000000;stroke-width:%0.6f"\n',
+ ident, lw/mm
+ )
+ bf[#bf + 1] = ident..'/>\n'
+end
+
+-- Vbar
+-- draw a group of vertical lines
+-- 36 <y1: DIM> <y2: DIM> <b: UINT> <x1: DIM> <t1: DIM> ...
+function SVG.append_036_start(st, bf, xt, nbar, y1, y2)
+ local lvl = st.ident_lvl
+ local ident = string.rep(" ", lvl)
+ bf[#bf + 1] = ident..'<g stroke="black">\n' -- open a group
+ st.ident_lvl = lvl + 1
+end
+function SVG.append_036_bar(st, bf, xt, x, w, y1, y2)
+ local lvl = st.ident_lvl
+ local ident = string.rep(" ", lvl)
+ local mm = st.mm -- conversion factor mm -> sp
+ bf[#bf + 1] = string.format(
+ '%s<path d="M%0.6f %0.6fV%0.6f" style="stroke-width:%0.6f"/>\n',
+ ident, x/mm, -y2/mm, -y1/mm, w/mm
+ )
+end
+function SVG.append_036_stop(st, bf, xt, nbar, y1, y2)
+ st.ident_lvl = st.ident_lvl - 1
+ local ident = string.rep(" ", st.ident_lvl)
+ bf[#bf + 1] = ident..'</g>\n' -- end group
+end
+
+-- Text
+-- 130 <text> Text with several glyphs
+-- 130 <ax: FLOAT> <ay: FLOAT> <xpos: DIM> <ypos: DIM> <c: CHARS>
+function SVG.append_130_char(st, bf, xt, c)
+ local ch = string.char(c)
+ if not st.char_buf then
+ st.char_buf = {ch}
+ else
+ local chars = st.char_buf
+ chars[#chars + 1] = ch
+ end
+end
+function SVG.append_130_stop(st, bf, xt, xpos, ypos, ax, ay) --> p1, p2
+ local c = st.char_buf
+ st.char_buf = nil
+ local txt = table.concat(c)
+ local w = st.w_char * #c -- approx dim
+ local h = st.h_char
+ local d = st.d_char
+ local anchor = ""
+ local x1 = xpos
+ local bx1 = xpos
+ if ax == 0 then -- start (default)
+ elseif ax == 0.5 then -- middle
+ anchor = ' text-anchor="middle"'
+ bx1 = bx1 - w/2
+ elseif ax == 1 then -- end
+ anchor = ' text-anchor="end"'
+ bx1 = bx1 - w
+ else
+ x1 = x1 - ax*w
+ bx1 = x1
+ end
+ local y1 = ypos
+ if ay > 0 then
+ y1 = y1 - h*ay
+ else
+ y1 = y1 - d*ay
+ end
+ local fs = st.h_char * 1.37 -- sp
+ local lvl = st.ident_lvl
+ local ident = string.rep(" ", lvl)
+ local mm = st.mm
+ bf[#bf + 1] = string.format(
+ '%s<text x="%0.6f" y="%0.6f" font-family="Verdana" font-size="%0.6f"%s>\n',
+ ident, x1/mm, -y1/mm, fs/mm, anchor
+ )
+ bf[#bf + 1] = ident..txt
+ bf[#bf + 1] = ident..'</text>\n'
+ return bx1, y1, bx1 + w, y1 + h
+end
+
+-- 131 <text_xspaced>, Text with glyphs equally spaced on its vertical axis
+-- 131 <x1: DIM> <xgap: DIM> <ay: FLOAT> <ypos: DIM> <c: CHARS>
+function SVG.append_131_char(st, bf, xt, c, xgap)
+ local ch = string.char(c)
+ if not st.char_buf then
+ st.char_buf = {ch}
+ else
+ local chars = st.char_buf
+ chars[#chars + 1] = ch
+ end
+end
+function SVG.append_131_stop(st, bf, xt, x1, xgap, ypos, ay) --> p1, p2
+ local chars = st.char_buf
+ st.char_buf = nil
+ local n = #chars
+ local h = st.h_char -- height
+ local d = st.d_char -- deep
+ local hw = st.w_char/2 -- sp half width
+ local y1 = ypos
+ if ay > 0 then
+ y1 = y1 - h*ay
+ else
+ y1 = y1 - d*ay
+ end
+ local lvl = st.ident_lvl
+ local ident = string.rep(" ", lvl)
+ local fs = st.h_char * 1.37 -- (sp) font-size -> inter baselines distance
+ local mm = st.mm
+ bf[#bf + 1] = string.format(
+ '%s<text y="%0.6f" font-family="Verdana" font-size="%0.6f" text-anchor="middle">\n',
+ ident, -y1/mm, fs/mm
+ )
+ local x = x1
+ for _, c in ipairs(chars) do
+ bf[#bf + 1] = string.format('%s<tspan x="%0.6f">%s</tspan>\n',
+ ident, x/mm, c
+ )
+ x = x + xgap
+ end
+ bf[#bf + 1] = ident..'</text>\n'
+ local x2 = x1 + (n - 1)*xgap -- sp
+ return x1 - hw, y1, x2 + hw, y1 + h -- text group bounding box
+end
+
+-- 132 <text_xwidth> Glyphs equally spaced on vertical axis between two x coordinates
+-- 132 <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS>
+function SVG.append_132_char(st, bf, xt, c, xgap)
+ local ch = string.char(c)
+ if not st.char_buf then
+ st.char_buf = {ch}
+ else
+ local chars = st.char_buf
+ chars[#chars + 1] = ch
+ end
+end
+function SVG.append_132_stop(st, bf, xt, x1, x2, ypos, ay) --> p1, p2
+ local chars = st.char_buf; st.char_buf = nil
+ local n = #chars
+ local h = st.h_char -- height (approx)
+ local d = st.d_char -- deep (approx)
+ local cw = st.w_char -- (sp) char width (approx)
+ local xgap = (x2 - x1 - cw)/(n - 1)
+ local y1 = ypos
+ if ay > 0 then
+ y1 = y1 - h*ay
+ else
+ y1 = y1 - d*ay
+ end
+ local lvl = st.ident_lvl
+ local ident = string.rep(" ", lvl)
+ local fs = st.h_char * 1.37 -- font-size -> inter baselines distance
+ local mm = st.mm
+ bf[#bf + 1] = string.format(
+ '%s<text y="%0.6f" font-family="Verdana" font-size="%0.6f" text-anchor="middle">\n',
+ ident, -y1/mm, fs/mm
+ )
+ local x = x1 + cw/2
+ for _, c in ipairs(chars) do
+ bf[#bf + 1] = string.format('%s<tspan x="%0.6f">%s</tspan>\n',
+ ident, x/mm, c
+ )
+ x = x + xgap
+ end
+ bf[#bf + 1] = ident..'</text>\n'
+ return x1, y1, x2, y1 + h -- text group bounding box
+end
+
+return SVG