summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/barracuda/src/lib-barcode
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/barracuda/src/lib-barcode')
-rw-r--r--macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua393
-rw-r--r--macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua12
-rw-r--r--macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua36
-rw-r--r--macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua767
-rw-r--r--macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua373
5 files changed, 1244 insertions, 337 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 415719a2f4..b43bc511d7 100644
--- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua
+++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua
@@ -1,6 +1,6 @@
--- Barcode abstract class
--- Copyright (C) 2019 Roberto Giacomelli
+-- Barcode Abstract Class
+-- Copyright (C) 2020 Roberto Giacomelli
-- Please see LICENSE.TXT for any legal information about present software
local Barcode = {
@@ -18,11 +18,15 @@ Barcode._available_enc = {-- keys must be lowercase
i2of5 = "lib-barcode.brcd-i2of5", -- Interleaved 2 of 5
}
Barcode._builder_instances = {} -- encoder builder instances repository
+Barcode._encoder_instances = {} -- encoder instances repository
-- common parameters to all the barcode objects
+Barcode._super_par_order = {
+ "ax",
+ "ay",
+}
Barcode._super_par_def = {}
local pardef = Barcode._super_par_def
-
-- set an Anchor point (ax, ay) relatively to the barcode bounding box
-- without considering any text object
-- ax = 0, ay = 0 is the lower left corner of the symbol
@@ -32,7 +36,6 @@ pardef.ax = {
default = 0.0,
unit = "sp", -- scaled point
isReserved = false,
- order = 1,
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"
@@ -43,7 +46,6 @@ pardef.ay = {
default = 0.0,
unit = "sp", -- scaled point
isReserved = false,
- order = 2,
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"
@@ -54,120 +56,203 @@ pardef.ay = {
-- Barcode methods
--- stateless iterator troughtout the ordered parameters collection
-local function p_iter(state, i)
- i = i + 1
- local t = state[i]
- if t then
- return i, t
+-- extract id from an encoder 'tree name'
+local function parse_treename(treename) --> fam, var, name, err
+ if not type(treename) == "string" then
+ return nil, nil, nil, "[ArgErr] 'treename' arg must be a string"
+ end
+ if treename:find(" ") then
+ return nil, nil, nil,
+ "[ArgErr] spaces are not allowed in an encoder identifier"
+ end
+ local fam, var, name
+ -- family name extraction
+ local idash = treename:find("-")
+ local icolon = treename:find(":")
+ if idash then
+ fam = treename:sub(1, idash - 1)
+ else
+ if icolon then
+ fam = treename:sub(1, icolon - 1)
+ else
+ fam = treename
+ end
+ end
+ if fam == "" then
+ return nil, nil, nil, "[ArgErr] empty encoder id"
end
+ if idash then
+ if icolon then
+ var = treename:sub(idash + 1, icolon - 1)
+ else
+ var = treename:sub(idash + 1)
+ end
+ if var == "" then
+ return nil, nil, nil, "[ArgErr] empty 'variant' encoder id"
+ end
+ end
+ if icolon then
+ name = treename:sub(icolon + 1)
+ if name == "" then
+ return nil, nil, nil, "[ArgErr] empty 'name' after colon"
+ end
+ if name:find("-") then
+ return nil, nil, nil, "[ArgErr] the name mustn't contain a dash"
+ end
+ if name:find(":") then
+ return nil, nil, nil, "[ArgErr] the name mustn't contain a colon"
+ end
+ end
+ return fam, var, name, nil
end
-- main iterator on parameter definitions
-function Barcode:param_ord_iter()
+-- optional argument 'filter' eventually excludes some parameters
+-- "*all" -> encoder and Barcode parameters
+-- "*enc" -> only encoder parameters
+-- "*super" -> only Barcode superclass paramenters
+function Barcode:param_ord_iter(filter)
+ local is_iter_enc, is_iter_super = true, true
+ if filter then
+ if type(filter) ~= "string" then
+ error("[param_ord_iter] 'filter' is not a string")
+ elseif filter == "*enc" then
+ is_iter_super = false
+ elseif filter == "*super" then
+ is_iter_enc = false
+ elseif filter ~= "*all" then
+ error("[param_ord_iter] 'filter' enumeration '"..filter.."' not found")
+ end
+ end
local state = {}
- -- append family parameter
- local p2_family = self._par_def -- base family parameters
- local fam_len = 0
- if p2_family then
- for pname, pdef in pairs(p2_family) do
- state[pdef.order] = {
- pname = pname,
- pdef = pdef,
- isSuper = false,
- }
- fam_len = fam_len + 1
+ local ordkey = {}
+ if is_iter_enc then
+ local var = self._variant
+ local p2_family = self._par_def -- base family parameters
+ local p2_family_var
+ if var then
+ local pvar = "_par_def_"..var
+ p2_family_var = self[pvar] -- variant specific family parameters
+ end
+ local p2_idlist = self._par_order
+ if p2_idlist then -- family parameters
+ for i, pid in ipairs(p2_idlist) do
+ if ordkey[pid] then
+ error("[Ops] duplicated entry in parameter ordered list")
+ end
+ ordkey[pid] = true
+ local pdef -- parameter definition
+ if var and p2_family_var then
+ pdef = p2_family_var[pid]
+ end
+ pdef = pdef or p2_family[pid]
+ assert(pdef, "[Ops] parameter definition for option '"..pid.."' not found")
+ state[i] = {
+ pname = pid,
+ pdef = pdef,
+ isSuper = false,
+ }
+ end
+ end
+ -- append variant parameters
+ if var and self._par_def_variant then
+ local p2_variant = self._par_def_variant[var]
+ if p2_variant then
+ local p2_idlist_var = self._par_variant_order[var] -- parameters' list
+ if p2_idlist_var then
+ for _, pid in ipairs(p2_idlist_var) do
+ if ordkey[pid] then
+ error("[Ops] duplicated entry in variant parameter ordered list")
+ end
+ ordkey[pid] = true
+ local pdef = p2_variant[pid] -- parameter definition
+ assert(pdef, "[Ops] parameter definition for option '"..pid.."' not found")
+ state[#state + 1] = {
+ pname = pid,
+ pdef = pdef,
+ isSuper = false,
+ }
+ end
+ end
+ end
end
- assert(fam_len == #state)
- end
- -- append the variant parameters
- local var_len = 0
- local var = self._variant
- if var then -- specific variant parameters
- local p2_variant = assert(self._par_def_variant[var])
- for pname, pdef in pairs(p2_variant) do
- if state[pname] then
- error("[InternalErr] overriding paramenter '"..pname.."'")
+ end
+ if is_iter_super then
+ -- append the super class parameter to the iterator state
+ local p1_idlist_super = self._super_par_order
+ local p1_super = self._super_par_def
+ for _, pid in ipairs(p1_idlist_super) do
+ if ordkey[pid] then
+ error("[Ops] duplicated entry in superclass parameter ordered list")
end
- state[pdef.order + fam_len] = {
- pname = pname,
+ ordkey[pid] = true
+ local pdef = p1_super[pid] -- parameter definition
+ assert(pdef, "[Ops] parameter definition for option '"..pid.."' not found")
+ state[#state + 1] = {
+ pname = pid,
pdef = pdef,
- isSuper = false,
+ isSuper = true,
}
- var_len = var_len + 1
end
- assert(fam_len + var_len == #state)
- end
- -- append the super class parameter to the iterator state
- local p1 = self._super_par_def
- local super_len = 0
- for pname, pdef in pairs(p1) do
- if state[pname] then
- error("[InternalError] overriding paramenter name '"..pname.."'")
+ end
+ -- stateless iterator troughtout the ordered parameters collection
+ local p_iter = function (st, i)
+ i = i + 1
+ local t = st[i]
+ if t then
+ return i, t
end
- state[fam_len + var_len + pdef.order] = {
- pname = pname,
- pdef = pdef,
- isSuper = true,
- }
- super_len = super_len + 1
end
- assert(super_len + fam_len + var_len == #state)
return p_iter, state, 0
end
-- encoder costructor
-- Symbology can be a family with many variants. This is represented by the
--- first argument 'bc_type' formatted as <family>-<variant>.
--- in more details:
--- <family id><dash char><variant id> if there are variants
--- <encoder id> if not
--- i.e. when 'bc_type' is the string "ean-13", "ean" is the barcode family and
+-- first argument 'tree_name' formatted as <family>-<variant>:<id>.
+-- i.e. when 'tree_name' is the string "ean-13", "ean" is the barcode family and
-- "13" is its variant name.
--- For whose barcodes that do not have variants, 'bc_type' is simply the endoder id
--- such as "code128".
--- 'id_enc' is an optional identifier useful to retrive an encoder reference later
--- 'opt' is an optional table with the user-defined parameters setting up encoders
---
-function Barcode:new_encoder(bc_type, id_enc, opt) --> object, err
+-- For whose barcodes that do not have variants, 'treename' is simply the
+-- encoder id such as in the case of "code128".
+-- <id> is an optional identifier useful if there are more than one encoders of
+-- the same type
+-- 'opt' is an optional table with the user-defined parameters setting up
+-- encoders
+function Barcode:new_encoder(treename, opt) --> object, err
-- argument checking
- if type(bc_type) ~= "string" then
- return nil, "[ArgErr] 'bc_type' is not a string"
- end
- local pdash = string.find(bc_type, "-")
- local family, variant
- if pdash then
- family = string.sub(bc_type, 1, pdash - 1)
- variant = string.sub(bc_type, pdash + 1)
- else
- family = bc_type
+ local family, variant, enc_name, err = parse_treename(treename)
+ if err then
+ return err
end
local av_enc = self._available_enc
- if not av_enc[family] then -- is the barcode type a real module?
- return nil, "[Err] barcode type '"..family.."' not found"
- end
- if id_enc == nil then
- id_enc = (variant or "") .. "_noname"
- elseif type(id_enc) ~= "string" then
- return nil, "[ArgErr] provided 'id_enc' is not a string"
- end
- if type(opt) == "table" or opt == nil then
- opt = opt or {}
- else
- return nil, "[ArgErr] provided 'opt' is wrong"
+ local mod_path = av_enc[family]
+ -- check family identifier
+ if not mod_path then
+ return nil, "[ArgErr] barcode family '"..family.."' not found"
end
+ -- retrive/load the builder
+ local builder
local tenc = self._builder_instances
- local builder;
if tenc[family] then -- is the encoder builder already loaded?
builder = tenc[family]
- else -- loading the encoder builder
- local mod_path = av_enc[family]
+ else -- load the encoder builder
builder = require(mod_path)
- tenc[family] = assert(builder, "[InternalErr] module not found!")
- builder._enc_instances = {}
+ tenc[family] = builder
end
- if builder._enc_instances[id_enc] then
- return nil, "[Err] 'id_enc' already present"
+ -- check the variant identifier
+ local av_var = builder._id_variant
+ if av_var and variant and (not av_var[variant]) then
+ local fmt = "[ArgErr] family '%s' does not have '%s' variant"
+ return nil, string.format(fmt, family, variant)
+ end
+ -- check unique encoder identifier
+ local enc_archive = self._encoder_instances
+ if enc_archive[treename] then
+ return nil, "[Err] encoder name '"..treename.."' already exists"
+ end
+ if type(opt) == "table" or opt == nil then
+ opt = opt or {}
+ else
+ return nil, "[ArgErr] provided 'opt' is not a table"
end
local enc = {} -- the new encoder
enc.__index = enc
@@ -180,19 +265,19 @@ function Barcode:new_encoder(bc_type, id_enc, opt) --> object, err
return self[k]
end
})
- builder._enc_instances[id_enc] = enc
- -- param defition
+ enc_archive[treename] = enc
+ -- parameters definition
for _, tpar in enc:param_ord_iter() do
local pname = tpar.pname
local pdef = tpar.pdef
local isSuper = tpar.isSuper
local val = opt[pname] -- param = val
if val ~= nil then
- local ok, err = pdef:fncheck(val, enc)
+ local ok, perr = pdef:fncheck(val, enc)
if ok then
enc[pname] = val
- else -- error!
- return nil, err
+ else -- parameter error!
+ return nil, perr
end
else
-- load the default value of <pname>
@@ -206,49 +291,30 @@ function Barcode:new_encoder(bc_type, id_enc, opt) --> object, err
end
end
end
- if enc.config then -- this must be called after the parameter definition
- enc:config(variant)
+ if enc._config then -- this must be called after the parameter definition
+ enc:_config()
end
return enc, nil
end
--- retrive encoder object already created
--- 'name' is optional in case you didn't assign one to the encoder
-function Barcode:enc_by_name(bc_type, name) --> <encoder object>, <err>
- if type(bc_type) ~= "string" then
- return nil, "[ArgErr] 'bc_type' must be a string"
- end
- local pdash = string.find(bc_type, "-")
- local family, variant
- if pdash then
- family = string.sub(bc_type, 1, pdash - 1)
- variant = string.sub(bc_type, pdash + 1)
- else
- family = bc_type
+-- retrive an encoder object already created
+-- 'trename' 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)
+ if err then
+ return nil, err
end
- local av_enc = self._available_enc
- if not av_enc[family] then -- is the barcode type a real module?
- return nil, "[Err] barcode type '"..family.."' not found"
- end
- local builder = self._builder_instances[family]
- if builder == nil then
- return nil, "[Err] enc builder '"..family.."' not loaded, use 'new_encoder()' method"
- end
- if name == nil then
- name = (variant or "") .. "_noname"
- elseif type(name) ~= "string" then
- return nil, "[ArgErr] 'name' must be a string"
- end
- local repo = builder._enc_instances
- local enc = repo[name]
- if enc == nil then
- return nil, "[Err] encoder '"..name.."' not found"
- else
+ local enc = self._encoder_instances[treename]
+ if enc then
return enc, nil
+ else
+ return nil, "[Err] encoder '"..treename.."' not found"
end
end
--- base constructors common to all the encoders
+-- base methods common to all the encoders
+
-- for numeric only simbology
function Barcode:_check_char(c) --> elem, err
if type(c) ~= "string" or #c ~= 1 then
@@ -260,19 +326,19 @@ function Barcode:_check_char(c) --> elem, err
end
return n, nil
end
+--
function Barcode:_check_digit(n) --> elem, err
if type(n) ~= "number" then
- return nil, "[InternalErr] not a number"
+ return nil, "[ArgErr] not a number"
end
if n < 0 or n > 9 then
- return nil, "[InternalErr] not a digit"
+ return nil, "[ArgErr] not a digit"
end
return n, nil
end
-- not empty string --> Barcode object
function Barcode:from_string(symb, opt) --> object, err
- assert(self._check_char, "[InternalErr] undefined _check_char() method")
if type(symb) ~= "string" then
return nil, "[ArgErr] 'symb' is not a string"
end
@@ -281,11 +347,12 @@ function Barcode:from_string(symb, opt) --> object, err
end
local chars = {}
local len = 0
+ local parse_state = {}
for c in string.gmatch(symb, ".") do
- local elem, err = self:_check_char(c)
+ local elem, err = self:_check_char(c, parse_state)
if err then
return nil, err
- else
+ elseif elem then
chars[#chars+1] = elem
len = len + 1
end
@@ -307,7 +374,7 @@ function Barcode:from_string(symb, opt) --> object, err
end
end
if o._finalize then
- local ok, e = o:_finalize()
+ local ok, e = o:_finalize(parse_state)
if not ok then return nil, e end
end
return o, nil
@@ -315,9 +382,12 @@ end
-- positive integer --> Barcode object
function Barcode:from_uint(n, opt) --> object, err
- assert(self._check_digit, "[InternalErr] undefined _check_digit() method")
- if type(n) ~= "number" then return nil, "[ArgErr] 'n' is not a number" end
- if n < 0 then return nil, "[ArgErr] 'n' must be a positive integer" end
+ if type(n) ~= "number" then
+ return nil, "[ArgErr] 'n' is not a number"
+ end
+ if n < 0 then
+ return nil, "[ArgErr] 'n' must be a positive integer"
+ end
if n - math.floor(n) ~= 0 then
return nil, "[ArgErr] 'n' is not an integer"
end
@@ -325,23 +395,28 @@ function Barcode:from_uint(n, opt) --> object, err
return nil, "[ArgErr] 'opt' is not a table"
end
local digits = {}
+ local parse_state = {}
local i = 0
if n == 0 then
- local elem, err = self:_check_digit(0)
+ local elem, err = self:_check_digit(0, parse_state)
if err then
return nil, err
end
- digits[1] = elem
- i = 1
+ if elem then
+ digits[1] = elem
+ i = 1
+ end
else
while n > 0 do
local d = n % 10
- i = i + 1
- local elem, err = self:_check_digit(d)
+ local elem, err = self:_check_digit(d, parse_state)
if err then
return nil, err
end
- digits[i] = elem
+ if elem then
+ i = i + 1
+ digits[i] = elem
+ end
n = (n - d) / 10
end
for k = 1, i/2 do -- reverse the array
@@ -368,7 +443,7 @@ function Barcode:from_uint(n, opt) --> object, err
end
end
if o._finalize then
- local ok, e = o:_finalize()
+ local ok, e = o:_finalize(parse_state)
if not ok then return nil, e end
end
return o, nil
@@ -458,20 +533,29 @@ function Barcode:info() --> table
param = {},
}
local tpar = info.param
- for _, pardef in self:param_ord_iter() do
- local id = pardef.pname
- local pdef = pardef.pdef
+ for _, pdef in self:param_ord_iter() do
+ local id = pdef.pname
+ local def = pdef.pdef
tpar[#tpar + 1] = {
name = id,
descr = nil, -- TODO:
value = self[id],
- isReserved = pdef.isReserved,
- unit = pdef.unit,
+ isReserved = def.isReserved,
+ unit = def.unit,
}
end
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)
+ end
+end
+
-- make accessible by name parameter values
-- id: parameter identifier
function Barcode:get_param(id) --> value, err
@@ -509,11 +593,10 @@ function Barcode:set_param(arg1, arg2) --> boolean, err
else
return false, "[ArgErr] param name must be a string"
end
- -- preparing to the checking process
+ -- preparing the check process
local cktab = {}
local ckparam = {}
- -- checking process
- for _, tpar in self:param_ord_iter() do
+ for _, tpar in self:param_ord_iter() do -- checking process
local pname = tpar.pname
local pdef = tpar.pdef
local val = targ[pname] -- par = val
diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua
index 317b3de8f8..1ee1c98343 100644
--- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua
+++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua
@@ -1,5 +1,5 @@
-- Code128 barcode generator module
--- Copyright (C) 2019 Roberto Giacomelli
+-- Copyright (C) 2020 Roberto Giacomelli
--
-- All dimension must be in scaled point (sp)
-- every fields that starts with an undercore sign are intended as private
@@ -41,6 +41,11 @@ Code128._switch = { -- codes for switching from a codeset to another one
}
-- parameters definition
+Code128._par_order = {
+ "xdim",
+ "ydim",
+ "quietzone_factor",
+}
Code128._par_def = {}
local pardef = Code128._par_def
@@ -49,7 +54,6 @@ pardef.xdim = {
default = 0.21 * 186467, -- X dimension
unit = "sp", -- scaled point
isReserved = true,
- order = 1, -- the one first to be modified
fncheck = function (self, x, _) --> boolean, err
if x >= self.default then
return true, nil
@@ -63,7 +67,6 @@ pardef.ydim = {
default = 10 * 186467, -- Y dimension
unit = "sp",
isReserved = false,
- order = 2,
fncheck = function (self, y, tpar) --> boolean, err
local xdim = tpar.xdim
if y >= 10*xdim then
@@ -78,7 +81,6 @@ pardef.quietzone_factor = {
default = 10,
unit = "absolute-number",
isReserved = false,
- order = 3,
fncheck = function (self, z, _) --> boolean, err
if z >= 10 then
return true, nil
@@ -89,7 +91,7 @@ pardef.quietzone_factor = {
}
-- create vbar objects
-function Code128:config() --> ok, err
+function Code128:_config() --> ok, err
-- build Vbar object for the start/stop symbol
local mod = self.xdim
local sc = self._codeset.stopChar -- build the stop char
diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua
index a639619c63..6d7f2ccea7 100644
--- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua
+++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua
@@ -1,5 +1,5 @@
-- Code39 barcode encoder implementation
--- Copyright (C) 2019 Roberto Giacomelli
+-- Copyright (C) 2020 Roberto Giacomelli
--
-- All dimensions must be in scaled point (sp)
-- every fields that starts with an undercore sign are intended as private
@@ -30,6 +30,18 @@ Code39._symb_def = {-- symbol definition
Code39._star_def = 112121121 -- '*' start/stop character
-- parameters definition
+Code39._par_order = {
+ "module",
+ "ratio",
+ "quietzone",
+ "interspace",
+ "height",
+ "text_enabled",
+ "text_vpos",
+ "text_hpos",
+ "text_gap",
+ "text_star",
+}
Code39._par_def = {}
local pardef = Code39._par_def
@@ -45,7 +57,6 @@ pardef.module = {
default = 7.5 * 0.0254 * 186467, -- 7.5 mils (sp) unit misure,
unit = "sp", -- scaled point
isReserved = true,
- order = 1, -- the one first to be modified
fncheck = function (self, mod, _) --> boolean, err
if mod >= self.default then return true, nil end
return false, "[OutOfRange] too small value for module"
@@ -62,7 +73,6 @@ pardef.ratio = {
default = 2.0, -- the minimum
unit = "absolute-number",
isReserved = true,
- order = 2,
fncheck = function (self, ratio, tparcheck) --> boolean, err
local mils = 0.0254 * 186467
local mod = tparcheck.module
@@ -85,7 +95,6 @@ pardef.quietzone = {
default = 2.54 * 186467, -- 0.1 inches equal to 100*mils
unit = "sp", -- scaled point
isReserved = false,
- order = 3,
fncheck = function (self, qz, tparcheck) --> boolean, err
local mils = 0.0254 * 186467
local mod = tparcheck.module
@@ -109,7 +118,6 @@ pardef.interspace = { -- Intercharacter gap
default = 7.5 * 0.0254 * 186467, -- 1 module, for quality printer
unit = "sp", -- scaled point
isReserved = false,
- order = 4,
fncheck = function (self, igw, tparcheck) --> boolean, err
local mod = tparcheck.module
if igw >= mod then return true, nil end
@@ -128,7 +136,6 @@ pardef.height = {
default = 8 * 186467, -- 8 mm -- TODO: better assessment for symbol length
unit = "sp", -- scaled point
isReserved = false,
- order = 5,
fncheck = function (self, h, _) --> boolean, err
local mils = 0.0254 * 186467
if h >= 250*mils then return true, nil end
@@ -141,7 +148,6 @@ pardef.text_enabled = { -- boolean type
-- enable/disable a text label upon the barcode symbol
default = true,
isReserved = false,
- order = 6,
fncheck = function (self, flag, _) --> boolean, err
if type(flag) == "boolean" then
return true, nil
@@ -155,7 +161,6 @@ pardef.text_enabled = { -- boolean type
pardef.text_vpos = { -- enumeration
default = "bottom",
isReserved = false,
- order = 7,
policy_enum = {
top = true, -- place text at the top of symbol
bottom = true, -- place text under the symbol
@@ -175,7 +180,6 @@ pardef.text_vpos = { -- enumeration
pardef.text_hpos = { -- enumeration
default = "left",
isReserved = false,
- order = 8,
policy_enum = {
left = true,
center = true,
@@ -197,7 +201,6 @@ pardef.text_hpos = { -- enumeration
pardef.text_gap = {
default = 2.2 * 65536, -- 2.2 pt
isReserved = false,
- order = 9,
unit = "em", --> TODO: please put this under further analisys asap
fncheck = function(self, g, _) --> boolean, err
if type(g) == "number" then
@@ -216,8 +219,7 @@ pardef.text_gap = {
pardef.text_star = {
default = false,
isReserved = false,
- order = 10,
- fncheck = function(self, flag, _) --> boolean, err
+ fncheck = function(_self, flag, _) --> boolean, err
if type(flag) == "boolean" then
return true, nil
else
@@ -227,7 +229,7 @@ pardef.text_star = {
}
-- configuration function
-function Code39:config() --> ok, err
+function Code39:_config() --> ok, err
-- build Vbar object for the start/stop symbol
local mod, ratio = self.module, self.ratio
local n_star = self._star_def
@@ -239,7 +241,7 @@ end
-- overriding Barcode method
function Code39:_check_char(c) --> elem, err
if type(c) ~= "string" or #c ~= 1 then
- return nil, "[InternalErr] invalid char"
+ return nil, "[ArgErr] invalid char"
end
local symb_def = self._symb_def
local n = symb_def[c]
@@ -253,12 +255,12 @@ end
-- overriding Barcode method
function Code39:_check_digit(n) --> elem, err
if type(n) ~= "number" then
- return nil, "[InteranlErr] not a number"
+ return nil, "[ArgErr] not a number"
end
if n < 0 or n > 9 then
- return nil, "[InternalErr] not a digit"
+ return nil, "[ArgErr] not a digit"
end
- return tostring(n), nil
+ return string.char(n + 48), nil
end
function Code39:_finalize() --> ok, err
diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua
index 6893550a5c..bddaa36103 100644
--- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua
+++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua
@@ -1,24 +1,31 @@
-- EAN family barcode generator
--
--- Copyright (C) 2019 Roberto Giacomelli
+-- Copyright (C) 2020 Roberto Giacomelli
-- see LICENSE.txt file
---
--- variant identifiers of the EAN family barcodes:
--- "13" EAN13
--- "8" EAN8
--- "5" EAN5 add-on
--- "2" EAN2 add-on
--- "13+5" EAN13 with EAN5 add-on
--- "13+2" EAN13 with EAN2 add-on
--- "8+5" EAN8 with EAN5 add-on
--- "8+2" EAN8 with EAN2 add-on
local EAN = {
- _VERSION = "ean v0.0.5",
+ _VERSION = "ean v0.0.6",
_NAME = "ean",
_DESCRIPTION = "EAN barcode encoder",
}
+EAN._id_variant = {
+ ["13"] = true, -- EAN13
+ ["8"] = true, -- EAN8
+ ["5"] = true, -- EAN5 add-on
+ ["2"] = true, -- EAN2 add-on
+ ["13+5"] = true, -- EAN13 with EAN5 add-on
+ ["13+2"] = true, -- EAN13 with EAN2 add-on
+ ["8+5"] = true, -- EAN8 with EAN5 add-on
+ ["8+2"] = true, -- EAN8 with EAN2 add-on
+ ["isbn"] = true, -- ISBN 13 digits
+ ["isbn+2"] = true, -- ISBN 13 digits with an EAN2 add-on
+ ["isbn+5"] = true, -- ISBN 13 digits with an EAN2 add-on
+ ["issn"] = true, -- ISSN 13 digits
+ ["issn+2"] = true, -- ISSN 13 digits with an EAN2 add-on
+ ["issn+5"] = true, -- ISSN 13 digits with an EAN2 add-on
+}
+
EAN._codeset_seq = {-- 1 -> A, 2 -> B, 3 -> C
[0]={1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3},
{1, 1, 2, 1, 2, 2, 3, 3, 3, 3, 3, 3},
@@ -58,17 +65,26 @@ EAN._is_first_bar = {false, false, true}
EAN._start = {111, true}
EAN._stop = {11111, false}
--- family parameters
-
-EAN._par_def = {}; local pardef = EAN._par_def
+-- common family parameters
+EAN._par_order = {
+ "mod",
+ "height",
+ "quietzone_left_factor",
+ "quietzone_right_factor",
+ "bars_depth_factor",
+ "text_enabled",
+ "text_ygap_factor",
+ "text_xgap_factor",
+}
+EAN._par_def = {}
+local pardef = EAN._par_def
-- standard module is 0.33 mm but it can vary from 0.264 to 0.66mm
pardef.mod = {
default = 0.33 * 186467, -- (mm to sp) X dimension (original value 0.33)
unit = "sp", -- scaled point
isReserved = true,
- order = 1, -- the one first to be modified
- fncheck = function (self, x, _) --> boolean, err
+ fncheck = function (_self, x, _) --> boolean, err
local mm = 186467
local min, max = 0.264 * mm, 0.660 * mm
if x < min then
@@ -84,7 +100,6 @@ pardef.height = {
default = 22.85 * 186467, -- 22.85 mm
unit = "sp",
isReserved = false,
- order = 2,
fncheck = function (self, h, _) --> boolean, err
if h > 0 then
return true, nil
@@ -98,8 +113,7 @@ pardef.quietzone_left_factor = {
default = 11,
unit = "absolute-number",
isReserved = false,
- order = 3,
- fncheck = function (self, qzf, _) --> boolean, err
+ fncheck = function (_self, qzf, _) --> boolean, err
if qzf > 0 then
return true, nil
else
@@ -112,8 +126,7 @@ pardef.quietzone_right_factor = {
default = 7,
unit = "absolute-number",
isReserved = false,
- order = 4,
- fncheck = function (self, qzf, _) --> boolean, err
+ fncheck = function (_self, qzf, _) --> boolean, err
if qzf > 0 then
return true, nil
else
@@ -126,8 +139,7 @@ pardef.bars_depth_factor = {
default = 5,
unit = "absolute-number",
isReserved = false,
- order = 5,
- fncheck = function (self, b, _) --> boolean, err
+ fncheck = function (_self, b, _) --> boolean, err
if b >= 0 then
return true, nil
else
@@ -140,8 +152,7 @@ pardef.bars_depth_factor = {
pardef.text_enabled = { -- boolean type
default = true,
isReserved = false,
- order = 6,
- fncheck = function (self, flag, _) --> boolean, err
+ fncheck = function (_self, flag, _) --> boolean, err
if type(flag) == "boolean" then
return true, nil
else
@@ -154,8 +165,7 @@ pardef.text_ygap_factor = {
default = 1.0,
unit = "absolute-number",
isReserved = false,
- order = 7,
- fncheck = function (self, t, _) --> boolean, err
+ fncheck = function (_self, t, _) --> boolean, err
if t >= 0 then
return true, nil
else
@@ -168,8 +178,7 @@ pardef.text_xgap_factor = {
default = 0.75,
unit = "absolute-number",
isReserved = false,
- order = 8,
- fncheck = function (self, t, _) --> boolean, err
+ fncheck = function (_self, t, _) --> boolean, err
if t >= 0 then
return true, nil
else
@@ -179,7 +188,44 @@ pardef.text_xgap_factor = {
}
-- variant parameters
-
+EAN._par_variant_order = {
+ ["13"] = {}, -- EAN13
+ ["8"] = {}, -- EAN8
+ ["5"] = {}, -- add-on EAN5
+ ["2"] = {}, -- add-on EAN2
+ ["isbn"] = { -- ISBN 13 digits
+ "text_isbn_enabled",
+ "text_isbn_ygap_factor",
+ },
+ ["13+5"] = {"addon_xgap_factor",}, -- EAN13 with EAN5 add-on
+ ["13+2"] = {"addon_xgap_factor",}, -- EAN13 with EAN2 add-on
+ ["8+5"] = {"addon_xgap_factor",}, -- EAN8 with EAN5 add-on
+ ["8+2"] = {"addon_xgap_factor",}, -- EAN8 with EAN2 add-on
+ ["isbn+2"] = { -- ISBN 13 digits with an EAN2 add-on
+ "text_isbn_enabled",
+ "text_isbn_ygap_factor",
+ "addon_xgap_factor",
+ },
+ ["isbn+5"] = { -- ISBN 13 digits with an EAN2 add-on
+ "text_isbn_enabled",
+ "text_isbn_ygap_factor",
+ "addon_xgap_factor",
+ },
+ ["issn"] = { -- ISSN 13 digits, International Standard Serial Number
+ "text_issn_enabled",
+ "text_issn_ygap_factor",
+ },
+ ["issn+2"] = { -- ISSN 13 digits with an EAN2 add-on
+ "text_issn_enabled",
+ "text_issn_ygap_factor",
+ "addon_xgap_factor",
+ },
+ ["issn+5"] = { -- ISSN 13 digits with an EAN2 add-on
+ "text_issn_enabled",
+ "text_issn_ygap_factor",
+ "addon_xgap_factor",
+ },
+}
EAN._par_def_variant = {
["13"] = {}, -- EAN13
["8"] = {}, -- EAN8
@@ -189,17 +235,23 @@ EAN._par_def_variant = {
["13+2"] = {}, -- EAN13 with EAN2 add-on
["8+5"] = {}, -- EAN8 with EAN5 add-on
["8+2"] = {}, -- EAN8 with EAN2 add-on
+ -- ISBN
+ ["isbn"] = {}, -- ISBN 13 digits
+ ["isbn+2"] = {}, -- ISBN 13 digits with an EAN2 add-on
+ ["isbn+5"] = {}, -- ISBN 13 digits with an EAN2 add-on
+ -- ISSN
+ ["issn"] = {}, -- ISBN 13 digits
+ ["issn+2"] = {}, -- ISBN 13 digits with an EAN2 add-on
+ ["issn+5"] = {}, -- ISBN 13 digits with an EAN2 add-on
}
+local par_def_var = EAN._par_def_variant
--- ean13_pardef.text_ISBN parameter -- TODO:
-
--- EAN 13/8 + add-on parameters
-local addon_xgap_factor = {-- distance between symbol
+-- EAN ISBN/ISSN/13/8 + add-on parameters
+local addon_xgap_factor = {-- distance between main and add-on symbol
default = 10,
unit = "absolute-number",
isReserved = false,
- order = 1,
- fncheck = function (self, t, _) --> boolean, err
+ fncheck = function (_self, t, _) --> boolean, err
if t >= 7 then
return true, nil
else
@@ -207,10 +259,78 @@ local addon_xgap_factor = {-- distance between symbol
end
end,
}
-EAN._par_def_variant["13+5"].addon_xgap_factor = addon_xgap_factor
-EAN._par_def_variant["13+2"].addon_xgap_factor = addon_xgap_factor
-EAN._par_def_variant["8+5"].addon_xgap_factor = addon_xgap_factor
-EAN._par_def_variant["8+2"].addon_xgap_factor = addon_xgap_factor
+par_def_var["13+5"].addon_xgap_factor = addon_xgap_factor
+par_def_var["13+2"].addon_xgap_factor = addon_xgap_factor
+par_def_var["8+5"].addon_xgap_factor = addon_xgap_factor
+par_def_var["8+2"].addon_xgap_factor = addon_xgap_factor
+-- ISBN
+par_def_var["isbn+5"].addon_xgap_factor = addon_xgap_factor
+par_def_var["isbn+2"].addon_xgap_factor = addon_xgap_factor
+-- ISSN
+par_def_var["issn+5"].addon_xgap_factor = addon_xgap_factor
+par_def_var["issn+2"].addon_xgap_factor = addon_xgap_factor
+
+-- text_ISBN_* parameter
+-- enable/disable a text ISBN label upon the barcode symbol
+-- if it is "auto" the isbn text appears or not and depends by input code
+local isbn_text_enabled = { -- boolean type
+ default = "auto",
+ isReserved = false,
+ fncheck = function (_self, flag, _) --> boolean, err
+ if type(flag) == "boolean" or
+ (type(flag) == "string" and flag == "auto") then
+ return true, nil
+ else
+ return false, "[TypeErr] not a boolean or 'auto' for text_isbn_enabled"
+ end
+ end,
+}
+-- ISBN
+par_def_var["isbn+5"].text_isbn_enabled = isbn_text_enabled
+par_def_var["isbn+2"].text_isbn_enabled = isbn_text_enabled
+par_def_var["isbn"].text_isbn_enabled = isbn_text_enabled
+
+-- text_ISSN_* parameter
+-- enable/disable a text ISBN label upon the barcode symbol
+-- if it is "auto" the isbn/issn text appears or not and depends by input code
+local issn_text_enabled = { -- boolean type
+ default = true,
+ isReserved = false,
+ fncheck = function (_self, flag, _) --> boolean, err
+ if type(flag) == "boolean" then
+ return true, nil
+ else
+ return false, "[TypeErr] not a boolean value for text_issn_enabled"
+ end
+ end,
+}
+
+-- ISSN
+par_def_var["issn+5"].text_issn_enabled = issn_text_enabled
+par_def_var["issn+2"].text_issn_enabled = issn_text_enabled
+par_def_var["issn"].text_issn_enabled = issn_text_enabled
+
+-- ISBN text vertical distance
+local text_ygap_factor = {
+ default = 2.0,
+ unit = "absolute-number",
+ isReserved = false,
+ fncheck = function (_self, t, _) --> boolean, err
+ if t >= 0 then
+ return true, nil
+ else
+ return false, "[OutOfRange] non positive value for text_isbn_ygap_factor"
+ end
+ end,
+}
+-- ISBN
+par_def_var["isbn+5"].text_isbn_ygap_factor = text_ygap_factor
+par_def_var["isbn+2"].text_isbn_ygap_factor = text_ygap_factor
+par_def_var["isbn"].text_isbn_ygap_factor = text_ygap_factor
+-- ISSN
+par_def_var["issn+5"].text_issn_ygap_factor = text_ygap_factor
+par_def_var["issn+2"].text_issn_ygap_factor = text_ygap_factor
+par_def_var["issn"].text_issn_ygap_factor = text_ygap_factor
-- configuration functions
@@ -229,7 +349,7 @@ local function config_full(ean, Vbar, mod, n1, n2)
ean._is_last_checksum = true
end
-EAN._config_variant = {
+local config_variant = {
["13"] = function (ean13, Vbar, mod)
ean13._main_len = 13
ean13._is_last_checksum = true
@@ -278,7 +398,6 @@ EAN._config_variant = {
for c = 1, 2 do
tvbar[c] = {}
local tcs = tvbar[c]
- local isbar = false
local sb = symbols[c]
for i = 0, 9 do
tcs[i] = Vbar:from_int(sb[i], mod, false)
@@ -296,7 +415,6 @@ EAN._config_variant = {
for c = 1, 2 do
tvbar[c] = {}
local tcs = tvbar[c]
- local isbar = false
local sb = symbols[c]
for i = 0, 9 do
tcs[i] = Vbar:from_int(sb[i], mod, false)
@@ -316,28 +434,21 @@ EAN._config_variant = {
config_full(ean, Vbar, mod, 8, 2)
end,
}
-
--- config function
--- create all the possible VBar object
-function EAN:config(variant) --> ok, err
- if not type(variant) == "string" then
- return false, "[ArgErr] incorrect type for 'variant', string expected"
- end
- local fnconfig = self._config_variant[variant]
- if not fnconfig then
- return false, "[Err] EAN variant '".. variant .."' not found"
- end
- local Vbar = self._libgeo.Vbar -- Vbar class
- local mod = self.mod
- fnconfig(self, Vbar, mod)
- return true, nil
-end
+-- ISBN
+config_variant["isbn"] = config_variant["13"]
+config_variant["isbn+2"] = config_variant["13+2"]
+config_variant["isbn+5"] = config_variant["13+5"]
+-- ISSN
+config_variant["issn"] = config_variant["13"]
+config_variant["issn+2"] = config_variant["13+2"]
+config_variant["issn+5"] = config_variant["13+5"]
+EAN._config_variant = config_variant
-- utility function
-- the checksum of EAN8 or EAN13 code
-- 'data' is an array of digits
-local function checksum_8_13(data, stop_index)
+local function checksum_8_13(data, stop_index) --> checksum
local s1 = 0; for i = 2, stop_index, 2 do
s1 = s1 + data[i]
end
@@ -369,6 +480,445 @@ local function checksum_5_2(data, i, len) --> checksum digit or nil
end
end
+-- ISBN utility function
+
+-- return the ISBN 10 digits checksum
+local function isbn_checksum(isbn)
+ local sum = 0
+ for w = 1, 9 do
+ sum = sum + w * isbn[w]
+ end
+ return sum % 11
+end
+
+-- group char for readibility '-' or ' '
+-- char won't be inserted in the top isbn code
+local function isbn_check_char(_, c, parse_state) --> elem, err
+ if type(c) ~= "string" or #c ~= 1 then
+ return nil, "[InternalErr] invalid char"
+ end
+ if parse_state.isbncode == nil then parse_state.isbncode = {} end
+ local code = parse_state.isbncode
+ if parse_state.isspace == nil then parse_state.isspace = false end
+ if parse_state.isdash == nil then parse_state.isdash = false end
+ if parse_state.isbn_len == nil then parse_state.isbn_len = 0 end
+ local isbn_len = parse_state.isbn_len
+ if c == "-" then
+ if isbn_len == 0 then
+ return nil, "[ArgErr] an initial dash is not allowed"
+ end
+ if parse_state.isdash then
+ return nil, "[ArgErr] two consecutive dash char found"
+ end
+ parse_state.isdash = true
+ return nil, nil
+ elseif c == " " then
+ if isbn_len == 0 then
+ return nil, "[ArgErr] an initial space is not allowed"
+ end
+ parse_state.isspace = true
+ return nil, nil
+ elseif c == "X" then -- ISBN-10 checksum for 10
+ code[#code + 1] = c
+ isbn_len = isbn_len + 1
+ parse_state.isbn_len = isbn_len
+ if isbn_len ~= 10 then
+ return nil, "[ArgErr] found a checksum 'X' in a wrong position"
+ end
+ return 10, nil
+ else -- c is at this point eventually a digit
+ local n = string.byte(c) - 48
+ if n < 0 or n > 9 then
+ return nil, "[ArgErr] found a not digit or a not grouping char"
+ end
+ if parse_state.isdash then -- close a group
+ code[#code + 1] = "-"
+ parse_state.isdash = false
+ parse_state.isspace = false
+ elseif parse_state.isspace then
+ code[#code + 1] = " "
+ parse_state.isspace = false
+ end
+ code[#code + 1] = c
+ isbn_len = isbn_len + 1
+ parse_state.isbn_len = isbn_len
+ return n, nil
+ end
+end
+
+-- overriding function called every time an input ISBN code has been completely
+-- parsed
+local function isbn_finalize(enc, parse_state) --> ok, err
+ local var = enc._variant
+ local code_len = enc._code_len
+ local isbn_len = parse_state.isbn_len
+ local l1, l2
+ if var == "isbn" then
+ if isbn_len == 10 then
+ l1 = 10
+ elseif isbn_len == 13 then
+ l1 = 13
+ else
+ return false, "[ArgErr] unsuitable ISBN code length"
+ end
+ assert(l1 == code_len)
+ elseif var == "isbn+5" then
+ assert(enc._addon_len == 5)
+ if isbn_len == 15 then
+ l1, l2 = 10, 5
+ elseif isbn_len == 18 then
+ l1, l2 = 13, 5
+ else
+ return false, "[ArgErr] unsuitable ISBN+5 code length"
+ end
+ assert(l1 + l2 == code_len)
+ elseif var == "isbn+2" then
+ assert(enc._addon_len == 2)
+ if isbn_len == 12 then
+ l1, l2 = 10, 2
+ elseif isbn_len == 15 then
+ l1, l2 = 13, 2
+ else
+ return false, "[ArgErr] unsuitable ISBN+2 code length"
+ end
+ assert(l1 + l2 == code_len)
+ else
+ error("[InternalErr] unexpected ISBN variant code")
+ end
+ local code_data = enc._code_data
+ local isbn_auto = false
+ if l1 == 10 then -- isbn 10 to 13 conversion
+ local ck = isbn_checksum(code_data)
+ if ck ~= code_data[10] then
+ return false, "[ArgErr] unmatched ISBN 10 checksum"
+ end
+ for i = l1 + (l2 or 0), 1, -1 do -- code_data sliding
+ code_data[i + 3] = code_data[i]
+ end
+ code_data[1] = 9
+ code_data[2] = 7
+ code_data[3] = 8
+ code_data[13] = checksum_8_13(code_data, 12)
+ isbn_auto = true
+ else
+ local ck = checksum_8_13(code_data, 12)
+ if code_data[13] ~= ck then
+ return false, "[ArgErr] unmatched ISBN 13 checksum"
+ end
+ end
+ local isbncode = parse_state.isbncode
+ if l2 then -- nils the add-on digits
+ local i = #isbncode
+ while l2 > 0 do
+ local c = isbncode[i]
+ isbncode[i] = nil
+ i = i - 1
+ if not (c == " " or c == "-") then
+ l2 = l2 - 1
+ end
+ end
+ local c = isbncode[i]
+ if c == " " or c == "-" then isbncode[i] = nil end
+ end
+ -- check group number
+ local g = 0
+ for _, c in ipairs(isbncode) do
+ if c == "-" or c == " " then
+ g = g + 1
+ end
+ end
+ if g > 4 then
+ return false, "[ArgErr] too many groups found in the ISBN code"
+ end
+ if g > 0 then isbn_auto = true end
+ enc._isbncode = isbncode
+ enc._isbntxt_on = isbn_auto
+ return true, nil
+end
+
+-- ISSN utility fucntion
+
+-- return the ISSN checksum
+local function issn_checksum(issn)
+ local sum = 0
+ for i = 1, 7 do
+ sum = sum + (9 - i) * issn[i]
+ end
+ local r = sum % 11
+ if r == 0 then
+ return 0
+ else
+ return 11 - r
+ end
+end
+
+local function to_n(c) --> n, err
+ local n = string.byte(c) - 48
+ if n < 0 or n > 9 then
+ return nil, true
+ end
+ return n, false
+end
+
+-- ISSN dddd-dddx[dd] or 13-long array
+-- spaces is always ignored
+local function issn_check_char(enc, c, parse_state) --> elem, err
+ if (type(c) ~= "string") or (#c ~= 1) then
+ return nil, "[InternalErr] invalid char"
+ end
+ if parse_state.is_dash == nil then parse_state.is_dash = false end
+ if parse_state.is_group_open == nil then parse_state.is_group_open = false end
+ if parse_state.is_group_close == nil then parse_state.is_group_close = false end
+ if parse_state.ed_var_len == nil then parse_state.ed_var_len = 0 end
+ if parse_state.ed_var_arr == nil then parse_state.ed_var_arr = {} end
+ if parse_state.code_len == nil then parse_state.code_len = 0 end
+ if parse_state.addon_len == nil then parse_state.addon_len = 0 end
+ local addon_len = enc._addon_len
+ -- edition variant part
+ if c == " " then
+ return nil, nil -- ignore all spaces
+ end
+ if parse_state.is_group_close then
+ if addon_len then
+ if parse_state.addon_len == enc._addon_len then
+ return nil, "[ArgErr] too many chars in the ISSN input code"
+ end
+ local n, e = to_n(c)
+ if e then
+ return nil, "[ArgErr] non digit char after a edition variant group"
+ end
+ parse_state.addon_len = parse_state.addon_len + 1
+ return n, nil
+ else
+ return nil, "[ArgErr] too many chars in the ISSN input code"
+ end
+ end
+ -- code part
+ if c == "-" then
+ if parse_state.is_dash then
+ return nil, "[ArgErr] two or more dash char in the input code"
+ end
+ if parse_state.code_len ~= 4 then
+ return nil, "[ArgErr] incorrect position for a dash sign"
+ end
+ parse_state.is_dash = true
+ return nil, nil
+ elseif c == "[" then -- two digits edition variant group opening
+ if parse_state.code_len ~= 8 then
+ return nil, "[ArgErr] not a 8 digits long code for the ISSN input"
+ end
+ parse_state.is_group_open = true
+ return nil, nil
+ elseif c == "]" then -- two digits edition variant closing
+ if not parse_state.is_group_open then
+ return nil, "[ArgErr] found a ']' without a '['"
+ end
+ if parse_state.ed_var_len ~= 2 then
+ return nil, "[ArgErr] edition variant group must be two digits long"
+ end
+ parse_state.is_group_open = false
+ parse_state.is_group_close = true
+ return nil, nil
+ elseif c == "X" then -- 8th ISSN checksum digit
+ if parse_state.code_len ~= 7 then
+ return nil, "[ArgErr] incorrect position for checksum digit 'X'"
+ end
+ parse_state.code_len = 8
+ return 10, nil
+ else -- at this point 'c' can be only a digit
+ local n, e = to_n(c)
+ if e then
+ return nil, "[ArgErr] found a non digit in code part"
+ end
+ if parse_state.is_group_open then
+ if parse_state.ed_var_len == 2 then
+ return nil, "[ArgErr] group digits are more than two"
+ end
+ parse_state.ed_var_len = parse_state.ed_var_len + 1
+ local t = parse_state.ed_var_arr
+ t[#t + 1] = n
+ return nil, nil
+ end
+ if parse_state.is_dash then
+ if addon_len then
+ if parse_state.code_len < 8 then
+ parse_state.code_len = parse_state.code_len + 1
+ else
+ if parse_state.addon_len == addon_len then
+ return nil, "[ArgErr] too many digits for a 8 + "..addon_len.." ISSN input code"
+ end
+ parse_state.addon_len = parse_state.addon_len + 1
+ end
+ else
+ if parse_state.code_len == 8 then
+ return nil, "[ArgErr] too many digits found for a 8 digits long ISSN input code"
+ end
+ parse_state.code_len = parse_state.code_len + 1
+ end
+ else
+ if addon_len then
+ if parse_state.code_len == (13 + addon_len) then
+ return nil, "[ArgErr] too many digits in ISSN input code"
+ end
+ else
+ if parse_state.code_len == 13 then
+ return nil, "[ArgErr] too many digits in a 13 digits long ISSN input code"
+ end
+ end
+ parse_state.code_len = parse_state.code_len + 1
+ end
+ return n, nil
+ end
+end
+
+-- translate an ISSN 8 in an EAN 13
+local function issn8_to_13(issn, ed_var_1, ed_var_2) --> i13, i8, err
+ local r13, r8 = {9, 7, 7}, {}
+ for i = 1, 7 do
+ r8[i] = issn[i]
+ r13[i + 3] = issn[i]
+ end
+ local issn_cs = issn_checksum(r8)
+ if issn_cs ~= issn[8] then
+ return nil, nil, "[Err] unmatch ISSN 8 checksum"
+ end
+ for i = 1, 7 do
+ r8[i] = string.char(r8[i] + 48)
+ end
+ if issn_cs == 10 then
+ r8[8] = "X"
+ else
+ r8[8] = string.char(issn_cs + 48)
+ end
+ r13[11] = ed_var_1
+ r13[12] = ed_var_2
+ r13[13] = checksum_8_13(r13, 12)
+ return r13, r8, nil
+end
+
+-- translate an EAN 13 to an ISSN 8 input code
+local function ean13_to_issn8(ean)
+ local res = {}
+ for i = 4, 10 do
+ res[i - 3] = ean[i]
+ end
+ local issn_cs = issn_checksum(res)
+ for i = 1, 7 do
+ res[i] = string.char(res[i] + 48)
+ end
+ if issn_cs == 10 then
+ res[8] = "X"
+ else
+ res[8] = string.char(issn_cs + 48)
+ end
+ return res
+end
+
+-- finalize the ISSN input code
+-- new field 'enc._issn_is_short_input' -- the input code was 8 digits long
+-- new filed 'enc._issn_is_dash' -- the 8 digits long input code contained a dash
+local function issn_finalize(enc, parse_state) --> ok, err
+ if parse_state.is_group_open then
+ return false, "[ArgErr] unclosed edition variant group in ISSN input code"
+ end
+ local data = enc._code_data
+ local code_len = enc._code_len
+ local addon_len = enc._addon_len
+ local main_len = code_len - (addon_len or 0)
+ if main_len == 8 then
+ -- make the 8 long array for human readable text
+ local ev1, ev2 = 0, 0
+ if parse_state.ed_var_len > 0 then
+ local edvar = parse_state.ed_var_arr
+ ev1, ev2 = edvar[1], edvar[2]
+ end
+ local issn13, issn8, err = issn8_to_13(data, ev1, ev2)
+ if err then return false, err end
+ if addon_len then
+ for i = 9, 9 + addon_len do
+ issn13[i + 5] = data[i] -- save addon digits
+ end
+ end
+ enc._code_data = issn13
+ enc._code_text = issn8
+ enc._issn_is_short_input = true
+ enc._issn_is_dash = parse_state.is_dash
+ elseif main_len == 13 then
+ local ck = checksum_8_13(data, 12) -- check EAN checksum
+ if ck ~= data[13] then
+ return false, "[Err] wrong checksum digit"
+ end
+ -- make 8 long array for human readable text
+ enc._code_text = ean13_to_issn8(data)
+ enc._issn_is_short_input = false
+ else
+ return nil, "[ArgErr] incorrect digits number of "..main_len.." in input ISSN code"
+ end
+ return true, nil
+end
+
+-- finalize for basic encoder
+local function basic_finalize(enc) --> ok, err
+ local l1 = enc._main_len
+ local l2 = enc._addon_len
+ local ok_len = l1 + (l2 or 0)
+ local symb_len = enc._code_len
+ if symb_len ~= ok_len then
+ return false, "[ArgErr] not a "..ok_len.."-digit long array"
+ end
+ if enc._is_last_checksum then -- is the last digit ok?
+ local data = enc._code_data
+ local ck = checksum_8_13(data, l1 - 1)
+ if ck ~= data[l1] then
+ return false, "[Err] wrong checksum digit"
+ end
+ end
+ return true, nil
+end
+
+-- config function called at the moment of encoder construction
+-- create all the possible VBar object
+function EAN:_config() --> ok, err
+ local variant = self._variant
+ if not variant then
+ return false, "[Err] variant is mandatory for EAN family"
+ end
+ local plus = variant:find("+")
+ local v1
+ if plus then
+ v1 = variant:sub(1, plus - 1)
+ self._sub_variant_1 = v1
+ self._sub_variant_2 = variant:sub(plus + 1)
+ else
+ v1 = variant
+ self._sub_variant_1 = v1
+ end
+ local fnconfig = self._config_variant[variant]
+ local VbarClass = self._libgeo.Vbar -- Vbar class
+ local mod = self.mod
+ fnconfig(self, VbarClass, mod)
+ if v1 == "isbn" then
+ self._check_char = isbn_check_char
+ elseif v1 == "issn" then
+ self._check_char = issn_check_char
+ end
+ return true, nil
+end
+
+-- internal methods for Barcode costructors
+
+-- function called every time an input EAN code has been completely parsed
+function EAN:_finalize(parse_state) --> ok, err
+ local v1 = self._sub_variant_1
+ if v1 == "isbn" then
+ return isbn_finalize(self, parse_state) --> ok, err
+ elseif v1 == "issn" then
+ return issn_finalize(self, parse_state) --> ok, err
+ else
+ return basic_finalize(self) --> ok, err
+ end
+end
+
-- public methods
-- return the checksum digit of the argument or an error
@@ -381,21 +931,21 @@ function EAN:checksum(n) --> n, err
return nil, "[ArgErr] number must be a positive integer"
end
if n - math.floor(n) > 0 then
- return nil, "[ArgErr] 'n' is not an integer"
+ return nil, "[ArgErr] 'n' argument is not an integer"
end
arr = {}
local i = 0
while n > 0 do
i = i + 1
arr[i] = n % 10
- n = (n - arr[i]) / 10
+ n = math.floor((n - arr[i]) / 10)
end
-- array reversing
local len = #arr + 1
- for i = 1, #arr/2 do
- local dt = arr[i]
- arr[i] = arr[len - i]
- arr[len - i] = dt
+ for k = 1, #arr/2 do
+ local dt = arr[k]
+ arr[k] = arr[len - k]
+ arr[len - k] = dt
end
elseif type(n) == "table" then
if not #n > 0 then return nil, "[ArgErr] empty array" end
@@ -430,32 +980,6 @@ function EAN:checksum(n) --> n, err
end
end
-function EAN:get_code() --> string
- local var = self._variant
- local code = self.code13 -- TODO:
- return table.concat(code)
-end
-
--- internal methods for Barcode costructors
-
-function EAN:_finalize() --> ok, err
- local l1 = self._main_len
- local l2 = self._addon_len
- local ok_len = l1 + (l2 or 0)
- local symb_len = self._code_len
- if symb_len ~= ok_len then
- return false, "[ArgErr] not a "..ok_len.."-digits long array"
- end
- if self._is_last_checksum then -- is the last digit ok?
- local data = self._code_data
- local ck = checksum_8_13(data, l1 - 1)
- if ck ~= data[l1] then
- return false, "[Err] wrong checksum digit"
- end
- end
- return true, nil
-end
-
-- drawing functions
EAN._append_ga_variant = {}
@@ -506,7 +1030,7 @@ fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay)
-- bounding box set up
local qzl = ean.quietzone_left_factor * mod
local qzr = ean.quietzone_right_factor * mod
- local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
+ err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
assert(not err, err)
if ean.text_enabled then -- human readable text
local Text = ean._libgeo.Text
@@ -515,7 +1039,6 @@ fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay)
local txt_3 = Text:from_digit_array(code, 8, 13)
local y_bl = ys - ean.text_ygap_factor * mod
local mx = ean.text_xgap_factor
- local err
err = canvas:encode_Text(txt_1, x0 - qzl, y_bl, 0, 1)
assert(not err, err)
local x2_1 = x0 + (3+mx)*mod
@@ -526,6 +1049,45 @@ fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay)
local x3_2 = x0 + (92-mx)*mod
err = canvas:encode_Text_xwidth(txt_3, x3_1, x3_2, y_bl, 1)
assert(not err, err)
+ local istxt = false
+ if ean.text_isbn_enabled then
+ if ean.text_isbn_enabled == "auto" then
+ if ean._isbntxt_on == true then
+ istxt = true
+ end
+ else
+ istxt = true
+ end
+ end
+ if istxt then
+ local isbn = assert(ean._isbncode, "[InternalErr] ISBN text not found")
+ local descr = {"I", "S", "B", "N", " ",}
+ for _, d in ipairs(isbn) do
+ descr[#descr + 1] = d
+ end
+ local isbn_txt = Text:from_chars(descr)
+ local x_isbn = x0 + 47.5 * mod
+ local y_isbn = y1 + ean.text_isbn_ygap_factor * mod
+ err = canvas:encode_Text(isbn_txt, x_isbn, y_isbn, 0.5, 0)
+ assert(not err, err)
+ end
+ -- issn text
+ if ean.text_issn_enabled then
+ local hri = {"I", "S", "S", "N", " "}
+ local txt = assert(ean._code_text, "[IternalErr] _code_text not found")
+ for i = 1, 4 do
+ hri[i + 5] = txt[i]
+ end
+ hri[10] = "-"
+ for i = 5, 8 do
+ hri[i + 6] = txt[i]
+ end
+ local issn_txt = Text:from_chars(hri)
+ local x_issn = x0 + 47.5 * mod
+ local y_issn = y1 + ean.text_issn_ygap_factor * mod
+ err = canvas:encode_Text(issn_txt, x_issn, y_issn, 0.5, 0)
+ assert(not err, err)
+ end
end
end
@@ -574,7 +1136,7 @@ fn_append_ga_variant["8"] = function (ean, canvas, tx, ty, ax, ay)
-- bounding box set up
local qzl = ean.quietzone_left_factor * mod
local qzr = ean.quietzone_right_factor * mod
- local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
+ err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
assert(not err, err)
if ean.text_enabled then -- human readable text
local Text = ean._libgeo.Text
@@ -640,7 +1202,7 @@ fn_append_ga_variant["5"] = function (ean, canvas, tx, ty, ax, ay, h)
-- bounding box set up
local qzl = ean.quietzone_left_factor * mod
local qzr = ean.quietzone_right_factor * mod
- local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
+ err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
assert(not err, err)
if ean.text_enabled then -- human readable text
local Text = ean._libgeo.Text
@@ -703,7 +1265,7 @@ fn_append_ga_variant["2"] = function (ean, canvas, tx, ty, ax, ay, h)
-- bounding box set up
local qzl = ean.quietzone_left_factor * mod
local qzr = ean.quietzone_right_factor * mod
- local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
+ err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1)
assert(not err, err)
if ean.text_enabled then -- human readable text
local Text = ean._libgeo.Text
@@ -776,6 +1338,15 @@ fn_append_ga_variant["8+2"] = function (ean, canvas, tx, ty, ax, ay)
fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h)
end
+-- ISBN
+fn_append_ga_variant["isbn"] = fn_append_ga_variant["13"]
+fn_append_ga_variant["isbn+5"] = fn_append_ga_variant["13+5"]
+fn_append_ga_variant["isbn+2"] = fn_append_ga_variant["13+2"]
+-- ISSN
+fn_append_ga_variant["issn"] = fn_append_ga_variant["13"]
+fn_append_ga_variant["issn+5"] = fn_append_ga_variant["13+5"]
+fn_append_ga_variant["issn+2"] = fn_append_ga_variant["13+2"]
+
-- Drawing into the provided channel geometrical data
-- tx, ty is the optional translation vector
-- the function return the canvas reference to allow call chaining
diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua
index 8097b855f7..2e1dcd4a02 100644
--- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua
+++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua
@@ -1,14 +1,18 @@
-- Interleaved 2 of 5 (ITF) barcode generator
--
--- Copyright (C) 2019 Roberto Giacomelli
+-- Copyright (C) 2020 Roberto Giacomelli
-- see LICENSE.txt file
local ITF = { -- main container
- _VERSION = "ITF v0.0.1",
- _NAME = "ITF",
+ _VERSION = "i2of5 v0.0.1",
+ _NAME = "i2of5",
_DESCRIPTION = "Interleaved 2 of 5 barcode encoder",
}
+ITF._id_variant = {
+ ITF14 = true, -- ITF 14 GS1 specification
+}
+
ITF._start = 111 -- nnnn
ITF._stop = 112 -- Wnn (integer must be in reverse order)
@@ -26,6 +30,17 @@ ITF._pattern = { -- true -> narrow, false -> Wide
}
-- define parameters
+ITF._par_order = {
+ "module",
+ "ratio",
+ "height",
+ "quietzone",
+ "check_digit_policy",
+ "check_digit_method",
+ "bearer_bars_enabled",
+ "bearer_bars_thickness",
+ "bearer_bars_layout",
+}
ITF._par_def = {}
local pardef = ITF._par_def
@@ -37,8 +52,7 @@ pardef.module = {
default = 7.5 * 0.0254 * 186467, -- 7.5 mils (sp) unit misure,
unit = "sp", -- scaled point
isReserved = true,
- order = 1, -- the one first to be modified
- fncheck = function (self, mod, _) --> boolean, err
+ fncheck = function (self, mod, _t_opt) --> boolean, err
if mod >= self.default then return true, nil end
return false, "[OutOfRange] too small lenght for X-dim"
end,
@@ -53,10 +67,9 @@ pardef.ratio = {
default = 3.0,
unit = "absolute-number",
isReserved = true,
- order = 2,
- fncheck = function (_, ratio, tpardef) --> boolean, err
- local mils = 0.0254 * 186467
- local mod = tpardef.module
+ fncheck = function (_self, ratio, t_opt) --> ok, err
+ local mils = 0.0254 * 186467 -- sp
+ local mod = t_opt.module
local minr; if mod < 20*mils then minr = 2.2 else minr = 2.0 end
if ratio < minr then
return false, "[OutOfRange] too small ratio (the min is "..minr..")"
@@ -73,9 +86,8 @@ pardef.height = {
default = 15 * 186467, -- 15mm -- TODO: better assessment for symbol length
unit = "sp", -- scaled point
isReserved = false,
- order = 3,
- fncheck = function (_self, h, _opt) --> boolean, err
- local mils = 0.0254 * 186467
+ fncheck = function (_self, h, _t_opt) --> boolean, err
+ local mils = 0.0254 * 186467 -- scaled point (sp)
if h >= 250*mils then
return true, nil
end
@@ -89,16 +101,14 @@ pardef.quietzone = {
default = 250 * 0.0254 * 186467, -- 0.25 inch (250 mils)
unit = "sp", -- scaled point
isReserved = false,
- order = 4,
- fncheck = function (self, qz, _opt) --> boolean, err
+ fncheck = function (self, qz, _t_opt) --> boolean, err
local mils = 0.0254 * 186467
local mod = self.module
local min = math.max(10*mod, 250*mils)
- if qz >= min then
- return true, nil
- else
+ if qz < min then
return false, "[OutOfRange] quietzone too small"
end
+ return true, nil
end,
}
@@ -110,8 +120,7 @@ pardef.check_digit_policy = { -- enumeration
verify = true, -- check the last digit of the symbol as check digit
none = true, -- do nothing
},
- order = 5,
- fncheck = function (self, e, _) --> boolean, err
+ fncheck = function (self, e, _t_opt) --> boolean, err
if type(e) ~= "string" then return false, "[TypeError] not a string" end
local keys = self.policy_enum
if keys[e] == true then
@@ -126,11 +135,10 @@ pardef.check_digit_method = { -- enumeration
-- determine the algorithm for the check digit calculation
default = "mod_10",
isReserved = false,
- order = 6,
method_enum = {
mod_10 = true, -- MOD 10 check digits method
},
- fncheck = function (self, e, _) --> boolean, err
+ fncheck = function (self, e, _t_opt) --> boolean, err
if type(e) ~= "string" then return false, "[TypeError] not a string" end
local keys = self.method_enum
if keys[e] == true then
@@ -145,8 +153,7 @@ pardef.bearer_bars_enabled = { -- boolean type
-- enable/disable Bearer bars around the barcode symbol
default = false,
isReserved = false,
- order = 7,
- fncheck = function (_, flag, _) --> boolean, err
+ fncheck = function (_self, flag, _t_opt) --> boolean, err
if type(flag) == "boolean" then
return true, nil
else
@@ -159,26 +166,162 @@ pardef.bearer_bars_thickness = { -- dimension
default = 37.5 * 0.0254 * 186467, -- 5 modules
unit = "sp", -- scaled point
isReserved = false,
- order = 8,
- fncheck = function (_self, thick, tpardef) --> boolean, err
- local module = tpardef.module
+ fncheck = function (_self, thick, t_opt) --> boolean, err
+ local module = t_opt.module
if thick >= 2*module then
return true, nil
end
- return false, "[OutOfRange] thickness too small"
+ return false, "[OutOfRange] too small bearer bar thickness"
end,
}
pardef.bearer_bars_layout = { -- enumeration
- -- determine the algorithm for the check digit calculation
+ -- horizontal/frame bearer bars
default = "hbar",
isReserved = false,
- order = 9,
+ method_enum = {
+ frame = true, -- a rectangle around the symbol
+ hbar = true, -- only top and bottom horizontal bars
+ },
+ fncheck = function (self, e, _t_opt) --> boolean, err
+ if type(e) ~= "string" then return false, "[TypeError] not a string" end
+ local keys = self.method_enum
+ if keys[e] == true then
+ return true, nil
+ else
+ return false, "[Err] enum value not found"
+ end
+ end,
+}
+
+-- ITF14: variant based on GS1 specification, see
+-- https://www.gs1.org/sites/default/files/docs/barcodes/GS1_General_Specifications.pdf
+-- GS1 ITF14 parameters vary in range and preferred value on the specific
+-- application. Default are chosen for better suite the majority of cases
+
+-- ITF14 variant parameters as family parameters alternative
+ITF._par_def_ITF14 = {}
+local itf14_pdef = ITF._par_def_ITF14
+
+itf14_pdef.module = { -- module main parameter
+ -- Narrow element X-dimension is the width of the smallest element.
+ -- The module width must follow GS1 specification
+ default = 0.495 * 186467, -- 0.495 mm
+ unit = "sp", -- scaled point
+ isReserved = true,
+ fncheck = function (_self, mod, _t_opt) --> boolean, err
+ local mod_mm = mod * 186467 -- mm
+ if (mod_mm < 0.264) or (mod_mm > 0.660) then
+ return false, "[OutOfRange] X-dim is out of [0.264mm, 0.660mm]"
+ end
+ return true, nil
+ end,
+}
+
+itf14_pdef.ratio = {
+ -- The "wide" element is a multiple of the "narrow" element that can
+ -- range between 2.25 and 3.0.
+ default = 2.5,
+ unit = "absolute-number",
+ isReserved = true,
+ fncheck = function (_self, ratio, _t_opt) --> boolean, err
+ if (ratio < 2.25) or (ratio > 3.0) then
+ return false, "[OutOfRange] wide-to-narrow ratio is out of [2.25, 3.0]"
+ end
+ return true, nil
+ end,
+}
+
+itf14_pdef.height = {
+ -- The height should be at least 5.08 mm. Target value is 12.70 mm
+ -- except in retail pharmacy and general distribution or non-retail pharmacy
+ -- and general distribution
+ default = 12.70 * 186467, -- mm
+ unit = "sp", -- scaled point
+ isReserved = false,
+ fncheck = function (_self, h, _t_opt) --> boolean, err
+ if h < 5.08 * 186467 then
+ return false, "[OutOfRange] height is too small"
+ end
+ return true, nil
+ end,
+}
+
+itf14_pdef.quietzone = {
+ -- Quiet zones must be at least 10 times the module width
+ default = 10,
+ unit = "absolute-number", -- scaled point
+ isReserved = false,
+ fncheck = function (_self, qz, _t_opt) --> boolean, err
+ if qz < 10 then
+ return false, "[OutOfRange] quietzone factor is too small (min 10x)"
+ else
+ return true, nil
+ end
+ end,
+}
+
+itf14_pdef.check_digit_policy = { -- enumeration
+ default = "check_or_add",
+ isReserved = false,
+ policy_enum = {
+ check_or_add = true,
+ add = true, -- add a check digit to the symbol
+ verify = true, -- check the last digit of the symbol as check digit
+ },
+ fncheck = function (self, e, _t_opt) --> boolean, err
+ if type(e) ~= "string" then return false, "[TypeError] not a string" end
+ local keys = self.policy_enum
+ if keys[e] == true then
+ return true, nil
+ else
+ return false, "[Err] enum value '"..e.."' not found"
+ end
+ end,
+}
+
+-- itf14_pdef.check_digit_method = {} the same as the basic parameter
+
+itf14_pdef.bearer_bars_enabled = { -- boolean type
+ -- enable/disable Bearer bars around the barcode symbol
+ default = true,
+ isReserved = false,
+ fncheck = function (_self, flag, _t_opt) --> boolean, err
+ if type(flag) == "boolean" then
+ return true, nil
+ else
+ return false, "[TypeErr] not a boolean value"
+ end
+ end,
+}
+
+-- from GS1 spec:
+-- For printing methods that do not require printing plates, the bearer bar
+-- SHALL be a minimum of twice the width of a narrow bar (dark bar) and need
+-- only appear at the top and bottom of the symbol, butting directly against
+-- the top and bottom of the symbol bars (dark bars).
+pardef.bearer_bars_thickness = { -- dimension
+ default = 5 * 0.495 * 186467, -- 5 modules
+ unit = "sp", -- scaled point
+ isReserved = false,
+ fncheck = function (_self, thick, t_opt) --> boolean, err
+ local module = t_opt.module
+ if thick >= 2*module then
+ return true, nil
+ end
+ return false, "[OutOfRange] too small bearer bar thickness"
+ end,
+}
+
+itf14_pdef.bearer_bars_layout = { -- enumeration
+ -- horizontal/frame bearer bars
+ default = "frame",
+ isReserved = false,
method_enum = {
frame = true, -- a rectangle around the symbol
hbar = true, -- top and bottom horizontal bars
},
- fncheck = function (self, e, _) --> boolean, err
+ fncheck = function (self, e, _) --> boolean, err
if type(e) ~= "string" then return false, "[TypeError] not a string" end
local keys = self.method_enum
if keys[e] == true then
@@ -224,18 +367,15 @@ local function rshift(t)
t[1] = 0
end
-
-local function check_mod10(t, last)
- local sum = 0
- local w = true
- for i = last, 1, -1 do
- if w then
- sum = sum + 3*t[i]
- else
- sum = sum + t[i]
- end
- w = not w
+-- for general i2of5 symbols
+local function check_mod10(data, last)
+ local s3 = 0; for i = last, 1, -2 do
+ s3 = s3 + data[i]
end
+ local s1 = 0; for i = last - 1, 1, -2 do
+ s1 = s1 + data[i]
+ end
+ local sum = s1 + 3 * s3
local m = sum % 10
if m == 0 then return 0 else return 10 - m end
end
@@ -244,13 +384,60 @@ local function checkdigit(t, last, method)
if method == "mod_10" then
return check_mod10(t, last)
else
- assert(false, "[InternalErr] unknow method")
- end
+ error("[InternalErr] unknow checksum method '"..method.."'")
+ end
end
+-- group char for readibility '(' or ')' or ' '
+local function itf14_check_char(enc, c, parse_state) --> elem, err
+ if type(c) ~= "string" or #c ~= 1 then
+ return nil, "[InternalErr] invalid char"
+ end
+ if parse_state.itf14_code == nil then parse_state.itf14_code = {} end
+ local code = parse_state.itf14_code
+ if parse_state.is_space == nil then parse_state.is_space = false end
+ if parse_state.is_popen == nil then parse_state.is_popen = false end
+ if parse_state.itf14_len == nil then parse_state.itf14_len = 0 end
+ local itf14_len = parse_state.itf14_len
+ -- parsing
+ if c == " " then
+ if itf14_len == 0 then -- ignore initial spaces
+ return nil, nil
+ end
+ parse_state.is_space = true
+ return nil, nil
+ elseif c == "(" then
+ if parse_state.is_popen then
+ return nil, "[Err] a parenthesis group is already open"
+ end
+ parse_state.is_popen = true
+ code[#code + 1] = c
+ return nil, nil
+ elseif c == ")" then
+ if not parse_state.is_popen then
+ return nil, "[Err] found a closing parenthesis without an opening one"
+ end
+ parse_state.is_popen = false
+ code[#code + 1] = c
+ return nil, nil
+ else -- c is at this point eventually a digit
+ local n = string.byte(c) - 48
+ if n < 0 or n > 9 then
+ return nil, "[ArgErr] found a not digit or a not grouping char"
+ end
+ if parse_state.is_space then
+ code[#code + 1] = " "
+ parse_state.is_space = false
+ end
+ code[#code + 1] = c
+ itf14_len = itf14_len + 1
+ parse_state.itf14_len = itf14_len
+ return n, nil
+ end
+end
-- configuration function
-function ITF:config() --> ok, err
+function ITF:_config() --> ok, err
-- init Vbar objects
local narrow = self.module
local wide = narrow * self.ratio
@@ -258,7 +445,6 @@ function ITF:config() --> ok, err
local Vbar = self._libgeo.Vbar -- Vbar class
self._vbar_start = Vbar:from_int_revpair(self._start, narrow, wide)
self._vbar_stop = Vbar:from_int_revpair(self._stop, narrow, wide)
-
-- build every possible pair of digits from 00 to 99
self._vbar_data = {}
local vbar = self._vbar_data
@@ -271,28 +457,66 @@ function ITF:config() --> ok, err
vbar[n] = Vbar:from_two_tab(t1, t2, narrow, wide)
end
end
+ local variant = self._variant
+ if variant == "ITF14" then
+ self._check_char = itf14_check_char
+ end
return true, nil
end
--- public functions
+-- internal methods for constructors
-function ITF:get_checkdigit(n, method)
- if type(n) ~= "number" then return nil, "[ArgErr] 'n' is not a number" end
- if n < 0 then return nil, "[ArgErr] found a negative number" end
- if n - math.floor(n) ~= 0 then return nil, "[ArgErr] found a float number" end
- method = method or self.check_digit_method
- local last, t = n_to_arr(n)
- return checkdigit(t, last, method)
+-- input code post processing for ITF14 variant
+local function itf14_finalize(enc) --> ok, err
+ -- check digit action
+ local policy = enc.check_digit_policy
+ local slen = enc._code_len
+ local digits = enc._code_data
+ local is_add
+ if policy == "verify" then
+ if slen ~= 14 then
+ return nil, "[DataErr] incorrect input lenght of "..slen..
+ " respect to 14 (checksum policy 'verify')"
+ end
+ is_add = false
+ elseif policy == "add" then
+ if slen ~= 13 then
+ return nil, "[DataErr] incorrect input lenght of "..slen..
+ " respect to 13 (checksum policy 'add')"
+ end
+ is_add = true
+ elseif policy == "check_or_add" then
+ if slen == 14 then
+ is_add = false
+ elseif slen == 13 then
+ is_add = true
+ else
+ return nil, "[DataErr] incorrect input lenght of "..slen..
+ " respect to the policy '"..policy.."'"
+ end
+ else
+ return false, "[InternalErr] incorrect policy enum value '"..policy.."'"
+ end
+ assert(type(is_add) == "boolean")
+ local cs = checkdigit(digits, 13, enc.check_digit_method)
+ if is_add then
+ digits[14] = cs
+ enc._code_len = 14
+ else
+ if cs ~= digits[14] then
+ return false, "[DataErr] last digit is not equal to checksum"
+ end
+ end
+ return true, nil
end
--- internal methods for constructors
-
-function ITF:_finalize() --> ok, err
+-- input code post processing for basic i2of5
+local function basic_finalize(enc) --> ok, err
-- check digit action
- local policy = self.check_digit_policy
- local slen = self._code_len
+ local policy = enc.check_digit_policy
+ local slen = enc._code_len
local is_even = (slen % 2 == 0)
- local digits = self._code_data
+ local digits = enc._code_data
if policy == "none" then
if not is_even then
rshift(digits) -- add a heading zero for padding
@@ -303,24 +527,46 @@ function ITF:_finalize() --> ok, err
rshift(digits) -- add a heading zero for padding
slen = slen + 1
end
- local c = checkdigit(digits, slen, self.check_digit_method)
+ local c = checkdigit(digits, slen, enc.check_digit_method)
digits[#digits + 1] = c
elseif policy == "verify" then
if not is_even then
rshift(digits)
slen = slen + 1
end
- local c = checkdigit(digits, slen - 1, self.check_digit_method)
+ local c = checkdigit(digits, slen - 1, enc.check_digit_method)
if c ~= digits[slen] then
return false, "[DataErr] wrong check digit"
end
else
return false, "[InternalError] wrong enum value"
end
- self._code_len = slen
+ enc._code_len = slen
return true, nil
end
+-- input code post processing
+function ITF:_finalize() --> ok, err
+ local var = self._variant
+ if var then
+ assert(var == "ITF14")
+ return itf14_finalize(self)
+ else
+ return basic_finalize(self)
+ end
+end
+
+-- public functions
+
+function ITF:get_checkdigit(n, method) --> checksum, err
+ if type(n) ~= "number" then return nil, "[ArgErr] 'n' is not a number" end
+ if n < 0 then return nil, "[ArgErr] found a negative number" end
+ if math.floor(n) ~= n then return nil, "[ArgErr] found a not integer number" end
+ method = method or self.check_digit_method
+ local last, t = n_to_arr(n)
+ return checkdigit(t, last, method)
+end
+
-- drawing function
-- tx, ty is an optional translator vector
function ITF:append_ga(canvas, tx, ty) --> canvas
@@ -352,6 +598,9 @@ function ITF:append_ga(canvas, tx, ty) --> canvas
-- bounding box setting
local x1 = xpos + (2 + ratio)*xdim
local qz = self.quietzone
+ if self._variant then
+ qz = qz * xdim
+ end
local b1x, b1y = x0 - qz, y0
local b2x, b2y = x1 + qz, y1
if self.bearer_bars_enabled then