From 48805021c5bf259adfb73b376eb2c99dfb968fa6 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 5 Feb 2020 21:43:34 +0000 Subject: barracuda (5feb20) git-svn-id: svn://tug.org/texlive/trunk@53683 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/scripts/barracuda/barracuda.lua | 87 ++- .../scripts/barracuda/lib-barcode/brcd-barcode.lua | 393 ++++++----- .../scripts/barracuda/lib-barcode/brcd-code128.lua | 12 +- .../scripts/barracuda/lib-barcode/brcd-code39.lua | 36 +- .../scripts/barracuda/lib-barcode/brcd-ean.lua | 767 ++++++++++++++++++--- .../scripts/barracuda/lib-barcode/brcd-i2of5.lua | 373 ++++++++-- .../scripts/barracuda/lib-driver/brcd-driver.lua | 2 +- .../barracuda/lib-driver/brcd-drv-pdfliteral.lua | 6 +- .../scripts/barracuda/lib-driver/brcd-drv-svg.lua | 2 +- .../scripts/barracuda/lib-geo/brcd-gacanvas.lua | 2 +- .../scripts/barracuda/lib-geo/brcd-libgeo.lua | 4 +- 11 files changed, 1316 insertions(+), 368 deletions(-) (limited to 'Master/texmf-dist/scripts/barracuda') diff --git a/Master/texmf-dist/scripts/barracuda/barracuda.lua b/Master/texmf-dist/scripts/barracuda/barracuda.lua index 4d587ef952b..d8eae352165 100644 --- a/Master/texmf-dist/scripts/barracuda/barracuda.lua +++ b/Master/texmf-dist/scripts/barracuda/barracuda.lua @@ -2,7 +2,7 @@ -- -- Encode a message into a barcode symbol, in Lua or within a LuaTeX source file -- --- Copyright (C) 2019 Roberto Giacomelli +-- Copyright (C) 2020 Roberto Giacomelli -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by @@ -19,14 +19,15 @@ -- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -- Basic Conventions: --- fields that start with an undercore are private +-- fields that start with an undercore must be considered as private -- class name follows the snake case naming convention -- the 'barracuda' table is the only global object to access every package -- modules. local Barracuda = { - _VERSION = "barracuda v0.0.9.1", _NAME = "barracuda", + _VERSION = "barracuda v0.0.10", + _DATE = "2020-02-04", _DESCRIPTION = "Lua library for barcode printing", _URL = "https://github.com/robitex/barracuda", _LICENSE = "GNU GENERAL PUBLIC LICENSE, Version 2, June 1991", @@ -40,13 +41,20 @@ Barracuda._barcode = require "lib-barcode.brcd-barcode" -- barcode abstract cla local Barcode = Barracuda._barcode Barcode._libgeo = Barracuda._libgeo --- encoder builder -function Barracuda:get_barcode_class() --> Barcode class object +-- return a reference of Barcode abstract class +function Barracuda:barcode() --> Barcode class object return self._barcode end --- where we place output driver library -function Barracuda:get_driver() --> Driver object, err +-- encoder costructor (a bridge to Barcode class method) +function Barracuda:new_encoder(treename, opt) --> object, err + local barcode = self._barcode + local enc, err = barcode:new_encoder(treename, opt) --> object, err + return enc, err +end + +-- where we place the output driver library +function Barracuda:get_driver() --> Driver object if not self._lib_driver then self._lib_driver = require "lib-driver.brcd-driver" end @@ -63,54 +71,83 @@ end -- panic on error -- save barcode as a graphic external file -function Barracuda:save(bc_type, data, filename, id_drv) - local barcode = self:get_barcode_class() - local enc, err = barcode:new_encoder(bc_type) - assert(enc, err) - local arg_data = type(data) +-- 'treename' mandatory encoder identifier -: +-- 'data' mandatory the object string or integer being encoded +-- 'filename' mandatory output filename +-- 'id_drv' optional driver identifier, defualt 'svg' +-- 'opt' optional table for symbol parameters +function Barracuda:save(treename, data, filename, id_drv, opt) + local barcode = self._barcode + local enc_archive = barcode._encoder_instances + local enc = enc_archive[treename] + if not enc then + local err + enc, err = barcode:new_encoder(treename) + assert(enc, err) + end + -- make symbol local symb + local arg_data = type(data) if arg_data == "number" then local err_data symb, err_data = enc:from_uint(data) - asser(symb, err_data) + assert(symb, err_data) elseif arg_data == "string" then local err_data symb, err_data = enc:from_string(data) assert(symb, err_data) else - error("[argErr] unsupported 'data' type") + error("[ArgErr] unsupported type for 'data'") + end + if opt then + local ok, err = symb:set_param(opt) + assert(ok, err) end local canvas = self:new_canvas() symb:append_ga(canvas) local driver = self:get_driver() id_drv = id_drv or "svg" - local ok, out_err = driver:save(id_drv, canvas, filename) - assert(ok, out_err) + local ok, err = driver:save(id_drv, canvas, filename) + assert(ok, err) end -- this is a only LuaTeX method -function Barracuda:hbox(bc_type, data, box_name) - local barcode = self:get_barcode_class() - local enc, err = barcode:new_encoder(bc_type) - assert(enc, err) - local arg_data = type(data) +-- 'treename' mandatory encoder identifier -: +-- 'data' mandatory the object string or integer being encoded +-- 'box_name' mandatory TeX hbox name +-- 'opt' optional table for symbol parameters +function Barracuda:hbox(treename, data, box_name, opt) + local barcode = self._barcode + local enc_archive = barcode._encoder_instances + local enc = enc_archive[treename] + if not enc then + local err + enc, err = barcode:new_encoder(treename) + assert(enc, err) + end + -- make symbol local symb + local arg_data = type(data) if arg_data == "number" then local err_data symb, err_data = enc:from_uint(data) - asser(symb, err_data) + assert(symb, err_data) elseif arg_data == "string" then local err_data symb, err_data = enc:from_string(data) assert(symb, err_data) else - error("[argErr] unsupported 'data' type") + error("[ArgErr] unsupported type for 'data'") + end + if opt then + local ok, err = symb:set_param(opt) + assert(ok, err) end local canvas = self:new_canvas() symb:append_ga(canvas) local driver = self:get_driver() - local ok, err_hbox = driver:ga_to_hbox(canvas, box_name) - assert(ok, err_hbox) + local ok, err = driver:ga_to_hbox(canvas, box_name) + assert(ok, err) end return Barracuda diff --git a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua index 415719a2f4d..b43bc511d72 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua +++ b/Master/texmf-dist/scripts/barracuda/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 -. --- in more details: --- if there are variants --- if not --- i.e. when 'bc_type' is the string "ean-13", "ean" is the barcode family and +-- first argument 'tree_name' formatted as -:. +-- 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". +-- 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 @@ -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) --> , - 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) --> , + -- 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/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-code128.lua b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-code128.lua index 317b3de8f8e..1ee1c983434 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-code128.lua +++ b/Master/texmf-dist/scripts/barracuda/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/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-code39.lua b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-code39.lua index a639619c639..6d7f2ccea7f 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-code39.lua +++ b/Master/texmf-dist/scripts/barracuda/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/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-ean.lua b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-ean.lua index 6893550a5cf..bddaa36103d 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-ean.lua +++ b/Master/texmf-dist/scripts/barracuda/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/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-i2of5.lua b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-i2of5.lua index 8097b855f7b..2e1dcd4a020 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-i2of5.lua +++ b/Master/texmf-dist/scripts/barracuda/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 diff --git a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua index 4827a190c57..045a23e9d62 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua +++ b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-driver.lua @@ -1,6 +1,6 @@ -- -- ga Intermediate Graphic Language for barcode drawing --- Copyright (C) 2019 Roberto Giacomelli +-- Copyright (C) 2020 Roberto Giacomelli -- -- Basic driver interface -- drawing elementary vector shape diff --git a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua index 50baea1472c..b36021f9b62 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua +++ b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-pdfliteral.lua @@ -1,7 +1,7 @@ -- -- ga graphic assembler or -- Intermediate Graphic Language for barcode drawing --- Copyright (C) 2019 Roberto Giacomelli +-- Copyright (C) 2020 Roberto Giacomelli -- -- All dimensions are in scaled point (sp) -- ga LuaTeX Driver (native implementation node+pdfliteral) @@ -13,6 +13,10 @@ local PDFnative = { _DESCRIPTION = "A LuaTeX native pdfliteral driver for ga graphic stream", } +local tex = assert(tex, "This require a Lua powered TeX engine") +local node = assert(node, "This require a Lua powered TeX engine") +local font = assert(font, "This require a Lua powered TeX engine") + PDFnative.ext = "txt" -- file extension PDFnative.buf_sep = "\n" -- separation string for buffer concat diff --git a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua index 7a2c5ab1128..ce1f5bffbc2 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua +++ b/Master/texmf-dist/scripts/barracuda/lib-driver/brcd-drv-svg.lua @@ -1,7 +1,7 @@ -- -- ga Intermediate Graphic Language for barcode drawing -- SVG library --- Copyright (C) 2019 Roberto Giacomelli +-- Copyright (C) 2020 Roberto Giacomelli -- -- All dimension in the ga stream are scaled point (sp) -- 1 pt = 65536 sp diff --git a/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-gacanvas.lua b/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-gacanvas.lua index cccc68f447f..86eba659d1b 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-gacanvas.lua +++ b/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-gacanvas.lua @@ -1,5 +1,5 @@ -- class gaCanvas --- Copyright (C) 2019 Roberto Giacomelli +-- Copyright (C) 2020 Roberto Giacomelli -- ga -- basic function diff --git a/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-libgeo.lua b/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-libgeo.lua index fd53ca65095..630ed91b438 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-libgeo.lua +++ b/Master/texmf-dist/scripts/barracuda/lib-geo/brcd-libgeo.lua @@ -70,7 +70,7 @@ function Vbar:from_int(ngen, mod, is_bar) --> is_bar = not is_bar end local o = { - _yline = yl, -- [, , ...] flat array + _yline = yl, -- [, , ...] flat array _x_lim = x0, -- right external coordinate } setmetatable(o, self) @@ -153,7 +153,7 @@ function Vbar:from_int_revpair(ngen, mod, MOD, is_bar) --> return o end --- return a Vbar inteleaving to sequence narrow/Wide +-- return a Vbar interleaving narrow/Wide sequences -- tbar, tspace = {boolean sequence}, true -> narrow, false -> Wide function Vbar:from_two_tab(tbar, tspace, mod, MOD) --> assert(type(tbar) == "table", "tbar must be a table") -- cgit v1.2.3