diff options
Diffstat (limited to 'macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua')
-rw-r--r-- | macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua | 767 |
1 files changed, 669 insertions, 98 deletions
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 |