diff options
Diffstat (limited to 'macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua')
-rw-r--r-- | macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua | 563 |
1 files changed, 436 insertions, 127 deletions
diff --git a/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua b/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua index 86eba659d1..fc58a85b7b 100644 --- a/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua +++ b/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua @@ -1,86 +1,208 @@ -- class gaCanvas --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli +-- <ga> encoding functions (see barracuda-manual.pdf) --- ga -- basic function - -local gaCanvas = { - _VERSION = "gacanvas v0.0.4", - _NAME = "gaCanvas", - _DESCRIPTION = "A library for dealing with ga stream", -} +local gaCanvas = {_classname = "gaCanvas"} gaCanvas.__index = gaCanvas +gaCanvas.mm = 186467.98110236 -- conversion factor sp -> mm (millimeter) +gaCanvas.bp = 65781.76 -- conversion factor sp -> bp (big point) +gaCanvas.pt = 65536 -- sp -> pt -- ga specification: see the file ga-grammar.pdf in the doc directory -- gaCanvas constructor function gaCanvas:new() --> object - local o = { - _data = {}, - _v = 100, -- version of the ga format - } + local drv = assert(self._driver_class) + -- graphic state fields returned by Driver:default_style() method + -- linewidth + -- linecap + -- linejoin + -- dashpattern + -- dashphase + local o = assert(drv:default_style()) -- initial graphic state + o._version = 100 -- version of the ga format + o._data = {} -- ga stream array + o.bb_on = true setmetatable(o, self) return o end --- Ipothetical another constructor +-- save graphic data in an external file with the 'id_drv' format +-- id_drv::= string, specific driver output identifier +-- filename ::= string, file name +-- ext ::= string, file extension (optional, default SVG) +function gaCanvas:save(id_drv, filename, ext) --> ok, err + local driver = self._driver_class + return driver:save(id_drv, self, filename, ext) +end + +-- insert a ga drawing in a TeX hbox +-- PDFnative only function +-- boxname ::= string +function gaCanvas:ga_to_hbox(boxname) --> ok, err + local driver = self._driver_class + return driver:ga_to_hbox(self, boxname) +end + +-- return a clone of the <ga> stream array +function gaCanvas:get_stream() --> table (as a flat array) + local data = self._data + local t = {} + for _, v in ipairs(data) do + t[#t + 1] = v + end + return t +end + +-- Ipothetical further constructor -- function gaCanvas:from_tcp_server() --> err -- end +-- function gaCanvas:get_bbox() +-- end + +-- function gaCanvas:check() --> ok, err +-- end + -- line width: opcode <1> <w: DIM> -function gaCanvas:encode_linethick(w) --> err - if type(w) ~= "number" then return "[ArgErr] 'w' number expected" end - if w < 0 then return "[ArgErr] negative value for 'w'" end +function gaCanvas:encode_linewidth(w) --> ok, err + if type(w) ~= "number" then + return false, "[ArgErr 'w'] number expected" + end + if w < 0 then return false, "[ArgErr: w] negative number not allowed" end + self.linewidth = w local data = self._data data[#data + 1] = 1 -- opcode for line thickness data[#data + 1] = w + return true, nil end --- line cap style: opcode <2> <cap: u8> --- 0 Butt cap --- 1 Round cap --- 2 Projecting square cap -function gaCanvas:encode_linecap(cap) --> err - if type(cap) ~= "number" then return "[ArgErr] 'cap' arg number expected" end - if cap == 0 or cap == 1 or cap == 2 then - local data = self._data - data[#data + 1] = 2 -- opcode for line cap style - data[#data + 1] = cap +-- line cap style: opcode <2> cap <u8>|<enum> +-- 0 | "butt": Butt cap +-- 1 | "round": Round cap +-- 2 | "proj": Projecting square cap +function gaCanvas:encode_linecap(cap) --> ok, err + local tcap = type(cap) + local cap_res + if tcap == "number" then + if cap == 0 or cap == 1 or cap == 2 then + cap_res = cap + else + return false, "[ArgErr: cap] 0, 1 or 2 expected" + end + elseif tcap == "string" then + if cap == "butt" then + cap_res = 0 + elseif cap == "round" then + cap_res = 1 + elseif cap == "proj" then + cap_res = 2 + else + return false, "[ArgErr: cap] 'butt', 'round' or 'proj' expected" + end else - return "[ArgErr] invalid value for 'cap'" + return false, "[ArgErr: cap] number or string expected" end + self.linecap = cap_res + local data = self._data + data[#data + 1] = 2 -- opcode for line cap style + data[#data + 1] = cap_res + return true, nil end --- line cap style: opcode <3> <join: u8> --- 0 Miter join --- 1 Round join --- 2 Bevel join -function gaCanvas:encode_linejoin(join) --> err - if type(join) ~= "number" then return "[ArgErr] 'join' arg number expected" end - if join == 0 or join == 1 or join == 2 then - local data = self._data - data[#data + 1] = 3 -- opcode for line join style - data[#data + 1] = join +-- line join style: opcode <3> join <u8>|<enum> +-- 0 | "miter" : Miter join +-- 1 | "round" : Round join +-- 2 | "bevel" : Bevel join +function gaCanvas:encode_linejoin(join) --> ok, err + local tjoin = type(join) + local join_res + if tjoin == "number" then + if join == 0 or join == 1 or join == 2 then + join_res = join + else + return false, "[ArgErr: join] 0, 1 or 2 integer expected" + end + elseif tjoin == "string" then + if join == "miter" then + join_res = 0 + elseif join == "round" then + join_res = 1 + elseif join == "bevel" then + join_res = 2 + else + return false, "[ArgErr: join] '"..join.."' join style not found" + end else - return "[ArgErr] invalid value for 'join'" + return false, "[ArgErr: join] number or string expected" + end + self.linejoin = join_res + local data = self._data + data[#data + 1] = 3 -- opcode for line join style + data[#data + 1] = join_res + return true, nil +end + +-- 5 <dash_pattern>, Dash pattern line style, p <len> n <qty> bi <len> +-- p: phase lenght +-- n: number of array element +-- [bi]: dash array of dash and gap lenghts +function gaCanvas:encode_dash_pattern(p, ...) --> ok, err + if type(p) ~= "number" then return false, "[ArgErr: phase] number expected" end + local t = {...} + for i, v in ipairs(t) do + if type(v) ~= "number" then + return false, "[ArgErr: array] found a not number value at index " .. i + end + end + self.dash_pattern = t + self.dash_phase = p + local n = #t + local d = self._data + d[#d + 1] = 5 + d[#d + 1] = p + d[#d + 1] = n + for _, b in ipairs(t) do + d[#d + 1] = b end + return true, nil +end + +-- 6 <reset_pattern>, set the continous line style +function gaCanvas:encode_reset_pattern() --> ok, err + self.dash_pattern = nil + self.dash_phase = nil + local d = self._data + d[#d + 1] = 6 + return true, nil +end + +-- checking the bounding box from now on +-- opcode: <29> +function gaCanvas:encode_enable_bbox() --> ok, err + self.bb_on = true + local data = self._data + data[#data + 1] = 29 + return true, nil end -- Stop checking the bounding box -- opcode: <30> -function gaCanvas:start_bbox_group() --> err +function gaCanvas:encode_disable_bbox() --> ok, err + self.bb_on = false local data = self._data data[#data + 1] = 30 + return true, nil end --- restart checking the bounding box --- and insert the specified bb for the entire object group +-- insert a figure bbox -- code: <31> x1 y1 x2 y2 -function gaCanvas:stop_bbox_group(x1, y1, x2, y2) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end - if x1 > x2 then x1, x2 = x2, x1 end -- reorder coordinates +function gaCanvas:encode_set_bbox(x1, y1, x2, y2) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(y1) ~= "number" then return false, "[ArgErr: y1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(y2) ~= "number" then return false, "[ArgErr: y2] number expected" end + if x1 > x2 then x1, x2 = x2, x1 end -- re-order coordinates if y1 > y2 then y1, y2 = y2, y1 end local data = self._data data[#data + 1] = 31 -- bounding box of the object group @@ -88,174 +210,368 @@ function gaCanvas:stop_bbox_group(x1, y1, x2, y2) --> err data[#data + 1] = y1 data[#data + 1] = x2 data[#data + 1] = y2 + return true, nil end -- insert a line from point (x1, y1) to the point (x2, y2) +-- tx optional translator x-vector +-- ty optional translator y-vector -- <32> x1 y1 x2 y2 -function gaCanvas:encode_line(x1, y1, x2, y2) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end +function gaCanvas:encode_line(x1, y1, x2, y2, tx, ty) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(y1) ~= "number" then return false, "[ArgErr: y1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(y2) ~= "number" then return false, "[ArgErr: y2] number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty + end local data = self._data data[#data + 1] = 32 -- append line data data[#data + 1] = x1 data[#data + 1] = y1 data[#data + 1] = x2 data[#data + 1] = y2 + return true, nil end -- insert an horizontal line from point (x1, y) to point (x2, y) +-- tx optional translator x-vector +-- ty optional translator y-vector -- <33> x1 x2 y -function gaCanvas:encode_hline(x1, x2, y) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y) ~= "number" then return "[ArgErr] 'y2' number expected" end +function gaCanvas:encode_hline(x1, x2, y, tx, ty) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(y) ~= "number" then return false, "[ArgErr: y] number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y = y + ty + end local data = self._data data[#data + 1] = 33 -- append hline data data[#data + 1] = x1 data[#data + 1] = x2 data[#data + 1] = y + return true, nil +end + +-- vline, Vertical line, from point (x, y1) to point (x, y2) +-- tx optional translator x-vector +-- ty optional translator y-vector +-- <34> y1 y2 x +function gaCanvas:encode_vline(y1, y2, x, tx, ty) --> ok, err + if type(y1) ~= "number" then return false, "[ArgErr] 'y1' number expected" end + if type(y2) ~= "number" then return false, "[ArgErr] 'y2' number expected" end + if type(x) ~= "number" then return false, "[ArgErr] 'x' number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x = x + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty + end + local data = self._data + data[#data + 1] = 34 -- append vline data + data[#data + 1] = y1 + data[#data + 1] = y2 + data[#data + 1] = x + return true, nil +end + +-- insert an open polyline +-- tx optional translator x-vector +-- ty optional translator y-vector +-- <38> <n> x1 y1 x2, y2, ... , xn, yn +function gaCanvas:encode_polyline(point, tx, ty) --> ok, err + if type(point) ~= "table" then + return false, "[ArgErr: point] table expected" + end + local n, p + if point._classname == "Polyline" then + n, p = point:get_points() + else + local len = #point + if len == 0 then return false, "[Err] 'point' is an empty table" end + if (len % 2) ~= 0 then + return false, "[Err] 'point' is not an even long array" + end + n = len/2 + for _, coord in ipairs(point) do + if type(coord) ~= "number" then + return false, "[Err] found a non-number in the 'point' array" + end + end + p = point + end + if n < 2 then return + false, "[Err] a polyline must have at least two points" + end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + else + tx = 0 + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + else + ty = 0 + end + local data = self._data + data[#data + 1] = 38 + data[#data + 1] = n + for i = 1, 2*n, 2 do + data[#data + 1] = p[i] + tx + data[#data + 1] = p[i + 1] + ty + end + return true, nil end -- insert a rectangle from point (x1, x2) to (x2, y2) +-- tx optional translator x-vector +-- ty optional translator y-vector -- <48> <x1: DIM> <y1: DIM> <x2: DIM> <y2: DIM> -function gaCanvas:encode_rectangle(x1, y1, x2, y2) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end +function gaCanvas:encode_rect(x1, y1, x2, y2, tx, ty) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr] 'x1' number expected" end + if type(y1) ~= "number" then return false, "[ArgErr] 'y1' number expected" end + if type(x2) ~= "number" then return false, "[ArgErr] 'x2' number expected" end + if type(y2) ~= "number" then return false, "[ArgErr] 'y2' number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty + end local d = self._data d[#d + 1] = 48 -- append rectangle data d[#d + 1] = x1 d[#d + 1] = y1 d[#d + 1] = x2 d[#d + 1] = y2 + return true, nil end -- Vbar object: opcode <36> +-- tx optional translator x-vector +-- ty optional translator y-vector -- x0, y1, y2 ordinates -function gaCanvas:encode_Vbar(vbar, x0, y1, y2) --> err +function gaCanvas:encode_vbar(vbar, x0, y1, y2, tx, ty) --> ok, err if type(vbar) ~= "table" then - return "[ArgErr] table expected for 'vbar'" + return false, "[ArgErr: vbar] table expected" end if x0 == nil then x0 = 0 elseif type(x0) ~= "number" then - return "[ArgErr] 'x0' number expected" + return false, "[ArgErr: x0] number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end + if type(y1) ~= "number" then return false, "[ArgErr: y1] number expected" end + if type(y2) ~= "number" then return false, "[ArgErr: y2] number expected" end -- ordinates - if y1 == y2 then return "[ArgErr] 'y1' 'y2' are the same value" end + if y1 == y2 then return false, "[ArgErr: y1, y2] same value" end if y1 > y2 then y1, y2 = y2, y1 end - local bars = assert(vbar._yline, "[InternalErr] no '_yline' field") - local bdim = #bars - if bdim == 0 then return "[InternalErr] number of bars is zero" end - if bdim % 2 ~= 0 then - return "[InternalErr] '_yline' does not have an even number of elements" + local bdim, bars + if vbar._classname == "Vbar" then + bdim, bars = vbar:get_bars() + bdim = 2*bdim + else + bdim = #vbar + if bdim % 2 ~= 0 then -- bdim must be even + return false, "[Err: vbar] found an odd array of elements" + end + bars = vbar + end + if bdim == 0 then return false, "[Err: vbar] the number of bars is zero" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x0 = x0 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty end local data = self._data data[#data + 1] = 36 -- vbar sequence start data[#data + 1] = y1 data[#data + 1] = y2 - data[#data + 1] = bdim / 2 -- the number of bars <x_i t_i> + data[#data + 1] = bdim/2 -- the number of bars, pair <x_i, w_i> for i = 1, bdim, 2 do local coord = bars[i] local width = bars[i + 1] if type(coord) ~= "number" then - return "[Err] a coordinates is not a number" + return false, "[Err] a coordinates is not a number" end if type(width) ~= "number" then - return "[Err] a width is not a number" + return false, "[Err] a width is not a number" end data[#data + 1] = coord + x0 data[#data + 1] = width end + return true, nil end --- [text] <130> ax ay x y chars -function gaCanvas:encode_Text(txt, xpos, ypos, ax, ay) --> err +-- print a Vbar queue starting at x position 'xpos', between the horizontal line +-- tx optional translator x-vector +-- ty optional translator y-vector +-- at y0 and y1 y-coordinates +function gaCanvas:encode_vbar_queue(queue, xpos, y0, y1, tx, ty) --> ok, err + -- check arg + if type(queue) ~= "table" then + return false, "[ArgErr: queue] table expected" + end + if type(xpos) ~= "number" then + return false, "[ArgErr: xpos] number expected" + end + if type(y0) ~= "number" then + return false, "[ArgErr: y0] number expected" + end + if type(y1) ~= "number" then + return false, "[ArgErr: y1] number expected" + end + local i = 2 + while queue[i] do + local x = queue[i - 1] + xpos + local vbar = queue[i] + local _, err = self:encode_vbar(vbar, x, y0, y1, tx, ty) + if err then return false, err end + i = i + 2 + end + return true, nil +end + +-- tx optional translator x-vector +-- ty optional translator y-vector +-- [text] <130> ax ay xpos ypos chars +function gaCanvas:encode_Text(txt, xpos, ypos, ax, ay, tx, ty) --> ok, err if type(txt) ~= "table" then - return "[ArgErr] 'txt' object table expected" + return false, "[ArgErr: txt] object table expected" end if type(xpos) ~= "number" then - return "[ArgErr] 'xpos' number expected" + return false, "[ArgErr: xpos] number expected" end if type(ypos) ~= "number" then - return "[ArgErr] 'ypos' number expected" + return false, "[ArgErr: ypos] number expected" end if ax == nil then ax = 0 elseif type(ax) ~= "number" then - return "[ArgErr] 'ax' number expected" + return false, "[ArgErr: ax] number expected" end if ay == nil then ay = 0 elseif type(ay) ~= "number" then - return "[ArgErr] 'ay' number expected" + return false, "[ArgErr: ay] number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + xpos = xpos + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + ypos = ypos + ty + end + local chars = assert(txt.codepoint, "[InternalErr: txt] no 'codepoint' found") + if #chars == 0 then return false, "[InternalErr: txt] no chars found" end local data = self._data data[#data + 1] = 130 data[#data + 1] = ax -- relative anchor x-coordinate data[#data + 1] = ay -- relative anchor y-coordinate data[#data + 1] = xpos -- text x-coordinate data[#data + 1] = ypos -- text y-coordinate - local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") - if #chars == 0 then return "[InternalErr] 'txt' has no chars" end for _, c in ipairs(chars) do data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- glyphs equally spaced along the baseline +-- tx optional translator x-vector +-- ty optional translator y-vector -- [text_xspaced] <131> x1 xgap ay ypos chars -function gaCanvas:encode_Text_xspaced(txt, x1, xgap, ypos, ay) --> err - if type(txt)~= "table" then return "[ArgErr] 'txt' object table expected" end - local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") - if #chars == 0 then return "[InternalErr] 'txt' has no chars" end - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(xgap) ~= "number" then return "[ArgErr] 'xgap' number expected" end +function gaCanvas:encode_Text_xspaced(txt, x1, xgap, ypos, ay, tx, ty) --> ok, err + if type(txt)~= "table" then return false, "[ArgErr: txt] object table expected" end + local chars = assert(txt.codepoint, "[InternalErr: txt] no 'codepoint' found") + local n = #chars + if n == 0 then return false, "[InternalErr: txt] no chars found" end + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(xgap) ~= "number" then return false, "[ArgErr: xgap] number expected" end if xgap < 0 then local n = #chars x1 = x1 + (n - 1) * xgap xgap = -xgap end - if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end + if type(ypos) ~= "number" then return false, "[ArgErr: ypos] number expected" end if ay == nil then ay = 0 elseif type(ay) ~= "number" then - return "[ArgErr] 'ay' number expected" + return false, "[ArgErr: ay] number expected" + end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + ypos = ypos + ty end local data = self._data data[#data + 1] = 131 data[#data + 1] = x1 -- x-coordinate of the first axis from left to right - data[#data + 1] = xgap -- axial distance among gliphs + data[#data + 1] = xgap -- axial distance between gliphs data[#data + 1] = ay -- anchor relative y-coordinate data[#data + 1] = ypos -- text y-coordinate for _, c in ipairs(chars) do data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- text_xwidth +-- tx optional translator x-vector +-- ty optional translator y-vector -- text equally spaced but within [x1, x2] coordinate interval -- <132> <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS> -function gaCanvas:encode_Text_xwidth(txt, x1, x2, ypos, ay) --> err - if type(txt)~= "table" then return "[ArgErr] 'txt' object table expected" end - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end +function gaCanvas:encode_Text_xwidth(txt, x1, x2, ypos, ay, tx, ty) --> ok, err + if type(txt)~= "table" then return false, "[ArgErr: txt] object table expected" end + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(ypos) ~= "number" then return false, "[ArgErr: ypos] number expected" end if ay == nil then ay = 0 elseif type(ay) ~= "number" then - return "[ArgErr] 'ay' number expected" + return false, "[ArgErr: ay] number expected" end - local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") - if #chars == 0 then return "[InternalErr] 'txt' has no chars" end + local chars = assert(txt.codepoint, "[InternalErr: txt] no 'codepoint' found") + if #chars == 0 then return false, "[InternalErr: txt] no chars found" end if x1 > x2 then x1, x2 = x2, x1 end -- reorder coordinates + + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + ypos = ypos + ty + end local data = self._data data[#data + 1] = 132 data[#data + 1] = ay -- anchor relative y-coordinate @@ -266,32 +582,35 @@ function gaCanvas:encode_Text_xwidth(txt, x1, x2, ypos, ay) --> err data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- experimental code section -- new opcodes under assessment -- [start_text_group] 140 -function gaCanvas:start_text_group() --> err +function gaCanvas:start_text_group() --> ok, err local data = self._data data[#data + 1] = 140 + return true, nil end -- [gtext] 141 -function gaCanvas:gtext(chars) --> err - if type(chars) ~= "table" then return "[ArgErr] 'chars' table expected" end +function gaCanvas:gtext(chars) --> ok, err + if type(chars) ~= "table" then return false, "[ArgErr: chars] table expected" end local data = self._data data[#data + 1] = 141 for _, c in ipairs(chars) do data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- [gtext_spaced] 142 gap string -function gaCanvas:gtext_spaced(gap, chars) --> err - if type(gap) ~= "number" then return "[ArgErr] 'gap' number expected" end - if type(chars) ~= "table" then return "[ArgErr] 'chars' table expected" end +function gaCanvas:gtext_spaced(gap, chars) --> ok, err + if type(gap) ~= "number" then return false, "[ArgErr: gap] number expected" end + if type(chars) ~= "table" then return false, "[ArgErr: chars] table expected" end local data = self._data data[#data + 1] = 142 data[#data + 1] = gap @@ -299,42 +618,32 @@ function gaCanvas:gtext_spaced(gap, chars) --> err data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- [gtext_space] 143 gap -function gaCanvas:gtext_gap(gap) --> err - if type(gap) ~= "number" then return "[ArgErr] 'gap' number expected" end +function gaCanvas:gtext_gap(gap) --> ok, err + if type(gap) ~= "number" then return false, "[ArgErr: gap] number expected" end local data = self._data data[#data + 1] = 143 data[#data + 1] = gap + return true, nil end -- [end_text_group] 149 ax ay x y -function gaCanvas:end_text_group(xpos, ypos, ax, ay) --> err - if type(xpos) ~= "number" then return "[ArgErr] 'xpos' number expected" end - if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end - if type(ax) ~= "number" then return "[ArgErr] 'ax' number expected" end - if type(ay) ~= "number" then return "[ArgErr] 'ay' number expected" end +function gaCanvas:end_text_group(xpos, ypos, ax, ay) --> ok, err + if type(xpos) ~= "number" then return false, "[ArgErr: xpos] '' number expected" end + if type(ypos) ~= "number" then return false, "[ArgErr: ypos] number expected" end + if type(ax) ~= "number" then return false, "[ArgErr: ax] number expected" end + if type(ay) ~= "number" then return false, "[ArgErr: ay] number expected" end local data = self._data data[#data + 1] = 149 data[#data + 1] = ax -- anchor relative x-coordinate data[#data + 1] = ay -- anchor relative y-coordinate data[#data + 1] = xpos -- text x-coordinate data[#data + 1] = ypos -- text y-coordinate -end - --- amazing... -function gaCanvas:to_string() --> string - -end - -function gaCanvas:get_bbox() - -end - -function gaCanvas:check() --> boolean, err - + return true, nil end return gaCanvas |