summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua')
-rw-r--r--macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua287
1 files changed, 227 insertions, 60 deletions
diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua
index b43bc511d7..1208adeb75 100644
--- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua
+++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua
@@ -1,13 +1,8 @@
-
-- Barcode Abstract Class
--- Copyright (C) 2020 Roberto Giacomelli
+-- Copyright (C) 2019-2022 Roberto Giacomelli
-- Please see LICENSE.TXT for any legal information about present software
-local Barcode = {
- _VERSION = "Barcode v0.0.9",
- _NAME = "Barcode",
- _DESCRIPTION = "Barcode abstract class",
-}
+local Barcode = {_classname = "Barcode"}
Barcode.__index = Barcode
-- barcode_type/submodule name
@@ -16,6 +11,7 @@ Barcode._available_enc = {-- keys must be lowercase
code128 = "lib-barcode.brcd-code128", -- Code128
ean = "lib-barcode.brcd-ean", -- EAN family (ISBN, EAN8, etc)
i2of5 = "lib-barcode.brcd-i2of5", -- Interleaved 2 of 5
+ upc = "lib-barcode.brcd-upc", -- UPC
}
Barcode._builder_instances = {} -- encoder builder instances repository
Barcode._encoder_instances = {} -- encoder instances repository
@@ -24,6 +20,7 @@ Barcode._encoder_instances = {} -- encoder instances repository
Barcode._super_par_order = {
"ax",
"ay",
+ "debug_bbox",
}
Barcode._super_par_def = {}
local pardef = Barcode._super_par_def
@@ -36,7 +33,7 @@ pardef.ax = {
default = 0.0,
unit = "sp", -- scaled point
isReserved = false,
- fncheck = function (self, ax, _) --> boolean, err
+ fncheck = function (_self, ax, _) --> boolean, err
if ax >= 0.0 and ax <= 1.0 then return true, nil end
return false, "[OutOfRange] 'ax' out of [0, 1] interval"
end,
@@ -46,13 +43,34 @@ pardef.ay = {
default = 0.0,
unit = "sp", -- scaled point
isReserved = false,
- fncheck = function (self, ay, _) --> boolean, err
+ fncheck = function (_self, ay, _) --> boolean, err
if ay >= 0.0 and ay <= 1.0 then return true, nil end
return false, "[OutOfRange] 'ay' out of [0, 1] interval"
end,
}
--- Barcode.bbox_to_quietzone -- under assessment
+-- debug only purpose
+-- enable/disable bounding box drawing of symbols
+Barcode.debug_bbox = "none"
+pardef.debug_bbox = {
+ default = "none",
+ isReserved = false,
+ enum = {
+ none = true, -- do nothing
+ symb = true, -- draw bbox of the symbol
+ qz = true, -- draw a bbox at quietzone border
+ qzsymb = true, -- draw quietzone and symbol bboxes
+ },
+ fncheck = function (self, e, _) --> boolean, err
+ if type(e) ~= "string" then return false, "[TypeError] not a string" end
+ local keys = self.enum
+ if keys[e] == true then
+ return true, nil
+ else
+ return false, "[Err] enumeration value '"..e.."' not found"
+ end
+ end,
+}
-- Barcode methods
@@ -221,7 +239,7 @@ function Barcode:new_encoder(treename, opt) --> object, err
-- argument checking
local family, variant, enc_name, err = parse_treename(treename)
if err then
- return err
+ return nil, err
end
local av_enc = self._available_enc
local mod_path = av_enc[family]
@@ -254,7 +272,7 @@ function Barcode:new_encoder(treename, opt) --> object, err
else
return nil, "[ArgErr] provided 'opt' is not a table"
end
- local enc = {} -- the new encoder
+ local enc = {_classname = "Encoder"} -- the new encoder
enc.__index = enc
enc._variant = variant
setmetatable(enc, {
@@ -292,13 +310,14 @@ function Barcode:new_encoder(treename, opt) --> object, err
end
end
if enc._config then -- this must be called after the parameter definition
- enc:_config()
+ local ok, e = enc:_config()
+ if not ok then return nil, e end
end
return enc, nil
end
-- retrive an encoder object already created
--- 'trename' is the special identifier of the encoder
+-- 'treename' is the special identifier of the encoder
function Barcode:enc_by_name(treename) --> <encoder object>, <err>
-- argument checking
local _family, _variant, _enc_name, err = parse_treename(treename)
@@ -316,25 +335,36 @@ end
-- base methods common to all the encoders
-- for numeric only simbology
-function Barcode:_check_char(c) --> elem, err
+-- elem_code : encoded char
+-- elem_text : human readable char
+-- err : error description
+function Barcode:_check_char(c, parse_state) --> elem_code, elem_text, err
if type(c) ~= "string" or #c ~= 1 then
- return nil, "[InternalErr] invalid char"
+ return nil, nil, "[InternalErr] invalid char"
+ end
+ local process_char = self._process_char
+ if process_char then
+ return process_char(self, c, parse_state)
end
local n = string.byte(c) - 48
if n < 0 or n > 9 then
- return nil, "[ArgErr] found a not digit char"
+ return nil, nil, "[ArgErr] found a not digit char"
end
- return n, nil
+ return n, nil, nil
end
--
-function Barcode:_check_digit(n) --> elem, err
+function Barcode:_check_digit(n, parse_state) --> elem_code, elem_text, err
if type(n) ~= "number" then
- return nil, "[ArgErr] not a number"
+ return nil, nil, "[ArgErr: n] not a number"
+ end
+ local process_digit = self._process_digit
+ if process_digit then
+ return process_digit(self, n, parse_state)
end
if n < 0 or n > 9 then
- return nil, "[ArgErr] not a digit"
+ return nil, nil, "[ArgErr: n] not a digit"
end
- return n, nil
+ return n, nil, nil
end
-- not empty string --> Barcode object
@@ -345,22 +375,33 @@ function Barcode:from_string(symb, opt) --> object, err
if #symb == 0 then
return nil, "[ArgErr] 'symb' is an empty string"
end
- local chars = {}
- local len = 0
- local parse_state = {}
+ local chars_code = {}
+ local chars_text
+ local parse_state
+ if self._init_parse_state then
+ parse_state = self:_init_parse_state()
+ else
+ parse_state = {}
+ end
for c in string.gmatch(symb, ".") do
- local elem, err = self:_check_char(c, parse_state)
+ local elem_code, elem_text, err = self:_check_char(c, parse_state)
if err then
return nil, err
- elseif elem then
- chars[#chars+1] = elem
- len = len + 1
+ else
+ if elem_code then
+ chars_code[#chars_code + 1] = elem_code
+ end
+ if elem_text then
+ chars_text = chars_text or {}
+ chars_text[#chars_text + 1] = elem_text
+ end
end
end
-- build the barcode object
local o = {
- _code_data = chars, -- array of chars
- _code_len = len, -- symbol lenght
+ _classname = "BarcodeSymbol",
+ _code_data = chars_code, -- array of chars
+ _code_text = chars_text,
}
setmetatable(o, self)
if opt ~= nil then
@@ -394,42 +435,58 @@ function Barcode:from_uint(n, opt) --> object, err
if opt ~= nil and type(opt) ~= "table" then
return nil, "[ArgErr] 'opt' is not a table"
end
- local digits = {}
- local parse_state = {}
- local i = 0
+ local digits_code = {}
+ local digits_text
+ local parse_state
+ if self._init_parse_state then
+ parse_state = self:_init_parse_state()
+ else
+ parse_state = {}
+ end
if n == 0 then
- local elem, err = self:_check_digit(0, parse_state)
+ local elem_code, elem_text, err = self:_check_digit(0, parse_state)
if err then
return nil, err
end
- if elem then
- digits[1] = elem
- i = 1
+ if elem_code then
+ digits_code[1] = elem_code
+ end
+ if elem_text then
+ digits_text = {elem_text}
end
else
while n > 0 do
local d = n % 10
- local elem, err = self:_check_digit(d, parse_state)
+ local elem_code, elem_text, err = self:_check_digit(d, parse_state)
if err then
return nil, err
end
- if elem then
- i = i + 1
- digits[i] = elem
+ if elem_code then
+ digits_code[#digits_code + 1] = elem_code
+ end
+ if elem_text then
+ digits_text = digits_text or {}
+ digits_text[#digits_text + 1] = elem_text
end
n = (n - d) / 10
end
- for k = 1, i/2 do -- reverse the array
- local d = digits[k]
- local h = i - k + 1
- digits[k] = digits[h]
- digits[h] = d
+ local rev_array = function (a)
+ local len = #a
+ for k = 1, len/2 do -- reverse the array
+ local h = len - k + 1
+ a[k], a[h] = a[h], a[k]
+ end
+ end
+ rev_array(digits_code)
+ if digits_text then
+ rev_array(digits_text)
end
end
-- build the barcode object
local o = {
- _code_data = digits, -- array of digits
- _code_len = i, -- symbol lenght
+ _classname = "BarcodeSymbol",
+ _code_data = digits_code, -- array of digits
+ _code_text = digits_text, -- array of human readable information
}
setmetatable(o, self)
if opt ~= nil then
@@ -449,6 +506,26 @@ function Barcode:from_uint(n, opt) --> object, err
return o, nil
end
+-- recursive general Barcode costructor
+function Barcode:new(code) --> object, err
+ local t = type(code)
+ if t == "string" then
+ return self:from_string(code)
+ elseif t == "number" then
+ return self:from_uint(code)
+ elseif t == "table" then
+ local res = {}
+ for _, c in ipairs(code) do
+ local b, err = self:new(c)
+ if err then return nil, err end
+ res[#res + 1] = b
+ end
+ return res, nil
+ else
+ return nil, "[ArgErr] unsuitable type '"..t.."' for the input code"
+ end
+end
+
-- check a parameter set
-- this method check also reserved parameter
-- argments: {k=v, ...}, "default" | "current"
@@ -532,13 +609,13 @@ function Barcode:info() --> table
description = self._DESCRIPTION,
param = {},
}
- local tpar = info.param
+ local tpar = info.param
for _, pdef in self:param_ord_iter() do
- local id = pdef.pname
+ local id = pdef.pname
local def = pdef.pdef
tpar[#tpar + 1] = {
name = id,
- descr = nil, -- TODO:
+ descr = def.descr,
value = self[id],
isReserved = def.isReserved,
unit = def.unit,
@@ -547,12 +624,32 @@ function Barcode:info() --> table
return info
end
--- return the code being represented as a string
--- or nil if the method is called from Barcode abstract class
-function Barcode:get_code() --> string|nil
- local code = self._code_data
- if code then
- return table.concat(code)
+-- return internal code representation
+function Barcode:get_code() --> array
+ if self._classname == "BarcodeSymbol" then
+ local code = self._code_data
+ local res = {}
+ for _, c in ipairs(code) do
+ res[#res + 1] = c
+ end
+ return res
+ else
+ error("[Err: OOP] 'BarcodeSymbol' only method")
+ end
+end
+
+-- human readable interpretation hri or nil
+function Barcode:get_hri() --> array|nil
+ if self._classname == "BarcodeSymbol" then
+ local code = self._code_text
+ if code == nil then return nil end
+ local res = {}
+ for _, c in ipairs(code) do
+ res[#res + 1] = c
+ end
+ return res
+ else
+ error("[Err: OOP] 'BarcodeSymbol' only method")
end
end
@@ -562,8 +659,8 @@ function Barcode:get_param(id) --> value, err
if type(id) ~= "string" then
return nil, "[ArgErr] 'id' must be a string"
end
- local pardef = self._par_def
- if not pardef[id] then
+ local par_def = self._par_def
+ if not par_def[id] then
return nil, "[Err] Parameter '"..id.."' doesn't exist"
end
local res = assert(self[id], "[InternalErr] parameter value unreachable")
@@ -622,6 +719,76 @@ function Barcode:set_param(arg1, arg2) --> boolean, err
return true, nil
end
+-- canvas is a gaCanvas object
+-- tx, ty is an optional point to place symbol local origin on the canvas plane
+function Barcode:draw(canvas, tx, ty) --> canvas, err
+ local nclass = self._classname
+ if nclass == "Barcode" then
+ error("[ErrOOP:Barcode] method 'draw' must be called only on a Symbol object")
+ end
+ if nclass == "Encoder" then
+ error("[ErrOOP:Encoder] method 'draw' must be called only on a Symbol object")
+ end
+ assert(nclass == "BarcodeSymbol")
+ if canvas._classname ~= "gaCanvas" then
+ return nil, "[ErrOOP:canvas] object 'gaCanvas' expected"
+ end
+ local ga_fn = assert(
+ self._append_ga,
+ "[InternalErr] unimplemented '_append_ga' method"
+ )
+ local bb_info = ga_fn(self, canvas, tx or 0, ty or 0)
+ local dbg_bbox = self.debug_bbox
+ if dbg_bbox == "none" then
+ -- do nothing
+ else
+ -- dashed style: phase = 3bp, dash pattern = 6bp 3bp
+ local bp = canvas.bp
+ local W = bp/10 -- 0.1bp
+ local w = W/2
+ assert(canvas:encode_linewidth(W))
+ assert(canvas:encode_dash_pattern(3*bp, 6*bp, 3*bp))
+ local x1, y1, x2, y2 = bb_info[1], bb_info[2], bb_info[3], bb_info[4]
+ if dbg_bbox == "symb" then
+ assert(canvas:encode_rect(x1 + w, y1 + w, x2 - w, y2 - w))
+ elseif dbg_bbox == "qz" then
+ local q1, q2, q3, q4 = bb_info[5], bb_info[6], bb_info[7], bb_info[8]
+ x1 = x1 - (q1 or 0) + w
+ y1 = y1 - (q2 or 0) + w
+ x2 = x2 + (q3 or 0) - w
+ y2 = y2 + (q4 or 0) - w
+ assert(canvas:encode_rect(x1, y1, x2, y2))
+ elseif dbg_bbox == "qzsymb" then
+ local q1, q2, q3, q4 = bb_info[5], bb_info[6], bb_info[7], bb_info[8]
+ x1 = x1 + w
+ y1 = y1 + w
+ x2 = x2 - w
+ y2 = y2 - w
+ if q1 then
+ assert(canvas:encode_vline(y1, y2, x1))
+ x1 = x1 - q1
+ end
+ if q3 then
+ assert(canvas:encode_vline(y1, y2, x2))
+ x2 = x2 + q3
+ end
+ if q2 then
+ assert(canvas:encode_hline(x1, x2, y1))
+ y1 = y1 - q2
+ end
+ if q4 then
+ assert(canvas:encode_hline(x1, x2, y2))
+ y2 = y2 + q4
+ end
+ assert(canvas:encode_rect(x1, y1, x2, y2))
+ else
+ error("[InternalErr:debug_bbox] unrecognized enum value")
+ end
+ assert(canvas:encode_reset_pattern())
+ end
+ return canvas
+end
+
return Barcode
--