diff options
author | Karl Berry <karl@freefriends.org> | 2019-12-05 21:23:07 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-12-05 21:23:07 +0000 |
commit | 0ed7b2cd92f7a81334f612df3e37211f8333ae75 (patch) | |
tree | 2bcbe01d8e86cbf57d64069a153346da4936b00a /Master/texmf-dist/scripts/barracuda/lib-driver | |
parent | 7f43f3692e1354166c0623faf83c84b23d041ea3 (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')
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 |