summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-upc.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-upc.lua')
-rw-r--r--Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-upc.lua251
1 files changed, 251 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-upc.lua b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-upc.lua
new file mode 100644
index 00000000000..99bfd4349e8
--- /dev/null
+++ b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-upc.lua
@@ -0,0 +1,251 @@
+-- Universal Product Code
+-- UPC family barcode generator
+--
+-- Copyright (C) 2019-2022 Roberto Giacomelli
+-- see LICENSE.txt file
+
+local UPC = {
+ _VERSION = "upc v0.0.2",
+ _NAME = "upc",
+ _DESCRIPTION = "UPC barcode encoder",
+}
+
+UPC._pattern = {[0] = 3211, 2221, 2122, 1411, 1132, 1231, 1114, 1312, 1213, 3112,}
+UPC._sepbar = 111
+
+UPC._id_variant = {
+ A = true, -- UPC-A
+}
+
+-- common family parameters
+UPC._par_order = {
+ "mod",
+ "height",
+ "bars_depth_factor",
+ "quietzone_factor",
+ "text_enabled",
+ "text_ygap_factor",
+ "text_xgap_factor",
+}
+UPC._par_def = {}
+local pardef = UPC._par_def
+
+-- from Wikipedia https://en.wikipedia.org/wiki/Universal_Product_Code
+-- The x-dimension for the UPC-A at the nominal size is 0.33 mm (0.013").
+-- UPC-A can be reduced or magnified anywhere from 80% to 200%.
+-- standard module is 0.33 mm but it may 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,
+ fncheck = function (_self, x, _) --> boolean, err
+ local mm = 186467
+ local min, max = 0.264*mm, 0.660*mm
+ if x < min then
+ return false, "[OutOfRange] too small value for mod"
+ elseif x > max then
+ return false, "[OutOfRange] too big value for mod"
+ end
+ return true, nil
+ end,
+}
+
+-- Nominal symbol height for UPC-A is 25.9 mm (1.02")
+pardef.height = {
+ default = 25.9 * 186467,
+ unit = "sp",
+ isReserved = false,
+ fncheck = function (self, h, _enc) --> boolean, err
+ if h > 0 then
+ return true, nil
+ else
+ return false, "[OutOfRange] non positive value for height"
+ end
+ end,
+}
+
+-- The bars forming the S (start), M (middle), and E (end) guard patterns, are
+-- extended downwards by 5 times x-dimension, with a resulting nominal symbol
+-- height of 27.55 mm (1.08")
+pardef.bars_depth_factor = {
+ default = 5,
+ unit = "absolute-number",
+ isReserved = false,
+ fncheck = function (_self, b, _) --> boolean, err
+ if b >= 0 then
+ return true, nil
+ else
+ return false, "[OutOfRange] non positive value for bars_depth_factor"
+ end
+ end,
+}
+
+-- A quiet zone, with a width of at least 9 times the x-dimension, must be
+-- present on each side of the scannable area of the UPC-A barcode.
+pardef.quietzone_factor = {
+ default = 9,
+ unit = "absolute-number",
+ isReserved = false,
+ fncheck = function (_self, qzf, _) --> boolean, err
+ if qzf > 0 then
+ return true, nil
+ else
+ return false, "[OutOfRange] non positive value for quietzone_right_factor"
+ end
+ end,
+}
+
+-- enable/disable human readble text
+pardef.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_enabled"
+ end
+ end,
+}
+
+-- vertical gap from text and symbol baseline
+pardef.text_ygap_factor = {
+ default = 1.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_ygap_factor"
+ end
+ end,
+}
+
+-- horizontal gap from text and symbol bars
+pardef.text_xgap_factor = {
+ default = 0.75,
+ 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_xgap_factor"
+ end
+ end,
+}
+
+-- utility function
+
+-- the checksum of UPC-A
+-- 'data' is an array of digits
+local function checkdigit_A(data) --> checksum, ok
+ local s = 0
+ for i = 1, 11, 2 do
+ s = s + data[i]
+ end
+ s = 3*s
+ for i = 2, 10, 2 do
+ s = s + data[i]
+ end
+ local res = s % 10
+ if res > 0 then
+ res = 10 - res
+ end
+ return res, data[12] == res
+end
+
+-- internal methods for Barcode costructors
+
+-- config function called at the moment of encoder construction
+function UPC:_config() --> ok, err
+ local variant = self._variant
+ if not variant then
+ return false, "[Err] variant is mandatory for the UPC family"
+ end
+ local Vbar = self._libgeo.Vbar -- Vbar class
+ local Vbar_archive = self._libgeo.Archive -- Archive class
+ local Codeset = Vbar_archive:new()
+ self._upca_codeset = Codeset
+ local mod = self.mod
+ local sepbar = self._sepbar
+ Codeset:insert(Vbar:from_int(sepbar, mod), "sepbar")
+ local symb = self._pattern
+ for i = 0, 9 do
+ Codeset:insert(Vbar:from_int(symb[i], mod, false), 0, i)
+ Codeset:insert(Vbar:from_int(symb[i], mod, true), 1, i)
+ end
+ return true, nil
+end
+
+-- function called every time an input UPC-A code has been completely parsed
+function UPC:_finalize() --> ok, err
+ local data = self._code_data
+ local symb_len = #data
+ if symb_len ~= 12 then
+ return false, "[ArgErr] not a 12-digit long array"
+ end
+ local ck, ok = checkdigit_A(data)
+ if not ok then -- is the last digit ok?
+ return false,
+ "[Err] incorrect last digit "..data[12]..", the checksum is "..ck
+ end
+ return true, nil
+end
+
+-- Drawing into the provided channel geometrical data
+-- tx, ty is the optional translation vector
+-- the function return the canvas reference to allow call chaining
+function UPC:_append_ga(canvas, tx, ty) --> bbox
+ local Codeset = self._upca_codeset
+ local code = self._code_data
+ local mod = self.mod
+ local sepbar = assert(Codeset:get("sepbar"))
+ local queue_0 = sepbar + assert(Codeset:get(0, code[1])) +
+ 36*mod + sepbar + 36*mod +
+ assert(Codeset:get(1, code[12])) + sepbar
+ local queue_1 = 10*mod
+ for i = 2, 6 do
+ queue_1 = queue_1 + assert(Codeset:get(0, code[i]))
+ end
+ queue_1 = queue_1 + 5*mod
+ for i = 7, 11 do
+ queue_1 = queue_1 + assert(Codeset:get(1, code[i]))
+ end
+ local bars_depth = mod * self.bars_depth_factor
+ local w, h = 95*mod, self.height + bars_depth
+ local x0 = tx - self.ax * w
+ local y0 = ty - self.ay * h
+ local x1 = x0 + w
+ local y1 = y0 + h
+ local ys = y0 + bars_depth
+ -- draw the symbol
+ assert(canvas:encode_disable_bbox())
+ assert(canvas:encode_vbar_queue(queue_0, x0, y0, y1))
+ assert(canvas:encode_vbar_queue(queue_1, x0, ys, y1))
+ -- bounding box set up
+ local qz = self.quietzone_factor * mod
+ assert(canvas:encode_set_bbox(x0 - qz, y0, x1 + qz, y1))
+ assert(canvas:encode_enable_bbox())
+ if self.text_enabled then -- human readable text
+ local Text = self._libgeo.Text
+ local txt_1 = Text:from_digit_array(code, 1, 1)
+ local txt_2 = Text:from_digit_array(code, 2, 6)
+ local txt_3 = Text:from_digit_array(code, 7, 11)
+ local txt_4 = Text:from_digit_array(code, 12, 12)
+ local y_bl = ys - self.text_ygap_factor * mod
+ assert(canvas:encode_Text(txt_1, x0 - qz, y_bl, 0, 1))
+ local mx = self.text_xgap_factor
+ local x2_1 = x0 + (10+mx)*mod
+ local x2_2 = x0 + (46-mx)*mod
+ assert(canvas:encode_Text_xwidth(txt_2, x2_1, x2_2, y_bl, 1))
+ local x3_1 = x0 + (49+mx)*mod
+ local x3_2 = x0 + (85-mx)*mod
+ assert(canvas:encode_Text_xwidth(txt_3, x3_1, x3_2, y_bl, 1))
+ assert(canvas:encode_Text(txt_4, x1 + qz, y_bl, 1, 1))
+ end
+ return {x0, y0, x1, y1, qz, nil, qz, nil,}
+end
+
+return UPC