--
-- ga Intermediate Graphic Language for barcode drawing
-- SVG driver for the ga graphic stream
-- Copyright (C) 2019-2022 Roberto Giacomelli
--
-- All dimension in the ga stream are scaled point (sp)
-- 1 pt = 65536 sp
-- class for drawing elementary geometric elements
local SVG = {_drvname = "SVG"}
SVG.ext = "svg" -- file extension
SVG.buf_sep = nil -- separation string for buffer concat
function SVG.init_buffer(st) --> buffer, text buffer
local bf = {
'\n',
'\n',
'\n',
'\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 or 0, st.bb_y1 or 0, st.bb_x2 or 0, st.bb_y2 or 0
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 ; set line width
function SVG.append_001(st, bf, xt, w) -- nothing to do
end
-- 2 ; set line cap style
function SVG.append_002(st, bf, xt, cap) -- nothing to do
end
-- 3 ; set line join style
function SVG.append_003(st, bf, xt, j) -- nothing to do
end
-- 5
function SVG.append_005(st, bf, xt) -- nothing to do
end
-- 6
function SVG.append_006(st, bf, xt) -- nothing to do
end
-- draw an horizontal line opcode
-- 33
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( -- element
'%s= 0)
if phase > 0 then
bf[#bf + 1] = string.format(
'%s stroke-dashoffset="%0.6f"\n', ident, phase/mm
)
end
end
bf[#bf + 1] = ident..'/>\n'
end
-- Vertical line: 34
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( -- element
'%s= 0)
if phase > 0 then
bf[#bf + 1] = string.format(
'%s stroke-dashoffset="%0.6f"\n', ident, phase/mm
)
end
end
bf[#bf + 1] = ident..'/>\n'
end
-- Vbar
-- draw a group of vertical lines
-- 36 ...
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..'\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\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..'\n' -- end group
end
-- Polyline
-- draw a polyline
-- 38 ...
function SVG.append_038_start(st, bf, xt, n, x1, y1)
local lvl = st.ident_lvl
local ident = string.rep(" ", lvl)
local mm = st.mm -- conversion factor mm -> sp
local style = string.format(
'%s= 0)
if phase > 0 then
style = string.format(
'%s stroke-dashoffset="%0.6f"', style, phase/mm
)
end
end
bf[#bf + 1] = style..'>\n'
ident = ident .. " "
bf[#bf + 1] = string.format('%s sp
bf[#bf + 1] = string.format('\n%s%0.6f,%0.6f', ident, x/mm, -y/mm)
end
function SVG.append_038_stop(st, bf, xt)
bf[#bf + 1] = '"/>\n' -- closing tag
local lvl = st.ident_lvl - 1
local ident = string.rep(" ", lvl)
st.ident_lvl = lvl
bf[#bf + 1] = ident..'\n' -- close the group
end
-- draw a rectangle
-- 48
function SVG.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 mm = st.mm -- conversion factor mm -> sp
local lvl = st.ident_lvl
local ident = string.rep(" ", lvl)
local fmt = '%s= 0)
if phase > 0 then
bf[#bf + 1] = string.format(
'%s stroke-dashoffset="%0.6f"\n', ident, phase/mm
)
end
end
bf[#bf + 1] = ident..'/>\n'
end
-- Text
-- 130 Text with several glyphs
-- 130
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\n',
ident, x1/mm, -y1/mm, fs/mm, anchor
)
bf[#bf + 1] = ident..txt
bf[#bf + 1] = ident..'\n'
return bx1, y1, bx1 + w, y1 + h
end
-- 131 , Text with glyphs equally spaced on its vertical axis
-- 131
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\n',
ident, -y1/mm, fs/mm
)
local x = x1
for _, c in ipairs(chars) do
bf[#bf + 1] = string.format('%s%s\n',
ident, x/mm, c
)
x = x + xgap
end
bf[#bf + 1] = ident..'\n'
local x2 = x1 + (n - 1)*xgap -- sp
return x1 - hw, y1, x2 + hw, y1 + h -- text group bounding box
end
-- 132 Glyphs equally spaced on vertical axis between two x coordinates
-- 132
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\n',
ident, -y1/mm, fs/mm
)
local x = x1 + cw/2
for _, c in ipairs(chars) do
bf[#bf + 1] = string.format('%s%s\n',
ident, x/mm, c
)
x = x + xgap
end
bf[#bf + 1] = ident..'\n'
return x1, y1, x2, y1 + h -- text group bounding box
end
return SVG