summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua')
-rw-r--r--macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua404
1 files changed, 232 insertions, 172 deletions
diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua
index 1ee1c98343..294162f6b6 100644
--- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua
+++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code128.lua
@@ -1,11 +1,11 @@
-- Code128 barcode generator module
--- Copyright (C) 2020 Roberto Giacomelli
+-- Copyright (C) 2019-2022 Roberto Giacomelli
--
-- All dimension must be in scaled point (sp)
-- every fields that starts with an undercore sign are intended as private
local Code128 = {
- _VERSION = "code128 v0.0.5",
+ _VERSION = "code128 v0.0.6",
_NAME = "Code128",
_DESCRIPTION = "Code128 barcode encoder",
}
@@ -23,7 +23,7 @@ Code128._int_def_bar = {-- code bar definitions
111242, 121142, 121241, 114212, 124112, 124211, 411212, 421112, 421211,
212141, 214121, 412121, 111143, 111341, 131141, 114113, 114311, 411113,
411311, 113141, 114131, 311141, 411131, 211412, 211214, 211232,
- 2331112, -- this is the stop char at index 106
+ 2331112, -- the last number is the stop char at index 106
}
Code128._codeset = {
@@ -96,248 +96,308 @@ function Code128:_config() --> ok, err
local mod = self.xdim
local sc = self._codeset.stopChar -- build the stop char
local n = self._int_def_bar[sc]
- local Vbar = self._libgeo.Vbar -- Vbar class
- self._vbar = {}
- local b = self._vbar
- b[sc] = Vbar:from_int(n, mod, true)
+ local repo = self._libgeo.Archive:new()
+ self._vbar_archive = repo
+ local Vbar = self._libgeo.Vbar
+ repo:insert(Vbar:from_int(n, mod, true), 106)
return true, nil
end
-- utility functions
--- the number of consecutive digits from the index 'i' in the code array
-local function count_digits_from(arr, i)
- local start = i
- local dim = #arr
- while i <= dim and (arr[i] > 47 and arr[i] < 58) do
- i = i + 1
- end
- return i - start
-end
-
--- evaluate the check digit of the data representation
+-- evaluate the check digit of encoded data
local function check_digit(code)
local sum = code[1] -- this is the start character
for i = 2, #code do
sum = sum + code[i]*(i-1)
end
- return sum % 103
+ code[#code + 1] = sum % 103
+end
+
+local function isdigit(char) --> true/false
+ assert(char)
+ return (char > 47) and (char < 58)
+end
+
+local function iscontrol(char) --> true/false
+ assert(char)
+ -- [0,31] control chars interval
+ return char < 32
+end
+
+local function islower(char)
+ assert(char)
+ -- [96, 127] lower case chars
+ return (char > 95) and (char < 128)
end
--- return a pair of boolean the first one is true
--- if a control char and a lower case char occurs in the data
--- and the second one is true if the control char occurs before
--- the lower case char
-local function ctrl_or_lowercase(pos, data) --> boolean, boolean|nil
- local len = #data
- local ctrl_occur, lower_occur = false, false
- for i = pos, len do
- local c = data[i]
- if (not ctrl_occur) and (c >= 0 and c < 32) then
- -- [0,31] control chars
- if lower_occur then
- return true, false -- lowercase char < ctrl char
+-- count digits
+local function digits_group(data, len) --> counting digits
+ local res = {}
+ local last = false
+ for i = len, 1, -1 do
+ local digit = isdigit(data[i])
+ if last then
+ if digit then
+ res[i] = res[i+1] + 1
else
- ctrl_occur = true
+ res[i] = 0
+ last = false
end
- elseif (not lower_occur) and (c > 95 and c < 128) then
- -- [96, 127] lower case chars
- if ctrl_occur then
- return true, true -- ctrl char < lowercase char
+ else
+ if digit then
+ res[i] = 1
+ last = true
else
- lower_occur = true
+ res[i] = 0
end
end
end
- return false -- no such data
+ return res
end
--- encode the provided char against a codeset
--- in the future this function will consider FN data
-local function encode_char(t, codesetAorB, char_code, codesetA)
- local code
- if codesetAorB == codesetA then -- codesetA
- if char_code < 32 then
- code = char_code + 64
- elseif char_code > 31 and char_code < 96 then
- code = char_code - 32
- else
- error("Not implemented or wrong code")
- end
- else -- codesetB
- if char_code > 31 and char_code < 128 then
- code = char_code - 32
- else
- error("Not implemented or wrong code")
+-- find the first char in the codeset that adhere
+-- with the function argument 'filter'
+local function indexof_char_by(filter, arr, counter) --> index or nil
+ counter = counter or 1
+ local char = arr[counter]
+ while char do
+ if filter(char) then
+ return counter
end
+ counter = counter + 1
+ char = arr[counter]
end
- t[#t + 1] = code
end
--- encode the message in a sequence of Code128 symbol minimizing its lenght
-local function encode128(arr, codeset, switch) --> data, err :TODO:
- local res = {} -- the result array (the check character will be appended)
- -- find the Start Character A, B, or C
- local cur_codeset
- local ndigit = count_digits_from(arr, 1)
- local len = #arr
- --local no_ctrl_lower_char
- if (ndigit == 2 and len == 2) or ndigit > 3 then -- start char code C
- cur_codeset = codeset.C
+-- determine the Start character
+local function start_codeset_char(codeset, arr, len)
+ assert(len>0)
+ local ctrl = indexof_char_by(iscontrol, arr)
+ local lowc = indexof_char_by(islower, arr)
+ local t_digits = digits_group(arr, len)
+ local first_digits = t_digits[1]
+ -- case 1
+ if (len == 2) and (first_digits == 2) then
+ return lowc, ctrl, codeset.C, t_digits
+ end
+ -- case 2
+ if first_digits >= 4 then
+ return lowc, ctrl, codeset.C, t_digits
+ end
+ -- case 3
+ local cs = codeset.B
+ if (ctrl and lowc) and (ctrl < lowc) then
+ cs = codeset.A
+ end
+ -- case 4
+ return lowc, ctrl, cs, t_digits
+end
+
+-- codeset A char
+local function encode_char_A(res, char)
+ local code
+ if char < 32 then
+ code = char + 64
+ elseif char > 31 and char < 96 then
+ code = char - 32
else
- local ok, ctrl_first = ctrl_or_lowercase(1, arr)
- if ok and ctrl_first then
- cur_codeset = codeset.A
- else
- cur_codeset = codeset.B
- end
+ error("[InternalErr] Not implemented or wrong code" )
end
- res[#res + 1] = cur_codeset
- local pos = 1 -- symbol's index to encode
- while pos <= len do
- if cur_codeset == codeset.C then
- if arr[pos] < 48 or arr[pos] > 57 then -- not numeric char
- local ok, ctrl_first = ctrl_or_lowercase(pos, arr)
- if ok and ctrl_first then
- cur_codeset = codeset.A
+ res[#res + 1] = code
+end
+-- codeset B char
+local function encode_char_B(res, char)
+ local code
+ if char > 31 and char < 128 then
+ code = char - 32
+ else
+ error("[InternalErr] Not implemented or wrong code")
+ end
+ res[#res + 1] = code
+end
+
+-- every function encodes a group of chars
+-- A = 103, -- Start char for Codeset A
+-- B = 104, -- Start char for Codeset B
+-- C = 105, -- Start char for Codeset C
+local encode_codeset = {
+ -- A
+ [103] = function (codeset, res, data, index, t_digits, i_low, _ctrl)
+ assert(t_digits[index] < 4, "[InternalErr] in codeset A digits must be less than 4")
+ while data[index] do
+ local char = data[index]
+ if i_low and islower(char) then -- ops a lower case char
+ local next = data[index + 1]
+ local next_next = data[index + 2]
+ if next and next_next then
+ -- case 5a
+ if iscontrol(char) and islower(next_next) then
+ res[#res+1] = codeset.shift
+ encode_char_B(res, char)
+ index = index + 1
+ end
else
- cur_codeset = codeset.B
+ -- case 5b
+ return codeset.B, index
end
- res[#res + 1] = switch[codeset.C][cur_codeset]
else
- local imax = pos + 2*math.floor(ndigit/2) - 1
- for idx = pos, imax, 2 do
- res[#res + 1] = (arr[idx] - 48)*10 + arr[idx+1] - 48
- end
- pos = pos + imax
- ndigit = ndigit - imax
- if ndigit == 1 then
- -- cur_codeset setup
- local ok, ctrl_first = ctrl_or_lowercase(pos + 1, arr)
- if ok and ctrl_first then
- cur_codeset = codeset.A
- else
- cur_codeset = codeset.B
+ local digits = t_digits[index]
+ if digits > 3 then -- go to codeset C
+ if (digits % 2) == 1 then -- odd number of a group of digits
+ encode_char_A(res, char)
+ digits = digits - 1
+ index = index + 1
end
- res[#res + 1] = switch[codeset.C][cur_codeset]
+ return codeset.C, index
end
+ encode_char_A(res, char)
+ index = index + 1
end
- else --- current codeset is A or B
- if ndigit > 3 then
- if ndigit % 2 > 1 then -- odd number of digits
- encode_char(res, cur_codeset, arr[pos], codeset.A)
- pos = pos + 1
- ndigit = ndigit - 1
- end
- res[#res + 1] = switch[cur_codeset][codeset.C]
- cur_codeset = codeset.C
- elseif (cur_codeset == codeset.B) and
- (arr[pos] >= 0 and arr[pos] < 32) then -- ops a control char
- local ok, ctrl_first = ctrl_or_lowercase(pos + 1, arr)
- if ok and (not ctrl_first) then -- shift to codeset A
- res[#res + 1] = codeset.shift
- encode_char(res, codeset.A, arr[pos], codeset.A)
- pos = pos + 1
- ndigit = count_digits_from(pos, arr)
- else -- switch to code set A
- res[#res + 1] = switch[cur_codeset][codeset.A]
- cur_codeset = codeset.A
- end
- elseif (cur_codeset == codeset.A) and
- (arr[pos] > 95 and arr[pos] < 128) then -- ops a lower case char
- local ok, ctrl_first = ctrl_or_lowercase(pos+1, arr)
- if ok and ctrl_first then -- shift to codeset B
- res[#res + 1] = codeset.shift
- encode_char(res, codeset.B, arr[pos], codeset.A)
- pos = pos + 1
- ndigit = count_digits_from(arr, pos)
- else -- switch to code set B
- res[#res + 1] = switch[cur_codeset][codeset.B]
- cur_codeset = codeset.B
+ end
+ return nil, index
+ end,
+ -- B
+ [104] = function (codeset, res, data, index, t_digits, _low, i_ctrl)
+ assert(t_digits[index] < 4, "[InternalErr] in codeset B digits must be less than 4")
+ while data[index] do
+ local char = data[index]
+ if i_ctrl and iscontrol(char) then -- ops a control char
+ local next = data[index + 1]
+ local next_next = data[index + 2]
+ if next and next_next then
+ -- case 4a
+ if islower(next) and iscontrol(next_next) then
+ res[#res+1] = codeset.shift
+ encode_char_A(res, char)
+ index = index + 1
+ end
+ else
+ -- case 4b
+ return codeset.A, index
end
else
- -- insert char
- encode_char(res, cur_codeset, arr[pos], codeset.A)
- pos = pos + 1
- ndigit = count_digits_from(arr, pos)
+ local digits = t_digits[index]
+ if digits > 3 then -- go to codeset C
+ if (digits % 2) == 1 then -- odd number of a group of digits
+ encode_char_B(res, char)
+ digits = digits - 1
+ index = index + 1
+ end
+ return codeset.C, index
+ end
+ encode_char_B(res, char)
+ index = index + 1
end
end
+ return nil, index
+ end,
+ -- C
+ [105] = function (codeset, res, data, index, t_digits, i_low, i_ctrl)
+ local digits = t_digits[index]
+ assert(digits > 1, "[InternalErr] at least a pair of digit is required")
+ while digits > 1 do
+ local d1, d2 = data[index], data[index + 1]
+ res[#res + 1] = (d1 - 48)*10 + d2 - 48
+ digits = digits - 2
+ index = index + 2
+ end
+ local res_codeset
+ if i_ctrl and i_low then
+ local ctrl = indexof_char_by(iscontrol, data, index)
+ local low = indexof_char_by(islower, data, index)
+ if low and (ctrl < low) then
+ res_codeset = codeset.A
+ end
+ else
+ res_codeset = codeset.B
+ end
+ return res_codeset, index
+ end,
+}
+
+-- encode the message in a sequence of Code128 symbol minimizing the symbol width
+local function encode128(arr, codeset, switch) --> data, err
+ local len = #arr
+ local i_low, i_ctrl, cur_codeset, t_digits = start_codeset_char(codeset, arr, len)
+ local res = {cur_codeset} -- the result array (the check character will be appended later)
+ local switch_codeset
+ local cur_index = 1
+ while cur_index <= len do
+ if switch_codeset then
+ res[#res+1] = switch[cur_codeset][switch_codeset]
+ cur_codeset = switch_codeset
+ end
+ local fn = assert(encode_codeset[cur_codeset], "[InternalErr] cur_codeset is "..(cur_codeset or "nil"))
+ switch_codeset, cur_index = fn(codeset, res, arr, cur_index, t_digits, i_low, i_ctrl)
end
- res[#res + 1] = check_digit(res)
- res[#res + 1] = codeset.stopChar
- return res
+ check_digit(res)
+ return res, nil
end
-- Code 128 internal functions used by Barcode costructors
-function Code128:_check_char(c) --> elem, err
- if type(c) ~= "string" or #c ~= 1 then
- return nil, "[InternalErr] invalid char"
- end
+function Code128:_process_char(c) --> char_code, char_text, err
local b = string.byte(c)
if b > 127 then
local fmt = "[unimplemented] the '%d' is an ASCII extented char"
return nil, string.format(fmt, c)
end
- return b, nil
+ return b, c, nil
end
-function Code128:_check_digit(n) --> elem, err
- if type(n) ~= "number" then
- return nil, "[InternalErr] invalid digit"
- end
- return n + 48, nil
+function Code128:_process_digit(n) --> digit_code, char_text, err
+ local res = n + 48
+ return res, string.char(res), nil
end
function Code128:_finalize() --> ok, err
local chr = assert(self._code_data, "[InternalErr] '_code_data' field is nil")
local data, err = encode128(chr, self._codeset, self._switch)
if err then return false, err end
- -- load dynamically required Vbar objects
- local vbar = self._vbar
- local oVbar = self._libgeo.Vbar
+ self._enc_data = data
+ -- dynamically load the required Vbar objects
+ local Repo = self._vbar_archive
+ local Vbar = self._libgeo.Vbar
for _, c in ipairs(data) do
- if not vbar[c] then
+ if not Repo:contains_key(c) then
local n = self._int_def_bar[c]
local mod = self.xdim
- vbar[c] = oVbar:from_int(n, mod, true)
+ assert(Repo:insert(Vbar:from_int(n, mod, true), c))
end
end
- self._enc_data = data
return true, nil
end
-- Drawing into the provided channel the geometrical barcode data
-- tx, ty is the optional translator vector
-- the function return the canvas reference to allow call chaining
-function Code128:append_ga(canvas, tx, ty) --> canvas
- local xdim, h = self.xdim, self.ydim
- local sw = 11*xdim -- the width of a symbol
+function Code128:_append_ga(canvas, tx, ty) --> bbox
local data = self._enc_data
- local w = #data * sw + 2 * xdim -- total symbol width
+ local Repo = self._vbar_archive
+ local queue = self._libgeo.Vbar_queue:new()
+ for _, c in ipairs(data) do
+ queue = queue + Repo:get(c)
+ end
+ local stop = self._codeset.stopChar
+ queue = queue + Repo:get(stop)
+ local xdim, h = self.xdim, self.ydim
+ local ns = #data + 1
+ local w = (11*ns + 2) * xdim -- total symbol width
local ax, ay = self.ax, self.ay
- local x0 = (tx or 0) - ax * w
- local y0 = (ty or 0) - ay * h
+ local x0 = tx - ax * w
+ local y0 = ty - ay * h
local x1 = x0 + w
local y1 = y0 + h
- local xpos = x0
-- drawing the symbol
- local err
- err = canvas:start_bbox_group()
- assert(not err, err)
- for _, c in ipairs(data) do
- local vb = self._vbar[c]
- err = canvas:encode_Vbar(vb, xpos, y0, y1)
- assert(not err, err)
- xpos = xpos + sw
- end
+ assert(canvas:encode_disable_bbox())
+ assert(canvas:encode_vbar_queue(queue, x0, y0, y1))
-- bounding box setting
local qz = self.quietzone_factor * xdim
-- { xmin, ymin, xmax, ymax }
- err = canvas:stop_bbox_group(x0 - qz, y0, x1 + qz, y1)
- assert(not err, err)
- return canvas
+ assert(canvas:encode_set_bbox(x0 - qz, y0, x1 + qz, y1))
+ assert(canvas:encode_enable_bbox())
+ return {x0, y0, x1, y1, qz, nil, qz, nil,}
end
return Code128
--- \ No newline at end of file