From 1ef4c041ba74d4619dd62209ae48a2b24563954c Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Fri, 24 Jun 2022 03:01:47 +0000 Subject: CTAN sync 202206240301 --- macros/luatex/generic/barracuda/PLANNER.txt | 120 +- macros/luatex/generic/barracuda/README.md | 33 +- macros/luatex/generic/barracuda/barracuda.sty | 2 +- .../generic/barracuda/doc/barracuda-ga-asm.pdf | Bin 38718 -> 0 bytes .../generic/barracuda/doc/barracuda-ga-asm.tex | 148 --- .../barracuda/doc/barracuda-manual-tool.tex | 39 - macros/luatex/generic/barracuda/doc/barracuda.pdf | Bin 67784 -> 0 bytes macros/luatex/generic/barracuda/doc/barracuda.tex | 413 ------ .../doc/ga-graphic-asm/barracuda-ga-asm.pdf | Bin 0 -> 38718 bytes .../doc/ga-graphic-asm/barracuda-ga-asm.tex | 148 +++ .../generic/barracuda/doc/image/8006194056290.pdf | Bin 5682 -> 0 bytes .../barracuda/doc/manual/barracuda-manual-tool.tex | 49 + .../barracuda/doc/manual/barracuda-manual.pdf | Bin 0 -> 125819 bytes .../barracuda/doc/manual/barracuda-manual.tex | 1312 ++++++++++++++++++++ .../barracuda/doc/manual/image/8006194056290.pdf | Bin 0 -> 5682 bytes macros/luatex/generic/barracuda/src/barracuda.lua | 30 +- .../barracuda/src/lib-barcode/brcd-barcode.lua | 287 ++++- .../barracuda/src/lib-barcode/brcd-code128.lua | 404 +++--- .../barracuda/src/lib-barcode/brcd-code39.lua | 164 ++- .../generic/barracuda/src/lib-barcode/brcd-ean.lua | 651 +++++----- .../barracuda/src/lib-barcode/brcd-i2of5.lua | 217 ++-- .../generic/barracuda/src/lib-barcode/brcd-upc.lua | 251 ++++ .../barracuda/src/lib-driver/brcd-driver.lua | 243 +++- .../src/lib-driver/brcd-drv-pdfliteral.lua | 50 +- .../barracuda/src/lib-driver/brcd-drv-svg.lua | 173 ++- .../barracuda/src/lib-geo/brcd-gacanvas.lua | 563 +++++++-- .../generic/barracuda/src/lib-geo/brcd-libgeo.lua | 216 +++- .../01-barracuda-latex-test.pdf | Bin 3810 -> 4047 bytes .../01-barracuda-latex-test.tex | 17 +- .../test-barracuda-package/02-ord_iter-test.tex | 2 +- .../test/test-code128/001-code128-test.lua | 32 - .../test/test-code128/001-code128-test.tex | 39 + .../test/test-code128/002-code128-test.pdf | Bin 22132 -> 24385 bytes .../test/test-code128/002-code128-test.tex | 114 +- .../test/test-code128/02-05-pdfliteral.txt | 8 + .../barracuda/test/test-code39/001-code39-test.lua | 41 - .../barracuda/test/test-code39/001-code39-test.tex | 39 + .../barracuda/test/test-code39/002-code39-test.pdf | Bin 22701 -> 23271 bytes .../barracuda/test/test-code39/002-code39-test.tex | 35 +- .../barracuda/test/test-code39/003-code39-test.pdf | Bin 19827 -> 19829 bytes .../barracuda/test/test-code39/003-code39-test.tex | 18 +- .../barracuda/test/test-code39/004-code39-test.pdf | Bin 15329 -> 15341 bytes .../barracuda/test/test-code39/004-code39-test.tex | 11 +- .../barracuda/test/test-code39/006-code39-test.lua | 12 +- .../barracuda/test/test-code39/007-code39-test.pdf | Bin 0 -> 18589 bytes .../barracuda/test/test-code39/007-code39-test.tex | 39 + .../barracuda/test/test-ean/001-13-ean-test.pdf | Bin 23620 -> 23924 bytes .../barracuda/test/test-ean/001-13-ean-test.tex | 29 +- .../barracuda/test/test-ean/002-ean-test.pdf | Bin 10601 -> 10674 bytes .../barracuda/test/test-ean/003-ean-test.pdf | Bin 3901 -> 3986 bytes .../barracuda/test/test-ean/004-ean-test.lua | 9 - .../barracuda/test/test-ean/004-ean-test.tex | 6 + .../barracuda/test/test-ean/005-isbn-test.pdf | Bin 19829 -> 19910 bytes .../barracuda/test/test-ean/006-issn-test.pdf | Bin 14883 -> 15099 bytes .../barracuda/test/test-ean/006-issn-test.tex | 20 +- .../barracuda/test/test-ean/8006194056290.svg | 16 +- .../luatex/generic/barracuda/test/test-ean/ars.svg | 16 +- .../test-ga-pdfliteral/001-ga-pdfliteral-test.pdf | Bin 30290 -> 30029 bytes .../test-ga-pdfliteral/001-ga-pdfliteral-test.tex | 222 ++-- .../test/test-ga-pdfliteral/002-polyline.pdf | Bin 0 -> 15101 bytes .../test/test-ga-pdfliteral/002-polyline.tex | 69 + .../barracuda/test/test-ga-pdfliteral/polygon.svg | 132 ++ .../barracuda/test/test-ga-svg/002-ga-svg-test.lua | 2 +- .../barracuda/test/test-i2of5/001-i2of5-test.pdf | Bin 19136 -> 20158 bytes .../barracuda/test/test-i2of5/001-i2of5-test.tex | 59 +- .../barracuda/test/test-i2of5/002-ITF14-test.pdf | Bin 16052 -> 16541 bytes .../barracuda/test/test-i2of5/002-ITF14-test.tex | 23 +- .../generic/barracuda/test/test-i2of5/02-itf14.svg | 76 ++ .../barracuda/test/test-libgeo/001-libgeo-test.pdf | Bin 0 -> 14087 bytes .../barracuda/test/test-libgeo/001-libgeo-test.tex | 48 + .../barracuda/test/test-libgeo/003-ga-svg-test.pdf | Bin 0 -> 1130 bytes .../barracuda/test/test-libgeo/003-ga-svg-test.tex | 41 + .../generic/barracuda/test/test-libgeo/test.svg | 79 ++ .../barracuda/test/test-upc/001-upca-test.pdf | Bin 0 -> 17692 bytes .../barracuda/test/test-upc/001-upca-test.tex | 41 + .../generic/barracuda/test/test-upc/002-upca.pdf | Bin 0 -> 3344 bytes .../generic/barracuda/test/test-upc/002-upca.tex | 9 + 77 files changed, 4849 insertions(+), 1968 deletions(-) delete mode 100644 macros/luatex/generic/barracuda/doc/barracuda-ga-asm.pdf delete mode 100644 macros/luatex/generic/barracuda/doc/barracuda-ga-asm.tex delete mode 100644 macros/luatex/generic/barracuda/doc/barracuda-manual-tool.tex delete mode 100644 macros/luatex/generic/barracuda/doc/barracuda.pdf delete mode 100644 macros/luatex/generic/barracuda/doc/barracuda.tex create mode 100644 macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.pdf create mode 100644 macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.tex delete mode 100644 macros/luatex/generic/barracuda/doc/image/8006194056290.pdf create mode 100644 macros/luatex/generic/barracuda/doc/manual/barracuda-manual-tool.tex create mode 100644 macros/luatex/generic/barracuda/doc/manual/barracuda-manual.pdf create mode 100644 macros/luatex/generic/barracuda/doc/manual/barracuda-manual.tex create mode 100644 macros/luatex/generic/barracuda/doc/manual/image/8006194056290.pdf create mode 100644 macros/luatex/generic/barracuda/src/lib-barcode/brcd-upc.lua delete mode 100644 macros/luatex/generic/barracuda/test/test-code128/001-code128-test.lua create mode 100644 macros/luatex/generic/barracuda/test/test-code128/001-code128-test.tex delete mode 100644 macros/luatex/generic/barracuda/test/test-code39/001-code39-test.lua create mode 100644 macros/luatex/generic/barracuda/test/test-code39/001-code39-test.tex create mode 100644 macros/luatex/generic/barracuda/test/test-code39/007-code39-test.pdf create mode 100644 macros/luatex/generic/barracuda/test/test-code39/007-code39-test.tex delete mode 100644 macros/luatex/generic/barracuda/test/test-ean/004-ean-test.lua create mode 100644 macros/luatex/generic/barracuda/test/test-ean/004-ean-test.tex create mode 100644 macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.pdf create mode 100644 macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.tex create mode 100644 macros/luatex/generic/barracuda/test/test-ga-pdfliteral/polygon.svg create mode 100644 macros/luatex/generic/barracuda/test/test-i2of5/02-itf14.svg create mode 100644 macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.pdf create mode 100644 macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.tex create mode 100644 macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.pdf create mode 100644 macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.tex create mode 100644 macros/luatex/generic/barracuda/test/test-libgeo/test.svg create mode 100644 macros/luatex/generic/barracuda/test/test-upc/001-upca-test.pdf create mode 100644 macros/luatex/generic/barracuda/test/test-upc/001-upca-test.tex create mode 100644 macros/luatex/generic/barracuda/test/test-upc/002-upca.pdf create mode 100644 macros/luatex/generic/barracuda/test/test-upc/002-upca.tex (limited to 'macros/luatex/generic') diff --git a/macros/luatex/generic/barracuda/PLANNER.txt b/macros/luatex/generic/barracuda/PLANNER.txt index ca7a9e041f..f6f613ddba 100644 --- a/macros/luatex/generic/barracuda/PLANNER.txt +++ b/macros/luatex/generic/barracuda/PLANNER.txt @@ -5,7 +5,7 @@ Basic rules ----------- + Every new version will be uploaded to CTAN network -+ For each single task there will be a correspomding commit ++ For each single task there will be a single commit Hypothetical development task list: ----------------------------------- @@ -18,52 +18,101 @@ Hypothetical development task list: 20__-__-__: [dev] proportional options 20__-__-__: [dev] a number parameter can be a string? unit measure... 20__-__-__: [prj] a command line program to print barcodes -20__-__-__: [dev] guard text in EAN simbology -20__-__-__: [dev] UPC support 20__-__-__: [dev] make optional file name in all the Driver methods 20__-__-__: [prj] test l3build for testing and CTAN files packaging 20__-__-__: [dev] load barcode parameters from an external file 20__-__-__: [dev] new Parameter Class +202_-__-__: [dev][barcode] new `alias` feature +202_-__-__: [dev][barcode] new `preset` feature +202_-__-__: [project][build] make a Lua script to easily create the CTAN upload + : compressed files +202_-__-__: [dev] statistical data on how many barcode symbols was printed +202_-__-__: [upc] UPC-E barcode symbology -Scheduled task list for Data Matrix 2D simbology implementation: +Scheduled task list for Data Matrix 2D symbology implementation: ---------------------------------------------------------------- -2020-__-__: [dmx] data matrix first run -2020-__-__: [dmx] ecc200 error correction code -2020-__-__: [svg] opcode for grids -2020-__-__: [pdf] opcode for grids -2020-__-__: [gas] ga-asm grid opcode -2020-__-__: [geo] grid vector object -2020-__-__: [dev] init source file encoder for Data Matrix -2020-__-__: [dev] parameter preset - -Dev Planner: -============ +202_-__-__: [dmx] data matrix first run +202_-__-__: [dmx] ecc200 error correction code +202_-__-__: [svg] opcode for grids +202_-__-__: [pdf] opcode for grids +202_-__-__: [ga] ga new grid opcode +202_-__-__: [geo] grid vector object +202_-__-__: [dev] init source file encoder for Data Matrix + +Ongoing Scheduler: +================== +------------------------------------------------------------------------------- +202_-__-__: [milestone] version 0.1 +202_-__-__: [test] update test files with recent changes +202_-__-__: [dev][ean] fix the `ean:checksum()` to include ISBN and ISSN variant +202_-__-__: [dev] control the method call on the right class +202_-__-__: [code128] add human readeable text +202_-__-__: [breaking change] refactor Text libgeo object +202_-__-__: [project] adhere to semver specification +202_-__-__: [doc] API reference +202_-__-__: [doc] barcode symbologies reference: code39 + +------------------------------------------------------------------------------- +2022-06-22: [code128] fix a bug in the encoder (complete rewriting) ------------------------------------------------------------------------------- -2020-__-__: [milestone] version completed task/commit list -2020-__-__: [doc] barcode symbologies reference -2020-__-__: [doc] put ga-asm-spec together with the manual -2020-__-__: [dev][barcode] new `alias` feature -2020-__-__: [dev][barcode] new `preset` feature -2020-__-__: [dev][i2of5] human readeable text for i2of5 -2020-__-__: [dev][libgeo] new `Vbar_group` class -2020-__-__: [test] update test files with recent changes -2020-__-__: [dev][libgeo][breaking change] return `ok, err` instead of `err` +2020-05-03: [barcode] debug_bbox option +2020-05-03: [libgeo] optional tx, ty moving point for encode_ +2020-04-06: [driver] new methods for gaCanvas class and default style graphic +2020-03-20: [upc] new UPC-A barcode symbology +2020-03-13: [barcode] new method get_code() and get_hri() +2020-03-11: [breaking change][barcode] new `draw()` method +2020-03-07: [ga] new and opcodes +2020-03-06: [doc] new section explains `Vbar` +2020-03-02: [doc] add a chess example for `ga` stream + +[merge]<--------+ + | + 2020-03-02: [doc] put ga-asm-spec together with the manual + | +[doc-basic-ref]-+ + +2020-02-27:*[dev][i2of5] human readeable text for i2of5 and ITF14 + +[merge]<--------+ + | + 2020-02-26: [ean] guard text in EAN symbology + 2020-02-25: [libgeo][gaCanvas] Polyline object test file + 2020-02-25: [libgeo][gaCanvas] new Polyline object + | +[Polyline]------+ + +2020-02-22: [dev] new methods _process_char() and _process_digit() +2020-02-09: [dev] new constructor `Barcode:new()` + +[merge]<--------+ + | + 2020-02-17: [libgeo] delete `Vbar_archive` in favour of `Archive` + 2020-02-16: [libgeo] arithmetic of new object `Queue` + 2020-02-12: [libgeo] new class `Archive` + 2020-02-12: [dev][libgeo] add method `Vbar_archive:add_space()` + 2020-02-12: [dev][libgeo] refactor `Vbar_archive:push_queue()` method + 2020-02-12: [dev][ean] refactor ean to use `Vbar_archive` + 2020-02-11: [dev][i2to5] refactor i2of5 to use `Vbar_archive` + 2020-02-10: [dev][code128] refactor code128 to use `Vbar_archive` + 2020-02-09: [dev][libgeo] refactor code39 to use `Vbar_archive` + 2020-02-06: [dev][libgeo] new `Vbar_archive` class in libgeo + | +[vbar_archive]--+ + +2020-02-05: [dev][libgeo][breaking change] return `ok, err` instead of `err` for canvas methods -2020-__-__: [dev] new constructor `Barcode:new()` -2020-__-__: [project][build] make a Lua script to easily create the CTAN upload - : compressed files -2020-__-__: [dev][ean] fix the `ean:checksum()` to include ISBN and ISSN variant -2020-__-__: [dev][i2of5] `encoder:_init_parse_state()` adoption for ITF14 +2020-02-04: [dev][ean] new function `encoder:_init_parse_state()`, and EAN + : family adoption; + : [dev][i2of5] `encoder:_init_parse_state()` adoption for ITF14 : variant -2020-__-__: [dev][ean] new function `encoder:_init_parse_state()`, and EAN - : family adoption -2020-__-__: update version number in preparetion of the next version. + : [project] update version number in preparation of the next version ------------------------------------------------------------------------------- + ------------------------------------------------------------------------------- -2020-02-04: [milestone] version completed task/commit list +2020-02-04: [milestone] version completed task/commit list: ------------------------------------------------------------------------------- -2020-02-04:*[dev][ean] ISSN support +2020-02-04: [dev][ean] ISSN support 2020-02-03: [dev][ean] move out of `_config()` `finalize()` method as in i2of5 2020-02-02: [dev][i2of5] new ITF14 variant, plan for the next version 2020-02-01: [dev] new semantic for barcode parameter: alternative family @@ -83,8 +132,7 @@ Dev Planner: : [api][breaking change] new encoder naming convention : reuse or create a new encoder object in barracuda:hbox() and : barracuda:save() methods - -(*) this commit +------------------------------------------------------------------------------- Task history and previous version: ================================== diff --git a/macros/luatex/generic/barracuda/README.md b/macros/luatex/generic/barracuda/README.md index 49bab5cb24..d1880c3d2c 100644 --- a/macros/luatex/generic/barracuda/README.md +++ b/macros/luatex/generic/barracuda/README.md @@ -1,42 +1,41 @@ # `barracuda` project -This a pure Lua library is for drawing barcode symbols. The project components -are able to typeset barcode from within a LuaTeX document. Therefore is also -possible to use `barracuda` with a Lua standalone interpreter to draw barcodes -with different graphic format such as `SVG` (see an example below). This package -does not have dependences. +This is a pure Lua library for drawing barcode symbols. `barracuda` components' +are able to typeset barcode from within a LuaTeX document in order to produce a +PDF file, or is also possible to use a Lua standalone interpreter to draw +barcodes in different graphic format such as `SVG` (see an example below). ![a Code39 symbol in SVG format](/test/test-ga-svg/test-code39.svg) -Internal modules are structured to ensure good performance and to give a -complete user control over barcode symbol parameters :thumbsup: . +The internal modules are structured to ensure good performance beside of a +complete user control over barcode symbol parameters :thumbsup: Although development is in beta stage, `barracuda` has a good level of -stability. +stability. The package does not have any dependences. ## Current version -Version: v0.0.10 -Date: 2020-02-04 +Version: 0.0.12 - Date: 2022-06-23 ## Barcode symbologies list -So far, the barcode symbologies included in the package are: +So far, the barcode symbologies supported by the package are: - Code 39 - Code 128 -- Interleaved 2 of 5 +- Interleaved 2 of 5 (ITF14, i2of5 general) - EAN family (ISBN, ISSN, EAN8, EAN13, and the add-ons EAN5 and EAN2) +- UPC-A -Other 1D encoding symbology will be added to the project, then it will be the -turn of 2D barcode types like Datamatrix, QRCode or PDF417. +Other 1D encoding symbology will be eventually added to the project, then it +will be the turn of 2D barcode types like Datamatrix, QRCode or PDF417. ## A very simple LaTeX example The LaTeX package `barracuda.sty` under the cover uses Lua code so you need to compile your source files with LuaTeX or LuajitTeX with the LaTeX format. -For instance, here is a minimal working example for LuaLaTeX: +For instance, the follow is a minimal working example for LuaLaTeX: ```latex % !TeX program = LuaLaTeX @@ -71,7 +70,7 @@ releases can be found only at . TeX Live distribution or Lua interpreter executable are available for a very large number of Operating Systems so it is also for `barracuda`. -Step by step istruction can be found in the INSTALL.txt file. +Step by step instruction can be found in the INSTALL.txt file. ## Contribute @@ -91,4 +90,4 @@ program. Please, for more legal details refer to LICENSE.txt file or visit the web page -Copyright (C) 2020 Roberto Giacomelli +Copyright (C) 2019-2022 Roberto Giacomelli diff --git a/macros/luatex/generic/barracuda/barracuda.sty b/macros/luatex/generic/barracuda/barracuda.sty index 4366cbdd22..c0a830bb2e 100644 --- a/macros/luatex/generic/barracuda/barracuda.sty +++ b/macros/luatex/generic/barracuda/barracuda.sty @@ -1,6 +1,6 @@ % \NeedsTeXFormat{LaTeX2e}[2009/06/27] -\ProvidesPackage{barracuda}[2020/01/15 v0.0.10 a barcode typesetting package]% +\ProvidesPackage{barracuda}[2022/06/23 v0.0.12 a barcode typesetting package]% \newbox\barracudabox \newcommand\barracuda[3][_brcdempty_=true]{\directlua{ local barracuda = require "barracuda" diff --git a/macros/luatex/generic/barracuda/doc/barracuda-ga-asm.pdf b/macros/luatex/generic/barracuda/doc/barracuda-ga-asm.pdf deleted file mode 100644 index 18ba18b9c2..0000000000 Binary files a/macros/luatex/generic/barracuda/doc/barracuda-ga-asm.pdf and /dev/null differ diff --git a/macros/luatex/generic/barracuda/doc/barracuda-ga-asm.tex b/macros/luatex/generic/barracuda/doc/barracuda-ga-asm.tex deleted file mode 100644 index 014cb9d1c4..0000000000 --- a/macros/luatex/generic/barracuda/doc/barracuda-ga-asm.tex +++ /dev/null @@ -1,148 +0,0 @@ -% !TeX program = LuaLaTeX -% Copyright (C) 2020 Roberto Giacomelli - -\documentclass{article} - -\usepackage{fontspec} -\setmainfont{Libertinus Serif} - -\usepackage[margin=18mm]{geometry} -\usepackage{array} -\usepackage{booktabs} - -\newcolumntype{C}{>{\ttfamily}c} -\newcolumntype{L}{>{\ttfamily}l} - -\begin{document} -Goal: describe geometrical object like lines and rectangles -mainly for a barcode drawing library. - - - -\section{\texttt{ga} instruction set} - -A graphic data specification format called '\texttt{ga}' \emph{graphic alchemy}, -or if you want \emph{generic graphic assembler}. - -\begin{verbatim} -ga := generic graphic assembler - := numeric type parameter for dimension, for example f64 or i32 - := numeric type parameter for quantity, an unsigned integer, i.e. u8 - -ga := +Elem - -Elem := Code + Args - -Code := State | Object | Fn - State := 1 -> 31 -- graphic properties - Object := 32 -> 239 -- graphic objects - Fn := 240 -> 255 -- functions - -Args : | | | - := a dimension value of type DIM - := an enumeration value of type u8 (unsigned byte) - := an unsigned integer for multiplicity - := chars sequence ended with 0 -\end{verbatim} - - - -\section{Properties} - -Colors, linecap style etc\dots - -\noindent\begin{tabular}{CLlL} -\toprule -OpCode & Mnemonic key & Graphic property & Operands\\ -\midrule - 1 & pen\_thick & Line thick & \\ - 2 & line\_cap\_style & Line cap style & \\ - 3 & line\_join\_style & Line join style & \\ - 8 & color & ... \\ -\midrule -30 & start\_bbox\_group & Stop to check the bounding box & -\\ -31 & end\_bbox\_group & Set a bounding box and restart to check & \\ -\bottomrule -\end{tabular} - - - -\section{Objects} - -\subsection{Lines} - -A segment that starts from point P1 (x1, y1) and ends to P2 (x2, y2). - -\noindent\begin{tabular}{CLlL} -\toprule -OpCode & Mnemonic key & Graphic object & Operands\\ -\midrule -32 & line & Line & \\ -33 & hline & Horizontal line & \\ -34 & vline & Vertical line & \\ -\midrule -36 & vbar & Vertical bars & ...\\ -37 & hbar & Horizontal bars & ...\\ -\midrule -38 & polyline & Open polyline & ...\\ -39 & c\_polyline & Closed polyline & ...\\ -\bottomrule -\end{tabular} - - -\subsection{Rectangles} - -\noindent\begin{tabular}{CLlL} -\toprule -OpCode & Mnemonic key & Graphic object & Operands\\ -\midrule - 48 & rect & Rectangle & \\ - 49 & f\_rect & Filled rectangle & \\ - 50 & rect\_size & Rectangle & \\ - 51 & f\_rect\_size & Filled rectangle & \\ - -\bottomrule -\end{tabular} - - -\subsection{Text} - -\noindent\begin{tabular}{CLl} -\toprule -OpCode & Mnemonic key & Graphic object/Operands\\ -\midrule - 130 & text & A text with several glyphs\\ - & & \ttfamily \\ -\midrule - 131 & text\_xspaced & A text with glyphs equally spaced on its vertical axis\\ - & & \ttfamily \\ -\midrule - 132 & text\_xwidth & Glyphs equally spaced on vertical axis between two x coordinates\\ - & & \ttfamily \\ -\midrule - & under design assessment\\ - 140 & \_text\_group & Texts on the same baseline \\ - & & \ttfamily < > \\ -\bottomrule -\end{tabular} - - -\subsection{Function} - - -\noindent\begin{tabular}{CLlL} -\toprule -OpCode & Mnemonic key & Function & Operands\\ -\midrule - 240 & move & Translate objects & \\ - 241 & copy & Copy object & ...\\ - 242 & and\_copy & Place and copy objects & ...\\ - 243 & grid & Copy next \(n\) objects on a grid & \\ - 244 & sl\_grid\\ - 250 & mirror\\ - 255 & comment & A string comment & \\ -\bottomrule -\end{tabular} - - -\end{document} diff --git a/macros/luatex/generic/barracuda/doc/barracuda-manual-tool.tex b/macros/luatex/generic/barracuda/doc/barracuda-manual-tool.tex deleted file mode 100644 index 8b00e1c2b5..0000000000 --- a/macros/luatex/generic/barracuda/doc/barracuda-manual-tool.tex +++ /dev/null @@ -1,39 +0,0 @@ -% an auxiliary package for the manual -\directlua{ - barracuda = require "barracuda" - local v = barracuda._VERSION - local p = v:find(" ") - brcd_data = { - version = v:sub(p+1), - date = barracuda._DATE - } -} - -\newcommand{\code}[1]{\texttt{#1}} -\newcommand{\brcd}{\code{barracuda}} - -\newbox\barracudabox -\newcommand\barracuda[3][_brcd_empty_=true]{\directlua{ - local enc_name = [[#2]] - local data = [[#3]] - local opt = {#1}; - if opt._brcd_empty_ == true then - barracuda:hbox(enc_name, data, "barracudabox") - else - barracuda:hbox(enc_name, data, "barracudabox", opt) - end -}% -\leavevmode\box\barracudabox -} - -\newcommand{\brcdkey}[1]{\directlua{ - local key = [===[#1]===] - if brcd_data[key] then - tex.sprint(brcd_data[key]) - else - error("Key '"..key.."' not found") - end -}} - - - diff --git a/macros/luatex/generic/barracuda/doc/barracuda.pdf b/macros/luatex/generic/barracuda/doc/barracuda.pdf deleted file mode 100644 index 99d8034ea3..0000000000 Binary files a/macros/luatex/generic/barracuda/doc/barracuda.pdf and /dev/null differ diff --git a/macros/luatex/generic/barracuda/doc/barracuda.tex b/macros/luatex/generic/barracuda/doc/barracuda.tex deleted file mode 100644 index 0fc6fbac28..0000000000 --- a/macros/luatex/generic/barracuda/doc/barracuda.tex +++ /dev/null @@ -1,413 +0,0 @@ -% !TeX program = LuaLaTeX -% Copyright (C) 2020 Roberto Giacomelli -% Barracuda manual, main TeX source file - -\documentclass[11pt,a4paper]{article} -\usepackage{fontspec} -\usepackage{geometry} -\usepackage{fancyvrb} -\usepackage{graphicx} -\usepackage{hyperref} - -% special macro for manual typesetting -\input{barracuda-manual-tool} - -\hypersetup{ -hidelinks, -linktoc = all, -pdfinfo={ - Title={the Barracuda manual}, - Subject={Barcode printing package}, - Author={Roberto Giacomelli}, - Keywords={Barcode EAN Code128 Lua} -}} - -\setmainfont{Libertinus Serif} -\setmonofont[Scale=0.82]{Fira Mono} -\fvset{ - fontsize=\small, - frame=single, - labelposition=topline, - framesep=5pt -} -\geometry{ - left=32mm, - right=40mm, - top=22mm, - bottom=28mm -} - -\author{Roberto Giacomelli\\\small email: \url{giaconet.mailbox@gmail.com}} -\title{the \code{barracuda} manual\\[1ex] -\small \url{https://github.com/robitex/barracuda}} -\date{\small Date \brcdkey{date} --- Version \brcdkey{version} --- Beta stage} - -\begin{document} -\maketitle - -\abstract{% -Welcome to the \brcd{} software project devoted to barcode printing. - -This manual shows you how to print barcodes in your \TeX{} documents and how to -export such graphic content to an external file, using \brcd{}. - -\brcd{} is written in Lua programming language and is free software released -under the GPL 2 License.% -} - -\tableofcontents -\newpage - - -\section{Getting started} -\label{secStart} - -\subsection{Introduction} -\label{secIntro} - -Barcode symbols are usually a sequence of vertical lines representing encoded -data that can be retrived with special laser scanner or more simpler with a -smartphone running dedicated apps. Almost every store item has a label with a -printed barcode for automatic identification purpose. - -So far, \brcd{} supported symbologies are as the following: -\begin{itemize} - \item Code 39, - \item Code 128, - \item EAN family (ISBN, ISSN, EAN 8, EAN 13, and the add-ons EAN 2 and EAN 5), - \item ITF 2of5, interleaved Two of Five. -\end{itemize} - -The package provides different output graphic format. At the moment they are: -\begin{itemize} - \item PDF Portable Document Format (a modern \TeX{} engine is required), - \item SVG Scalable Vector Graphic. -\end{itemize} - -The name \brcd{} is an assonance to the name Barcode. I started the project back -in 2016 for getting barcode in my \TeX{} generated PDF documents, studying the -Lua\TeX{} technology such as direct \emph{pdfliteral node} creation. - -At the moment \brcd{} is in \emph{beta} stage. In this phase the Lua API can -change respect to the result of development research. - - -\subsection{Manual Content} - -The manual is divided into five part. In part~\ref{secIntro} introduces the -package and gives to the user a proof of concept to how to use it. The next -parts present detailed information about option parameter of each barcode -symbology and methods description to change the \emph{module} width of a EAN-13 -barcode. It's also detailed how the Lua code works internally and how to -implement a barcode symbology not already included in the package. - -The plan of the manual is (but some sections are not completed yet): -\begin{description} -\item[Part 1:] Getting started -\begin{itemize} - \item general introduction \( \to \) \pageref{secIntro} - \item print your first barcode \( \to \) \pageref{secEnter} - \item installing \brcd{} on your system \( \to \) \pageref{secInstall} -\end{itemize} - -\item[Part 2:] \LaTeX{} packages -\begin{itemize} - \item \brcd{} \LaTeX{} package \( \to \) \pageref{secLaTeXPkg} -\end{itemize} - -\item[Part 3:] Barcode Reference and Parameters -\begin{itemize} - \item encoder identification rule \( \to \) \pageref{secEncName} - \item barcode symbologies reference \( \to \) \pageref{secBcRef} -\end{itemize} - -\item[Part 4:] Advanced Work with \brcd{} -\begin{itemize} - \item Lua framework description \( \to \) \pageref{secFramework} - \item API reference \( \to \) \pageref{secAPI} - \item \code{ga} specification \( \to \) \pageref{secGA} -\end{itemize} - -\item[Part 5:] Real examples -\begin{itemize} - \item working example and use cases \( \to \) \pageref{secExample} -\end{itemize} -\end{description} - - -\subsection{Required knowledge and useful resources} - -\brcd{} is a Lua package that can be executed by any Lua interpreter. To use it, -it's necessary a minimal knowledge of Lua programming language and a certain -ability with the terminal of your computer system in order to run command line -task or make software installation. - -It's also possible to run \brcd{} directly within a \TeX{} source file, and -compile it with a suitable typesetting engine like Lua\TeX{}. In this case a -minimal \TeX{} system knowledge is required. As an example of this workflow you -simply can look to this manual because itself is typesetted with LuaLa\TeX{}, -running \brcd{} to include barcodes as a vector graphic object. - -A third way is to use the \LaTeX{} package \code{barracuda.sty} with its high -level macros. A minimal knowledge of the \LaTeX{} format is obviously required. - -Here is a collection of useful learning resources: -\begin{description} -\item[Lua:] to learn Lua the main reference is the book called PIL, Programming -in Lua from one of the language's Author Roberto Ierusalimschy. -\item[\LaTeX:] \dots -\item[Lua\TeX:] \dots -\end{description} - - -\subsection{Running Barracuda} -\label{secEnter} - -The starting point to work with \brcd{} is always a plain text file with some -code processed by a command line program with a Lua interpreter. - -The paradigm of \brcd{} is the Object Oriented Programming. Generally speaking -every object must be created with a function called \emph{costructor} and every -action must be run calling a \emph{method} of it. - -In this section you'll take a taste of \brcd{} coding in three different -execution context: a Lua script, a Lua\TeX{} document and a \LaTeX{} source file -using the macro package \code{barracuda.sty} providing an high level interface -to Lua code. - -High level package like \code{barracuda.sty} make to write Lua code unnecessary. -It will be always possible return to Lua code in order to resolve complex -barcode requirements. - - -\subsubsection{A Lua script} - -As a practical example to produce an EAN~13 barcode, open a text editor of your -choice on an empty file and save it as \code{first-run.lua} with the content of -the following two lines of code: -\medskip -\begin{Verbatim}[label=\footnotesize\code{first-run.lua}] -local barracuda = require "barracuda" -barracuda:save("ean-13", "8006194056290", "my_barcode", "svg") -\end{Verbatim} - -What you have done is to write a \emph{script}. If you have installed a Lua -interpreter along with \brcd{}, open a terminal and run it with the command: -\begin{Verbatim} -$ lua first-run.lua -\end{Verbatim} - -You will see in the same directory of your script, appearing a new file called -\code{my\_barcode.svg} with the drawing: -\begin{center} -\includegraphics{image/8006194056290} -\end{center} - -Coming back to the script first of all, it's necessary to load the library -\brcd{} with the standard Lua function \code{require()} that returns an -object---more precisely a reference to a table where are stored all the -package machinery. - -With the second line of code, an EAN~13 barcode is saved as -\code{my\_barcode.svg} using the method \code{save()} of the \brcd{} object. The -\code{save()} method takes in order the barcode symbology identifier called -\emph{treename}, an argument as a string or as a whole number that represents -data to be encoded, the output file name and the optional output format. With a -fifth optional argument we can pass options to the barcode encoder as a Lua -table. - -Each encoder has an own identifier called treename explained at -section~\ref{secEncName}. In short, in \brcd{} we can build more encoders of the -same symbology with different parameters. - - -\subsubsection{A Lua\TeX{} source file} - -\brcd{} can also runs with Lua\TeX{} and any others Lua powered \TeX{} -engines. The source file is a bit difference respect to the previuos script: the -Lua code lives inside the argument of a \verb=\directlua= primitive, moreover we -must use an horizontal box register as output destination. -\begin{Verbatim} -% !TeX program = LuaTeX -\newbox\mybox -\directlua{ - local require "barracuda" - barracuda:hbox("ean-13", "8006194056290", "mybox") -}\leavevmode\box\mybox -\bye -\end{Verbatim} - -The method \code{hbox()} works only with Lua\TeX{}. It takes three\footnote{A -fourth argment is optional as a table with user defined barcode parameters.} -arguments: encoder \emph{treename}, encoding data as a string, the \TeX{} -horizontal box name. - - -\subsubsection{A Lua\LaTeX{} source file} - -\LaTeX{} working minimal example would be: -\begin{Verbatim} -% !TeX program = LuaLaTeX -\documentclass{article} -\usepackage{barracuda} -\begin{document} -\barracuda{ean-13}{8006194056290} -\end{document} -\end{Verbatim} - - -\subsection{A more deep look} - -\brcd{} is designed to be modular and flexible. For example it is possible to -draw different barcodes on the same canvas or tune barcode parameters. - -The main workflow to draw a barcode object reveals more details on internal -structure. In fact, to draw an EAN~13 barcode we must do at least the following -steps: -\begin{enumerate} -\item load the library, -\item get a reference to the \code{Barcode} abstract class, -\item build an \code{ean} encoder of the variant \code{13}, -\item build an EAN~13 symbol passing data to a costructor, -\item get a reference to a new canvas object, -\item draw barcode on the canvas object, -\item get a reference of the driver object, -\item print the graphic material saving an external \code{svg} file. -\end{enumerate} - -Following that step by step procedure the corresponding code is translated in -the next listing: -\begin{Verbatim} --- lua script -local barracuda = require "barracuda" -- step 1 -local barcode = barracuda:barcode() -- step 2 - -local ean13, err_enc = barcode:new_encoder("ean-13") -- step 3 -assert(ean13, err_enc) - -local symb, err_symb = ean13:from_string("8006194056290") -- step 4 -assert(symb, err_symb) - -local canvas = barracuda:new_canvas() -- step 5 -symb:append_ga(canvas) -- step 6 - -local driver = barracuda:get_driver() -- step 7 -local ok, err_out = driver:save("svg", canvas, "my_barcode") -- step 8 -assert(ok, err_out) -\end{Verbatim} - -Late the manual will give objects and methods references at -section~\ref{secAPI}. - - -\subsection{Installing} -\label{secInstall} - -\subsubsection{Installing for Lua} - -Manually copy \code{src} folder content to a suitable directory of your system -that is reachable to the system Lua interpreter. - -\subsubsection{Installing for TeX Live} - -If you have TeX Live installed from CTAN or from DVD TeX Collection, before any -modification to your system check if the package is already installed looking -for \emph{installed} key in the output of the command: -\begin{Verbatim} -$ tlmgr show barracuda -\end{Verbatim} - -If `barracuda` is not present, run the command: -\begin{Verbatim} -$ tlmgr install barracuda -\end{Verbatim} - -If you have installed TeX Live via Linux OS repository try your distribution's -package management system running a software update. - -It's also possible to install the package manually: -\begin{enumerate} -\item Grab the sources from CTAN or \url{https://github.com/robitex/barracuda}. -\item Unzip it at the root of one or your TDS trees (local or personal). -\item You may need to update some filename database after this, see your \TeX{} -distribution's manual for details. -\end{enumerate} - - -\section{Barracuda \LaTeX{} Package} -\label{secLaTeXPkg} - -The \LaTeX{} package delivered with \brcd{} is still under an early stage of -development. The only macro available is \verb=\barracuda{encoder}{data}=. -A simple example is the following source file for Lua\LaTeX{}: -\begin{Verbatim} -% !TeX program = LuaLaTeX -\documentclass{article} -\usepackage{barracuda} -\begin{document} -\leavevmode -\barracuda{code39}{123ABC}\\ -\barracuda{code128}{123ABC} -\end{document} -\end{Verbatim} - -Every macro \verb=\barracuda= typesets a barcode symbol with the encoder defined -in the first argument, encoding data defined by the second. - - -\section{Barcode parameters} -\label{secBarcodeReference} - -\subsection{Encoder treename} -\label{secEncName} - -TODO - -\subsection{Barcode Reference} -\label{secBcRef} - -TODO - -\section{Developer zone} - -\subsection{The Barracuda Framework} -\label{secFramework} - -The \brcd{} package framework consists in indipendent modules: a barcode class -hierarchy encoding a text into a barcode symbology; a geometrical library called -\code{libgeo} representing several graphic objects; an encoding library for the -\code{ga} format (graphic assembler) and several driver to \emph{print} a ga -stream into a file or a \TeX{} hbox register. - -To implement a barcode encoder you have to write a component called -\emph{encoder} defining every parameters and implementing the encoder builder, -while a driver must understand ga opcode stream and print the corresponding -graphic object. - -Every barcode encoder come with a set of parameters, some of them can be -reserved and can't be edit after the encoder was build. So, you can create many -instances of the same encoder for a single barcode type, with its own parameter -set. - -The basic idea is getting faster encoders, for which the user may set up -paramenters at any level: barcode abstract class, encoder globally, down to a -single symbol object. - -The Barcode class is completely indipendent from the ouput driver and viceversa. - -\subsection{Lua API reference} -\label{secAPI} - -TODO - -\subsection{\code{ga} specification} -\label{secGA} - -TODO - -\section{Example and use cases} -\label{secExample} - -TODO - -\end{document} diff --git a/macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.pdf b/macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.pdf new file mode 100644 index 0000000000..18ba18b9c2 Binary files /dev/null and b/macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.pdf differ diff --git a/macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.tex b/macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.tex new file mode 100644 index 0000000000..ff8d3e1ff4 --- /dev/null +++ b/macros/luatex/generic/barracuda/doc/ga-graphic-asm/barracuda-ga-asm.tex @@ -0,0 +1,148 @@ +% !TeX program = LuaLaTeX +% Copyright (C) 2019-2022 Roberto Giacomelli + +\documentclass{article} + +\usepackage{fontspec} +\setmainfont{Libertinus Serif} + +\usepackage[margin=18mm]{geometry} +\usepackage{array} +\usepackage{booktabs} + +\newcolumntype{C}{>{\ttfamily}c} +\newcolumntype{L}{>{\ttfamily}l} + +\begin{document} +Goal: describe geometrical object like lines and rectangles +mainly for a barcode drawing library. + + + +\section{\texttt{ga} instruction set} + +A graphic data specification format called '\texttt{ga}' \emph{graphic alchemy}, +or if you want \emph{generic graphic assembler}. + +\begin{verbatim} +ga := generic graphic assembler + := numeric type parameter for dimension, for example f64 or i32 + := numeric type parameter for quantity, an unsigned integer, i.e. u8 + +ga := +Elem + +Elem := Code + Args + +Code := State | Object | Fn + State := 1 -> 31 -- graphic properties + Object := 32 -> 239 -- graphic objects + Fn := 240 -> 255 -- functions + +Args : | | | + := a dimension value of type DIM + := an enumeration value of type u8 (unsigned byte) + := an unsigned integer for multiplicity + := chars sequence ended with 0 +\end{verbatim} + + + +\section{Properties} + +Colors, linecap style etc\dots + +\noindent\begin{tabular}{CLlL} +\toprule +OpCode & Mnemonic key & Graphic property & Operands\\ +\midrule + 1 & pen\_thick & Line thick & \\ + 2 & line\_cap\_style & Line cap style & \\ + 3 & line\_join\_style & Line join style & \\ + 8 & color & ... \\ +\midrule +29 & enable\_bbox & start to update the bounding box & -\\ +30 & disable\_bbox & Stop to check the bounding box & -\\ +31 & set\_bbox & Set a bounding box & \\ +\bottomrule +\end{tabular} + + + +\section{Objects} + +\subsection{Lines} + +A segment that starts from point P1 (x1, y1) and ends to P2 (x2, y2). + +\noindent\begin{tabular}{CLlL} +\toprule +OpCode & Mnemonic key & Graphic object & Operands\\ +\midrule +32 & line & Line & \\ +33 & hline & Horizontal line & \\ +34 & vline & Vertical line & \\ +\midrule +36 & vbar & Vertical bars & ...\\ +37 & hbar & Horizontal bars & ...\\ +\midrule +38 & polyline & Open polyline & ...\\ +39 & c\_polyline & Closed polyline & ...\\ +\bottomrule +\end{tabular} + + +\subsection{Rectangles} + +\noindent\begin{tabular}{CLlL} +\toprule +OpCode & Mnemonic key & Graphic object & Operands\\ +\midrule + 48 & rect & Rectangle & \\ + 49 & f\_rect & Filled rectangle & \\ + 50 & rect\_size & Rectangle & \\ + 51 & f\_rect\_size & Filled rectangle & \\ +\bottomrule +\end{tabular} + + +\subsection{Text} + +\noindent\begin{tabular}{CLl} +\toprule +OpCode & Mnemonic key & Graphic object/Operands\\ +\midrule + 130 & text & A text with several glyphs\\ + & & \ttfamily \\ +\midrule + 131 & text\_xspaced & A text with glyphs equally spaced on its vertical axis\\ + & & \ttfamily \\ +\midrule + 132 & text\_xwidth & Glyphs equally spaced on vertical axis between two x coordinates\\ + & & \ttfamily \\ +\midrule + & under design assessment\\ + 140 & \_text\_group & Texts on the same baseline \\ + & & \ttfamily < > \\ +\bottomrule +\end{tabular} + + +\subsection{Function} + + +\noindent\begin{tabular}{CLlL} +\toprule +OpCode & Mnemonic key & Function & Operands\\ +\midrule + 240 & move & Translate objects & \\ + 241 & copy & Copy object & ...\\ + 242 & and\_copy & Place and copy objects & ...\\ + 243 & grid & Copy next \(n\) objects on a grid & \\ + 244 & sl\_grid\\ + 250 & mirror\\ + 255 & comment & A string comment & \\ +\bottomrule +\end{tabular} + + +\end{document} diff --git a/macros/luatex/generic/barracuda/doc/image/8006194056290.pdf b/macros/luatex/generic/barracuda/doc/image/8006194056290.pdf deleted file mode 100644 index 8effe87846..0000000000 Binary files a/macros/luatex/generic/barracuda/doc/image/8006194056290.pdf and /dev/null differ diff --git a/macros/luatex/generic/barracuda/doc/manual/barracuda-manual-tool.tex b/macros/luatex/generic/barracuda/doc/manual/barracuda-manual-tool.tex new file mode 100644 index 0000000000..3b19fd5ab5 --- /dev/null +++ b/macros/luatex/generic/barracuda/doc/manual/barracuda-manual-tool.tex @@ -0,0 +1,49 @@ +% an auxiliary package for the manual +\directlua{ + barracuda = require "barracuda" + local v = barracuda._VERSION + local p = v:find(" ") + brcd_data = { + version = v:sub(p+1), + date = barracuda._DATE + } +} + +\newcommand{\code}[1]{\texttt{#1}} +\newcommand{\brcd}{\code{barracuda}} + +\newbox\barracudabox +\newcommand\barracuda[3][_brcd_empty_=true]{\directlua{ + local enc_name = [[#2]] + local data = [[#3]] + local opt = {#1}; + if opt._brcd_empty_ == true then + barracuda:hbox(enc_name, data, "barracudabox") + else + barracuda:hbox(enc_name, data, "barracudabox", opt) + end +}% +\leavevmode\box\barracudabox +} + +\newcommand{\brcdkey}[1]{\directlua{ + local key = [===[#1]===] + if brcd_data[key] then + tex.sprint(brcd_data[key]) + else + error("Key '"..key.."' not found") + end +}} + +\newcommand{\brcdparametertab}[1]{\directlua{ + local enc_id = [=[#1]=] + local t = {} + tex.print() + + local barcode = barracuda:barcode() + local info = barcode:info() + local param = info.param + +}} + +\endinput diff --git a/macros/luatex/generic/barracuda/doc/manual/barracuda-manual.pdf b/macros/luatex/generic/barracuda/doc/manual/barracuda-manual.pdf new file mode 100644 index 0000000000..af224cc148 Binary files /dev/null and b/macros/luatex/generic/barracuda/doc/manual/barracuda-manual.pdf differ diff --git a/macros/luatex/generic/barracuda/doc/manual/barracuda-manual.tex b/macros/luatex/generic/barracuda/doc/manual/barracuda-manual.tex new file mode 100644 index 0000000000..971650e813 --- /dev/null +++ b/macros/luatex/generic/barracuda/doc/manual/barracuda-manual.tex @@ -0,0 +1,1312 @@ +% !TeX program = LuaLaTeX +% Copyright (C) 2019-2022 Roberto Giacomelli +% Barracuda manual, main TeX source file + +\documentclass[11pt,a4paper]{article} +\usepackage{fontspec} +\usepackage{geometry} +\usepackage{fancyvrb} +\usepackage{graphicx} +\usepackage{booktabs} +\usepackage{array} +\usepackage{tikz} +\usepackage{tcolorbox} +\usepackage{hyperref} + +\newcolumntype{C}{>{\ttfamily}c} +\newcolumntype{L}{>{\ttfamily}l} + +\usetikzlibrary{arrows.meta} + +% special macro for manual typesetting +\input{barracuda-manual-tool} + +\tcbuselibrary{skins} +\tcbset{ + sharpish corners, + drop shadow=gray!75, + halign lower=center, + left=5pt, + boxrule=1.2pt, + titlerule=0.8pt, + colback=green!10!white, + colbacktitle=green!10!white, + coltitle=black, + bicolor,colbacklower=white, + righthand width=80pt +} + +\hypersetup{ +hidelinks, +linktoc = all, +pdfinfo={ + Title={The Barracuda manual}, + Subject={Barcode printing package}, + Author={Roberto Giacomelli}, + Keywords={Barcode EAN UPC Code128 ITF14 Lua} +}} +\definecolor{CodeBlue}{rgb}{0.05,0.05,0.80} +\setmainfont{Libertinus Serif} +\setmonofont[Scale=0.82]{Fira Mono} +\fvset{ + fontsize=\small, + labelposition=topline, + formatcom=\color{black}, +} +\geometry{ + left=38mm, + right=28mm, + top=22mm, + bottom=28mm +} + +\author{Roberto Giacomelli\\\small email: \url{giaconet.mailbox@gmail.com}} +\title{the \code{barracuda} manual\\[1ex] +\small \url{https://github.com/robitex/barracuda}} +\date{\small Date \brcdkey{date} --- Version \brcdkey{version} --- Beta stage} + +\newbox\mybox + +\begin{document} +\maketitle + +\abstract{% +Welcome to the \brcd{} software project devoted to barcode printing. + +This manual shows you how to print barcodes in your \TeX{} documents and how to +export such graphic content to an external file. + +\brcd{} is written in Lua and is free software released under the GPL 2 License. +} + +\tableofcontents +\newpage + + +\section{Getting started} +\label{secStart} + +\subsection{Introduction} +\label{secIntro} + +Barcode symbols are usually a sequence of vertical lines representing encoded +data that can be retrived with special laser scanner or more simpler with a +smartphone running dedicated apps. Almost every store item has a label with a +printed barcode for automatic identification purpose. + +So far, \brcd{} supported symbologies are as the following: +\begin{itemize} +\item Code 39, +\item Code 128, +\item EAN family (ISBN, ISSN, EAN 8, EAN 13, and the add-ons EAN 2 and EAN 5), +\item ITF 2of5, interleaved Two of Five (ITF14, i2of5 in general), +\item UPC-A. +\end{itemize} + +The package provides different output graphic format. At the moment they are: +\begin{itemize} +\item PDF Portable Document Format (a modern \TeX{} engine is required), +\item SVG Scalable Vector Graphic. +\end{itemize} + +The name \brcd{} is an assonance to the name Barcode. I started the project back +in 2016 for getting barcode in my \TeX{} generated PDF documents, studying the +Lua\TeX{} technology such as direct \emph{pdfliteral} node creation. + +At the moment \brcd{} is in \emph{beta} stage. In this phase the Lua API may +change respect to the result of development activity. + + +\subsection{Manual Content} + +The manual is divided into five part. In part~\ref{secIntro} introduces the +package and gives to the user a proof of concept to how to use it. The next +parts present detailed information about option parameter of each barcode +symbology and methods description to change the \emph{module} width of a EAN-13 +barcode. It's also detailed how the Lua code works internally and how to +implement a barcode symbology not already included in the package. + +The manual plan is: +\begin{description} +\item[Part 1:] Getting started +\begin{itemize} + \item general introduction \( \to \) \pageref{secIntro} + \item print your first barcode \( \to \) \pageref{secEnter} + \item installing \brcd{} on your system \( \to \) \pageref{secInstall} +\end{itemize} + +\item[Part 2:] \LaTeX{} packages +\begin{itemize} + \item \brcd{} \LaTeX{} package \( \to \) \pageref{secLaTeXPkg} +\end{itemize} + +\item[Part 3:] Barcode Reference +\begin{itemize} + \item barcode symbologies reference \( \to \) \pageref{secBcRef} +\end{itemize} + +\item[Part 4:] Developer zone +\begin{itemize} + \item the Lua framework \( \to \) \pageref{secFramework} + \item encoder identification rule \( \to \) \pageref{secEncName} + \item API reference \( \to \) \pageref{secAPI} + \item \code{ga} specification \( \to \) \pageref{secGA} +\end{itemize} + +\item[Part 5:] Real examples +\begin{itemize} + \item working example and use cases \( \to \) \pageref{secExample} +\end{itemize} +\end{description} + + +\subsection{Required knowledge and useful resources} + +\brcd{} is a Lua package that can be executed by any Lua interpreter. To use it, +it's necessary a minimal knowledge of Lua programming language and a certain +ability with the terminal of your computer system in order to run command line +task or make software installation. + +It's also possible to run \brcd{} directly within a \TeX{} source file, and +compile it with a suitable typesetting engine like Lua\TeX{}. In this case a +minimal \TeX{} system knowledge is required. As an example of this workflow you +simply can look to this manual because itself is typesetted with LuaLa\TeX{}, +running \brcd{} to include barcodes as a vector graphic object. + +A third way is to use the \LaTeX{} package \code{barracuda.sty} with its high +level macros. A minimal knowledge of the \LaTeX{} format is obviously required. + +Here is a collection of useful learning resources: +\begin{description} +\item[Lua:] to learn Lua the main reference is the book called PIL that stands +for Programming in Lua from one of the language's Author Roberto Ierusalimschy. +\item[Lua\TeX:] the typesetting engine manual can be opened running the +\code{texdoc} utility in a terminal window of your system, typing the command: +\begin{Verbatim} +$ texdoc luatex +\end{Verbatim} +\end{description} + + +\subsection{Running Barracuda} +\label{secEnter} + +The starting point to work with \brcd{} is always a plain text file with some +code processed by a command line program with a Lua interpreter. + +In this section you'll take a taste of \brcd{} coding in three different +execution context: a Lua script, a Lua\TeX{} document and a \LaTeX{} source file +using the macro package \code{barracuda.sty} providing an high level interface +to the Lua library. + +High level package like \code{barracuda.sty} make to write Lua code unnecessary. +It will be always possible to return to Lua code in order to resolve complex +barcode requirements. + + +\subsubsection{A Lua script} + +The paradigm of \brcd{} is the Object Oriented Programming. Generally speaking +every library object must be created with a function called \emph{constructor} +and every action on it must be run calling an object \emph{method}. + +In Lua a constructor or even a method call syntax it's a little bit different +from the usual form because we have to use the \emph{colon notation}: +\begin{BVerbatim} +object:method(args) +\end{BVerbatim} + +As a practical example, to produce an EAN~13 barcode, open a text editor of your +choice on an empty file and save it as \code{first-run.lua} with the content of +the following two lines of code: +\begin{tcolorbox}[ + title={\code{first-run.lua}} +] +\begin{BVerbatim} +local barracuda = require "barracuda" +barracuda:save("ean-13", "8006194056290", "my_barcode", "svg") +\end{BVerbatim} +\end{tcolorbox} + +What you have done is to write a \emph{script}. If you have installed a Lua +interpreter along with \brcd{}, open a terminal and run it with the command: +\begin{BVerbatim} +$ lua first-run.lua +\end{BVerbatim} + +Into the same directory of your script you will see a new file called +\code{my\_barcode.svg} with the drawing: +\begin{center} +\includegraphics{image/8006194056290} +\end{center} + +Coming back to the script, the first statement loads the library \brcd{} with +the standard Lua function \code{require()} that returns an object---more +precisely a reference to a table where are stored all the package machinery. + +With the second line of code, an EAN~13 barcode is saved as +\code{my\_barcode.svg} using the method \code{save()} of the \brcd{} object. The +\code{save()} method takes four mandatory argumetns: the barcode symbology +identifier called \emph{treename}, an argument as a string or as a whole number +that represents data to be encoded, the output file name and the optional output +format. With a fifth optional argument we can pass options to the barcode +encoder as a Lua table in the \code{option=value} format. + +In more detail, thanks to treename identifier explained at +section~\ref{secEncName} is possible to build more encoders of the same +symbology each with a different set of parameters. + +It's also possible to run a Lua script with \code{texlua}, the Lua interpreter +improved with certain Lua\TeX{} libraries delivered by any modern \TeX{} +distribution. \code{texlua} saves you to install Lua if you are a \TeX{} user. + +The command to run \code{first-run.lua} is the same as before, just a +substitution of the name \code{lua} with \code{texlua}, but an adjustment is +required if we want to run the script with \TeX{} delivered \brcd{} library +leaving untouched the system outside \code{texmf}. + +An alternative path searching procedure consists to find the main file of +\brcd{} with an internal Lua\TeX{} library called \code{kpse}: +\begin{Verbatim} +-- texlua script +kpse.set_program_name("luatex") +local path_to_brcd = kpse.find_file("barracuda", "lua") +local barracuda = dofile(path_to_brcd) +barracuda:save("ean-13", "8006194056290", "my_barcode", "svg") +\end{Verbatim} + + +\subsubsection{A Lua\TeX{} source file} + +\brcd{} can also runs with Lua\TeX{} and any others Lua powered \TeX{} +engines. The source file is a bit difference respect to the previous script: the +Lua code lives inside the argument of a \verb=\directlua= primitive, moreover we +must use an horizontal box register as the output destination. +\begin{tcolorbox}[ + title={\code{first-run.tex}: Lua\TeX{} version} +] +\begin{BVerbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local require "barracuda" + barracuda:hbox("ean-13", "8006194056290", "mybox") +}\leavevmode\box\mybox +\bye +\end{BVerbatim} +\end{tcolorbox} +The method \code{hbox()} works only with Lua\TeX{}. It takes three\footnote{A +fourth argment is optional as a table with user defined barcode parameters.} +arguments: encoder \emph{treename}, encoding data as a string, the \TeX{} +horizontal box name. + + +\subsubsection{A Lua\LaTeX{} source file} + +A \LaTeX{} working minimal example would be: +\begin{tcolorbox}[ + sidebyside, + title={\code{first-run.tex}: Lua\LaTeX{} version}, + righthand width=120pt +] +\begin{BVerbatim} +% !TeX program = LuaLaTeX +\documentclass{article} +\usepackage{barracuda} +\begin{document} +\barracuda{ean-13}{8006194056290} +\end{document} +\end{BVerbatim} +\tcblower\ttfamily +\hfill\barracuda{ean-13}{8006194056290}\hfill\hbox{} +\end{tcolorbox} + + +\subsection{A more deep look} + +\brcd{} is designed to be modular and flexible. For example it is possible to +draw different barcodes on the same canvas or tuning barcode parameters. + +The low level workflow to draw a barcode object reveals more details on the +internal architecture. In fact, we must do at least the following steps divided +into three phases: +\begin{description} +\item[a.1] load the library, +\item[a.2] get a reference to the \code{Barcode} abstract class, +\item[a.3] build an encoder, +\item[a.4] build a symbol passing data to an encoder's constructor, +\item[b.1] get a reference to a new canvas object, +\item[b.2] draw barcode on the canvas object, +\item[c.1] load the driver, +\item[c.2] print the figure as an external \code{svg} file. +\end{description} + +In the phase \textbf{a} a barcode symbols is created, then in phase \textbf{b} a +canvas object is filled with the graphic elements of the symbol, and finally in +the phase \textbf{c} the canvas is sent to the driver output channel. + +Following the procedure step by step, the resulting code is as the following +listing, where the encoder is EAN variant 13: +\begin{tcolorbox} +\begin{BVerbatim} +-- a lua script +local barracuda = require "barracuda" -- step a.1 +local barcode = barracuda:barcode() -- step a.2 +local ean13, err_enc = barcode:new_encoder("ean-13") -- step a.3 +assert(ean13, err_enc) +local symb, err_symb = ean13:from_string("8006194056290") -- step a.4 +assert(symb, err_symb) + +local canvas = barracuda:new_canvas() -- step b.1 +symb:draw(canvas) -- step b.2 + +local drv = barracuda:get_driver() -- step c.1 +local ok, err_out = drv:save("svg", canvas, "my_barcode") -- step c.2 +assert(ok, err_out) +\end{BVerbatim} +\end{tcolorbox} + +Anyway, more abstract methods allow the user to write a more compact code. For +instance, phase \textbf{b} can be fuse with \textbf{c}, thanks to a +a reference to the driver object included in the \code{canvas} object: +\begin{Verbatim} +-- phase b + c +local canvas = barracuda:new_canvas() -- step bc.1 +symb:draw(canvas) -- step bc.2 +local ok, err_out = canvas:save("svg", "my_barcode") -- step bc.3 +assert(ok, err_out) +\end{Verbatim} + +As we have been seen before an high level method provides a way to unify all the +phases: +\begin{Verbatim} +-- unique phase version +local require "barracuda" +barracuda:save("ean-13", "8006194056290", "my_barcode", "svg") +\end{Verbatim} + +Low level code offers more control while high level programming is quite +compact. Late in the manual you will find the objects and methods reference at +section~\ref{secAPI}. + + +\subsection{Installing \brcd} +\label{secInstall} + +\subsubsection{Installing for Lua} + +Manually copy \code{src} folder content to a suitable directory of your system +that is reachable to the system Lua interpreter. + + +\subsubsection{Installing for TeX Live} + +If you have TeX Live installed from CTAN or from DVD TeX Collection, before any +modification to your system check if the package is already installed looking +for \emph{installed} key in the output of the command: +\begin{Verbatim} +$ tlmgr show barracuda +\end{Verbatim} + +If \brcd{} is reported as not installed, run the command: +\begin{Verbatim} +$ tlmgr install barracuda +\end{Verbatim} + +If you have installed TeX Live via your Linux repository, try your +distribution's package manager an update or check for optional packages not yet +installed. + +It's also possible to install \brcd{} manually with these steps: +\begin{enumerate} +\item Grab the sources from CTAN or from the official repository +\url{https://github.com/robitex/barracuda}. +\item Unzip it at the root of one of your TDS trees (local or personal). +\item You may need to update some filename database after this, see your \TeX{} +distribution's manual for details. +\end{enumerate} + + +\section{Barracuda \LaTeX{} Package} +\label{secLaTeXPkg} + +The \LaTeX{} package delivered with \brcd{} is still under an early stage of +development. The only macro available is +\verb=\barracuda[option]{encoder}{data}=. A simple example is the following +source file for Lua\LaTeX{}: +\begin{tcolorbox}[sidebyside] +\begin{BVerbatim} +% !TeX program = LuaLaTeX +\documentclass{article} +\usepackage{barracuda} +\begin{document} +\leavevmode +\barracuda{code128}{123ABC}\\[2ex] +\barracuda[text_star=true]{code39}{123ABC} +\end{document} +\end{BVerbatim} +\tcblower +\leavevmode +\barracuda{code128}{123ABC}\\[2ex] +\barracuda[text_star=true]{code39}{123ABC} +\end{tcolorbox} + +Every macro \brcd{} typesets a barcode symbol with the encoder defined in the +first argument, encoding data defined by the second. + + +\section{Barcode Reference} +\label{secBcRef} + +\begin{figure} +\centering +\begin{tikzpicture} +\ttfamily +\draw (-20mm, -20mm) rectangle (20mm, 20mm); +\end{tikzpicture} +\caption{Barcode class hierarchy.} +\label{figBarcodeHierarchy} +\end{figure} + +\subsection{Common, Global and Local Barcode Options} + +Every barcode encoder inherits from \code{Barcode} abstract class methods and +options. If we change its option values, the changes will be global for all the +encoders except if the encoder has not an own local option overwritten before. + +The same schema applying also for encoder and the barcode symbols build apart +from it. Every symbol inherits methods and options from its encoder. + +Such three levels option system is designed to allow the user to set up option +not only in a certain point in the tree object, but also any time in the code. +When changes are accepted by an object they become valid for that time on. + +The architecture of barcode classes is shown in more details in +figure~\ref{figBarcodeHierarchy}. At the top of the hierarchy there is the +\code{Barcode} class. It's an abstract class in the sense that no symbols can be +printed by that class. + +At an intermediate level we found a \code{Builder} with an instance of one of +its \code{Encoder} class. When we call method \code{new\_encoder()} provided by +\code{Barcode} class, what really happen is the loading of the \code{Builder} if +not just loaded before, that is the actual library of the specific simbology, +and a linked \code{Encoder} object incorporates its own options. + +At the last level are placed the symbol instances derived both from the +\code{Builder} and \code{Encoder}, the first provides methods while the second +provides option values. Only these objects are printable in a barcode graphic. + +Common options of \code{Barcode} are the following: +\begin{center} +\begin{tabular}{@{}ccp{75mm}@{}} +\toprule +Option Id & Type/default & Description\\ +\midrule +\code{ax} & numeric/0 & Relative x-coordinate for insertion point of the barcode symbol\\ +\midrule +\code{ay} & numeric/0 & Relative y-coordinate for insertion point of the barcode symbol\\ +\midrule +\code{debug\_bbox} & enum/\code{none} & Draw symbol bounding box with a thin dashed line\\ + & \code{none} & \small do nothing\\ + & \code{symb} & \small draw the bbox of the symbol\\ + & \code{qz} & \small draw the bbox at quietzone border\\ + & \code{qzsymb} & \small draw symbol and quietzone bboxes\\ +\bottomrule +\end{tabular} +\end{center} + + +For each barcode symbologies the next section reports parameters and optional +methods of it. + +\subsection{Code39} +\label{secCode39} + +\code{Code39} is one of the oldest symbologies ever invented. It doesn't include +any checksum digit and the only encodable characters are digits, uppercase +letters and a few symbol like \code{+} or \code{\$}. + + + + + +\subsection{Code128} +\label{secCode128} + + + +% devzone color setup +\tcbset{ + colback=blue!10!white, + colbacktitle=blue!10!white, +} + +\section{Developer zone} + +\subsection{The Barracuda Framework} +\label{secFramework} + +The \brcd{} package framework consists in independent modules: a barcode class +hierarchy encoding a text into a barcode symbology; a geometrical library called +\code{libgeo} modeling several graphic objects; an encoding library for the +\code{ga} format (graphic assembler) and several driver to \emph{print} a +\code{ga} stream into a file or in a \TeX{} \code{hbox} register. + +To implement a barcode encoder you have to write a component called +\emph{encoder} defining every parameters and implementing the encoder builder, +while a driver must understand ga opcode stream and print the corresponding +graphic object. + +Every barcode encoder come with a set of parameters, some of them can be +reserved and can't be edit after the encoder was build. So, you can create many +instances of the same encoder for a single barcode type, with its own parameter +set. + +The basic idea is getting faster encoders, for which the user may set up +parameters at any level: barcode abstract class, encoder globally, down to a +single symbol object. + +The Barcode class is completely independent from the output driver and vice +versa. + + +\subsection{Error Management} + +Functions in Lua may return more than one parameters. \brcd{} methods takes +advantage by this feature for the error management. In fact, \brcd{} as a +library, remind the responsibility to the caller in order to choose what to do +in case an error is reported. + +When a method may fail depending on the correctness of the input, it returns two +parameters alternatively valid: the first is the expected result while the +second is the error description. + +This behavior perfectly match the arguments required by the \code{assert()} +built-in function. + + + + +\subsection{Encoder Treename} +\label{secEncName} + +In \brcd{} in order to draw a barcode symbol it's necessary to create an +\code{Encoder} object + + +\subsection{API reference of Lua modules} +\label{secAPI} + +TODO + +\subsection{\code{ga} specification} +\label{secGA} + +This section defines and explains with code examples the \code{ga} instruction +stream. \code{ga} stands for \emph{graphic assembler}, a sort of essential +language that describes geometrical object like lines and rectangles mainly for +a barcode drawing library on a cartesian plane \( (O, x, y) \). + +The major goal of any \brcd{} encoder is to create the \code{ga} stream +corresponding to a vector drawing of a barcode symbol. + +In details, a \code{ga} stream is a numeric sequence that like a program defines +what must be draw. It is not a fully binary sequence---which is a byte stream +and ideally is what a \code{ga} stream would really be---but a sequence of +integers or floating point numbers. + +In Lua this is very easy to implement. Simply append a numeric value to a table +that behave as an array. Anyway \code{ga} must be basically a binary format +almost ready to be sent or received by means of a network channel. + +In the Backus–Naur form a valid \code{ga} stream grammar is described by the +following code: +\begin{Verbatim} + ::= + ::= + | + ::= + | + + ::= + | + | + ::= 1 .. 31; graphic properties + ::= 32 .. 239; graphic objects + ::= 240 .. 255; functions + + ::= + | + ::= + | + | + | + | + | + | + | + + ::= f64; unit measure scaled point sp = 1/65536pt + ::= f64; unit measure scaled point sp = 1/65536pt + ::= u64 + ::= 0 + ::= + | + ::= u64 + ::= u8 + ::= f64 + ::= + | + ::= + ::= + ::= + ::= + | + := + +; u8 unsigned 8 bit integer +; u64 unsigned 64 bit integer +; f64 floating point 64 bit number +\end{Verbatim} + + +Every \code{} changes the graphic state---for instance the current +line width---or defines a graphic object, depending on the \code{opcode} value. +Coordinates or dimensions must be expressed as \emph{scaled point}, the +basic unit of measure of \TeX{} equivalent to \( 1/65536\, \)pt. + + +\subsubsection{Hard coded an horizontal line} + +The \code{opcode} for the \code{linewidth} operation is 1, while +for the \code{hline} operation is 33. An horizontal line 6pt width from the +point (0pt, 0pt) to the point (32pt, 0pt) is represented by this \code{ga} +stream: +\begin{Verbatim} +1 393216 33 0 2097152 0 +\end{Verbatim} + +Introducing \code{mnemonic opcode} in \code{opcode} places and separate the +operations in a multiline fashion, the same sequence become more readable and +more similar to an assembler listing: +\begin{Verbatim} +linewidth 393216 ; set line width to 393216sp +hline 0 2097152 0 ; draw hline x1 x2 y +\end{Verbatim} + +To prove and visualize the meaning of the stream, we can simply use the native +graphic driver of \brcd{} compiling this Lua\TeX{} source file: +\begin{Verbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local ga = {1, 393216, 33, 0, 2097152, 0} + local drv = barracuda:get_driver() + drv:ga_to_hbox(ga, "mybox") +}\leavevmode\box\mybox +\bye +\end{Verbatim} + +The result is:\directlua{ +local ga = {1, 393216, 33, 0, 2097152, 0} +local drv = barracuda:get_driver() +drv:ga_to_hbox(ga, "mybox") +}\box\mybox + + +\subsubsection{Encoding \code{ga} with the \code{gaCanvas} class} + +A more abstract way to write a \code{ga} stream is provided by the +\code{gaCanvas} class of the \code{libgeo} module. Every operation with +identifier \code{opcode} is mapped to a method named \code{encode\_()} +of a canvas object: +\begin{Verbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local canvas = barracuda:new_canvas() + local pt = canvas.pt + canvas:encode_linewidth(6*pt) + canvas:encode_hline(0, 32*pt, 0) + local drv = barracuda:get_driver() + drv:ga_to_hbox(canvas, "mybox") + tex.print("[") + for _, n in ipairs(canvas:get_stream()) do + tex.print(tostring(n)) + end + tex.print("]") +} results in \box\mybox +\bye +\end{Verbatim} + +The stream is printed beside the drawing in the output PDF file. Therefore the +same \code{ga} stream can also generate a different output, for instance a SVG +file. For this purpose execute the \code{save()} method of the \code{Driver} +class (the drawing is showed side-by-side the listing): +\begin{tcolorbox}[sidebyside] +\begin{BVerbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local canvas = barracuda:new_canvas() + local pt = canvas.pt + local side = 16*pt + local s = side/2 - 1.5*pt + local l = side/2 - 2*pt + local dim = 4 + canvas:encode_linewidth(1*pt) + canvas:encode_disable_bbox() + for c = 0, dim do + for r = 0, dim do + local x, y = c*side, r*side + canvas:encode_hline(x-l, x+l, y-s) + canvas:encode_hline(x-l, x+l, y+s) + canvas:encode_vline(y-l, y+l, x-s) + canvas:encode_vline(y-l, y+l, x+s) + end + end + local b1 = -s - 0.5*pt + local b2 = dim*side + s + 0.5*pt + canvas:encode_set_bbox(b1, b1, b2, b2) + canvas:ga_to_hbox("mybox") + canvas:save("svg", "grid") +}\leavevmode\box\mybox +\bye +\end{BVerbatim} +\tcblower +\directlua{ + local canvas = barracuda:new_canvas() + local pt = canvas.pt + local side = 16*pt + local s = side/2 - 1.5*pt + local l = side/2 - 2*pt + local dim = 4 + canvas:encode_linewidth(1*pt) + canvas:encode_disable_bbox() + for c = 0, dim do + for r = 0, dim do + local x, y = c*side, r*side + canvas:encode_hline(x-l, x+l, y-s) + canvas:encode_hline(x-l, x+l, y+s) + canvas:encode_vline(y-l, y+l, x-s) + canvas:encode_vline(y-l, y+l, x+s) + end + end + local b1 = -s - 0.5*pt + local b2 = dim*side + s + 0.5*pt + canvas:encode_set_bbox(b1, b1, b2, b2) + canvas:ga_to_hbox("mybox") +}\hfill\box\mybox\hfill{} +\end{tcolorbox} + +An automatic process updates the bounding box of the figure meanwhile the stream +is read instruction after instruction. The \code{disable\_bbox} operation +produces a more fast execution and the figure maintains the bounding box +computed until that point. The \code{set\_bbox} operation imposes a bounding box +in comparison to the current one of the figure. + +The initial bounding box is simply empty. As a consequence, different +strategies can be used to optimize runtime execution, such as in the previous +code example, where bounding box is always disabled and it is set up at the last +\code{canvas} method call. More often than not, we know the bounding box of the +barcode symbol including quiet zones. + +Every encoding method of \code{gaCanvas} class gives two output result: a +boolean value called \code{ok} plus an error \code{err}. If \code{ok} is +\code{true} then \code{err} is \code{nil} and, viceversa, when \code{ok} is +\code{false} then \code{err} is a string describing the error. + +The error management is a responsability of the caller. For instance, if we +decide to stop the execution this format is perfectly suitable for the Lua +function \code{assert()}, otherwise we can explicity check the output pair: +\begin{Verbatim} +local pt = 65536 +assert(canvas:encode_linewidth(6*pt)) --> true, nil +local ok, err = canvas:encode_hline(nil, 32*pt, 0) +-- ok = false +-- err = "[ArgErr] 'x1' number expected" +\end{Verbatim} + + +\subsubsection{\code{ga} reference} +\label{secGAtabref} + +\noindent +\begin{tabular}{CLlL} +\toprule +\multicolumn{4}{l}{\textbf{Properties of the graphic state}}\\ +OpCode & Mnemonic key & Graphic property & Operands\\ +\midrule + 1 & linewidth & Line width & w \\ + 2 & linecap & Line cap style & e \\ + &&& 0: Butt cap\\ + &&& 1: Round cap\\ + &&& 2: Projecting square cap\\ + 3 & linejoin & Line join style & e \\ + &&& 0: Miter join\\ + &&& 1: Round join\\ + &&& 2: Bevel join\\ + 5 & dash\_pattern & Dash pattern line style & p n [bi ]+\\ + &&& p: phase lenght\\ + &&& n: number of array element\\ + &&& bi: dash array lenght\\ + 6 & reset\_pattern & Set the solid line style & -\\ +\midrule +29 & enable\_bbox & Compute bounding box & -\\ +30 & disable\_bbox & Do not compute bounding box & -\\ +31 & set\_bbox & Overlap current bounding box & x1 y1 x2 y2 \\ +\bottomrule +\end{tabular} + +\bigskip +\noindent +\begin{tabular}{CLlL} +\toprule +\multicolumn{4}{l}{\textbf{Lines}}\\ +OpCode & Mnemonic key & Graphic object & Operands\\ +\midrule +32 & line & Line & x1 y1 x2 y2 \\ +33 & hline & Horizontal line & x1 x2 y \\ +34 & vline & Vertical line & y1 y2 x \\ +\bottomrule +\end{tabular} + +\bigskip +\noindent +\begin{tabular}{CLlL} +\toprule +\multicolumn{4}{l}{\textbf{Group of bars}}\\ +OpCode & Mnemonic key & Graphic object & Operands\\ +\midrule +36 & vbar & Vertical bars & y1 y2 b [xi wi ]+\\ + & & & y1: bottom y-coord\\ + & & & y2: top y-coord\\ + & & & b: number of bars\\ + & & & xi: axis x-coord of bars number i\\ + & & & wi: width of bars number i\\ +37 & hbar & Horizontal bars & x1 x2 b [yi wi ]+\\ + & & & unimplemented\\ +\midrule +38 & polyline & Opened polyline & n [xi yi ]+\\ + & & & n: number of points\\ + & & & xi: x-coord of point i\\ + & & & yi: y-coord of point i\\ +39 & c\_polyline & Closed polyline & n [xi yi ]\\ + & & & unimplemented\\ +\bottomrule +\end{tabular} + +\bigskip +\noindent +\begin{tabular}{CLlL} +\toprule +\multicolumn{4}{l}{\textbf{Rectangles}}\\ +OpCode & Mnemonic key & Graphic object & Operands\\ +\midrule +48 & rect & Rectangle & x1 y1 x2 y2 \\ +49 & f\_rect & Filled rectangle & x1 y1 x2 y2 \\ + &&& unimplemented\\ +50 & rect\_size & Rectangle & x1 y1 w h \\ + &&& unimplemented\\ +51 & f\_rect\_size & Filled rectangle & x1 y1 w h \\ + &&& unimplemented\\ +\bottomrule +\end{tabular} + +\bigskip +\noindent +\begin{tabular}{CLl} +\toprule +\multicolumn{3}{l}{\textbf{Text}}\\ +OpCode & Mnemonic key & Graphic object/Operands\\ +\midrule +130 & text & A text with several glyphs\\ + & & \ttfamily ax ay xpos ypos [c ]+\\ +\midrule +131 & text\_xspaced & A text with glyphs equally spaced on its vertical axis\\ + & & \ttfamily x1 xgap ay ypos [c ]+\\ +\midrule +132 & text\_xwidth & Glyphs equally spaced on vertical axis between two x coordinates\\ + & & \ttfamily ay x1 x2 y c \\ +\midrule +140 & \_text\_group & Texts on the same baseline\\ +& & \ttfamily ay y n [xi ai ci ]+\\ +& & unimplemented\\ +\bottomrule +\end{tabular} + + +\subsection{\code{Vbar} class} + +This section show you how to draw a group of vertical lines, the main component +of every 1D barcode symbol. In the \brcd{} jargon a group of vertical lines is +called \code{Vbar} and is defined by a flat array of pair numbers sequence: the +first one is the x-coordinate of the bar while the second is its width. + +For instance, consider a \code{Vbar} of three bars for which width is a +multiple of the fixed length called \code{mod}, defined by the array and figure +showed below: +\begin{Verbatim} +-- { x1, w1, x2, w2, x3, w3} + {1.5*mod, 3*mod, 5.5*mod, 1*mod, 7.5*mod, 1*mod} +\end{Verbatim} +\directlua{ +local libgeo = barracuda:libgeo() +local Vbar = libgeo.Vbar +local drv = barracuda:get_driver() +local mm = drv.mm +local b = Vbar:from_int(32111, 2*mm) +local canvas = barracuda:new_canvas() +canvas:encode_vbar(b, 0, 0, 25*mm) +drv:ga_to_hbox(canvas, "mybox") +} +\begin{center} +\begin{tikzpicture} +\foreach \i in {0,2,...,16} +\draw[help lines] (\i mm, -2mm) -- (\i mm, 28mm); +\node at (8mm, 12.5mm) {\box\mybox}; +\draw[-{Latex[open]}] (0, 0) -- (20mm, 0); +\draw[-{Latex[open]}] (0, 0) -- (0, 30mm); +\draw[white, dashed] (3mm, 0) -- (3mm, 25mm); +\draw[white, dashed] (11mm, 0) -- (11mm, 25mm); +\draw[white, dashed] (15mm, 0) -- (15mm, 25mm); +\end{tikzpicture} +\end{center} + +For clearness, to the drawing were added a gray vertical grid stepping one +module and white dashed lines at every vbar axis. + +Spaces between bars can be seen as white bars. In fact, an integer number can +represents the sequence of black and white bars with the rule that the single +digit is the width module multiplier. So, the previous \code{Vbar} can be +defined by 32111 with module equals to 2 mm. + +The class \code{Vbar} of module \code{libgeo} has several constructors one of +which is \code{from\_int()}. Its arguments are the multiplier integer +\code{ngen}, the module length \code{mod} and the optional boolean flag +\code{is\_bar}, true if the first bar is black (default to true): +\begin{Verbatim} +b = Vbar:from_int(32111, 2*mm) +\end{Verbatim} + +A \code{Vbar} object has a local axis \( x \) and is unbounded. Constructors +place the axis origin at the left of the first bar. Bars are infinite vertical +straight lines. In order to draw a \code{Vbar} addition information must be +passed to \code{encode\_vbar()} method of the \code{gaCanvas} class: the global +position of the local origin \( x_0 \), and the bottom and top limit \( y_1 \) +\( y_2 \): +\begin{Verbatim} +canvas:encode_vbar(ovbar, x0, y1, y2) +\end{Verbatim} + +The following listing is the complete source code to draw the \code{Vbar} taken +as example in this section: +\begin{Verbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local Vbar = barracuda:libgeo().Vbar + local drv = barracuda:get_driver() + local mm = drv.mm + local b = Vbar:from_int(32111, 2*mm) + local canvas = barracuda:new_canvas() + canvas:encode_vbar(b, 0, 0, 25*mm) + drv:ga_to_hbox(canvas, "mybox") +}\leavevmode\box\mybox +\bye +\end{Verbatim} + + +\subsubsection{\code{Vbar} class arithmetic} + +Can two \code{Vbar} objects be added? Yes, they can! And also with numbers. +Thanks to metamethod and metatable feature of Lua, \code{libgeo} module can +provide arithmetic for \code{Vbar}s. More in detail, to add two \code{Vbar}s +deploy them side by side while to add a number put a distance between the +previous or the next object, depending on the order of addends. + +Anyway, every sum creates or modifies a \code{VbarQueue} object that can be +encoded in a \code{ga} stream with the method \code{encode\_vbar\_queue()}. The +method arguments' are the same needed to encode a \code{Vbar}: an axis position +\( x_0 \) and the two y-coordinates bound \( y_1 \) and \( y_2 \). + +A \code{VbarQueue} code example is the following: +\begin{tcolorbox} +\begin{BVerbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local Vbar = barracuda:libgeo().Vbar + local canvas = barracuda:new_canvas() + local mm = canvas.mm + local mod = 2 * mm + local queue = Vbar:from_int(32111, mod) + for _, ngen in ipairs {131, 21312, 11412} do + queue = queue + mod + Vbar:from_int(ngen, mod) + end + canvas:encode_vbar_queue(queue, 0, 0, 25*mm) + canvas:ga_to_hbox "mybox" +}\leavevmode\box\mybox +\bye +\end{BVerbatim} +\tcblower +\directlua{ + local Vbar = barracuda:libgeo().Vbar + local canvas = barracuda:new_canvas() + local mm = canvas.mm + local mod = 2 * mm + local queue = Vbar:from_int(32111, mod) + for _, ngen in ipairs {131, 21312, 11412} do + queue = queue + mod + Vbar:from_int(ngen, mod) + end + canvas:encode_vbar_queue(queue, 0, 0, 25*mm) + canvas:ga_to_hbox "mybox" +} +\hfill +\begin{tikzpicture} +\fill[orange!50!white] (16mm, -3mm) rectangle (18mm, 28mm); % +\fill[orange!50!white] (28mm, -3mm) rectangle (30mm, 28mm); % +\fill[orange!50!white] (48mm, -3mm) rectangle (50mm, 28mm); % +\foreach \i in {0,2,...,68} +\draw[help lines] (\i mm, -3mm) -- (\i mm, 28mm); +\node at (34mm, 12.5mm) {\box\mybox}; +\end{tikzpicture} +\hfill\hbox{} + +\footnote{Respect to the showed code some graphical helps has been added: a +vertical grid marks the module wide steps and light colored bars mark the +space added between two \code{Vbar}s.} +\end{tcolorbox} + +\subsection{\code{ga} programming} + +To provide a better learning experience several \code{ga} stream examples is +discussed, each of which must be compiled with Lua\TeX{}. + +\subsubsection{Example 1: a rectangle} + +Suppose we want to draw a simple rectangle. In the \code{ga} reference of +section~\ref{secGAtabref} there is a dedicated instruction \code{}. +Let's give it a try: + +\begin{tcolorbox}[ + title={Example 1: dealing with raw \code{ga} stream}, + sidebyside, +] +\begin{BVerbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local pt = 65536 + local ga = {48, 0, 0, 72*pt, 36*pt} + local drv = barracuda:get_driver() + drv:ga_to_hbox(ga, "mybox") +}\leavevmode\box\mybox +\bye +\end{BVerbatim} +\tcblower +\directlua{ + local pt = 65536 + local side = 36*pt + local ga = {48, 0, 0, 2*side, side} + local drv = barracuda:get_driver() + drv:ga_to_hbox(ga, "mybox") +}\box\mybox +\end{tcolorbox} + +Dealing with low level \code{ga} stream is not necessary. We can use more safely +a \code{gaCanvas} object running its \code{encode\_rect()} method: +\begin{Verbatim} +... +local canvas = barracuda:new_canvas() +assert(canvas:encode_rect(0, 0, 2*side, side)) +assert(canvas:ga_to_hbox("mybox")) +... +\end{Verbatim} + + +\subsubsection{Example 2: a chessboard} + +A more complex drawing is a chessboard. Let's begin to draw a single cell with a +square 1cm wide: +\begin{Verbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local canvas = barracuda:new_canvas() + local mm = canvas.mm + local s, t = 7.5*mm, 1.5*mm + canvas:encode_linewidth(t) + assert(canvas:encode_rect(t/2, t/2, s-t/2, s-t/2)) + assert(canvas:ga_to_hbox("mybox")) +}\leavevmode\box\mybox +\bye +\end{Verbatim} + +Then repeat the game for the entire grid: +\begin{tcolorbox} +\begin{BVerbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local canvas = barracuda:new_canvas() + local mm = canvas.mm + local s, t = 6*mm, 1*mm + assert(canvas:encode_linewidth(t)) + for row = 1, 5 do + for col = 1, 5 do + local l = (row + col)/2 + if l == math.floor(l) then + local x = (col - 1)*s + local y = (row - 1)*s + local x1, y1 = x + t/2, y + t/2 + local x2, y2 = x + s - t/2, y + s - t/2 + assert(canvas:encode_rect(x1, y1, x2, y2)) + end + end + end + drv:ga_to_hbox(canvas, "mybox") +}\leavevmode\box\mybox +\bye +\end{BVerbatim} +\vspace*{-10pt} +\tcblower +\directlua{ + local barracuda = require "barracuda" + local canvas = barracuda:new_canvas() + local mm = canvas.mm + local s, t = 6*mm, 1*mm + assert(canvas:encode_linewidth(t)) + for row = 1, 5 do + for col = 1, 5 do + local l = (row + col)/2 + if l == math.floor(l) then + local x = (col - 1)*s + local y = (row - 1)*s + local x1, y1 = x + t/2, y + t/2 + local x2, y2 = x + s - t/2, y + s - t/2 + assert(canvas:encode_rect(x1, y1, x2, y2)) + end + end + end + canvas:ga_to_hbox("mybox") +}\hfill\box\mybox\hfill\hbox{} +\end{tcolorbox} + +\subsubsection{Example 3: a staircase} + +A drawing of a zig zag staircase can be represented by a \code{ga} stream with +a \code{} operation. The \code{gaCanvas} method we have to call is +\code{encode\_polyline()} that accept a Lua table as a flat structure with the +coordinates of every point of the polyline: +\begin{BVerbatim} +{x1, y1, x2, y2, ..., xn, yn} +\end{BVerbatim} + +It is what we do with this code: +\begin{tcolorbox} +\begin{BVerbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local pt = 65536 + local side = 16*pt + local dim = 5 + local x, y = 0, 0 + local point = {x, y} + local i = 3 + for _ = 1, dim do + y = y + side + point[i] = x; i = i + 1 + point[i] = y; i = i + 1 + x = x + side + point[i] = x; i = i + 1 + point[i] = y; i = i + 1 + end + local canvas = barracuda:new_canvas() + canvas:encode_linewidth(2.25*pt) + canvas:encode_polyline(point) + canvas:ga_to_hbox("mybox") +}\leavevmode\box\mybox +\bye +\end{BVerbatim} +\vspace*{-10pt} +\tcblower +\directlua{ + local pt = 65536 + local side = 16*pt + local dim = 5 + local x, y = 0, 0 + local point = {x, y} + local i = 3 + for _ = 1, dim do + y = y + side + point[i] = x; i = i + 1 + point[i] = y; i = i + 1 + x = x + side + point[i] = x; i = i + 1 + point[i] = y; i = i + 1 + end + local canvas = barracuda:new_canvas() + canvas:encode_linewidth(2.25*pt) + canvas:encode_polyline(point) + canvas:ga_to_hbox("mybox") +}\hfill\box\mybox\hfill\hbox{} +\end{tcolorbox} + +A feature of \code{encode\_()} methods is their \emph{polymorphic} +behavior for their first argument. They accept different types as an object +of a geometric class or the raw geometric data. + +Method \code{encode\_polyline} is not an exception: it accepts a \code{Polyline} +object provided by the \code{libgeo} module, or instead a flat array of +coordinates. For instance the previous code may be re-implement as: +\begin{Verbatim} +% !TeX program = LuaTeX +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + local pt = 65536 + local side = 18*pt + local dim = 5 + local Polyline = barracuda:libgeo().Polyline + local pl = Polyline:new(0, 0) + for _ = 1, dim do + pl:add_relpoint(0, side) + pl:add_relpoint(side, 0) + end + local canvas = barracuda:new_canvas() + canvas:encode_linewidth(2.5*pt) + canvas:encode_polyline(pl) + canvas:ga_to_hbox("mybox") +}\leavevmode\box\mybox +\bye +\end{Verbatim} + +Pretty sure that this new version is more clear and intuitive. + + +%\subsubsection{Example 4: } + +% A polyline that represents a path of ... Hilbert curve +% Text pyramid + + +\section{Practical examples and use cases} +\label{secExample} + +Previous sections as shown how \brcd{} is capable to draw simple graphics. This +section is dedicated to barcode applications. + + + +\end{document} diff --git a/macros/luatex/generic/barracuda/doc/manual/image/8006194056290.pdf b/macros/luatex/generic/barracuda/doc/manual/image/8006194056290.pdf new file mode 100644 index 0000000000..8effe87846 Binary files /dev/null and b/macros/luatex/generic/barracuda/doc/manual/image/8006194056290.pdf differ diff --git a/macros/luatex/generic/barracuda/src/barracuda.lua b/macros/luatex/generic/barracuda/src/barracuda.lua index d8eae35216..c854941d27 100644 --- a/macros/luatex/generic/barracuda/src/barracuda.lua +++ b/macros/luatex/generic/barracuda/src/barracuda.lua @@ -2,7 +2,7 @@ -- -- Encode a message into a barcode symbol, in Lua or within a LuaTeX source file -- --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 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 @@ -26,26 +26,36 @@ local Barracuda = { _NAME = "barracuda", - _VERSION = "barracuda v0.0.10", - _DATE = "2020-02-04", + _VERSION = "barracuda v0.0.12", + _DATE = "2022-06-23", _DESCRIPTION = "Lua library for barcode printing", _URL = "https://github.com/robitex/barracuda", _LICENSE = "GNU GENERAL PUBLIC LICENSE, Version 2, June 1991", } -- essential sub-module loading -Barracuda._libgeo = require "lib-geo.brcd-libgeo" -- basic vectorial objects +Barracuda._libgeo = require "lib-geo.brcd-libgeo" -- basic vector objects Barracuda._gacanvas = require "lib-geo.brcd-gacanvas" -- ga stream library Barracuda._barcode = require "lib-barcode.brcd-barcode" -- barcode abstract class +Barracuda._lib_driver = require "lib-driver.brcd-driver" -- abstract driver class local Barcode = Barracuda._barcode Barcode._libgeo = Barracuda._libgeo +-- a reference to Driver class for gaCancas class +local canvas = Barracuda._gacanvas +canvas._driver_class = Barracuda._lib_driver + -- return a reference of Barcode abstract class -function Barracuda:barcode() --> Barcode class object +function Barracuda:barcode() --> return self._barcode end +-- return a reference to the libgeo library +function Barracuda:libgeo() --> + return self._libgeo +end + -- encoder costructor (a bridge to Barcode class method) function Barracuda:new_encoder(treename, opt) --> object, err local barcode = self._barcode @@ -55,19 +65,15 @@ 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 return self._lib_driver end -function Barracuda:new_canvas() --> driver +function Barracuda:new_canvas() --> canvas local gacanvas = self._gacanvas return gacanvas:new() end -- high level barcode functions --- only default options -- panic on error -- save barcode as a graphic external file @@ -104,7 +110,7 @@ function Barracuda:save(treename, data, filename, id_drv, opt) assert(ok, err) end local canvas = self:new_canvas() - symb:append_ga(canvas) + symb:draw(canvas) local driver = self:get_driver() id_drv = id_drv or "svg" local ok, err = driver:save(id_drv, canvas, filename) @@ -144,7 +150,7 @@ function Barracuda:hbox(treename, data, box_name, opt) assert(ok, err) end local canvas = self:new_canvas() - symb:append_ga(canvas) + symb:draw(canvas) local driver = self:get_driver() local ok, err = driver:ga_to_hbox(canvas, box_name) assert(ok, err) diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua index b43bc511d7..1208adeb75 100644 --- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua +++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-barcode.lua @@ -1,13 +1,8 @@ - -- Barcode Abstract Class --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli -- Please see LICENSE.TXT for any legal information about present software -local Barcode = { - _VERSION = "Barcode v0.0.9", - _NAME = "Barcode", - _DESCRIPTION = "Barcode abstract class", -} +local Barcode = {_classname = "Barcode"} Barcode.__index = Barcode -- barcode_type/submodule name @@ -16,6 +11,7 @@ Barcode._available_enc = {-- keys must be lowercase code128 = "lib-barcode.brcd-code128", -- Code128 ean = "lib-barcode.brcd-ean", -- EAN family (ISBN, EAN8, etc) i2of5 = "lib-barcode.brcd-i2of5", -- Interleaved 2 of 5 + upc = "lib-barcode.brcd-upc", -- UPC } Barcode._builder_instances = {} -- encoder builder instances repository Barcode._encoder_instances = {} -- encoder instances repository @@ -24,6 +20,7 @@ Barcode._encoder_instances = {} -- encoder instances repository Barcode._super_par_order = { "ax", "ay", + "debug_bbox", } Barcode._super_par_def = {} local pardef = Barcode._super_par_def @@ -36,7 +33,7 @@ pardef.ax = { default = 0.0, unit = "sp", -- scaled point isReserved = false, - fncheck = function (self, ax, _) --> boolean, err + 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" end, @@ -46,13 +43,34 @@ pardef.ay = { default = 0.0, unit = "sp", -- scaled point isReserved = false, - fncheck = function (self, ay, _) --> boolean, err + 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" end, } --- Barcode.bbox_to_quietzone -- under assessment +-- debug only purpose +-- enable/disable bounding box drawing of symbols +Barcode.debug_bbox = "none" +pardef.debug_bbox = { + default = "none", + isReserved = false, + enum = { + none = true, -- do nothing + symb = true, -- draw bbox of the symbol + qz = true, -- draw a bbox at quietzone border + qzsymb = true, -- draw quietzone and symbol bboxes + }, + fncheck = function (self, e, _) --> boolean, err + if type(e) ~= "string" then return false, "[TypeError] not a string" end + local keys = self.enum + if keys[e] == true then + return true, nil + else + return false, "[Err] enumeration value '"..e.."' not found" + end + end, +} -- Barcode methods @@ -221,7 +239,7 @@ function Barcode:new_encoder(treename, opt) --> object, err -- argument checking local family, variant, enc_name, err = parse_treename(treename) if err then - return err + return nil, err end local av_enc = self._available_enc local mod_path = av_enc[family] @@ -254,7 +272,7 @@ function Barcode:new_encoder(treename, opt) --> object, err else return nil, "[ArgErr] provided 'opt' is not a table" end - local enc = {} -- the new encoder + local enc = {_classname = "Encoder"} -- the new encoder enc.__index = enc enc._variant = variant setmetatable(enc, { @@ -292,13 +310,14 @@ function Barcode:new_encoder(treename, opt) --> object, err end end if enc._config then -- this must be called after the parameter definition - enc:_config() + local ok, e = enc:_config() + if not ok then return nil, e end end return enc, nil end -- retrive an encoder object already created --- 'trename' is the special identifier of the encoder +-- 'treename' is the special identifier of the encoder function Barcode:enc_by_name(treename) --> , -- argument checking local _family, _variant, _enc_name, err = parse_treename(treename) @@ -316,25 +335,36 @@ end -- base methods common to all the encoders -- for numeric only simbology -function Barcode:_check_char(c) --> elem, err +-- elem_code : encoded char +-- elem_text : human readable char +-- err : error description +function Barcode:_check_char(c, parse_state) --> elem_code, elem_text, err if type(c) ~= "string" or #c ~= 1 then - return nil, "[InternalErr] invalid char" + return nil, nil, "[InternalErr] invalid char" + end + local process_char = self._process_char + if process_char then + return process_char(self, c, parse_state) end local n = string.byte(c) - 48 if n < 0 or n > 9 then - return nil, "[ArgErr] found a not digit char" + return nil, nil, "[ArgErr] found a not digit char" end - return n, nil + return n, nil, nil end -- -function Barcode:_check_digit(n) --> elem, err +function Barcode:_check_digit(n, parse_state) --> elem_code, elem_text, err if type(n) ~= "number" then - return nil, "[ArgErr] not a number" + return nil, nil, "[ArgErr: n] not a number" + end + local process_digit = self._process_digit + if process_digit then + return process_digit(self, n, parse_state) end if n < 0 or n > 9 then - return nil, "[ArgErr] not a digit" + return nil, nil, "[ArgErr: n] not a digit" end - return n, nil + return n, nil, nil end -- not empty string --> Barcode object @@ -345,22 +375,33 @@ function Barcode:from_string(symb, opt) --> object, err if #symb == 0 then return nil, "[ArgErr] 'symb' is an empty string" end - local chars = {} - local len = 0 - local parse_state = {} + local chars_code = {} + local chars_text + local parse_state + if self._init_parse_state then + parse_state = self:_init_parse_state() + else + parse_state = {} + end for c in string.gmatch(symb, ".") do - local elem, err = self:_check_char(c, parse_state) + local elem_code, elem_text, err = self:_check_char(c, parse_state) if err then return nil, err - elseif elem then - chars[#chars+1] = elem - len = len + 1 + else + if elem_code then + chars_code[#chars_code + 1] = elem_code + end + if elem_text then + chars_text = chars_text or {} + chars_text[#chars_text + 1] = elem_text + end end end -- build the barcode object local o = { - _code_data = chars, -- array of chars - _code_len = len, -- symbol lenght + _classname = "BarcodeSymbol", + _code_data = chars_code, -- array of chars + _code_text = chars_text, } setmetatable(o, self) if opt ~= nil then @@ -394,42 +435,58 @@ function Barcode:from_uint(n, opt) --> object, err if opt ~= nil and type(opt) ~= "table" then return nil, "[ArgErr] 'opt' is not a table" end - local digits = {} - local parse_state = {} - local i = 0 + local digits_code = {} + local digits_text + local parse_state + if self._init_parse_state then + parse_state = self:_init_parse_state() + else + parse_state = {} + end if n == 0 then - local elem, err = self:_check_digit(0, parse_state) + local elem_code, elem_text, err = self:_check_digit(0, parse_state) if err then return nil, err end - if elem then - digits[1] = elem - i = 1 + if elem_code then + digits_code[1] = elem_code + end + if elem_text then + digits_text = {elem_text} end else while n > 0 do local d = n % 10 - local elem, err = self:_check_digit(d, parse_state) + local elem_code, elem_text, err = self:_check_digit(d, parse_state) if err then return nil, err end - if elem then - i = i + 1 - digits[i] = elem + if elem_code then + digits_code[#digits_code + 1] = elem_code + end + if elem_text then + digits_text = digits_text or {} + digits_text[#digits_text + 1] = elem_text end n = (n - d) / 10 end - for k = 1, i/2 do -- reverse the array - local d = digits[k] - local h = i - k + 1 - digits[k] = digits[h] - digits[h] = d + local rev_array = function (a) + local len = #a + for k = 1, len/2 do -- reverse the array + local h = len - k + 1 + a[k], a[h] = a[h], a[k] + end + end + rev_array(digits_code) + if digits_text then + rev_array(digits_text) end end -- build the barcode object local o = { - _code_data = digits, -- array of digits - _code_len = i, -- symbol lenght + _classname = "BarcodeSymbol", + _code_data = digits_code, -- array of digits + _code_text = digits_text, -- array of human readable information } setmetatable(o, self) if opt ~= nil then @@ -449,6 +506,26 @@ function Barcode:from_uint(n, opt) --> object, err return o, nil end +-- recursive general Barcode costructor +function Barcode:new(code) --> object, err + local t = type(code) + if t == "string" then + return self:from_string(code) + elseif t == "number" then + return self:from_uint(code) + elseif t == "table" then + local res = {} + for _, c in ipairs(code) do + local b, err = self:new(c) + if err then return nil, err end + res[#res + 1] = b + end + return res, nil + else + return nil, "[ArgErr] unsuitable type '"..t.."' for the input code" + end +end + -- check a parameter set -- this method check also reserved parameter -- argments: {k=v, ...}, "default" | "current" @@ -532,13 +609,13 @@ function Barcode:info() --> table description = self._DESCRIPTION, param = {}, } - local tpar = info.param + local tpar = info.param for _, pdef in self:param_ord_iter() do - local id = pdef.pname + local id = pdef.pname local def = pdef.pdef tpar[#tpar + 1] = { name = id, - descr = nil, -- TODO: + descr = def.descr, value = self[id], isReserved = def.isReserved, unit = def.unit, @@ -547,12 +624,32 @@ function Barcode:info() --> table 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) +-- return internal code representation +function Barcode:get_code() --> array + if self._classname == "BarcodeSymbol" then + local code = self._code_data + local res = {} + for _, c in ipairs(code) do + res[#res + 1] = c + end + return res + else + error("[Err: OOP] 'BarcodeSymbol' only method") + end +end + +-- human readable interpretation hri or nil +function Barcode:get_hri() --> array|nil + if self._classname == "BarcodeSymbol" then + local code = self._code_text + if code == nil then return nil end + local res = {} + for _, c in ipairs(code) do + res[#res + 1] = c + end + return res + else + error("[Err: OOP] 'BarcodeSymbol' only method") end end @@ -562,8 +659,8 @@ function Barcode:get_param(id) --> value, err if type(id) ~= "string" then return nil, "[ArgErr] 'id' must be a string" end - local pardef = self._par_def - if not pardef[id] then + local par_def = self._par_def + if not par_def[id] then return nil, "[Err] Parameter '"..id.."' doesn't exist" end local res = assert(self[id], "[InternalErr] parameter value unreachable") @@ -622,6 +719,76 @@ function Barcode:set_param(arg1, arg2) --> boolean, err return true, nil end +-- canvas is a gaCanvas object +-- tx, ty is an optional point to place symbol local origin on the canvas plane +function Barcode:draw(canvas, tx, ty) --> canvas, err + local nclass = self._classname + if nclass == "Barcode" then + error("[ErrOOP:Barcode] method 'draw' must be called only on a Symbol object") + end + if nclass == "Encoder" then + error("[ErrOOP:Encoder] method 'draw' must be called only on a Symbol object") + end + assert(nclass == "BarcodeSymbol") + if canvas._classname ~= "gaCanvas" then + return nil, "[ErrOOP:canvas] object 'gaCanvas' expected" + end + local ga_fn = assert( + self._append_ga, + "[InternalErr] unimplemented '_append_ga' method" + ) + local bb_info = ga_fn(self, canvas, tx or 0, ty or 0) + local dbg_bbox = self.debug_bbox + if dbg_bbox == "none" then + -- do nothing + else + -- dashed style: phase = 3bp, dash pattern = 6bp 3bp + local bp = canvas.bp + local W = bp/10 -- 0.1bp + local w = W/2 + assert(canvas:encode_linewidth(W)) + assert(canvas:encode_dash_pattern(3*bp, 6*bp, 3*bp)) + local x1, y1, x2, y2 = bb_info[1], bb_info[2], bb_info[3], bb_info[4] + if dbg_bbox == "symb" then + assert(canvas:encode_rect(x1 + w, y1 + w, x2 - w, y2 - w)) + elseif dbg_bbox == "qz" then + local q1, q2, q3, q4 = bb_info[5], bb_info[6], bb_info[7], bb_info[8] + x1 = x1 - (q1 or 0) + w + y1 = y1 - (q2 or 0) + w + x2 = x2 + (q3 or 0) - w + y2 = y2 + (q4 or 0) - w + assert(canvas:encode_rect(x1, y1, x2, y2)) + elseif dbg_bbox == "qzsymb" then + local q1, q2, q3, q4 = bb_info[5], bb_info[6], bb_info[7], bb_info[8] + x1 = x1 + w + y1 = y1 + w + x2 = x2 - w + y2 = y2 - w + if q1 then + assert(canvas:encode_vline(y1, y2, x1)) + x1 = x1 - q1 + end + if q3 then + assert(canvas:encode_vline(y1, y2, x2)) + x2 = x2 + q3 + end + if q2 then + assert(canvas:encode_hline(x1, x2, y1)) + y1 = y1 - q2 + end + if q4 then + assert(canvas:encode_hline(x1, x2, y2)) + y2 = y2 + q4 + end + assert(canvas:encode_rect(x1, y1, x2, y2)) + else + error("[InternalErr:debug_bbox] unrecognized enum value") + end + assert(canvas:encode_reset_pattern()) + end + return canvas +end + return Barcode -- 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 diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua index 6d7f2ccea7..0768912987 100644 --- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua +++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-code39.lua @@ -1,31 +1,27 @@ -- Code39 barcode encoder implementation --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli -- -- All dimensions must be in scaled point (sp) --- every fields that starts with an undercore sign are intended as private +-- every field that starts with an underscore sign are intended to be private local Code39 = { - _VERSION = "code39 v0.0.5", + _VERSION = "code39 v0.0.6", _NAME = "Code39", _DESCRIPTION = "Code39 barcode encoder", } Code39._symb_def = {-- symbol definition - ["0"] = 112122111, ["1"] = 211112112, ["2"] = 211112211, - ["3"] = 111112212, ["4"] = 211122111, ["5"] = 111122112, - ["6"] = 111122211, ["7"] = 212112111, ["8"] = 112112112, - ["9"] = 112112211, ["A"] = 211211112, ["B"] = 211211211, - ["C"] = 111211212, ["D"] = 211221111, ["E"] = 111221112, - ["F"] = 111221211, ["G"] = 212211111, ["H"] = 112211112, - ["I"] = 112211211, ["J"] = 112221111, ["K"] = 221111112, - ["L"] = 221111211, ["M"] = 121111212, ["N"] = 221121111, - ["O"] = 121121112, ["P"] = 121121211, ["Q"] = 222111111, - ["R"] = 122111112, ["S"] = 122111211, ["T"] = 122121111, - ["U"] = 211111122, ["V"] = 211111221, ["W"] = 111111222, - ["X"] = 211121121, ["Y"] = 111121122, ["Z"] = 111121221, - ["-"] = 212111121, ["."] = 112111122, [" "] = 112111221, - ["$"] = 111212121, ["/"] = 121112121, ["+"] = 121211121, - ["%"] = 121212111, + ["0"] = 112122111, ["1"] = 211112112, ["2"] = 211112211, ["3"] = 111112212, + ["4"] = 211122111, ["5"] = 111122112, ["6"] = 111122211, ["7"] = 212112111, + ["8"] = 112112112, ["9"] = 112112211, ["A"] = 211211112, ["B"] = 211211211, + ["C"] = 111211212, ["D"] = 211221111, ["E"] = 111221112, ["F"] = 111221211, + ["G"] = 212211111, ["H"] = 112211112, ["I"] = 112211211, ["J"] = 112221111, + ["K"] = 221111112, ["L"] = 221111211, ["M"] = 121111212, ["N"] = 221121111, + ["O"] = 121121112, ["P"] = 121121211, ["Q"] = 222111111, ["R"] = 122111112, + ["S"] = 122111211, ["T"] = 122121111, ["U"] = 211111122, ["V"] = 211111221, + ["W"] = 111111222, ["X"] = 211121121, ["Y"] = 111121122, ["Z"] = 111121221, + ["-"] = 212111121, ["."] = 112111122, [" "] = 112111221, ["$"] = 111212121, + ["/"] = 121112121, ["+"] = 121211121, ["%"] = 121212111, } Code39._star_def = 112121121 -- '*' start/stop character @@ -54,7 +50,7 @@ pardef.module = { -- with label or form design. -- The module width (width of narrow element) should be at least 7.5 mils -- or 0.1905mm (a mil is 1/1000 inch). - default = 7.5 * 0.0254 * 186467, -- 7.5 mils (sp) unit misure, + default = 10 * 0.0254 * 186467, -- 7.5 mils (sp) unit misure, unit = "sp", -- scaled point isReserved = true, fncheck = function (self, mod, _) --> boolean, err @@ -230,98 +226,83 @@ pardef.text_star = { -- configuration function function Code39:_config() --> ok, err + local Vbar = self._libgeo.Vbar -- Vbar class + local Archive = self._libgeo.Archive -- Archive class + local c39_vbars = Archive:new() + self._vbar_archive = c39_vbars -- build Vbar object for the start/stop symbol local mod, ratio = self.module, self.ratio local n_star = self._star_def - local Vbar = self._libgeo.Vbar -- Vbar class - self._vbar = {['*'] = Vbar:from_int_revpair(n_star, mod, mod*ratio)} + local star = Vbar:from_int_revpair(n_star, mod, mod*ratio) + c39_vbars:insert(star, "*") return true, nil end --- overriding Barcode method -function Code39:_check_char(c) --> elem, err - if type(c) ~= "string" or #c ~= 1 then - return nil, "[ArgErr] invalid char" - end - local symb_def = self._symb_def - local n = symb_def[c] - if not n then - local fmt = "[ArgErr] '%s' is not a valid Code 39 symbol" - return nil, string.format(fmt, c) +function Code39:_ensure_symbol(c) + local Archive = self._vbar_archive + if not Archive:contains_key(c) then + local Vbar = self._libgeo.Vbar + local mod, ratio = self.module, self.ratio + local symb_def = self._symb_def + local n_def = symb_def[c] + local v = Vbar:from_int_revpair(n_def, mod, mod*ratio) + Archive:insert(v, c) end - return c, nil end -- overriding Barcode method -function Code39:_check_digit(n) --> elem, err - if type(n) ~= "number" then - return nil, "[ArgErr] not a number" - end - if n < 0 or n > 9 then - return nil, "[ArgErr] not a digit" +function Code39:_process_char(c) --> elem_code, elem_text, err + local symb_def = self._symb_def + if not symb_def[c] then + local fmt = "[ArgErr] '%s' is not a valid Code 39 symbol" + return nil, nil, string.format(fmt, c) end - return string.char(n + 48), nil + self:_ensure_symbol(c) + return c, nil, nil end -function Code39:_finalize() --> ok, err - local v = assert(self._code_data, "[InternalErr] '_code_data' field is nil") - local vbar = self._vbar - local g_Vbar = self._libgeo.Vbar - local mod, ratio = self.module, self.ratio - local symb_def = self._symb_def - for _, c in ipairs(v) do - if not vbar[c] then - local n1 = symb_def[c] - vbar[c] = g_Vbar:from_int_revpair(n1, mod, mod*ratio) - end - end - return true, nil +-- overriding Barcode method +function Code39:_process_digit(n) --> elem_code, elem_text, err + local c = string.char(n + 48) + self:_ensure_symbol(c) + return c, nil, nil end -- tx, ty is an optional translator vector -function Code39:append_ga(canvas, tx, ty) --> canvas - local code = self._code_data - local ns = self._code_len -- number of chars inside the symbol - local mod = self.module - local ratio = self.ratio - local interspace = self.interspace - local h = self.height - local xs = mod*(6 + 3*ratio) - local xgap = xs + interspace - local w = xgap*(ns + 1) + xs -- (ns + 2)*xgap - interspace - local ax, ay = self.ax, self.ay - local x0 = (tx or 0) - ax * w - local y0 = (ty or 0) - ay * h - local x1 = x0 + w - local y1 = y0 + h - local xpos = x0 - local err - err = canvas:start_bbox_group() - assert(not err, err) - local vbar = self._vbar - -- start/stop symbol - local term_vbar = vbar['*'] - -- draw start symbol - err = canvas:encode_Vbar(term_vbar, xpos, y0, y1) - assert(not err, err) - for _, c in ipairs(code) do -- draw code symbols - xpos = xpos + xgap - local vb = vbar[c] - err = canvas:encode_Vbar(vb, xpos, y0, y1) - assert(not err, err) +function Code39:_append_ga(canvas, tx, ty) --> x1, y1, x2, y2 -- bbox + local code = self._code_data + local ns = #code -- number of chars inside the symbol + local archive = self._vbar_archive + local q = assert(archive:get("*")) -- form the vbar queue, actually it is just a Vbar + local dx = self.interspace + for _, c in ipairs(code) do + q = q + dx + assert(archive:get(c)) end - -- draw stop symbol - err = canvas:encode_Vbar(term_vbar, xpos + xgap, y0, y1) - assert(not err, err) + q = q + dx + assert(archive:get("*")) -- final stop char + assert(canvas:encode_disable_bbox()) + -- draw the symbol + local ax, ay = self.ax, self.ay + local mod = self.module + local ratio = self.ratio + local xs = mod*(6 + 3*ratio) + local xgap = xs + dx + local h = self.height + local w = xgap*(ns + 1) + xs -- (ns + 2)*xgap - interspace + -- + local x0 = tx - ax * w + local x1 = x0 + w + local y0 = ty - ay * h + local y1 = y0 + h + assert(canvas:encode_vbar_queue(q, x0, y0, y1)) -- bounding box setting local qz = self.quietzone - err = canvas:stop_bbox_group(x0 - qz, y0, x1 + qz, y1) - assert(not err, err) + assert(canvas:encode_set_bbox(x0 - qz, y0, x1 + qz, y1)) -- check height as the minimum of 15% of length -- TODO: message could warn the user -- if 0.15 * w > h then -- message("The height of the barcode is to small") -- end + assert(canvas:encode_enable_bbox()) if self.text_enabled then -- human readable text local chars; if self.text_star then chars = {"*"} @@ -356,8 +337,7 @@ function Code39:append_ga(canvas, tx, ty) --> canvas xaxis = xaxis + xgap end xaxis = xaxis + xs/2 - err = canvas:encode_Text_xspaced(txt, xaxis, xgap, ypos, tay) - assert(not err, err) + assert(canvas:encode_Text_xspaced(txt, xaxis, xgap, ypos, tay)) else local xpos, tax if txt_hpos == "left" then @@ -372,12 +352,10 @@ function Code39:append_ga(canvas, tx, ty) --> canvas else error("[InternalErr] wrong option for text_pos") end - err = canvas:encode_Text(txt, xpos, ypos, tax, tay) - assert(not err, err) + assert(canvas:encode_Text(txt, xpos, ypos, tax, tay)) end end - return canvas + return {x0, y0, x1, y1, qz, nil, qz, nil} end return Code39 --- \ No newline at end of file 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 bddaa36103..d7f7733f3a 100644 --- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua +++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-ean.lua @@ -1,10 +1,10 @@ -- EAN family barcode generator -- --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli -- see LICENSE.txt file local EAN = { - _VERSION = "ean v0.0.6", + _VERSION = "ean v0.0.8", _NAME = "ean", _DESCRIPTION = "EAN barcode encoder", } @@ -75,6 +75,7 @@ EAN._par_order = { "text_enabled", "text_ygap_factor", "text_xgap_factor", + "text_guard_enabled", } EAN._par_def = {} local pardef = EAN._par_def @@ -148,7 +149,7 @@ pardef.bars_depth_factor = { end, } --- enable/disable a text label upon the barcode symbol +-- enable/disable human readble text pardef.text_enabled = { -- boolean type default = true, isReserved = false, @@ -187,6 +188,30 @@ pardef.text_xgap_factor = { end, } +pardef.text_guard_enabled = { -- boolean type + default = false, + 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_guard_enabled" + end + end, +} + +EAN._par_def_8 = {} -- ean8 substitute parameters +local pardef8 = EAN._par_def_8 +pardef8.quietzone_left_factor = pardef.quietzone_right_factor + +EAN._par_def_5 = {} -- ean5 add-on substitute parameters +local pardef5 = EAN._par_def_5 +pardef5.quietzone_left_factor = pardef.quietzone_right_factor + +EAN._par_def_2 = {} -- ean2 add-on substitute parameters +local pardef2 = EAN._par_def_2 +pardef2.quietzone_left_factor = pardef.quietzone_right_factor + -- variant parameters EAN._par_variant_order = { ["13"] = {}, -- EAN13 @@ -337,101 +362,103 @@ par_def_var["issn"].text_issn_ygap_factor = text_ygap_factor -- utility for generic configuration of full symbol, add-on included -- n1 length of main symbol, 8 or 13 -- n2 length of add-on symbol, 2 or 5 -local function config_full(ean, Vbar, mod, n1, n2) +local function config_full(ean, n1, n2) local i1 = tostring(n1) local fn_1 = assert(ean._config_variant[i1]) - fn_1(ean, Vbar, mod) + fn_1(ean) local i2 = tostring(n2) local fn_2 = assert(ean._config_variant[i2]) - fn_2(ean, Vbar, mod) + fn_2(ean) ean._main_len = n1 ean._addon_len = n2 ean._is_last_checksum = true end local config_variant = { - ["13"] = function (ean13, Vbar, mod) + ["13"] = function (ean13) ean13._main_len = 13 ean13._is_last_checksum = true - local start = ean13._start + local Vbar = ean13._libgeo.Vbar -- Vbar class + local Vbar_archive = ean13._libgeo.Archive -- Archive class + local Codeset = Vbar_archive:new() + ean13._13_codeset_vbar = Codeset + local mod = ean13.mod local stop = ean13._stop - ean13._13_start_stop_vbar = Vbar:from_int(start[1], mod, start[2]) - ean13._13_ctrl_center_vbar = Vbar:from_int(stop[1], mod, stop[2]) - ean13._13_codeset_vbar = {} - local tvbar = ean13._13_codeset_vbar + local start = ean13._start + Codeset:insert(Vbar:from_int(start[1], mod, start[2]), "start_stop") + Codeset:insert(Vbar:from_int(stop[1], mod, stop[2]), "central") for i_cs, codetab in ipairs(ean13._symbol) do - tvbar[i_cs] = {} - local tv = tvbar[i_cs] local isbar = ean13._is_first_bar[i_cs] for i = 0, 9 do - tv[i] = Vbar:from_int(codetab[i], mod, isbar) + Codeset:insert(Vbar:from_int(codetab[i], mod, isbar), i_cs, i) end end end, - ["8"] = function (ean8, Vbar, mod) + ["8"] = function (ean8) ean8._main_len = 8 ean8._is_last_checksum = true + local Vbar = ean8._libgeo.Vbar + local Vbar_archive = ean8._libgeo.Archive local start = ean8._start local stop = ean8._stop - ean8._8_start_stop_vbar = Vbar:from_int(start[1], mod, start[2]) - ean8._8_ctrl_center_vbar = Vbar:from_int(stop[1], mod, stop[2]) - ean8._8_codeset_vbar = {} - local tvbar = ean8._8_codeset_vbar + local mod = ean8.mod + local Codeset = Vbar_archive:new() + ean8._8_codeset_vbar = Codeset + Codeset:insert(Vbar:from_int(start[1], mod, start[2]), "start_stop") + Codeset:insert(Vbar:from_int(stop[1], mod, stop[2]), "central") for k = 1, 3, 2 do -- only codeset A and C (k == 1, 3) - tvbar[k] = {} local codetab = ean8._symbol[k] local isbar = ean8._is_first_bar[k] - local tv = tvbar[k] for i = 0, 9 do - tv[i] = Vbar:from_int(codetab[i], mod, isbar) + Codeset:insert(Vbar:from_int(codetab[i], mod, isbar), k, i) end end end, - ["5"] = function (ean5, Vbar, mod) -- add-on EAN5 + ["5"] = function (ean5) -- add-on EAN5 ean5._main_len = 5 ean5._is_last_checksum = false - ean5._5_start_vbar = Vbar:from_int(112, mod, true) - ean5._5_sep_vbar = Vbar:from_int(11, mod, false) - ean5._5_codeset_vbar = {} - local tvbar = ean5._5_codeset_vbar + local mod = ean5.mod + local Vbar = ean5._libgeo.Vbar + local Vbar_archive = ean5._libgeo.Archive + local Codeset = Vbar_archive:new() + Codeset:insert(Vbar:from_int(112, mod, true), "start") + Codeset:insert(Vbar:from_int(11, mod, false), "sep") + ean5._5_codeset_vbar = Codeset local symbols = ean5._symbol for c = 1, 2 do - tvbar[c] = {} - local tcs = tvbar[c] - local sb = symbols[c] for i = 0, 9 do - tcs[i] = Vbar:from_int(sb[i], mod, false) + Codeset:insert(Vbar:from_int(symbols[c][i], mod, false), c, i) end end end, - ["2"] = function (ean2, Vbar, mod) -- add-on EAN2 + ["2"] = function (ean2) -- add-on EAN2 ean2._main_len = 2 ean2._is_last_checksum = false - ean2._2_start_vbar = Vbar:from_int(112, mod, true) - ean2._2_sep_vbar = Vbar:from_int(11, mod, false) - ean2._2_codeset_vbar = {} - local tvbar = ean2._2_codeset_vbar + local mod = ean2.mod + local Vbar = ean2._libgeo.Vbar + local Vbar_archive = ean2._libgeo.Archive + local Codeset = Vbar_archive:new() + ean2._2_codeset_vbar = Codeset + Codeset:insert(Vbar:from_int(112, mod, true), "start") + Codeset:insert(Vbar:from_int(11, mod, false), "sep") local symbols = ean2._symbol for c = 1, 2 do - tvbar[c] = {} - local tcs = tvbar[c] - local sb = symbols[c] for i = 0, 9 do - tcs[i] = Vbar:from_int(sb[i], mod, false) + Codeset:insert(Vbar:from_int(symbols[c][i], mod, false), c, i) end end end, ["13+5"] = function (ean, Vbar, mod) -- EAN13 with EAN5 add-on - config_full(ean, Vbar, mod, 13, 5) + config_full(ean, 13, 5) end, ["13+2"] = function(ean, Vbar, mod) -- EAN13 with EAN2 add-on - config_full(ean, Vbar, mod, 13, 2) + config_full(ean, 13, 2) end, ["8+5"] = function(ean, Vbar, mod) -- EAN8 with EAN5 add-on - config_full(ean, Vbar, mod, 8, 5) + config_full(ean, 8, 5) end, ["8+2"] = function(ean, Vbar, mod) -- EAN8 with EAN2 add-on - config_full(ean, Vbar, mod, 8, 2) + config_full(ean, 8, 2) end, } -- ISBN @@ -491,58 +518,58 @@ local function isbn_checksum(isbn) return sum % 11 end +local function isbn_parse_state() --> parse state + return { + is_space = false, + is_dash = false, + isbn_len = 0, + } +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 function isbn_process_char(_, c, parse_state) --> elem_code, elem_text, err local isbn_len = parse_state.isbn_len if c == "-" then if isbn_len == 0 then - return nil, "[ArgErr] an initial dash is not allowed" + return nil, nil, "[ArgErr] an initial dash is not allowed" end - if parse_state.isdash then - return nil, "[ArgErr] two consecutive dash char found" + if parse_state.is_dash then + return nil, nil, "[ArgErr] found two consecutive dash" end - parse_state.isdash = true - return nil, nil + parse_state.is_dash = true + return nil, c, nil elseif c == " " then if isbn_len == 0 then - return nil, "[ArgErr] an initial space is not allowed" + return nil, nil, "[ArgErr] an initial space is not allowed" + end + if parse_state.is_space then + return nil, nil, nil + else + parse_state.is_space = true + return nil, c, nil 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" + return nil, nil, "[ArgErr] found a checksum 'X' in a wrong position" end - return 10, nil + return 10, c, 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" + return nil, nil, "[ArgErr] found a not digit or a not group 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 + if parse_state.is_dash then -- close a group + parse_state.is_dash = false + parse_state.is_space = false + elseif parse_state.is_space then + parse_state.is_space = false end - code[#code + 1] = c isbn_len = isbn_len + 1 parse_state.isbn_len = isbn_len - return n, nil + return n, c, nil end end @@ -550,7 +577,8 @@ end -- parsed local function isbn_finalize(enc, parse_state) --> ok, err local var = enc._variant - local code_len = enc._code_len + local code_data = enc._code_data + local code_len = #code_data local isbn_len = parse_state.isbn_len local l1, l2 if var == "isbn" then @@ -559,7 +587,7 @@ local function isbn_finalize(enc, parse_state) --> ok, err elseif isbn_len == 13 then l1 = 13 else - return false, "[ArgErr] unsuitable ISBN code length" + return false, "[ArgErr] wrong ISBN code length of "..isbn_len end assert(l1 == code_len) elseif var == "isbn+5" then @@ -569,7 +597,7 @@ local function isbn_finalize(enc, parse_state) --> ok, err elseif isbn_len == 18 then l1, l2 = 13, 5 else - return false, "[ArgErr] unsuitable ISBN+5 code length" + return false, "[ArgErr] wrong ISBN+5 code length of "..isbn_len end assert(l1 + l2 == code_len) elseif var == "isbn+2" then @@ -579,13 +607,12 @@ local function isbn_finalize(enc, parse_state) --> ok, err elseif isbn_len == 15 then l1, l2 = 13, 2 else - return false, "[ArgErr] unsuitable ISBN+2 code length" + return false, "[ArgErr] wrong ISBN+2 code length of "..isbn_len 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) @@ -606,7 +633,7 @@ local function isbn_finalize(enc, parse_state) --> ok, err return false, "[ArgErr] unmatched ISBN 13 checksum" end end - local isbncode = parse_state.isbncode + local isbncode = enc._code_text if l2 then -- nils the add-on digits local i = #isbncode while l2 > 0 do @@ -631,7 +658,6 @@ local function isbn_finalize(enc, parse_state) --> ok, err 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 @@ -660,84 +686,86 @@ local function to_n(c) --> n, err return n, false end +local function issn_parse_state() + return { + is_dash = false, + is_group_open = false, + is_group_close = false, + ed_var_len = 0, + ed_var_arr = {}, + code_len = 0, + addon_len = 0, + } +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 function issn_process_char(enc, c, parse_state) --> e_data, e_txt, err local addon_len = enc._addon_len - -- edition variant part + -- `edition variant` input code part if c == " " then - return nil, nil -- ignore all spaces + return nil, 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" + return nil, 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" + return nil, nil, "[ArgErr] non digit char after an edition variant group" end parse_state.addon_len = parse_state.addon_len + 1 - return n, nil + return n, n, nil else - return nil, "[ArgErr] too many chars in the ISSN input code" + return nil, 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" + return nil, nil, "[ArgErr] two or more dash chars in the input code" end if parse_state.code_len ~= 4 then - return nil, "[ArgErr] incorrect position for a dash sign" + return nil, nil, "[ArgErr] incorrect position for a dash sign" end parse_state.is_dash = true - return nil, nil + return nil, c, 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" + return nil, nil, "[ArgErr] not a 8-digits long code for the ISSN input" end parse_state.is_group_open = true - return nil, nil + return nil, 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 '['" + return nil, nil, "[ArgErr] found a ']' without an opened '['" end if parse_state.ed_var_len ~= 2 then - return nil, "[ArgErr] edition variant group must be two digits long" + return nil, 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 + return nil, 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'" + return nil, 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 + return 10, c, nil + else -- at this point 'c' may be only a digit local n, e = to_n(c) if e then - return nil, "[ArgErr] found a non digit in code part" + return nil, 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" + return nil, 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 + return nil, c, nil end if parse_state.is_dash then if addon_len then @@ -745,29 +773,29 @@ local function issn_check_char(enc, c, parse_state) --> elem, err 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" + return nil, 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" + return nil, 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" + return nil, 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" + return nil, 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 + return n, n, nil end end @@ -822,7 +850,7 @@ local function issn_finalize(enc, parse_state) --> ok, err return false, "[ArgErr] unclosed edition variant group in ISSN input code" end local data = enc._code_data - local code_len = enc._code_len + local code_len = #data local addon_len = enc._addon_len local main_len = code_len - (addon_len or 0) if main_len == 8 then @@ -862,12 +890,12 @@ 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 + local data = enc._code_data + local symb_len = #data 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" @@ -881,7 +909,7 @@ end function EAN:_config() --> ok, err local variant = self._variant if not variant then - return false, "[Err] variant is mandatory for EAN family" + return false, "[Err] variant is mandatory for the EAN family" end local plus = variant:find("+") local v1 @@ -894,13 +922,13 @@ function EAN:_config() --> ok, err 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) + fnconfig(self) if v1 == "isbn" then - self._check_char = isbn_check_char + self._process_char = isbn_process_char + self._init_parse_state = isbn_parse_state elseif v1 == "issn" then - self._check_char = issn_check_char + self._process_char = issn_process_char + self._init_parse_state = issn_parse_state end return true, nil end @@ -987,51 +1015,39 @@ local fn_append_ga_variant = EAN._append_ga_variant -- draw EAN13 symbol fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay) - local code = ean._code_data - local mod = ean.mod - local bars_depth = mod * ean.bars_depth_factor - local w, h = 95*mod, ean.height + bars_depth - local x0 = (tx or 0) - ax * w - local y0 = (ty or 0) - ay * h - local x1 = x0 + w - local y1 = y0 + h - local xpos = x0 -- current insertion x-coord - local ys = y0 + bars_depth - local s_width = 7*mod - local code_seq = ean._codeset_seq[code[1]] - -- draw the start symbol - local err - err = canvas:start_bbox_group(); assert(not err, err) - local be = ean._13_start_stop_vbar - err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) - xpos = xpos + 3*mod - -- draw the first 6 numbers + local Codeset = ean._13_codeset_vbar + local mod = ean.mod + local queue_0 = assert(Codeset:get("start_stop")) + + 42*mod + + assert(Codeset:get("central")) + + 42*mod + + assert(Codeset:get("start_stop")) + local code = ean._code_data + local code_seq = ean._codeset_seq[code[1]] + local queue_1 = ean._libgeo.Vbar_queue:new() for i = 2, 7 do - local codeset = code_seq[i-1] - local n = code[i] - local vbar = ean._13_codeset_vbar[codeset][n] - err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) - xpos = xpos + s_width + queue_1 = queue_1 + assert(Codeset:get(code_seq[i-1], code[i])) end - -- draw the control symbol - local ctrl = ean._13_ctrl_center_vbar - err = canvas:encode_Vbar(ctrl, xpos, y0, y1); assert(not err, err) - xpos = xpos + 5*mod - -- draw the last 6 numbers + queue_1 = queue_1 + 5*mod for i = 8, 13 do - local codeset = code_seq[i-1] - local n = code[i] - local vbar = ean._13_codeset_vbar[codeset][n] - err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) - xpos = xpos + s_width + queue_1 = queue_1 + assert(Codeset:get(code_seq[i-1], code[i])) end - -- draw the stop char - err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) + local bars_depth = mod * ean.bars_depth_factor + local w, h = 95*mod, ean.height + bars_depth + local x0 = tx - ax * w + local y0 = ty - 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 + 3*mod, ys, y1)) -- bounding box set up local qzl = ean.quietzone_left_factor * mod local qzr = ean.quietzone_right_factor * mod - err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) - assert(not err, err) + assert(canvas:encode_set_bbox(x0 - qzl, y0, x1 + qzr, y1)) + assert(canvas:encode_enable_bbox()) if ean.text_enabled then -- human readable text local Text = ean._libgeo.Text local txt_1 = Text:from_digit_array(code, 1, 1) @@ -1039,16 +1055,30 @@ 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 - err = canvas:encode_Text(txt_1, x0 - qzl, y_bl, 0, 1) - assert(not err, err) + assert(canvas:encode_Text(txt_1, x0 - qzl, y_bl, 0, 1)) local x2_1 = x0 + (3+mx)*mod local x2_2 = x0 + (46-mx)*mod - err = canvas:encode_Text_xwidth(txt_2, x2_1, x2_2, y_bl, 1) - assert(not err, err) + 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 + (92-mx)*mod - err = canvas:encode_Text_xwidth(txt_3, x3_1, x3_2, y_bl, 1) - assert(not err, err) + assert(canvas:encode_Text_xwidth(txt_3, x3_1, x3_2, y_bl, 1)) + if ean.text_guard_enabled and (not ean._addon_len) then + local Polyline = ean._libgeo.Polyline + local mm = 186467.98 + local alpha = 36 * math.pi/180 + local pw = 0.30*mm + local dx = pw/(2*math.sin(alpha)) + local dy = (pw/2) * math.cos(alpha) + local px = x1 + qzr - dx + local pb = 1.55*mm + local ph = pb * math.tan(alpha) + local p = Polyline:new() + p:add_point(px - pb, y_bl - 2*ph - dy) + p:add_point(px, y_bl - ph - dy) + p:add_point(px - pb, y_bl - dy) + assert(canvas:encode_linewidth(pw)) + assert(canvas:encode_polyline(p)) + end local istxt = false if ean.text_isbn_enabled then if ean.text_isbn_enabled == "auto" then @@ -1060,7 +1090,7 @@ fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay) end end if istxt then - local isbn = assert(ean._isbncode, "[InternalErr] ISBN text not found") + local isbn = assert(ean._code_text, "[InternalErr] ISBN text not found") local descr = {"I", "S", "B", "N", " ",} for _, d in ipairs(isbn) do descr[#descr + 1] = d @@ -1068,13 +1098,12 @@ fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay) 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) + assert(canvas:encode_Text(isbn_txt, x_isbn, y_isbn, 0.5, 0)) 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") + local txt = assert(ean._code_text, "[InternalErr] _code_text not found") for i = 1, 4 do hri[i + 5] = txt[i] end @@ -1085,59 +1114,46 @@ fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay) 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) + assert(canvas:encode_Text(issn_txt, x_issn, y_issn, 0.5, 0)) end end + return {x0, y0, x1, y1, qzl, nil, qzr, nil,} end -- draw EAN8 symbol fn_append_ga_variant["8"] = function (ean, canvas, tx, ty, ax, ay) - local code = ean._code_data - local mod = ean.mod - local bars_depth = mod * ean.bars_depth_factor - local w, h = 67*mod, ean.height + bars_depth - local x0 = (tx or 0) - ax * w - local y0 = (ty or 0) - ay * h - local x1 = x0 + w - local y1 = y0 + h - local xpos = x0 -- current insertion x-coord - local ys = y0 + bars_depth - local s_width = 7*mod - -- draw the start symbol - local err - err = canvas:start_bbox_group(); assert(not err, err) - local be = ean._8_start_stop_vbar - err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) - xpos = xpos + 3*mod - -- draw the first 4 numbers - local t_vbar = ean._8_codeset_vbar + local Codeset = ean._8_codeset_vbar + local mod = ean.mod + local q0 = assert(Codeset:get("start_stop")) + 28*mod + + assert(Codeset:get("central")) + 28*mod + + assert(Codeset:get("start_stop")) + local code = ean._code_data local cs14 = ean._codeset14_8 + local q1 = ean._libgeo.Vbar_queue:new() for i = 1, 4 do - local n = code[i] - local vbar = t_vbar[cs14][n] - err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) - xpos = xpos + s_width + q1 = q1 + assert(Codeset:get(cs14, code[i])) end - -- draw the control symbol - local ctrl = ean._8_ctrl_center_vbar - err = canvas:encode_Vbar(ctrl, xpos, y0, y1); assert(not err, err) - xpos = xpos + 5*mod - -- draw the product code + q1 = q1 + 5*mod local cs58 = ean._codeset58_8 for i = 5, 8 do - local n = code[i] - local vbar = t_vbar[cs58][n] - err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) - xpos = xpos + s_width + q1 = q1 + assert(Codeset:get(cs58, code[i])) end - -- draw the stop char - err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) + local bars_depth = mod * ean.bars_depth_factor + local w, h = 67*mod, ean.height + bars_depth + local x0 = tx - ax * w + local y0 = ty - 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(q0, x0, y0, y1)) + assert(canvas:encode_vbar_queue(q1, x0 + 3*mod, ys, y1)) -- bounding box set up local qzl = ean.quietzone_left_factor * mod local qzr = ean.quietzone_right_factor * mod - err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) - assert(not err, err) + assert(canvas:encode_set_bbox(x0 - qzl, y0, x1 + qzr, y1)) + assert(canvas:encode_enable_bbox()) if ean.text_enabled then -- human readable text local Text = ean._libgeo.Text local t_1 = Text:from_digit_array(code, 1, 4) @@ -1146,18 +1162,40 @@ fn_append_ga_variant["8"] = function (ean, canvas, tx, ty, ax, ay) local mx = ean.text_xgap_factor local x1_1 = x0 + ( 3 + mx)*mod local x1_2 = x0 + (32 - mx)*mod - err = canvas:encode_Text_xwidth(t_1, x1_1, x1_2, y_bl, 1) - assert(not err, err) + assert(canvas:encode_Text_xwidth(t_1, x1_1, x1_2, y_bl, 1)) local x2_1 = x0 + (35+mx)*mod local x2_2 = x0 + (64-mx)*mod - err = canvas:encode_Text_xwidth(t_2, x2_1, x2_2, y_bl, 1) - assert(not err, err) + assert(canvas:encode_Text_xwidth(t_2, x2_1, x2_2, y_bl, 1)) + if ean.text_guard_enabled and (not ean._addon_len) then + local Polyline = ean._libgeo.Polyline + local mm = 186467.98 + local alpha = 36 * math.pi/180 + local pw = 0.30*mm + local pb = 1.55*mm + local ph = pb * math.tan(alpha) + local dx = pw/(2*math.sin(alpha)) + local dy = (pw/2) * math.cos(alpha) + local px1, px2 = x0 - qzl + dx, x1 + qzr - dx + local p1 = Polyline:new() + p1:add_point(px1 + pb, y_bl - 2*ph - dy) + p1:add_point(px1, y_bl - ph - dy) + p1:add_point(px1 + pb, y_bl - dy) + local p2 = Polyline:new() + p2:add_point(px2 - pb, y_bl - 2*ph - dy) + p2:add_point(px2, y_bl - ph - dy) + p2:add_point(px2 - pb, y_bl - dy) + assert(canvas:encode_linewidth(pw)) + assert(canvas:encode_polyline(p1)) + assert(canvas:encode_polyline(p2)) + end end + return {x0, y0, x1, y1, qzl, nil, qzr, nil,} end -- draw EAN5 add-on symbol fn_append_ga_variant["5"] = function (ean, canvas, tx, ty, ax, ay, h) - local code = ean._code_data + local Codeset = ean._5_codeset_vbar + local queue = assert(Codeset:get("start")) local l1 = ean._main_len local i1; if l1 == 5 then i1 = 1 @@ -1165,81 +1203,70 @@ fn_append_ga_variant["5"] = function (ean, canvas, tx, ty, ax, ay, h) i1 = l1 + 1 end local i2 = i1 + 4 - local mod = ean.mod - local w = 47*mod - h = h or ean.height - local x0 = (tx or 0) - ax * w - local y0 = (ty or 0) - ay * h - local x1 = x0 + w - local y1 = y0 + h - local xpos = x0 -- current insertion x-coord - local sym_w = 7*mod - local sep_w = 2*mod - -- draw the start symbol - local err - err = canvas:start_bbox_group(); assert(not err, err) - local start = ean._5_start_vbar - err = canvas:encode_Vbar(start, xpos, y0, y1); assert(not err, err) - xpos = xpos + 4*mod - local ck = checksum_5_2(code, i1, 5) - local codeset = ean._codeset_5[ck] - local sep = ean._5_sep_vbar - local t_vbar = ean._5_codeset_vbar + local mod = ean.mod -- draw the five digits + local code = ean._code_data + local ck = checksum_5_2(code, i1, 5) + local cset = ean._codeset_5[ck] local k = 0 for i = i1, i2 do k = k + 1 - local cs = codeset[k] -- 1 or 2 - local d = code[i] - local vbar = t_vbar[cs][d] - err = canvas:encode_Vbar(vbar, xpos, y0, y1); assert(not err, err) - xpos = xpos + sym_w + queue = queue + assert(Codeset:get(cset[k], code[i])) if k < 5 then - err = canvas:encode_Vbar(sep, xpos, y0, y1); assert(not err, err) - xpos = xpos + sep_w + queue = queue + assert(Codeset:get("sep")) end end + local w = 47*mod + h = h or ean.height + local x0 = tx - ax * w + local y0 = ty - ay * h + local x1 = x0 + w + local y1 = y0 + h + -- draw the symbol + assert(canvas:encode_disable_bbox()) + assert(canvas:encode_vbar_queue(queue, x0, y0, y1)) -- bounding box set up local qzl = ean.quietzone_left_factor * mod local qzr = ean.quietzone_right_factor * mod - err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) - assert(not err, err) + assert(canvas:encode_set_bbox(x0 - qzl, y0, x1 + qzr, y1)) + assert(canvas:encode_enable_bbox()) if ean.text_enabled then -- human readable text local Text = ean._libgeo.Text local txt = Text:from_digit_array(code, i1, i2) local y_bl = y1 + ean.text_ygap_factor * mod local x1_1 = x0 + 3*mod local x1_2 = x1 - 3*mod - err = canvas:encode_Text_xwidth(txt, x1_1, x1_2, y_bl, 0) - assert(not err, err) + assert(canvas:encode_Text_xwidth(txt, x1_1, x1_2, y_bl, 0)) + if ean.text_guard_enabled then + local Polyline = ean._libgeo.Polyline + local mm = 186467.98 + local alpha = 36 * math.pi/180 + local pw = 0.30*mm + local dx = pw/(2*math.sin(alpha)) + local dy = (pw/2) * math.cos(alpha) + local px = x1 + qzr - dx + local pb = 1.55*mm + local ph = pb * math.tan(alpha) + local p = Polyline:new() + p:add_point(px - pb, y_bl + dy) + p:add_point(px, y_bl + ph + dy) + p:add_point(px - pb, y_bl + 2*ph + dy) + assert(canvas:encode_linewidth(pw)) + assert(canvas:encode_polyline(p)) + end end + return {x0, y0, x1, y1, qzl, nil, qzr, nil,} end -- draw EAN2 symbol fn_append_ga_variant["2"] = function (ean, canvas, tx, ty, ax, ay, h) - local code = ean._code_data local l1 = ean._main_len local i1; if l1 == 2 then i1 = 1 else i1 = l1 + 1 end - local mod = ean.mod - local w = 20*mod - h = h or ean.height - local x0 = (tx or 0.0) - ax * w - local y0 = (ty or 0.0) - ay * h - local x1 = x0 + w - local y1 = y0 + h - local xpos = x0 -- current insertion x-coord - local sym_w = 7*mod - local sep_w = 2*mod - -- draw the start symbol - local err - err = canvas:start_bbox_group(); assert(not err, err) - local start = ean._2_start_vbar - err = canvas:encode_Vbar(start, xpos, y0, y1); assert(not err, err) - xpos = xpos + 4*mod + local code = ean._code_data local r = checksum_5_2(code, i1, 2) local s1, s2 if r == 0 then -- LL scheme @@ -1251,31 +1278,52 @@ fn_append_ga_variant["2"] = function (ean, canvas, tx, ty, ax, ay, h) else -- r == 3 -- GG scheme s1, s2 = 2, 2 end - local t_vbar = ean._2_codeset_vbar - local d1 = code[i1] -- render the first digit - local vb1 = t_vbar[s1][d1] - err = canvas:encode_Vbar(vb1, xpos, y0, y1); assert(not err, err) - xpos = xpos + sym_w - local sep = ean._2_sep_vbar - err = canvas:encode_Vbar(sep, xpos, y0, y1); assert(not err, err) - xpos = xpos + sep_w - local d2 = code[i1 + 1] -- render the second digit - local vb2 = t_vbar[s2][d2] - err = canvas:encode_Vbar(vb2, xpos, y0, y1); assert(not err, err) + local Codeset = ean._2_codeset_vbar + local queue = assert(Codeset:get("start")) + + assert(Codeset:get(s1, code[i1])) + -- first digit + assert(Codeset:get("sep")) + + assert(Codeset:get(s2, code[i1 + 1])) -- second digit + -- draw the symbol + local mod = ean.mod + local w = 20*mod + h = h or ean.height + local x0 = tx - ax * w + local y0 = ty - ay * h + local x1 = x0 + w + local y1 = y0 + h + assert(canvas:encode_disable_bbox()) + assert(canvas:encode_vbar_queue(queue, x0, y0, y1)) -- bounding box set up local qzl = ean.quietzone_left_factor * mod local qzr = ean.quietzone_right_factor * mod - err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) - assert(not err, err) + assert(canvas:encode_set_bbox(x0 - qzl, y0, x1 + qzr, y1)) + assert(canvas:encode_enable_bbox()) if ean.text_enabled then -- human readable text local Text = ean._libgeo.Text local txt = Text:from_digit_array(code, i1, i1 + 1) local y_bl = y1 + ean.text_ygap_factor * mod local x1_1 = x0 + 3*mod local x1_2 = x1 - 3*mod - err = canvas:encode_Text_xwidth(txt, x1_1, x1_2, y_bl, 0) - assert(not err, err) + assert(canvas:encode_Text_xwidth(txt, x1_1, x1_2, y_bl, 0)) + if ean.text_guard_enabled then + local Polyline = ean._libgeo.Polyline + local mm = 186467.98 + local alpha = 36 * math.pi/180 + local pw = 0.30*mm + local dx = pw/(2*math.sin(alpha)) + local dy = (pw/2) * math.cos(alpha) + local px = x1 + qzr - dx + local pb = 1.55*mm + local ph = pb * math.tan(alpha) + local p = Polyline:new() + p:add_point(px - pb, y_bl + dy) + p:add_point(px, y_bl + ph + dy) + p:add_point(px - pb, y_bl + 2*ph + dy) + assert(canvas:encode_linewidth(pw)) + assert(canvas:encode_polyline(p)) + end end + return {x0, y0, x1, y1, qzl, nil, qzr, nil,} end fn_append_ga_variant["13+5"] = function (ean, canvas, tx, ty, ax, ay) @@ -1283,14 +1331,15 @@ fn_append_ga_variant["13+5"] = function (ean, canvas, tx, ty, ax, ay) local bars_depth = mod * ean.bars_depth_factor local h = ean.height + bars_depth local w = (142 + ean.addon_xgap_factor) * mod - 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 fn_ga = ean._append_ga_variant local fn_1 = fn_ga["13"] local fn_2 = fn_ga["5"] - fn_1(ean, canvas, x0, y0, 0, 0) - fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + local b1 = fn_1(ean, canvas, x0, y0, 0, 0) + local b2 = fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + return {b1[1], b1[2], b2[3], b1[4], b1[5], nil, b2[7], nil,} end fn_append_ga_variant["13+2"] = function (ean, canvas, tx, ty, ax, ay) @@ -1298,14 +1347,15 @@ fn_append_ga_variant["13+2"] = function (ean, canvas, tx, ty, ax, ay) local bars_depth = mod * ean.bars_depth_factor local h = ean.height + bars_depth local w = (115 + ean.addon_xgap_factor) * mod - 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 fn_ga = ean._append_ga_variant local fn_1 = fn_ga["13"] local fn_2 = fn_ga["2"] - fn_1(ean, canvas, x0, y0, 0, 0) - fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + local b1 = fn_1(ean, canvas, x0, y0, 0, 0) + local b2 = fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + return {b1[1], b1[2], b2[3], b1[4], b1[5], nil, b2[7], nil,} end fn_append_ga_variant["8+5"] = function (ean, canvas, tx, ty, ax, ay) @@ -1313,14 +1363,15 @@ fn_append_ga_variant["8+5"] = function (ean, canvas, tx, ty, ax, ay) local bars_depth = mod * ean.bars_depth_factor local h = ean.height + bars_depth local w = (114 + ean.addon_xgap_factor) * mod - 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 fn_ga = ean._append_ga_variant local fn_1 = fn_ga["8"] local fn_2 = fn_ga["5"] - fn_1(ean, canvas, x0, y0, 0, 0) - fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + local b1 = fn_1(ean, canvas, x0, y0, 0, 0) + local b2 = fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + return {b1[1], b1[2], b2[3], b1[4], b1[5], nil, b2[7], nil,} end fn_append_ga_variant["8+2"] = function (ean, canvas, tx, ty, ax, ay) @@ -1328,14 +1379,15 @@ fn_append_ga_variant["8+2"] = function (ean, canvas, tx, ty, ax, ay) local bars_depth = mod * ean.bars_depth_factor local h = ean.height + bars_depth local w = (87 + ean.addon_xgap_factor) * mod - 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 fn_ga = ean._append_ga_variant local fn_1 = fn_ga["8"] local fn_2 = fn_ga["2"] - fn_1(ean, canvas, x0, y0, 0, 0) - fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + local b1 = fn_1(ean, canvas, x0, y0, 0, 0) + local b2 = fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) + return {b1[1], b1[2], b2[3], b1[4], b1[5], nil, b2[7], nil,} end -- ISBN @@ -1350,12 +1402,11 @@ 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 -function EAN:append_ga(canvas, tx, ty) --> canvas +function EAN:_append_ga(canvas, tx, ty) --> bbox local var = self._variant local fn_append_ga = assert(self._append_ga_variant[var]) local ax, ay = self.ax, self.ay - fn_append_ga(self, canvas, tx, ty, ax, ay) - return canvas + return fn_append_ga(self, canvas, tx, ty, ax, ay) end return EAN diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua index 2e1dcd4a02..f029263930 100644 --- a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua +++ b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-i2of5.lua @@ -1,6 +1,6 @@ -- Interleaved 2 of 5 (ITF) barcode generator -- --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli -- see LICENSE.txt file local ITF = { -- main container @@ -13,7 +13,7 @@ ITF._id_variant = { ITF14 = true, -- ITF 14 GS1 specification } -ITF._start = 111 -- nnnn +ITF._start = 1111 -- nnnn ITF._stop = 112 -- Wnn (integer must be in reverse order) ITF._pattern = { -- true -> narrow, false -> Wide @@ -40,6 +40,7 @@ ITF._par_order = { "bearer_bars_enabled", "bearer_bars_thickness", "bearer_bars_layout", + "text_enabled", } ITF._par_def = {} local pardef = ITF._par_def @@ -194,6 +195,19 @@ pardef.bearer_bars_layout = { -- enumeration end, } +-- human readable information +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] option 'text_enabled' is not a boolean value" + 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 @@ -300,7 +314,7 @@ itf14_pdef.bearer_bars_enabled = { -- boolean type -- 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 +itf14_pdef.bearer_bars_thickness = { -- dimension default = 5 * 0.495 * 186467, -- 5 modules unit = "sp", -- scaled point isReserved = false, @@ -388,51 +402,50 @@ local function checkdigit(t, last, method) end end +local function itf14_parse_state() + return { + is_space = false, + is_popen = false, + itf14_len = 0, + } +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 +local function itf14_process_char(_, c, parse_state) --> e_data, e_text, err + local len14 = parse_state.itf14_len -- parsing if c == " " then - if itf14_len == 0 then -- ignore initial spaces - return nil, nil + if (len14 == 0) or (len14 == 14) then -- ignore initial or final spaces + return nil, nil, nil + end + if parse_state.is_space then -- ignore more than one consecutive space + return nil, nil, nil + else + parse_state.is_space = true + return nil, c, 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" + return nil, nil, "[Err] a parenthesis is already opened" end parse_state.is_popen = true - code[#code + 1] = c - return nil, nil + return nil, c, nil elseif c == ")" then if not parse_state.is_popen then - return nil, "[Err] found a closing parenthesis without an opening one" + return nil, nil, "[Err] found a closing parenthesis without an opening one" end parse_state.is_popen = false - code[#code + 1] = c - return nil, nil + return nil, c, 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 + parse_state.itf14_len = len14 + 1 + return n, c, nil end end @@ -443,23 +456,25 @@ function ITF:_config() --> ok, err local wide = narrow * self.ratio -- start symbol 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) + local archive = self._libgeo.Archive -- Vbar_archive class + local Repo = archive:new() + self._vbar_data = Repo + Repo:insert(Vbar:from_int_revpair(self._start, narrow, wide), "start") + Repo:insert(Vbar:from_int_revpair(self._stop, narrow, wide), "stop") -- build every possible pair of digits from 00 to 99 - self._vbar_data = {} - local vbar = self._vbar_data local pattern = self._pattern for dec = 0, 9 do for unit = 0, 9 do local t1 = pattern[dec] local t2 = pattern[unit] local n = dec*10 + unit - vbar[n] = Vbar:from_two_tab(t1, t2, narrow, wide) + Repo:insert(Vbar:from_two_tab(t1, t2, narrow, wide), n) end end local variant = self._variant if variant == "ITF14" then - self._check_char = itf14_check_char + self._process_char = itf14_process_char + self._init_parse_state = itf14_parse_state end return true, nil end @@ -467,21 +482,24 @@ end -- internal methods for constructors -- input code post processing for ITF14 variant -local function itf14_finalize(enc) --> ok, err +local function itf14_finalize(enc, parse_state) --> ok, err + if parse_state.is_popen then + return false, "[ArgErr] unclosed group in input code" + end -- check digit action local policy = enc.check_digit_policy - local slen = enc._code_len local digits = enc._code_data + local slen = #digits local is_add if policy == "verify" then if slen ~= 14 then - return nil, "[DataErr] incorrect input lenght of "..slen.. + return false, "[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.. + return false, "[DataErr] incorrect input lenght of "..slen.. " respect to 13 (checksum policy 'add')" end is_add = true @@ -491,18 +509,27 @@ local function itf14_finalize(enc) --> ok, err elseif slen == 13 then is_add = true else - return nil, "[DataErr] incorrect input lenght of "..slen.. - " respect to the policy '"..policy.."'" + return false, "[DataErr] incorrect input lenght of "..slen.. + " respect to the current 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 + if is_add then -- add the final checkdigit digits[14] = cs - enc._code_len = 14 - else + local dtxt = enc._code_text + if dtxt then + local len = #dtxt + local last = dtxt[len] + if last == " " then + dtxt[len] = cs + else + dtxt[len + 1] = cs + end + end + else -- check only the final digit if cs ~= digits[14] then return false, "[DataErr] last digit is not equal to checksum" end @@ -514,13 +541,13 @@ end local function basic_finalize(enc) --> ok, err -- check digit action local policy = enc.check_digit_policy - local slen = enc._code_len - local is_even = (slen % 2 == 0) local digits = enc._code_data + local slen = #digits + local is_even = (slen % 2 == 0) + if policy == "none" then if not is_even then rshift(digits) -- add a heading zero for padding - slen = slen + 1 end elseif policy == "add" then if is_even then @@ -541,16 +568,15 @@ local function basic_finalize(enc) --> ok, err else return false, "[InternalError] wrong enum value" end - enc._code_len = slen return true, nil end -- input code post processing -function ITF:_finalize() --> ok, err +function ITF:_finalize(parse_state) --> ok, err local var = self._variant if var then assert(var == "ITF14") - return itf14_finalize(self) + return itf14_finalize(self, parse_state) else return basic_finalize(self) end @@ -569,59 +595,74 @@ end -- drawing function -- tx, ty is an optional translator vector -function ITF:append_ga(canvas, tx, ty) --> canvas - local err = canvas:start_bbox_group(); assert(not err, err) - -- draw the start symbol - local xdim = self.module - local ratio = self.ratio - local symb_len = 2 * xdim * (3 + 2*ratio) - local x0 = tx or 0 - local xpos = x0 - local y0 = ty or 0 - local y1 = y0 + self.height - local start = self._vbar_start - local err - err = canvas:encode_Vbar(start, xpos, y0, y1); assert(not err, err) - xpos = xpos + 4 * xdim - -- draw the code symbol +function ITF:_append_ga(canvas, tx, ty) --> bbox + local Repo = self._vbar_data + local queue = assert(Repo:get("start")) -- build the vbars queue local digits = self._code_data - local vbars = self._vbar_data - for i = 1, #digits, 2 do + local n = #digits + for i = 1, n, 2 do local index = 10 * digits[i] + digits[i+1] - local b = vbars[index] - err = canvas:encode_Vbar(b, xpos, y0, y1); assert(not err, err) - xpos = xpos + symb_len + queue = queue + assert(Repo:get(index)) end - -- draw the stop symbol - local stop = self._vbar_stop - err = canvas:encode_Vbar(stop, xpos, y0, y1); assert(not err, err) + queue = queue + assert(Repo:get("stop")) + -- draw the start symbol + local xdim = self.module + local ratio = self.ratio + local w = xdim * (6 + ratio + n * (3 + 2 * ratio)) + local ax, ay = self.ax, self.ay + local h = self.height + local x0 = tx - w * ax + local y0 = ty - h * ay + local y1 = y0 + h + assert(canvas:encode_disable_bbox()) + assert(canvas:encode_vbar_queue(queue, x0, y0, y1)) -- bounding box setting - local x1 = xpos + (2 + ratio)*xdim + local x1 = x0 + w local qz = self.quietzone - if self._variant then + if self._variant == "ITF14" then -- "ITF14" qz = qz * xdim end - local b1x, b1y = x0 - qz, y0 - local b2x, b2y = x1 + qz, y1 + local b1x, b1y = x0 - qz, y0 + local b2x, b2y = x1 + qz, y1 + local bq1, bq3 = qz, qz + local bq2, bq4 if self.bearer_bars_enabled then - local w = self.bearer_bars_thickness - err = canvas:encode_linethick(w); assert(not err, err) - b1y, b2y = b1y - w, b2y + w + local t = self.bearer_bars_thickness + local t2 = t/2 + assert(canvas:encode_linewidth(t)) + b1y, b2y = b1y - t, b2y + t + bq2, bq4 = t, t local layout = self.bearer_bars_layout if layout == "hbar" then - err = canvas:encode_hline(b1x, b2x, y0 - w/2); assert(not err, err) - err = canvas:encode_hline(b1x, b2x, y1 + w/2); assert(not err, err) + assert(canvas:encode_hline(b1x, b2x, y0 - t2)) + assert(canvas:encode_hline(b1x, b2x, y1 + t2)) elseif layout == "frame" then - err = canvas:encode_rectangle(b1x - w/2, y0 - w/2, b2x + w/2, y1 + w/2) - assert(not err, err) - b1x, b2x = b1x - w, b2x + w + assert(canvas:encode_rect(b1x - t2, y0 - t2, b2x + t2, y1 + t2)) + b1x, b2x = b1x - t, b2x + t + bq1, bq3 = bq1 + t, bq3 + t + else + error("[InternalErr] unexpected bearer bars layout option value") + end + end + assert(canvas:encode_set_bbox(b1x, b1y, b2x, b2y)) + assert(canvas:encode_enable_bbox()) + if self.text_enabled then + local Text = self._libgeo.Text + local t + if self._variant == "ITF14" then + local code = self._code_text + if code == nil then + code = self._code_data + end + t = Text:from_chars(code) else - error("[IntenalErr] bearer bars layout option is wrong") + t = Text:from_digit_array(self._code_data) end + local y_top = b1y - 0.6 * 186467 -- mm + local x_top = (b1x + b2x)/2 + assert(canvas:encode_Text(t, x_top, y_top, 0.50, 1)) end - local err = canvas:stop_bbox_group(b1x, b1y, b2x, b2y) - assert(not err, err) - return canvas + return {x0, y0, x1, y1, bq1, bq2, bq3, bq4,} end return ITF diff --git a/macros/luatex/generic/barracuda/src/lib-barcode/brcd-upc.lua b/macros/luatex/generic/barracuda/src/lib-barcode/brcd-upc.lua new file mode 100644 index 0000000000..99bfd4349e --- /dev/null +++ b/macros/luatex/generic/barracuda/src/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 diff --git a/macros/luatex/generic/barracuda/src/lib-driver/brcd-driver.lua b/macros/luatex/generic/barracuda/src/lib-driver/brcd-driver.lua index 045a23e9d6..d2d86720ae 100644 --- a/macros/luatex/generic/barracuda/src/lib-driver/brcd-driver.lua +++ b/macros/luatex/generic/barracuda/src/lib-driver/brcd-driver.lua @@ -1,19 +1,16 @@ -- -- ga Intermediate Graphic Language for barcode drawing --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli -- -- Basic driver interface --- drawing elementary vector shape +-- drawing elementary vector graphic -- All dimensions are in scaled point (sp) -local Driver = { - _VERSION = "Driver v0.0.9", - _NAME = "Driver", - _DESCRIPTION = "Driver for ga graphic assembler stream", -} - +local Driver = {_classname = "Driver"} Driver.__index = Driver Driver._drv_instance = {} -- driver instances repository +Driver.mm = 186467.98110236 -- conversion factor sp -> mm (millimeter) +Driver.bp = 65781.76 -- conversion factor sp -> bp (big point) -- driver_type/submodule name Driver._drv_available_drv = { -- lowercase keys please @@ -21,12 +18,13 @@ Driver._drv_available_drv = { -- lowercase keys please svg = "lib-driver.brcd-drv-svg", } +-- id_drv is specific driver identifier as a string function Driver:_get_driver(id_drv) --> object, err if type(id_drv) ~= "string" then - return nil, "[ArgErr] 'id_drv' is not a string" + return nil, "[ArgErr: id_drv] string expected" end if not self._drv_available_drv[id_drv] then - return nil, "[ArgErr] driver '"..id_drv.."' not found" + return nil, "[ArgErr: id_drv] driver '"..id_drv.."' not found" end local t_drv = self._drv_instance if t_drv[id_drv] then -- is the repo already loaded? @@ -39,47 +37,87 @@ function Driver:_get_driver(id_drv) --> object, err end end -function Driver:_new_state() --> a new state +function Driver:default_style() --> new table as default graphic init state return { - line_width = 65781.76, -- line width 1bp (in scaled point sp) - line_cap = 0, -- line cap style - line_join = 0, -- line join style - gtext = false, -- text group off - bb_on = true, -- bounding box checking activation - bb_x1 = nil, -- bounding box coordinates in sp (nil means no data) - bb_y1 = nil, - bb_x2 = nil, - bb_y2 = nil, - mm = 186467.98110236, -- conversion factor sp -> mm (millimeter) - bp = 65781.76, -- conversion factor sp -> bp (big point) + linewidth = 65781.76, -- line width 1bp (in scaled point sp) + linecap = 0, -- line cap style + linejoin = 0, -- line join style + dashpattern = nil, -- dash definition + dashphase = nil, -- dash phase definition } end -function Driver:_ga_process(drv, ga, st, bf, xt) +function Driver:_new_state() --> a new state + local st = self:default_style() + st.bb_on = true -- bounding box checking is active + st.gtext = false -- text group off + st.bb_x1 = nil -- bounding box coordinates in sp (nil means no data) + st.bb_y1 = nil + st.bb_x2 = nil + st.bb_y2 = nil + st.mm = self.mm -- conversion factor sp -> mm (millimeter) + st.bp = self.bp -- conversion factor sp -> bp (big point) + return st +end + +function Driver:_ga_init_style(drv, st, bf, xt) + local op_fn = self._opcode_v001 + -- linewidth + if not drv.append_001 then + error("[InternalErr] unimplemented opcode 1 for "..drv._drvname) + end + local w = st.linewidth + drv.append_001(st, bf, xt, w) + -- linecap + if not drv.append_002 then + error("[InternalErr] unimplemented opcode 2 for "..drv._drvname) + end + local linecap = st.linecap + drv.append_002(st, bf, xt, linecap) + -- line join style + if not drv.append_003 then + error("[InternalErr] unimplemented opcode 3 for "..drv._drvname) + end + local join = st.linejoin + drv.append_003(st, bf, xt, join) + -- dash pattern (reset) + if not drv.append_006 then + error("[InternalErr] unimplemented opcode 6 for "..drv._drvname) + end + drv.append_006(st, bf, xt) +end + +function Driver:_ga_process(drv, ga_stream, st, bf, xt) local op_fn = self._opcode_v001 local pc = 1 -- program counter - local data = ga._data - while data[pc] do -- stream processing - local opcode = data[pc] + while ga_stream[pc] do -- stream processing + local opcode = ga_stream[pc] local fn = assert(op_fn[opcode], "[InternalErr] unimpl opcode ".. opcode) - pc = fn(drv, st, pc + 1, data, bf, xt) + pc = fn(drv, st, pc + 1, ga_stream, bf, xt) end end -- save graphic data in an external file with the 'id_drv' format --- id_drv: specific driver output --- ga: ga object --- filename: file name --- ext: file extension (optional) +-- id_drv: specific driver output identifier +-- ga ::= gaCanvas class | ga stream table array +-- filename ::= string, file name +-- ext ::= string, file extension (optional, default SVG) function Driver:save(id_drv, ga, filename, ext) --> ok, err -- retrive the output library local drv, err = self:_get_driver(id_drv) if err then return false, err end + local ga_stream; if ga._classname == "gaCanvas" then + ga_stream = ga:get_stream() + else + ga_stream = ga + end -- init local state = self:_new_state() local buf, txt_buf = drv.init_buffer(state) -- a new buffer and text_buffer + -- send every defualt style parameter to the special driver + self:_ga_init_style(drv, state, buf, txt_buf) -- processing - self:_ga_process(drv, ga, state, buf, txt_buf) + self:_ga_process(drv, ga_stream, state, buf, txt_buf) -- buffer finalizing drv.close_buffer(state, buf, txt_buf) -- finalize the istruction -- file saving @@ -91,9 +129,19 @@ function Driver:save(id_drv, ga, filename, ext) --> ok, err return true, nil end --- insert a ga drawing in a TeX box +-- insert a ga drawing in a TeX hbox -- PDFnative only function +-- ga ::= gaCanvas class | ga stream table array +-- boxname ::= string function Driver:ga_to_hbox(ga, boxname) --> ok, err + if type(ga) ~= "table" then + return false, "[ArgErr: ga] table expected" + end + local ga_stream; if ga._classname == "gaCanvas" then + ga_stream = ga:get_stream() + else + ga_stream = ga + end -- retrive the output library local id_drv = "native" local drv, err = self:_get_driver(id_drv) @@ -101,13 +149,14 @@ function Driver:ga_to_hbox(ga, boxname) --> ok, err -- init process local state = self:_new_state() local buf, txt_buf = drv.init_buffer(state) -- a new buffer and text_buffer + -- send every defualt style parameter to the special driver + self:_ga_init_style(drv, state, buf, txt_buf) -- processing - self:_ga_process(drv, ga, state, buf, txt_buf) + self:_ga_process(drv, ga_stream, state, buf, txt_buf) -- finalizing drv.close_buffer(state, buf, txt_buf) -- finalize the istruction sequence -- build hbox - local ok, err = drv.hboxcreate(boxname, state, buf, txt_buf) - return ok, err + return drv.hboxcreate(boxname, state, buf, txt_buf) end @@ -124,38 +173,62 @@ end Driver._opcode_v001 = { [1] = function (drv, st, pc, ga, bf, xt) -- 1 ; set line width local w = ga[pc] - st.line_width = w - if not drv.append_001 then - error("[InternalErr] unimplemented opcode 1 for "..drv._NAME) - end + st.linewidth = w drv.append_001(st, bf, xt, w) return pc + 1 end, [2] = function (drv, st, pc, ga, bf, xt) -- 2 ; set line cap style local style = ga[pc] - st.line_cap = style + st.linecap = style if not drv.append_002 then - error("[InternalErr] unimplemented opcode 2 for "..drv._NAME) + error("[InternalErr] unimplemented opcode 2 for "..drv._drvname) end drv.append_002(st, bf, xt, style) return pc + 1 end, [3] = function (drv, st, pc, ga, bf, xt) -- 3 ; set line join style local join = ga[pc] - if not drv.append_003 then - error("[InternalErr] unimplemented opcode 3 for "..drv._NAME) - end + st.linejoin = join drv.append_003(st, bf, xt, join) return pc + 1 end, - [30] = function (drv, st, pc, ga, bf, xt) -- start_bbox_group - assert(st.bb_on) - st.bb_on = false + -- 5 , Dash pattern line style + -- phase n [bi ]+ + [5] = function (drv, st, pc, ga, bf, xt) + if not drv.append_005 then + error("[InternalErr] unimplemented opcode 5 for "..drv._drvname) + end + local phase = ga[pc]; pc = pc + 1 + local n = ga[pc]; pc = pc + 1 + assert(n > 0, "[Err] dash pattern needs one length or more ("..n..")") + st.dashphase = phase + local dash = {} + for i = pc, pc + n - 1 do + local v = ga[i] + dash[#dash + 1] = v + end + st.dashpattern = dash + drv.append_005(st, bf, xt, phase, dash) + return pc + n + end, + [6] = function (drv, st, pc, ga, bf, xt) -- 6 + if not drv.append_006 then + error("[InternalErr] unimplemented opcode 6 for "..drv._drvname) + end + st.dashpattern = nil -- reset dash pattern array and phase + st.dashphase = nil + drv.append_006(st, bf, xt) return pc end, - [31] = function (drv, st, pc, ga, bf, xt) -- end_bbox_group - assert(st.bb_on == false) + [29] = function (drv, st, pc, ga, bf, xt) -- enable_bbox st.bb_on = true + return pc + end, + [30] = function (drv, st, pc, ga, bf, xt) -- disable_bbox + st.bb_on = false + return pc + end, + [31] = function (drv, st, pc, ga, bf, xt) -- set_bbox local x1 = ga[pc]; pc = pc + 1 local y1 = ga[pc]; pc = pc + 1 local x2 = ga[pc]; pc = pc + 1 @@ -180,7 +253,7 @@ Driver._opcode_v001 = { local x2 = ga[pc]; pc = pc + 1 local y = ga[pc]; pc = pc + 1 if st.bb_on then -- eventually update bbox - local hw = st.line_width/2 + local hw = st.linewidth/2 local by1 = y - hw local by2 = y + hw if st.bb_x1 == nil then @@ -196,7 +269,7 @@ Driver._opcode_v001 = { end end if not drv.append_033 then - error("[InternalErr] unimplemented opcode 33 for "..drv._NAME) + error("[InternalErr] unimplemented opcode 33 for "..drv._drvname) end drv.append_033(st, bf, xt, x1, x2, y) return pc @@ -206,8 +279,8 @@ Driver._opcode_v001 = { local y1 = ga[pc]; pc = pc + 1 local y2 = ga[pc]; pc = pc + 1 local x = ga[pc]; pc = pc + 1 - if st.bb_on then -- eventually update the figure bounding box - local hw = st.line_width/2 + if st.bb_on then -- eventually update the figure's bounding box + local hw = st.linewidth/2 local bx1 = x - hw local bx2 = x + hw if st.bb_x1 == nil then @@ -223,7 +296,7 @@ Driver._opcode_v001 = { end end if not drv.append_034 then - error("[InternalErr] unimplemented opcode 34 for "..drv._NAME) + error("[InternalErr] unimplemented opcode 34 for "..drv._drvname) end drv.append_034(st, bf, xt, y1, y2, x) return pc @@ -277,16 +350,64 @@ Driver._opcode_v001 = { end return pc_next end, + -- draw a polyline + -- 38 ... + -- basic support for bounding box calculation + [38] = function(drv, st, pc, ga, bf, xt) -- polyline + local n = ga[pc]; pc = pc + 1; assert(n > 1) + local x1 = ga[pc]; pc = pc + 1 + local y1 = ga[pc]; pc = pc + 1 + if drv.append_038_start then + drv.append_038_start(st, bf, xt, n, x1, y1) + end + local pc_next = pc + 2*(n - 1) + local bx1, bx2, by1, by2 = x1, x1, y1, y1 -- simplified bb vertex + for i = pc, pc_next - 1, 2 do -- reading coordinates + local x = assert(ga[i], "[InternalErr] ga prematurely reached the end") + local y = assert(ga[i+1], "[InternalErr] ga prematurely reached the end") + drv.append_038_point(st, bf, xt, x, y) + -- check the bounding box only if the corresponding flag is true + if st.bb_on then + if x > bx2 then + bx2 = x + elseif x < bx1 then + bx1 = x + end + if y > by2 then + by2 = y + elseif y < by1 then + by1 = y + end + end + end + if drv.append_038_stop then + drv.append_038_stop(st, bf, xt) + end + if st.bb_on then -- eventually update bbox + if st.bb_x1 == nil then + st.bb_x1 = bx1 + st.bb_x2 = bx2 + st.bb_y1 = by1 + st.bb_y2 = by2 + else + if bx1 < st.bb_x1 then st.bb_x1 = bx1 end + if bx2 > st.bb_x2 then st.bb_x2 = bx2 end + if by1 < st.bb_y1 then st.bb_y1 = by1 end + if by2 > st.bb_y2 then st.bb_y2 = by2 end + end + end + return pc_next + end, -- draw a rectangle -- 48 [48] = function(drv, st, pc, ga, bf, xt) - local x1 = ga[pc]; pc = pc + 1 - local y1 = ga[pc]; pc = pc + 1 - local x2 = ga[pc]; pc = pc + 1 - local y2 = ga[pc]; pc = pc + 1 + local x1 = ga[pc]; pc = pc + 1 + local y1 = ga[pc]; pc = pc + 1 + local x2 = ga[pc]; pc = pc + 1 + local y2 = ga[pc]; pc = pc + 1 -- check the bounding box only if the flag is true if st.bb_on then - local hw = st.line_width/2 + local hw = st.linewidth/2 local bx1, bx2 = x1 - hw, x2 + hw local by1, by2 = y1 - hw, y2 + hw if st.bb_x1 == nil then @@ -302,7 +423,7 @@ Driver._opcode_v001 = { end end if not drv.append_048 then - error("[InternalErr] unimplemented opcode 48 for "..drv._NAME) + error("[InternalErr] unimplemented opcode 48 for "..drv._drvname) end drv.append_048(st, bf, xt, x1, y1, x2, y2) return pc diff --git a/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-pdfliteral.lua b/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-pdfliteral.lua index b36021f9b6..a5cfccf4cb 100644 --- a/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-pdfliteral.lua +++ b/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-pdfliteral.lua @@ -1,22 +1,17 @@ -- -- ga graphic assembler or -- Intermediate Graphic Language for barcode drawing --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli -- -- All dimensions are in scaled point (sp) -- ga LuaTeX Driver (native implementation node+pdfliteral) --- class for drawing elementary geometric elements -local PDFnative = { - _VERSION = "PDFnative v0.0.4", - _NAME = "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") +-- class for drawing elementary geometric elements +local PDFnative = {_drvname = "PDFnative"} PDFnative.ext = "txt" -- file extension PDFnative.buf_sep = "\n" -- separation string for buffer concat @@ -24,6 +19,7 @@ function PDFnative.init_buffer(st) --> buffer, text buffer st.head = nil -- addition for text processing (to remember purpose) st.last = nil st.hbox = nil + st.dash_array = nil st.cw = nil st.x_hbox = nil st.char_counter = nil @@ -126,12 +122,27 @@ function PDFnative.append_003(st, bf, xt, j) bf[#bf + 1] = string.format("%d j", j) end +-- 5 dash_pattern +function PDFnative.append_005(st, bf, xt, phase, dash_array) + local bp = st.bp -- conversion factor bp -> sp + local t = {} + for _, d in ipairs(dash_array) do + t[#t + 1] = string.format("%0.6f", d/bp) + end + bf[#bf + 1] = string.format("[%s] %0.6f d",table.concat(t, " "), phase/bp) +end + +-- 6 reset_pattern +function PDFnative.append_006(st, bf, xt) + bf[#bf + 1] = string.format("[] 0 d") +end + -- draw an horizontal line -- 33 function PDFnative.append_033(st, bf, xt, x1, x2, y) local bp = st.bp -- conversion factor bp -> sp - bf[#bf + 1] = string.format("% 0.6f %0.6f m", x1/bp, y/bp) - bf[#bf + 1] = string.format("% 0.6f %0.6f l", x2/bp, y/bp) + bf[#bf + 1] = string.format("%0.6f %0.6f m", x1/bp, y/bp) + bf[#bf + 1] = string.format("%0.6f %0.6f l", x2/bp, y/bp) bf[#bf + 1] = "S" -- stroke end @@ -140,8 +151,8 @@ end -- 34 function PDFnative.append_034(st, bf, xt, y1, y2, x) local bp = st.bp -- conversion factor bp -> sp - bf[#bf + 1] = string.format("% 0.6f %0.6f m", x/bp, y1/bp) - bf[#bf + 1] = string.format("% 0.6f %0.6f l", x/bp, y2/bp) + bf[#bf + 1] = string.format("%0.6f %0.6f m", x/bp, y1/bp) + bf[#bf + 1] = string.format("%0.6f %0.6f l", x/bp, y2/bp) bf[#bf + 1] = "S" -- stroke end @@ -161,6 +172,21 @@ function PDFnative.append_036_stop(st, bf, xt, nbar, y1, y2) bf[#bf + 1] = "S" -- stroke end +-- Polyline +-- draw a polyline +-- 38 ... +function PDFnative.append_038_start(st, bf, xt, n, x1, y1) + local bp = st.bp -- conversion factor bp -> sp + bf[#bf + 1] = string.format("%0.6f %0.6f m", x1/bp, y1/bp) +end +function PDFnative.append_038_point(st, bf, xt, x, y) + local bp = st.bp -- conversion factor bp -> sp + bf[#bf + 1] = string.format("%0.6f %0.6f l", x/bp, y/bp) +end +function PDFnative.append_038_stop(st, bf, xt) + bf[#bf + 1] = "S" -- stroke +end + -- draw a rectangle -- 48 function PDFnative.append_048(st, bf, xt, x1, y1, x2, y2) diff --git a/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-svg.lua b/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-svg.lua index ce1f5bffbc..df5ae0e366 100644 --- a/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-svg.lua +++ b/macros/luatex/generic/barracuda/src/lib-driver/brcd-drv-svg.lua @@ -1,18 +1,13 @@ -- -- ga Intermediate Graphic Language for barcode drawing --- SVG library --- Copyright (C) 2020 Roberto Giacomelli +-- SVG driver for the ga graphic stream +-- Copyright (C) 2019-2022 Roberto Giacomelli -- -- All dimension in the ga stream are scaled point (sp) -- 1 pt = 65536 sp -- class for drawing elementary geometric elements -local SVG = { - _VERSION = "SVGdriver v0.0.1", - _NAME = "SVGdriver", - _DESCRIPTION = "A SVG driver for the ga graphic stream", -} - +local SVG = {_drvname = "SVG"} SVG.ext = "svg" -- file extension SVG.buf_sep = nil -- separation string for buffer concat @@ -30,10 +25,10 @@ function SVG.init_buffer(st) --> buffer, text buffer } -- additions for SVG driver to 'state' st.ident_lvl = 1 -- identation level - st.char_buf = nil + st.char_buf = nil -- character buffer local mm = st.mm st.h_char = 2.1 * mm -- char height (mm) - st.w_char = st.h_char / 1.303 -- avg char width (mm) + st.w_char = st.h_char / 1.303 -- average char width (mm) st.d_char = st.h_char / 3.7 -- char deep (mm) return bf, {} end @@ -42,7 +37,7 @@ function SVG.close_buffer(st, bf, xt) bf[#bf + 1] = '\n' -- close svg xml element bf[#bf + 1] = '\n' -- a last empty line local mm = st.mm - local x1, y1, x2, y2 = st.bb_x1, st.bb_y1, st.bb_x2, st.bb_y2 + local x1, y1, x2, y2 = st.bb_x1 or 0, st.bb_y1 or 0, st.bb_x2 or 0, st.bb_y2 or 0 local w = (x2 - x1)/mm local h = (y2 - y1)/mm local fmt_wh = bf[7] @@ -55,25 +50,55 @@ end -- SVG encoding functions -- 1 ; set line width -function SVG.append_001(st, bf, xt, w) - -- nothing to do +function SVG.append_001(st, bf, xt, w) -- nothing to do +end + +-- 2 ; set line cap style +function SVG.append_002(st, bf, xt, cap) -- nothing to do +end + +-- 3 ; set line join style +function SVG.append_003(st, bf, xt, j) -- nothing to do +end + +-- 5 +function SVG.append_005(st, bf, xt) -- nothing to do +end + +-- 6 +function SVG.append_006(st, bf, xt) -- nothing to do end --- draw an horizontal line +-- draw an horizontal line opcode -- 33 function SVG.append_033(st, bf, xt, x1, x2, y) local lvl = st.ident_lvl local ident = string.rep(" ", lvl) -- a couple of spaces as indentation local mm = st.mm -- conversion ratio sp -> bp bf[#bf + 1] = string.format( -- element - '%s= 0) + if phase > 0 then + bf[#bf + 1] = string.format( + '%s stroke-dashoffset="%0.6f"\n', ident, phase/mm + ) + end + end bf[#bf + 1] = ident..'/>\n' end @@ -83,14 +108,29 @@ function SVG.append_034(st, bf, xt, y1, y2, x) local ident = string.rep(" ", lvl) -- a couple of spaces as indentation local mm = st.mm -- conversion ratio sp -> mm bf[#bf + 1] = string.format( -- element - '%s= 0) + if phase > 0 then + bf[#bf + 1] = string.format( + '%s stroke-dashoffset="%0.6f"\n', ident, phase/mm + ) + end + end bf[#bf + 1] = ident..'/>\n' end @@ -118,6 +158,91 @@ function SVG.append_036_stop(st, bf, xt, nbar, y1, y2) bf[#bf + 1] = ident..'\n' -- end group end +-- Polyline +-- draw a polyline +-- 38 ... +function SVG.append_038_start(st, bf, xt, n, x1, y1) + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) + local mm = st.mm -- conversion factor mm -> sp + local style = string.format( + '%s= 0) + if phase > 0 then + style = string.format( + '%s stroke-dashoffset="%0.6f"', style, phase/mm + ) + end + end + bf[#bf + 1] = style..'>\n' + ident = ident .. " " + bf[#bf + 1] = string.format('%s sp + bf[#bf + 1] = string.format('\n%s%0.6f,%0.6f', ident, x/mm, -y/mm) +end +function SVG.append_038_stop(st, bf, xt) + bf[#bf + 1] = '"/>\n' -- closing tag + local lvl = st.ident_lvl - 1 + local ident = string.rep(" ", lvl) + st.ident_lvl = lvl + bf[#bf + 1] = ident..'\n' -- close the group +end + +-- draw a rectangle +-- 48 +function SVG.append_048(st, bf, xt, x1, y1, x2, y2) + local w = x2 - x1 -- rectangle width + assert(w > 0) + local h = y2 - y1 -- rectangle height + assert(h > 0) + local mm = st.mm -- conversion factor mm -> sp + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) + local fmt = '%s= 0) + if phase > 0 then + bf[#bf + 1] = string.format( + '%s stroke-dashoffset="%0.6f"\n', ident, phase/mm + ) + end + end + bf[#bf + 1] = ident..'/>\n' +end + -- Text -- 130 Text with several glyphs -- 130 diff --git a/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua b/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua index 86eba659d1..fc58a85b7b 100644 --- a/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua +++ b/macros/luatex/generic/barracuda/src/lib-geo/brcd-gacanvas.lua @@ -1,86 +1,208 @@ -- class gaCanvas --- Copyright (C) 2020 Roberto Giacomelli +-- Copyright (C) 2019-2022 Roberto Giacomelli +-- encoding functions (see barracuda-manual.pdf) --- ga -- basic function - -local gaCanvas = { - _VERSION = "gacanvas v0.0.4", - _NAME = "gaCanvas", - _DESCRIPTION = "A library for dealing with ga stream", -} +local gaCanvas = {_classname = "gaCanvas"} gaCanvas.__index = gaCanvas +gaCanvas.mm = 186467.98110236 -- conversion factor sp -> mm (millimeter) +gaCanvas.bp = 65781.76 -- conversion factor sp -> bp (big point) +gaCanvas.pt = 65536 -- sp -> pt -- ga specification: see the file ga-grammar.pdf in the doc directory -- gaCanvas constructor function gaCanvas:new() --> object - local o = { - _data = {}, - _v = 100, -- version of the ga format - } + local drv = assert(self._driver_class) + -- graphic state fields returned by Driver:default_style() method + -- linewidth + -- linecap + -- linejoin + -- dashpattern + -- dashphase + local o = assert(drv:default_style()) -- initial graphic state + o._version = 100 -- version of the ga format + o._data = {} -- ga stream array + o.bb_on = true setmetatable(o, self) return o end --- Ipothetical another constructor +-- save graphic data in an external file with the 'id_drv' format +-- id_drv::= string, specific driver output identifier +-- filename ::= string, file name +-- ext ::= string, file extension (optional, default SVG) +function gaCanvas:save(id_drv, filename, ext) --> ok, err + local driver = self._driver_class + return driver:save(id_drv, self, filename, ext) +end + +-- insert a ga drawing in a TeX hbox +-- PDFnative only function +-- boxname ::= string +function gaCanvas:ga_to_hbox(boxname) --> ok, err + local driver = self._driver_class + return driver:ga_to_hbox(self, boxname) +end + +-- return a clone of the stream array +function gaCanvas:get_stream() --> table (as a flat array) + local data = self._data + local t = {} + for _, v in ipairs(data) do + t[#t + 1] = v + end + return t +end + +-- Ipothetical further constructor -- function gaCanvas:from_tcp_server() --> err -- end +-- function gaCanvas:get_bbox() +-- end + +-- function gaCanvas:check() --> ok, err +-- end + -- line width: opcode <1> -function gaCanvas:encode_linethick(w) --> err - if type(w) ~= "number" then return "[ArgErr] 'w' number expected" end - if w < 0 then return "[ArgErr] negative value for 'w'" end +function gaCanvas:encode_linewidth(w) --> ok, err + if type(w) ~= "number" then + return false, "[ArgErr 'w'] number expected" + end + if w < 0 then return false, "[ArgErr: w] negative number not allowed" end + self.linewidth = w local data = self._data data[#data + 1] = 1 -- opcode for line thickness data[#data + 1] = w + return true, nil end --- line cap style: opcode <2> --- 0 Butt cap --- 1 Round cap --- 2 Projecting square cap -function gaCanvas:encode_linecap(cap) --> err - if type(cap) ~= "number" then return "[ArgErr] 'cap' arg number expected" end - if cap == 0 or cap == 1 or cap == 2 then - local data = self._data - data[#data + 1] = 2 -- opcode for line cap style - data[#data + 1] = cap +-- line cap style: opcode <2> cap | +-- 0 | "butt": Butt cap +-- 1 | "round": Round cap +-- 2 | "proj": Projecting square cap +function gaCanvas:encode_linecap(cap) --> ok, err + local tcap = type(cap) + local cap_res + if tcap == "number" then + if cap == 0 or cap == 1 or cap == 2 then + cap_res = cap + else + return false, "[ArgErr: cap] 0, 1 or 2 expected" + end + elseif tcap == "string" then + if cap == "butt" then + cap_res = 0 + elseif cap == "round" then + cap_res = 1 + elseif cap == "proj" then + cap_res = 2 + else + return false, "[ArgErr: cap] 'butt', 'round' or 'proj' expected" + end else - return "[ArgErr] invalid value for 'cap'" + return false, "[ArgErr: cap] number or string expected" end + self.linecap = cap_res + local data = self._data + data[#data + 1] = 2 -- opcode for line cap style + data[#data + 1] = cap_res + return true, nil end --- line cap style: opcode <3> --- 0 Miter join --- 1 Round join --- 2 Bevel join -function gaCanvas:encode_linejoin(join) --> err - if type(join) ~= "number" then return "[ArgErr] 'join' arg number expected" end - if join == 0 or join == 1 or join == 2 then - local data = self._data - data[#data + 1] = 3 -- opcode for line join style - data[#data + 1] = join +-- line join style: opcode <3> join | +-- 0 | "miter" : Miter join +-- 1 | "round" : Round join +-- 2 | "bevel" : Bevel join +function gaCanvas:encode_linejoin(join) --> ok, err + local tjoin = type(join) + local join_res + if tjoin == "number" then + if join == 0 or join == 1 or join == 2 then + join_res = join + else + return false, "[ArgErr: join] 0, 1 or 2 integer expected" + end + elseif tjoin == "string" then + if join == "miter" then + join_res = 0 + elseif join == "round" then + join_res = 1 + elseif join == "bevel" then + join_res = 2 + else + return false, "[ArgErr: join] '"..join.."' join style not found" + end else - return "[ArgErr] invalid value for 'join'" + return false, "[ArgErr: join] number or string expected" + end + self.linejoin = join_res + local data = self._data + data[#data + 1] = 3 -- opcode for line join style + data[#data + 1] = join_res + return true, nil +end + +-- 5 , Dash pattern line style, p n bi +-- p: phase lenght +-- n: number of array element +-- [bi]: dash array of dash and gap lenghts +function gaCanvas:encode_dash_pattern(p, ...) --> ok, err + if type(p) ~= "number" then return false, "[ArgErr: phase] number expected" end + local t = {...} + for i, v in ipairs(t) do + if type(v) ~= "number" then + return false, "[ArgErr: array] found a not number value at index " .. i + end + end + self.dash_pattern = t + self.dash_phase = p + local n = #t + local d = self._data + d[#d + 1] = 5 + d[#d + 1] = p + d[#d + 1] = n + for _, b in ipairs(t) do + d[#d + 1] = b end + return true, nil +end + +-- 6 , set the continous line style +function gaCanvas:encode_reset_pattern() --> ok, err + self.dash_pattern = nil + self.dash_phase = nil + local d = self._data + d[#d + 1] = 6 + return true, nil +end + +-- checking the bounding box from now on +-- opcode: <29> +function gaCanvas:encode_enable_bbox() --> ok, err + self.bb_on = true + local data = self._data + data[#data + 1] = 29 + return true, nil end -- Stop checking the bounding box -- opcode: <30> -function gaCanvas:start_bbox_group() --> err +function gaCanvas:encode_disable_bbox() --> ok, err + self.bb_on = false local data = self._data data[#data + 1] = 30 + return true, nil end --- restart checking the bounding box --- and insert the specified bb for the entire object group +-- insert a figure bbox -- code: <31> x1 y1 x2 y2 -function gaCanvas:stop_bbox_group(x1, y1, x2, y2) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end - if x1 > x2 then x1, x2 = x2, x1 end -- reorder coordinates +function gaCanvas:encode_set_bbox(x1, y1, x2, y2) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(y1) ~= "number" then return false, "[ArgErr: y1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(y2) ~= "number" then return false, "[ArgErr: y2] number expected" end + if x1 > x2 then x1, x2 = x2, x1 end -- re-order coordinates if y1 > y2 then y1, y2 = y2, y1 end local data = self._data data[#data + 1] = 31 -- bounding box of the object group @@ -88,174 +210,368 @@ function gaCanvas:stop_bbox_group(x1, y1, x2, y2) --> err data[#data + 1] = y1 data[#data + 1] = x2 data[#data + 1] = y2 + return true, nil end -- insert a line from point (x1, y1) to the point (x2, y2) +-- tx optional translator x-vector +-- ty optional translator y-vector -- <32> x1 y1 x2 y2 -function gaCanvas:encode_line(x1, y1, x2, y2) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end +function gaCanvas:encode_line(x1, y1, x2, y2, tx, ty) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(y1) ~= "number" then return false, "[ArgErr: y1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(y2) ~= "number" then return false, "[ArgErr: y2] number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty + end local data = self._data data[#data + 1] = 32 -- append line data data[#data + 1] = x1 data[#data + 1] = y1 data[#data + 1] = x2 data[#data + 1] = y2 + return true, nil end -- insert an horizontal line from point (x1, y) to point (x2, y) +-- tx optional translator x-vector +-- ty optional translator y-vector -- <33> x1 x2 y -function gaCanvas:encode_hline(x1, x2, y) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y) ~= "number" then return "[ArgErr] 'y2' number expected" end +function gaCanvas:encode_hline(x1, x2, y, tx, ty) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(y) ~= "number" then return false, "[ArgErr: y] number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y = y + ty + end local data = self._data data[#data + 1] = 33 -- append hline data data[#data + 1] = x1 data[#data + 1] = x2 data[#data + 1] = y + return true, nil +end + +-- vline, Vertical line, from point (x, y1) to point (x, y2) +-- tx optional translator x-vector +-- ty optional translator y-vector +-- <34> y1 y2 x +function gaCanvas:encode_vline(y1, y2, x, tx, ty) --> ok, err + if type(y1) ~= "number" then return false, "[ArgErr] 'y1' number expected" end + if type(y2) ~= "number" then return false, "[ArgErr] 'y2' number expected" end + if type(x) ~= "number" then return false, "[ArgErr] 'x' number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x = x + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty + end + local data = self._data + data[#data + 1] = 34 -- append vline data + data[#data + 1] = y1 + data[#data + 1] = y2 + data[#data + 1] = x + return true, nil +end + +-- insert an open polyline +-- tx optional translator x-vector +-- ty optional translator y-vector +-- <38> x1 y1 x2, y2, ... , xn, yn +function gaCanvas:encode_polyline(point, tx, ty) --> ok, err + if type(point) ~= "table" then + return false, "[ArgErr: point] table expected" + end + local n, p + if point._classname == "Polyline" then + n, p = point:get_points() + else + local len = #point + if len == 0 then return false, "[Err] 'point' is an empty table" end + if (len % 2) ~= 0 then + return false, "[Err] 'point' is not an even long array" + end + n = len/2 + for _, coord in ipairs(point) do + if type(coord) ~= "number" then + return false, "[Err] found a non-number in the 'point' array" + end + end + p = point + end + if n < 2 then return + false, "[Err] a polyline must have at least two points" + end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + else + tx = 0 + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + else + ty = 0 + end + local data = self._data + data[#data + 1] = 38 + data[#data + 1] = n + for i = 1, 2*n, 2 do + data[#data + 1] = p[i] + tx + data[#data + 1] = p[i + 1] + ty + end + return true, nil end -- insert a rectangle from point (x1, x2) to (x2, y2) +-- tx optional translator x-vector +-- ty optional translator y-vector -- <48> -function gaCanvas:encode_rectangle(x1, y1, x2, y2) --> err - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end +function gaCanvas:encode_rect(x1, y1, x2, y2, tx, ty) --> ok, err + if type(x1) ~= "number" then return false, "[ArgErr] 'x1' number expected" end + if type(y1) ~= "number" then return false, "[ArgErr] 'y1' number expected" end + if type(x2) ~= "number" then return false, "[ArgErr] 'x2' number expected" end + if type(y2) ~= "number" then return false, "[ArgErr] 'y2' number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty + end local d = self._data d[#d + 1] = 48 -- append rectangle data d[#d + 1] = x1 d[#d + 1] = y1 d[#d + 1] = x2 d[#d + 1] = y2 + return true, nil end -- Vbar object: opcode <36> +-- tx optional translator x-vector +-- ty optional translator y-vector -- x0, y1, y2 ordinates -function gaCanvas:encode_Vbar(vbar, x0, y1, y2) --> err +function gaCanvas:encode_vbar(vbar, x0, y1, y2, tx, ty) --> ok, err if type(vbar) ~= "table" then - return "[ArgErr] table expected for 'vbar'" + return false, "[ArgErr: vbar] table expected" end if x0 == nil then x0 = 0 elseif type(x0) ~= "number" then - return "[ArgErr] 'x0' number expected" + return false, "[ArgErr: x0] number expected" end - if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end - if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end + if type(y1) ~= "number" then return false, "[ArgErr: y1] number expected" end + if type(y2) ~= "number" then return false, "[ArgErr: y2] number expected" end -- ordinates - if y1 == y2 then return "[ArgErr] 'y1' 'y2' are the same value" end + if y1 == y2 then return false, "[ArgErr: y1, y2] same value" end if y1 > y2 then y1, y2 = y2, y1 end - local bars = assert(vbar._yline, "[InternalErr] no '_yline' field") - local bdim = #bars - if bdim == 0 then return "[InternalErr] number of bars is zero" end - if bdim % 2 ~= 0 then - return "[InternalErr] '_yline' does not have an even number of elements" + local bdim, bars + if vbar._classname == "Vbar" then + bdim, bars = vbar:get_bars() + bdim = 2*bdim + else + bdim = #vbar + if bdim % 2 ~= 0 then -- bdim must be even + return false, "[Err: vbar] found an odd array of elements" + end + bars = vbar + end + if bdim == 0 then return false, "[Err: vbar] the number of bars is zero" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x0 = x0 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + y1 = y1 + ty + y2 = y2 + ty end local data = self._data data[#data + 1] = 36 -- vbar sequence start data[#data + 1] = y1 data[#data + 1] = y2 - data[#data + 1] = bdim / 2 -- the number of bars + data[#data + 1] = bdim/2 -- the number of bars, pair for i = 1, bdim, 2 do local coord = bars[i] local width = bars[i + 1] if type(coord) ~= "number" then - return "[Err] a coordinates is not a number" + return false, "[Err] a coordinates is not a number" end if type(width) ~= "number" then - return "[Err] a width is not a number" + return false, "[Err] a width is not a number" end data[#data + 1] = coord + x0 data[#data + 1] = width end + return true, nil end --- [text] <130> ax ay x y chars -function gaCanvas:encode_Text(txt, xpos, ypos, ax, ay) --> err +-- print a Vbar queue starting at x position 'xpos', between the horizontal line +-- tx optional translator x-vector +-- ty optional translator y-vector +-- at y0 and y1 y-coordinates +function gaCanvas:encode_vbar_queue(queue, xpos, y0, y1, tx, ty) --> ok, err + -- check arg + if type(queue) ~= "table" then + return false, "[ArgErr: queue] table expected" + end + if type(xpos) ~= "number" then + return false, "[ArgErr: xpos] number expected" + end + if type(y0) ~= "number" then + return false, "[ArgErr: y0] number expected" + end + if type(y1) ~= "number" then + return false, "[ArgErr: y1] number expected" + end + local i = 2 + while queue[i] do + local x = queue[i - 1] + xpos + local vbar = queue[i] + local _, err = self:encode_vbar(vbar, x, y0, y1, tx, ty) + if err then return false, err end + i = i + 2 + end + return true, nil +end + +-- tx optional translator x-vector +-- ty optional translator y-vector +-- [text] <130> ax ay xpos ypos chars +function gaCanvas:encode_Text(txt, xpos, ypos, ax, ay, tx, ty) --> ok, err if type(txt) ~= "table" then - return "[ArgErr] 'txt' object table expected" + return false, "[ArgErr: txt] object table expected" end if type(xpos) ~= "number" then - return "[ArgErr] 'xpos' number expected" + return false, "[ArgErr: xpos] number expected" end if type(ypos) ~= "number" then - return "[ArgErr] 'ypos' number expected" + return false, "[ArgErr: ypos] number expected" end if ax == nil then ax = 0 elseif type(ax) ~= "number" then - return "[ArgErr] 'ax' number expected" + return false, "[ArgErr: ax] number expected" end if ay == nil then ay = 0 elseif type(ay) ~= "number" then - return "[ArgErr] 'ay' number expected" + return false, "[ArgErr: ay] number expected" end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + xpos = xpos + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + ypos = ypos + ty + end + local chars = assert(txt.codepoint, "[InternalErr: txt] no 'codepoint' found") + if #chars == 0 then return false, "[InternalErr: txt] no chars found" end local data = self._data data[#data + 1] = 130 data[#data + 1] = ax -- relative anchor x-coordinate data[#data + 1] = ay -- relative anchor y-coordinate data[#data + 1] = xpos -- text x-coordinate data[#data + 1] = ypos -- text y-coordinate - local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") - if #chars == 0 then return "[InternalErr] 'txt' has no chars" end for _, c in ipairs(chars) do data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- glyphs equally spaced along the baseline +-- tx optional translator x-vector +-- ty optional translator y-vector -- [text_xspaced] <131> x1 xgap ay ypos chars -function gaCanvas:encode_Text_xspaced(txt, x1, xgap, ypos, ay) --> err - if type(txt)~= "table" then return "[ArgErr] 'txt' object table expected" end - local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") - if #chars == 0 then return "[InternalErr] 'txt' has no chars" end - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(xgap) ~= "number" then return "[ArgErr] 'xgap' number expected" end +function gaCanvas:encode_Text_xspaced(txt, x1, xgap, ypos, ay, tx, ty) --> ok, err + if type(txt)~= "table" then return false, "[ArgErr: txt] object table expected" end + local chars = assert(txt.codepoint, "[InternalErr: txt] no 'codepoint' found") + local n = #chars + if n == 0 then return false, "[InternalErr: txt] no chars found" end + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(xgap) ~= "number" then return false, "[ArgErr: xgap] number expected" end if xgap < 0 then local n = #chars x1 = x1 + (n - 1) * xgap xgap = -xgap end - if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end + if type(ypos) ~= "number" then return false, "[ArgErr: ypos] number expected" end if ay == nil then ay = 0 elseif type(ay) ~= "number" then - return "[ArgErr] 'ay' number expected" + return false, "[ArgErr: ay] number expected" + end + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + ypos = ypos + ty end local data = self._data data[#data + 1] = 131 data[#data + 1] = x1 -- x-coordinate of the first axis from left to right - data[#data + 1] = xgap -- axial distance among gliphs + data[#data + 1] = xgap -- axial distance between gliphs data[#data + 1] = ay -- anchor relative y-coordinate data[#data + 1] = ypos -- text y-coordinate for _, c in ipairs(chars) do data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- text_xwidth +-- tx optional translator x-vector +-- ty optional translator y-vector -- text equally spaced but within [x1, x2] coordinate interval -- <132> -function gaCanvas:encode_Text_xwidth(txt, x1, x2, ypos, ay) --> err - if type(txt)~= "table" then return "[ArgErr] 'txt' object table expected" end - if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end - if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end - if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end +function gaCanvas:encode_Text_xwidth(txt, x1, x2, ypos, ay, tx, ty) --> ok, err + if type(txt)~= "table" then return false, "[ArgErr: txt] object table expected" end + if type(x1) ~= "number" then return false, "[ArgErr: x1] number expected" end + if type(x2) ~= "number" then return false, "[ArgErr: x2] number expected" end + if type(ypos) ~= "number" then return false, "[ArgErr: ypos] number expected" end if ay == nil then ay = 0 elseif type(ay) ~= "number" then - return "[ArgErr] 'ay' number expected" + return false, "[ArgErr: ay] number expected" end - local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") - if #chars == 0 then return "[InternalErr] 'txt' has no chars" end + local chars = assert(txt.codepoint, "[InternalErr: txt] no 'codepoint' found") + if #chars == 0 then return false, "[InternalErr: txt] no chars found" end if x1 > x2 then x1, x2 = x2, x1 end -- reorder coordinates + + if tx ~= nil then + if type(tx) ~= "number" then return false, "[ArgErr: tx] number expected" end + x1 = x1 + tx + x2 = x2 + tx + end + if ty ~= nil then + if type(ty) ~= "number" then return false, "[ArgErr: ty] number expected" end + ypos = ypos + ty + end local data = self._data data[#data + 1] = 132 data[#data + 1] = ay -- anchor relative y-coordinate @@ -266,32 +582,35 @@ function gaCanvas:encode_Text_xwidth(txt, x1, x2, ypos, ay) --> err data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- experimental code section -- new opcodes under assessment -- [start_text_group] 140 -function gaCanvas:start_text_group() --> err +function gaCanvas:start_text_group() --> ok, err local data = self._data data[#data + 1] = 140 + return true, nil end -- [gtext] 141 -function gaCanvas:gtext(chars) --> err - if type(chars) ~= "table" then return "[ArgErr] 'chars' table expected" end +function gaCanvas:gtext(chars) --> ok, err + if type(chars) ~= "table" then return false, "[ArgErr: chars] table expected" end local data = self._data data[#data + 1] = 141 for _, c in ipairs(chars) do data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- [gtext_spaced] 142 gap string -function gaCanvas:gtext_spaced(gap, chars) --> err - if type(gap) ~= "number" then return "[ArgErr] 'gap' number expected" end - if type(chars) ~= "table" then return "[ArgErr] 'chars' table expected" end +function gaCanvas:gtext_spaced(gap, chars) --> ok, err + if type(gap) ~= "number" then return false, "[ArgErr: gap] number expected" end + if type(chars) ~= "table" then return false, "[ArgErr: chars] table expected" end local data = self._data data[#data + 1] = 142 data[#data + 1] = gap @@ -299,42 +618,32 @@ function gaCanvas:gtext_spaced(gap, chars) --> err data[#data + 1] = c end data[#data + 1] = 0 -- end string signal + return true, nil end -- [gtext_space] 143 gap -function gaCanvas:gtext_gap(gap) --> err - if type(gap) ~= "number" then return "[ArgErr] 'gap' number expected" end +function gaCanvas:gtext_gap(gap) --> ok, err + if type(gap) ~= "number" then return false, "[ArgErr: gap] number expected" end local data = self._data data[#data + 1] = 143 data[#data + 1] = gap + return true, nil end -- [end_text_group] 149 ax ay x y -function gaCanvas:end_text_group(xpos, ypos, ax, ay) --> err - if type(xpos) ~= "number" then return "[ArgErr] 'xpos' number expected" end - if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end - if type(ax) ~= "number" then return "[ArgErr] 'ax' number expected" end - if type(ay) ~= "number" then return "[ArgErr] 'ay' number expected" end +function gaCanvas:end_text_group(xpos, ypos, ax, ay) --> ok, err + if type(xpos) ~= "number" then return false, "[ArgErr: xpos] '' number expected" end + if type(ypos) ~= "number" then return false, "[ArgErr: ypos] number expected" end + if type(ax) ~= "number" then return false, "[ArgErr: ax] number expected" end + if type(ay) ~= "number" then return false, "[ArgErr: ay] number expected" end local data = self._data data[#data + 1] = 149 data[#data + 1] = ax -- anchor relative x-coordinate data[#data + 1] = ay -- anchor relative y-coordinate data[#data + 1] = xpos -- text x-coordinate data[#data + 1] = ypos -- text y-coordinate -end - --- amazing... -function gaCanvas:to_string() --> string - -end - -function gaCanvas:get_bbox() - -end - -function gaCanvas:check() --> boolean, err - + return true, nil end return gaCanvas diff --git a/macros/luatex/generic/barracuda/src/lib-geo/brcd-libgeo.lua b/macros/luatex/generic/barracuda/src/lib-geo/brcd-libgeo.lua index 630ed91b43..1e76ba1c67 100644 --- a/macros/luatex/generic/barracuda/src/lib-geo/brcd-libgeo.lua +++ b/macros/luatex/generic/barracuda/src/lib-geo/brcd-libgeo.lua @@ -1,20 +1,137 @@ - +-- this file is part of barracuda project +-- Copyright (C) 2019-2022 Roberto Giacomelli +-- see https://github.com/robitex/barracuda +-- -- libgeo simple Geometric Library --- Copyright (C) 2018 Roberto Giacomelli - --- All dimension must be in scaled point (sp) +-- All dimension must be in scaled point (sp) a TeX unit equal to 1/65536pt local libgeo = { - _VERSION = "libgeo v0.0.3", + _VERSION = "libgeo v0.0.6", _NAME = "libgeo", _DESCRIPTION = "simple geometric library", } --- VBar class +-- a simple tree structured Archive class +libgeo.Archive = {_classname = "Archive"} +local Archive = libgeo.Archive +Archive.__index = Archive + +function Archive:new() --> object + local o = { + _archive = {} + } + setmetatable(o, self) + return o +end + +function Archive:insert(o, ...) --> ok, err + if type(o) ~= "table" then + return false, "[Err] " + end + local a = self._archive + local keys = {...} + for i = 1, (#keys - 1) do -- dive into the tree + local k = keys[i] + local leaf = a[k] + if not leaf then + a[k] = {} + leaf = a[k] + end + a = leaf + end + local k = keys[#keys] + if a[k] ~= nil then + return false, "[Err] an object " + end + a[k] = o + return true, nil +end + +function Archive:contains_key(...) --> boolean + local a = self._archive + for _, k in ipairs{...} do + local leaf = a[k] + if leaf == nil then + return false + end + a = leaf + end + return true +end + +function Archive:get(...) --> object, err + local a = self._archive + for _, k in ipairs{...} do + local leaf = a[k] + if leaf == nil then + return nil, "[Err] key '"..k.."' not found" + end + a = leaf + end + return a, nil +end + +-- Queue Class +local VbarQueue = {_classname = "VbarQueue"} +libgeo.Vbar_queue = VbarQueue +VbarQueue.__index = VbarQueue + +function VbarQueue:new() + local o = { 0 } + setmetatable(o, self) + return o +end + +VbarQueue.__add = function (lhs, rhs) + if type(lhs) == "number" then -- dist + queue + local i = 1 + while rhs[i] do + rhs[i] = rhs[i] + lhs + i = i + 2 + end + return rhs + else -- queue + object + if type(rhs) == "number" then + lhs[#lhs] = lhs[#lhs] + rhs + return lhs + elseif type(rhs) == "table" then + if rhs._classname == "VbarQueue" then -- queue + queue + local q = {} + for _, v in ipairs(lhs) do + q[#q + 1] = v + end + local w = lhs[#lhs] + for i = 1, #rhs/2 do + q[#q + 1] = rhs[i] + w + q[#q + 1] = rhs[i + 1] + end + return q + elseif rhs._classname == "Vbar" then -- queue + vbar + local w = lhs[#lhs] + lhs[#lhs + 1] = rhs + lhs[#lhs + 1] = w + rhs._x_lim + return lhs + else + error("[Err] unsupported object type for queue operation") + end + else + error("[Err] unsupported type for queue operation") + end + end +end + +function VbarQueue:width() + return self[#self] - self[1] +end + +-- Vbar class -- a pure geometric entity of several infinite vertical lines -libgeo.Vbar = {} +libgeo.Vbar = {_classname = "Vbar"} local Vbar = libgeo.Vbar Vbar.__index = Vbar +Vbar.__add = function (lhs, rhs) + return VbarQueue:new() + lhs + rhs +end -- Vbar costructors @@ -23,6 +140,7 @@ function Vbar:from_array(yl_arr) --> assert(type(yl_arr) == "table", "'yline_array' is a mandatory arg") -- stream scanning local i = 1 + local nbars = 0 local xlim = 0.0 while yl_arr[i] do local x = yl_arr[i]; i = i + 1 @@ -30,12 +148,14 @@ function Vbar:from_array(yl_arr) --> assert(type(x) == "number", "[InternalErr] not a number") assert(type(w) == "number", "[InternalErr] not a number") xlim = x + w/2 + nbars = nbars + 1 end assert(i % 2 == 0, "[InternalErr] the index is not even") - assert(i > 0, "[InternalErr] empty array") + assert(nbars > 0, "[InternalErr] empty array") local o = { _yline = yl_arr, -- [, , ...] flat array _x_lim = xlim, -- right external bounding box coordinates + _nbars = nbars, -- number of bars } setmetatable(o, self) return o @@ -57,6 +177,7 @@ function Vbar:from_int(ngen, mod, is_bar) --> digits[#digits + 1] = d ngen = (ngen - d)/10 end + local nbars = 0 local x0 = 0.0 -- axis reference local yl = {} for k = #digits, 1, -1 do @@ -65,13 +186,16 @@ function Vbar:from_int(ngen, mod, is_bar) --> if is_bar then -- bar yl[#yl + 1] = x0 + w/2 yl[#yl + 1] = w + nbars = nbars + 1 end x0 = x0 + w is_bar = not is_bar end + assert(nbars > 0, "[InternalErr] no bars") local o = { _yline = yl, -- [, , ...] flat array _x_lim = x0, -- right external coordinate + _nbars = nbars, -- number of bars } setmetatable(o, self) return o @@ -86,7 +210,8 @@ function Vbar:from_int_revstep(ngen, mod, is_bar) --> if is_bar == nil then is_bar = true else assert(type(is_bar) == "boolean", "Invalid argument for is_bar") end - -- + -- + local nbars = 0 local x0 = 0.0 -- axis reference local i = 0 local yl = {} @@ -96,15 +221,18 @@ function Vbar:from_int_revstep(ngen, mod, is_bar) --> if is_bar then -- bar i = i + 1; yl[i] = x0 + w/2 i = i + 1; yl[i] = w + nbars = nbars + 1 end x0 = x0 + w is_bar = not is_bar ngen = (ngen - d)/10 end assert(not is_bar, "[InternalErr] the last element in not a bar") + assert(nbars > 0, "[InternalErr] no bars") local o = { _yline = yl, -- [, , ...] flat array _x_lim = x0, -- right external coordinate + _nbars = nbars, -- number of bars } setmetatable(o, self) return o @@ -126,8 +254,9 @@ function Vbar:from_int_revpair(ngen, mod, MOD, is_bar) --> else assert(type(is_bar) == "boolean", "Invalid argument for 'is_bar'") end + local nbars = 0 local yl = {} - local x0 = 0.0 + local x0 = 0.0 local k = 0 while ngen > 0 do local d = ngen % 10 -- digit @@ -140,14 +269,16 @@ function Vbar:from_int_revpair(ngen, mod, MOD, is_bar) --> if is_bar then -- bars k = k + 1; yl[k] = x0 + w/2 -- xcenter k = k + 1; yl[k] = w -- width + nbars = nbars + 1 end is_bar = not is_bar x0 = x0 + w end - assert(not is_bar, "[InternalErr] the last element is not a bar") + assert(nbars > 0, "[InternalErr] no bars") local o = { _yline = yl, -- [, , ...] flat array _x_lim = x0, -- external x coordinate + _nbars = nbars, -- number of bars } setmetatable(o, self) return o @@ -162,6 +293,7 @@ function Vbar:from_two_tab(tbar, tspace, mod, MOD) --> assert(type(mod) == "number", "Invalid argument for narrow module width") assert(type(MOD) == "number", "Invalid argument for wide module width") assert(mod < MOD, "Not ordered narrow/Wide values") + local nbars = 0 local x0 = 0.0 -- x-coordinate local yl = {} for i = 1, #tbar do @@ -176,6 +308,7 @@ function Vbar:from_two_tab(tbar, tspace, mod, MOD) --> yl[#yl + 1] = MOD -- bar width x0 = x0 + MOD end + nbars = nbars + 1 local is_narrow_space = tspace[i] assert(type(is_narrow_space) == "boolean", "[InternalErr] found a not boolean value") if is_narrow_space then @@ -184,17 +317,76 @@ function Vbar:from_two_tab(tbar, tspace, mod, MOD) --> x0 = x0 + MOD end end + assert(nbars > 0, "[InternalErr] no bars") local o = { _yline = yl, -- [, , ...] flat array _x_lim = x0, -- external x coordinate + _nbars = nbars, -- number of bars + } + setmetatable(o, self) + return o +end + +function Vbar:get_bars() --> nbars, + return self._nbars, self._yline +end + +-- Polyline class +local Polyline = {_classname = "Polyline"} +Polyline.__index = Polyline +libgeo.Polyline = Polyline + +-- optional argument a first point (x, y) +function Polyline:new(x, y) --> + local o = { + _point = {}, + _n = 0, } setmetatable(o, self) + if x ~= nil then + assert(type(x) == "number", "[Polyline:new()] Invalid type for x-coordinate") + assert(type(y) == "number", "[Polyline:new()] Invalid type for y-coordinate") + self:add_point(x, y) + end return o end +-- get a clone of points' coordinates +function Polyline:get_points() + local res = {} + local p = self._point + for i, c in ipairs(p) do + res[i] = c + end + return self._n, res +end + +-- append a new point with absolute coordinates +function Polyline:add_point(x, y) + assert(type(x) == "number", "[Polyline:add_point()] Invalid type for x-coordinate") + assert(type(y) == "number", "[Polyline:add_point()] Invalid type for y-coordinate") + local point = self._point + point[#point + 1] = x + point[#point + 1] = y + self._n = self._n + 1 +end + +-- append a new point with relative coordinates respect to the last one +function Polyline:add_relpoint(x, y) + assert(type(x) == "number", "Invalid type for x-coordinate") + assert(type(y) == "number", "Invalid type for y-coordinate") + local point = self._point + local n = self._n + assert(n > 0, "Attempt to add a relative point to an empty polyline") + local i = 2 * n + point[#point + 1] = point[i - 1] + x + point[#point + 1] = point[i] + y + self._n = n + 1 +end + -- Text class -libgeo.Text = {} +libgeo.Text = {_classname="Text"} local Text = libgeo.Text Text.__index = Text diff --git a/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.pdf b/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.pdf index b05ed417eb..9da41b5c50 100644 Binary files a/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.pdf and b/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.tex b/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.tex index 8932f9eaaf..ba055eb9d5 100644 --- a/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.tex +++ b/macros/luatex/generic/barracuda/test/test-barracuda-package/01-barracuda-latex-test.tex @@ -1,7 +1,7 @@ % !TeX program = LuaLaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli -% test file: make a Code39 barcodes in a LaTeX document +% test file: make Code39 barcodes in a LaTeX document \documentclass{article} \usepackage{barracuda} @@ -10,6 +10,17 @@ A\barracuda{code39}{123QWE}A B\barracuda[text_vpos='top']{code39}{123QWE}B -\end{document} +%\barracudasetup[option]{ treename } + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:barcode() +local code39 = assert(barcode:enc_by_name("code39")) +assert(code39:set_param{debug_bbox = "qz"}) +}\bigskip + +A\barracuda{code39}{123QWE}A +B\barracuda[text_vpos='top']{code39}{123QWE}B +\end{document} diff --git a/macros/luatex/generic/barracuda/test/test-barracuda-package/02-ord_iter-test.tex b/macros/luatex/generic/barracuda/test/test-barracuda-package/02-ord_iter-test.tex index 1b5d6509d4..89236a8bfc 100644 --- a/macros/luatex/generic/barracuda/test/test-barracuda-package/02-ord_iter-test.tex +++ b/macros/luatex/generic/barracuda/test/test-barracuda-package/02-ord_iter-test.tex @@ -1,5 +1,5 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \directlua{ local barracuda = require "barracuda" diff --git a/macros/luatex/generic/barracuda/test/test-code128/001-code128-test.lua b/macros/luatex/generic/barracuda/test/test-code128/001-code128-test.lua deleted file mode 100644 index 33dd927dc7..0000000000 --- a/macros/luatex/generic/barracuda/test/test-code128/001-code128-test.lua +++ /dev/null @@ -1,32 +0,0 @@ --- Copyright (C) 2020 Roberto Giacomelli - -local barracuda = require "barracuda" -local barcode = barracuda:barcode() -local c128, err = barcode:new_encoder("code128") -assert(not err, err) - -print(c128._NAME) -print(c128._VERSION) - -local info = c128:info() -print("encoder name = ", info.name) -print("description = ", info.description) -for k, tp in ipairs(info.param) do - print(k, tp.name, tp.value) -end - -local symb = c128:from_string("123") -print("Symbol char list:") -for _, c in ipairs(symb._code_data) do - print(c) -end - -local canvas = barracuda:new_canvas() - -symb:append_ga(canvas) - --- driver library -local drv = barracuda:get_driver() -drv:save("svg", canvas, "c128-123") - - diff --git a/macros/luatex/generic/barracuda/test/test-code128/001-code128-test.tex b/macros/luatex/generic/barracuda/test/test-code128/001-code128-test.tex new file mode 100644 index 0000000000..335b880d5b --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-code128/001-code128-test.tex @@ -0,0 +1,39 @@ +% !TeX program = LuaTeX +% Copyright (C) 2019-2022 Roberto Giacomelli + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:barcode() +local c128 = assert(barcode:new_encoder("code128")) +print() +print(c128._NAME) +print(c128._VERSION) + +local info = c128:info() +print("encoder name = ", info.name) +print("description = ", info.description) +for k, tp in ipairs(info.param) do + print(k, tp.name, tp.value) +end + +local symb = c128:new("123") +print("Symbol char list:") +for _, c in ipairs(symb:get_code()) do + print(c) +end +print("Symbol hri char list:") +for _, c in ipairs(symb:get_hri()) do + print(c) +end + + +local canvas = barracuda:new_canvas() + +symb:draw(canvas) + +% driver library +local drv = barracuda:get_driver() +drv:save("svg", canvas, "c128-123") +} +\bye + diff --git a/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.pdf b/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.pdf index 4cf993a396..731c7ca279 100644 Binary files a/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.pdf and b/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.tex b/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.tex index b5c081659e..9bb3915908 100644 --- a/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.tex +++ b/macros/luatex/generic/barracuda/test/test-code128/002-code128-test.tex @@ -1,12 +1,12 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \newbox\mybox \nopagenumbers Code 128 encoder test. -Test 1: one simple barcode with default parameter: +Test 1: one simple barcode with default parameters: \directlua{ barracuda = require "barracuda" @@ -14,7 +14,7 @@ barracuda = require "barracuda" \directlua{ local barcode = barracuda:barcode() - +barcode:set_param{debug_bbox="symb"} local c128, err = barcode:new_encoder("code128") assert(not err, err) @@ -22,7 +22,7 @@ local symbo, err = c128:from_string("5465468132546812") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") @@ -51,8 +51,8 @@ local s2_ax = s2:get_param("ax") assert(s2.ax == 0, "0 ax is "..tostring(s2.ax)) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) -s2:append_ga(canvas) +s1:draw(canvas) +s2:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") @@ -69,13 +69,13 @@ assert(c128, err) local s, err = c128:from_string("123456"); assert(s, err) local canvas = barracuda:new_canvas() -s:append_ga(canvas) +s:draw(canvas) local ok, err = s:set_param("ydim", tex.sp "30mm") -s:append_ga(canvas, tex.sp "20mm") +s:draw(canvas, tex.sp "20mm") local ok, err = s:set_param("ydim", tex.sp "60mm") -s:append_ga(canvas, tex.sp "40mm") +s:draw(canvas, tex.sp "40mm") local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") @@ -93,14 +93,14 @@ local c128, err = barcode:enc_by_name "code128"; assert(c128, err) local s, err = c128:from_string("ABCDEFGHI"); assert(s, err) local canvas = barracuda:new_canvas() -local _, err = s:append_ga(canvas); assert(not err, err) +local _, err = s:draw(canvas); assert(not err, err) % set ay to 0.5 for the encoder local ok, err = c128:set_param("ay", 0.5); assert(ok, err) -local _, err = s:append_ga(canvas, tex.sp "30mm"); assert(not err, err) +local _, err = s:draw(canvas, tex.sp "30mm"); assert(not err, err) % set locally to the symbol ay to 1.0 local ok, err = s:set_param("ay", 1) -local _, err = s:append_ga(canvas, tex.sp "60mm"); assert(not err, err) +local _, err = s:draw(canvas, tex.sp "60mm"); assert(not err, err) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") @@ -114,14 +114,96 @@ local c128, err = barcode:enc_by_name("code128"); assert(c128, err) local s, e = c128:from_uint(1234567890); assert(s, e) local canvas = barracuda:new_canvas() -local _, errc = s:append_ga(canvas); assert(not errc, errc) +local _, errc = s:draw(canvas); assert(not errc, errc) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") drv:save("native", canvas, "02-05-pdfliteral") }\box\mybox -That's all folks! +Test 6: encode ABC123: -\bye +\directlua{ +local barcode = barracuda:barcode() +local c128, err = barcode:enc_by_name "code128"; assert(c128, err) +local s, err = c128:from_string("ABC123"); assert(s, err) + +local canvas = barracuda:new_canvas() +local _, err = s:draw(canvas); assert(not err, err) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +}\box\mybox + +Test 7: encode ABC123999: + +\directlua{ +local barcode = barracuda:barcode() +local c128, err = barcode:enc_by_name "code128"; assert(c128, err) +local s, err = c128:from_string("ABC123999"); assert(s, err) + +local canvas = barracuda:new_canvas() +local _, err = s:draw(canvas); assert(not err, err) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +}\box\mybox + +Test 8: encode ABC123456789: + +\directlua{ +local barcode = barracuda:barcode() +local c128, err = barcode:enc_by_name "code128"; assert(c128, err) +local s, err = c128:from_string("ABC123456789"); assert(s, err) + +local canvas = barracuda:new_canvas() +local _, err = s:draw(canvas); assert(not err, err) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +}\box\mybox + +Test 9: encode A1B2C3D999: -function Driver:save(id_drv, ga, filename, ext) --> ok, err \ No newline at end of file +\directlua{ +local barcode = barracuda:barcode() +local c128, err = barcode:enc_by_name "code128"; assert(c128, err) +local s, err = c128:from_string("A1B2C3D999"); assert(s, err) + +local canvas = barracuda:new_canvas() +local _, err = s:draw(canvas); assert(not err, err) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +}\box\mybox + +Test 10: encode 123abcedfg: + +\directlua{ +local barcode = barracuda:barcode() +local c128, err = barcode:enc_by_name "code128"; assert(c128, err) +local s, err = c128:from_string("123abcedfg"); assert(s, err) + +local canvas = barracuda:new_canvas() +local _, err = s:draw(canvas); assert(not err, err) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +}\box\mybox + +Test 11: encode 999Aaaa: + +\directlua{ +local barcode = barracuda:barcode() +barcode:set_param{debug_bbox="none"} +local c128, err = barcode:enc_by_name "code128"; assert(c128, err) +local s, err = c128:from_string("999Aaaa"); assert(s, err) + +local canvas = barracuda:new_canvas() +local _, err = s:draw(canvas); assert(not err, err) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +}\box\mybox + +That's all folks! +\bye diff --git a/macros/luatex/generic/barracuda/test/test-code128/02-05-pdfliteral.txt b/macros/luatex/generic/barracuda/test/test-code128/02-05-pdfliteral.txt index fe16d33c50..894b9f1d4a 100644 --- a/macros/luatex/generic/barracuda/test/test-code128/02-05-pdfliteral.txt +++ b/macros/luatex/generic/barracuda/test/test-code128/02-05-pdfliteral.txt @@ -1,4 +1,8 @@ q +1.000000 w +0 J +0 j +[] 0 d -53.574521 -14.173154 1.190545 28.346308 re -51.788704 -14.173154 0.595272 28.346308 re -50.002887 -14.173154 1.785817 28.346308 re @@ -40,4 +44,8 @@ S -1.190545 -14.173154 1.190545 28.346308 re f S +0.100000 w +[6.000000 3.000000] 3.000000 d +-53.524521 -14.123154 53.474521 28.246308 re S +[] 0 d Q \ No newline at end of file diff --git a/macros/luatex/generic/barracuda/test/test-code39/001-code39-test.lua b/macros/luatex/generic/barracuda/test/test-code39/001-code39-test.lua deleted file mode 100644 index a9d8894ba0..0000000000 --- a/macros/luatex/generic/barracuda/test/test-code39/001-code39-test.lua +++ /dev/null @@ -1,41 +0,0 @@ --- Copyright (C) 2020 Roberto Giacomelli --- test Code 39 encoder - -local barracuda = require "barracuda" - -for k, v in pairs(barracuda) do - print(k,v) -end - -local barcode = barracuda:barcode() - -local c39, err = barcode:new_encoder("code39") -assert(not err, err) - -print(c39._NAME) -print(c39._VERSION) - -local info = c39:info() - -print("encoder name = ", info.name) -print("description = ", info.description) - -for k, tp in ipairs(info.param) do - print(k, tp.name, tp.value) -end - -local symb = c39:from_string("123") - -print("print internal representation of chars") -for _, c in ipairs(symb._code_data) do - print(c) -end -print() - -local canvas = barracuda:new_canvas() -symb:append_ga(canvas) - --- native driver -local drv = barracuda:get_driver() - -for _, code in ipairs(canvas._data) do print(code) end diff --git a/macros/luatex/generic/barracuda/test/test-code39/001-code39-test.tex b/macros/luatex/generic/barracuda/test/test-code39/001-code39-test.tex new file mode 100644 index 0000000000..c08e1f242a --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-code39/001-code39-test.tex @@ -0,0 +1,39 @@ +% !TeX program = LuaTeX +% Copyright (C) 2019-2022 Roberto Giacomelli +% test Code 39 encoder + +\directlua{ +local barracuda = require "barracuda" + +for k, v in pairs(barracuda) do + print(k, v) +end + +local barcode = barracuda:barcode() + +local c39, err = barcode:new_encoder("code39") +assert(not err, err) + +print(c39._NAME) +print(c39._VERSION) + +local info = c39:info() + +print("encoder name = ", info.name) +print("description = ", info.description) +for k, tp in ipairs(info.param) do + print(k, tp.name, tp.value) +end + +local symb = c39:from_string("123") + +print("print internal representation of chars") +print(table.concat(symb:get_code(), " ")) +print("end") +assert(symb:get_hri() == nil) + +local canvas = barracuda:new_canvas() +symb:draw(canvas) +% canvas:prettyprint_ga() +} +\bye diff --git a/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.pdf b/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.pdf index 63ced9a342..c114e9339f 100644 Binary files a/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.pdf and b/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.tex b/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.tex index eb1693b5ba..f242fafa4d 100644 --- a/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.tex +++ b/macros/luatex/generic/barracuda/test/test-code39/002-code39-test.tex @@ -1,5 +1,5 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \newbox\mybox \nopagenumbers @@ -19,10 +19,10 @@ local symbol, err = c39:from_string("ABC12QJ31") assert(not err, err) local canvas = barracuda:new_canvas() -symbol:append_ga(canvas) +symbol:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox +}\leavevmode\box\mybox Test 2: get the reference of the previous encoder and typeset two Code 39 symbols on the same canvas, one above to the other: @@ -36,13 +36,13 @@ local s1, err = c39:from_string("ZKPQJ31"); assert(s1, err) local s2, err = c39:from_string("RTFG746", {text_vpos="top"}); assert(s2, err) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) +s1:draw(canvas) local h2 = s2:get_param("height") -s2:append_ga(canvas, 0.0, h2 + tex.sp "5pt") +s2:draw(canvas, 0.0, h2 + tex.sp "5pt") local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox +}\leavevmode\box\mybox Test 3: with the same encoder print a symbol, change globally the height, and reprint the same symbol again on the same canvas: @@ -55,17 +55,17 @@ assert(c39, err) local s1, err = c39:from_string("ZKPQJ31"); assert(s1, err) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) +s1:draw(canvas) local h = s1:get_param("height") c39:set_param("height", 2*h) c39:set_param {text_vpos = "top"} -s1:append_ga(canvas, 0.0, h + tex.sp "5pt") +s1:draw(canvas, 0.0, h + tex.sp "5pt") local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox +}\leavevmode\box\mybox Test 4: do the same in test 3 but change locally parameters as height and text properties: @@ -78,7 +78,7 @@ assert(c39, err) local s1, err = c39:from_string("0123456789"); assert(s1, err) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) +s1:draw(canvas) local h, err = s1:get_param("height"); assert(h, err) local ok, err = s1:set_param{ height = h/2, @@ -88,27 +88,30 @@ local ok, err = s1:set_param{ text_star = true, ay = 1, }; assert(ok, err) -s1:append_ga(canvas, 0.0, - tex.sp "5pt") +s1:draw(canvas, 0.0, - tex.sp "5pt") local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox +}\leavevmode\box\mybox -Test 5: create a new encoder with a large module value: +Test 5: create a new encoder with a large module value. +It's also activeted the debug\_bbox\_on option. + +\bigskip \directlua{ local barcode = barracuda:barcode() -local c39, err = barcode:new_encoder("code39:e2", {module = tex.sp "0.5mm"}) +local c39, err = barcode:new_encoder("code39:e2", {module = tex.sp "0.5mm", debug_bbox_on = true}) assert(c39, err) local s1, err = c39:from_string("02040608"); assert(s1, err) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) +s1:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox +}\leavevmode\box\mybox \bye diff --git a/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.pdf b/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.pdf index 544a4b34ff..3dcd314a4a 100644 Binary files a/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.pdf and b/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.tex b/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.tex index 884cdd0df4..d9df0e8110 100644 --- a/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.tex +++ b/macros/luatex/generic/barracuda/test/test-code39/003-code39-test.tex @@ -1,5 +1,5 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \newbox\mybox \nopagenumbers @@ -18,33 +18,35 @@ local ok, err = c39:set_param("text_vpos", "top") assert(ok, err) local canvas = barracuda:new_canvas() -symbol:append_ga(canvas) +symbol:draw(canvas) local ok, err = symbol:set_param("text_hpos", "center") assert(ok, err) -symbol:append_ga(canvas, tex.sp "4.5cm") +symbol:draw(canvas, tex.sp "4.5cm") local ok, err = symbol:set_param("text_hpos", "right") assert(ok, err) -symbol:append_ga(canvas, tex.sp "9.0cm") +symbol:draw(canvas, tex.sp "9.0cm") local ok, err = c39:set_param("text_vpos", "bottom") assert(ok, err) local ok, err = symbol:set_param("text_hpos", "left") -symbol:append_ga(canvas, 0, tex.sp "-2.0cm") +symbol:draw(canvas, 0, tex.sp "-2.0cm") local ok, err = symbol:set_param("text_hpos", "center") assert(ok, err) -symbol:append_ga(canvas, tex.sp "4.5cm", tex.sp "-2.0cm") +symbol:draw(canvas, tex.sp "4.5cm", tex.sp "-2.0cm") local ok, err = symbol:set_param("text_hpos", "right") assert(ok, err) -symbol:append_ga(canvas, tex.sp "9.0cm", tex.sp "-2.0cm") +symbol:draw(canvas, tex.sp "9.0cm", tex.sp "-2.0cm") local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox +} +\bigskip +\leavevmode\box\mybox \bye diff --git a/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.pdf b/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.pdf index 0e5bfa42d0..660dd4a1fa 100644 Binary files a/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.pdf and b/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.tex b/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.tex index 9066d4dee8..1af5fdaaa0 100644 --- a/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.tex +++ b/macros/luatex/generic/barracuda/test/test-code39/004-code39-test.tex @@ -1,5 +1,5 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \newbox\mybox \nopagenumbers @@ -17,11 +17,11 @@ symbol, err = c39:from_uint(0, {text_hpos="center"}) assert(not err, err) local canvas = barracuda:new_canvas() -symbol:append_ga(canvas) +symbol:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox +}\bigskip\leavevmode\box\mybox \directlua{ local c39, err = barracuda:barcode() @@ -33,10 +33,9 @@ symbol, e = c39:from_uint(0123456789, {text_hpos="spaced",text_star=true}) assert(not e, e) local canvas = barracuda:new_canvas() -symbol:append_ga(canvas) +symbol:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -}\box\mybox - +}\bigskip\leavevmode\box\mybox \bye diff --git a/macros/luatex/generic/barracuda/test/test-code39/006-code39-test.lua b/macros/luatex/generic/barracuda/test/test-code39/006-code39-test.lua index 1b8ee9f4a1..0ad6169fca 100644 --- a/macros/luatex/generic/barracuda/test/test-code39/006-code39-test.lua +++ b/macros/luatex/generic/barracuda/test/test-code39/006-code39-test.lua @@ -14,29 +14,29 @@ local ok, err = c39:set_param("text_vpos", "top") assert(ok, err) local canvas = barracuda:new_canvas() -symbol:append_ga(canvas) +symbol:draw(canvas) local ok, err = symbol:set_param("text_hpos", "center") assert(ok, err) -symbol:append_ga(canvas, 4.5*cm) +symbol:draw(canvas, 4.5*cm) local ok, err = symbol:set_param("text_hpos", "right") assert(ok, err) -symbol:append_ga(canvas, 9.0*cm) +symbol:draw(canvas, 9.0*cm) local ok, err = c39:set_param("text_vpos", "bottom") assert(ok, err) local ok, err = symbol:set_param("text_hpos", "left") -symbol:append_ga(canvas, 0, -2.0*cm) +symbol:draw(canvas, 0, -2.0*cm) local ok, err = symbol:set_param("text_hpos", "center") assert(ok, err) -symbol:append_ga(canvas, 4.5*cm, -2.0*cm) +symbol:draw(canvas, 4.5*cm, -2.0*cm) local ok, err = symbol:set_param("text_hpos", "right") assert(ok, err) -symbol:append_ga(canvas, 9.0*cm, -2.0*cm) +symbol:draw(canvas, 9.0*cm, -2.0*cm) local drv = barracuda:get_driver() drv:save("svg", canvas, "006-six") diff --git a/macros/luatex/generic/barracuda/test/test-code39/007-code39-test.pdf b/macros/luatex/generic/barracuda/test/test-code39/007-code39-test.pdf new file mode 100644 index 0000000000..e49b38b256 Binary files /dev/null and b/macros/luatex/generic/barracuda/test/test-code39/007-code39-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-code39/007-code39-test.tex b/macros/luatex/generic/barracuda/test/test-code39/007-code39-test.tex new file mode 100644 index 0000000000..5090e54058 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-code39/007-code39-test.tex @@ -0,0 +1,39 @@ +% !TeX program = LuaTeX +% Copyright (C) 2019-2022 Roberto Giacomelli + +\newbox\mybox +\nopagenumbers + +\directlua{ +barracuda = require "barracuda" +local c39 = assert( + barracuda:barcode() + :new_encoder("code39", {debug_bbox_on = true}) +) + +local bars = c39:new { + 123456, + "123456", + "ABCDEF", + 87429, + 982398, + "HDUHBE" +} + +local canvas = barracuda:new_canvas() +local tx, ty = 0, 0 +local dh = tex.sp "40pt" +for _, b in ipairs(bars) do + b:draw(canvas, tx, ty) + ty = ty + dh +end + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} + +Test 1: check Barcode recursive costructor new(): +\bigskip +\leavevmode\box\mybox +\bye + diff --git a/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.pdf b/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.pdf index 12eac36ba1..bc9d8f894b 100644 Binary files a/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.pdf and b/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.tex b/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.tex index 7c7b373a6c..42850bcd13 100644 --- a/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.tex +++ b/macros/luatex/generic/barracuda/test/test-ean/001-13-ean-test.tex @@ -1,5 +1,5 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \newbox\mybox \nopagenumbers @@ -11,6 +11,7 @@ Test 1: one simple barcode EAN13 with default parameter: \directlua{ barracuda = require "barracuda" local barcode = barracuda:barcode() +barcode:set_param{debug_bbox="qz"} local ean13, err = barcode:new_encoder("ean-13") assert(not err, err) @@ -19,7 +20,7 @@ local symbo, err = ean13:from_string("8006194056290") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") @@ -39,7 +40,7 @@ local symbo, err = ean8:from_string("96385074") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") @@ -56,7 +57,7 @@ assert(not err, err) local symbo, err = ean5:from_string("54495") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") } @@ -72,7 +73,7 @@ assert(not err, err) local symbo, err = ean2:from_string("53") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") } @@ -89,7 +90,7 @@ local c = assert(ean:checksum(n)) local symbo, err = ean:from_string(n..c.."12345") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") } @@ -107,7 +108,7 @@ local s = n .. c local symbo, err = ean:from_string(s.."12") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") } @@ -125,7 +126,7 @@ local s = n .. c local symbo, err = ean:from_string(s.."12345") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") } @@ -143,7 +144,7 @@ local s = n .. c local symbo, err = ean:from_string(s.."88") assert(not err, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") } @@ -167,10 +168,10 @@ local s = n .. c local symbo, err = ean:from_string(s); assert(not err, err) local ok, err = symbo:set_param("height", tex.sp "5mm"); assert(ok, err) local canvas = barracuda:new_canvas() -symbo:append_ga(canvas) +symbo:draw(canvas) local s2, err = ean:from_uint(8001120972163); assert(not err, err) -s2:append_ga(canvas, tex.sp "45mm", 0) +s2:draw(canvas, tex.sp "45mm", 0) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") @@ -191,12 +192,12 @@ local ok, err = ean:set_param("height", tex.sp "5mm"); assert(ok, err) local n = 758458535897; local c = ean:checksum(n); local s = n .. c local s1, err = ean:from_string(s); assert(not err, err) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) +s1:draw(canvas) local s2, err = ean:from_uint(8001120972163); assert(not err, err) -s2:append_ga(canvas, tex.sp "40mm", 0) +s2:draw(canvas, tex.sp "40mm", 0) local s3, err = ean:from_uint(8000570000310); assert(not err, err) local ok, e = s3:set_param{height = tex.sp "10mm"}; assert(ok, e) -s3:append_ga(canvas, tex.sp "90mm", 0) +s3:draw(canvas, tex.sp "90mm", 0) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") } diff --git a/macros/luatex/generic/barracuda/test/test-ean/002-ean-test.pdf b/macros/luatex/generic/barracuda/test/test-ean/002-ean-test.pdf index 796ad29ab0..54762d4dfc 100644 Binary files a/macros/luatex/generic/barracuda/test/test-ean/002-ean-test.pdf and b/macros/luatex/generic/barracuda/test/test-ean/002-ean-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-ean/003-ean-test.pdf b/macros/luatex/generic/barracuda/test/test-ean/003-ean-test.pdf index c52c77a847..cfeea7167f 100644 Binary files a/macros/luatex/generic/barracuda/test/test-ean/003-ean-test.pdf and b/macros/luatex/generic/barracuda/test/test-ean/003-ean-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-ean/004-ean-test.lua b/macros/luatex/generic/barracuda/test/test-ean/004-ean-test.lua deleted file mode 100644 index 017e0725b8..0000000000 --- a/macros/luatex/generic/barracuda/test/test-ean/004-ean-test.lua +++ /dev/null @@ -1,9 +0,0 @@ - -local barracuda = require "barracuda" -barracuda:save("ean-13", "8006194056290", "8006194056290") - - - - - - diff --git a/macros/luatex/generic/barracuda/test/test-ean/004-ean-test.tex b/macros/luatex/generic/barracuda/test/test-ean/004-ean-test.tex new file mode 100644 index 0000000000..4d9b5208e9 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-ean/004-ean-test.tex @@ -0,0 +1,6 @@ +% !TeX program = LuaTeX +\directlua{ +local barracuda = require "barracuda" +barracuda:save("ean-13", "8006194056290", "8006194056290") +} +\bye diff --git a/macros/luatex/generic/barracuda/test/test-ean/005-isbn-test.pdf b/macros/luatex/generic/barracuda/test/test-ean/005-isbn-test.pdf index d71e87141d..ad4028750c 100644 Binary files a/macros/luatex/generic/barracuda/test/test-ean/005-isbn-test.pdf and b/macros/luatex/generic/barracuda/test/test-ean/005-isbn-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.pdf b/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.pdf index 57f3739fb7..a40f50669e 100644 Binary files a/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.pdf and b/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.tex b/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.tex index 576963bd81..61148b0b70 100644 --- a/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.tex +++ b/macros/luatex/generic/barracuda/test/test-ean/006-issn-test.tex @@ -30,28 +30,30 @@ barracuda:hbox("ean-issn+5", ars_issn.online.."00028", "mybox") \vskip10pt \leavevmode -\directlua{barracuda:hbox("ean-issn", "1828-2350", "mybox")} +\directlua{ +local barcode = barracuda:barcode() +barcode:set_param("debug_bbox_on", true) +barracuda:hbox("ean-issn", "1828-2350", "mybox") +} \box\mybox \vskip10pt \leavevmode -\directlua{barracuda:hbox("ean-issn", "1828-2350 [01]", "mybox")} +\directlua{ +barracuda:hbox("ean-issn+2", "1828-2350 [01] 22", "mybox") +barracuda:save("ean-issn+2", "1828-2350 [01] 22", "ars") +} \box\mybox \vskip10pt \leavevmode -\directlua{barracuda:hbox("ean-issn+5", "1828-2350 [01] 00028", "mybox")} +\directlua{barracuda:hbox("ean-issn", "1828-2350 [01]", "mybox")} \box\mybox \vskip10pt \leavevmode -\directlua{ -barracuda:hbox("ean-issn+2", "1828-2350 [01] 22", "mybox") -barracuda:save("ean-issn+2", "1828-2350 [01] 22", "ars") -} +\directlua{barracuda:hbox("ean-issn+5", "1828-2350 [01] 00028", "mybox")} \box\mybox - \bye - diff --git a/macros/luatex/generic/barracuda/test/test-ean/8006194056290.svg b/macros/luatex/generic/barracuda/test/test-ean/8006194056290.svg index f7965e94d4..e553800370 100644 --- a/macros/luatex/generic/barracuda/test/test-ean/8006194056290.svg +++ b/macros/luatex/generic/barracuda/test/test-ean/8006194056290.svg @@ -11,6 +11,14 @@ + + + + + + + + @@ -35,10 +43,6 @@ - - - - @@ -63,10 +67,6 @@ - - - - 8 diff --git a/macros/luatex/generic/barracuda/test/test-ean/ars.svg b/macros/luatex/generic/barracuda/test/test-ean/ars.svg index 5bfc01d0f3..8f48c1054e 100644 --- a/macros/luatex/generic/barracuda/test/test-ean/ars.svg +++ b/macros/luatex/generic/barracuda/test/test-ean/ars.svg @@ -11,6 +11,14 @@ + + + + + + + + @@ -35,10 +43,6 @@ - - - - @@ -63,10 +67,6 @@ - - - - 9 diff --git a/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.pdf b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.pdf index b3f3336f43..d741453c5b 100644 Binary files a/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.pdf and b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.tex b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.tex index c51fa3dfb0..a40ba4ec8b 100644 --- a/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.tex +++ b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/001-ga-pdfliteral-test.tex @@ -1,7 +1,7 @@ % !TeX program = LuaTeX % test for ga-canvas pdfliteral driver % -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli % see LICENSE.txt file ---ga--- is a binary format as an istruction set similar to @@ -28,35 +28,36 @@ the PDF output file. \newbox\mybox \directlua{ - driver = require [[lib-driver.brcd-driver]] % global Lua variables + brcd = require "barracuda" + driver = brcd:get_driver() % global Lua variables pt = tex.sp [[1pt]] % 1pt = 65536sp } Let's start drawing an horizontal line 100pt long: \directlua{ - local ga = {_data = {33, 0*pt, 100*pt, 0*pt}} + local ga = {33, 0*pt, 100*pt, 0*pt} driver:ga_to_hbox(ga, [[mybox]]) }\box\mybox or two different parallel lines 24pt long: \directlua{ - local ga = {_data = {33, 0*pt, 24*pt, 0*pt, 33, 0*pt, 24*pt, 5*pt}} + local ga = {33, 0*pt, 24*pt, 0*pt, 33, 0*pt, 24*pt, 5*pt} driver:ga_to_hbox(ga, [[mybox]]) }\box\mybox and again two horizontal lines 10pt thick, touching a corner: \directlua{ - local ga = {_data = { + local ga = { 1, 10*pt, 33, -24*pt, 0*pt, -5*pt, 33, 0*pt, 24*pt, 5*pt, - }} + } driver:ga_to_hbox(ga, [[mybox]]) }\box\mybox Several vertical lines with its horizontal limits: \directlua{ - local ga = { _data = { + local ga = { 34, -20*pt, 20*pt, 0*pt, 34, -15*pt, 15*pt, 5*pt, 34, -10*pt, 10*pt, 10*pt, @@ -69,16 +70,16 @@ Several vertical lines with its horizontal limits: 1, .05*pt, 33, 0*pt, 40*pt, -20*pt, 33, 0*pt, 40*pt, 20*pt, - }} + } driver:ga_to_hbox(ga, [[mybox]]) }\box\mybox Finally a little rectangle: \directlua{ - local ga = {_data = { + local ga = { 1, 5*pt, 48, 0*pt, 0*pt, 15*pt, 10*pt, - }} + } driver:ga_to_hbox(ga, [[mybox]]) }\box\mybox @@ -86,7 +87,7 @@ Finally a little rectangle: Test number 1: a vbar 2pt width, 20pt height: \directlua{ % vbar: <36> y1 y2 x1 w1 x2 w2 ... xn wn - local ga = {_data = {36, 0, 20*pt, 1, 0.0, 2*pt}} + local ga = {36, 0, 20*pt, 1, 0.0, 2*pt} driver:ga_to_hbox(ga, [[mybox]]) }\box\mybox @@ -98,7 +99,7 @@ Test number 2: ten vbars in a row equally spaced by 10pt: ga[i*2 + 5] = 5*pt + i*20*pt ga[i*2 + 6] = 10*pt end - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip @@ -117,7 +118,7 @@ Test number 3: two series of vbars 10pt and 5pt large: ga[i*2 + 29] = 15*pt + i*20*pt ga[i*2 + 30] = 5*pt end - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip @@ -132,7 +133,7 @@ Test number 4: a bunch of thin vertical bars (25): ga[i*2 + 5] = 1*pt + i*4*pt ga[i*2 + 6] = 2*pt end - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule A\box\mybox A\vrule \bigskip @@ -155,7 +156,7 @@ Test number 5: two rows of a bunch of thin bars: ga[i*2 + 59] = 3*pt + i*4*pt ga[i*2 + 60] = 2*pt end - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip @@ -181,7 +182,7 @@ Test number 6: staircase of Vbars (manually data definition): 25*pt, % x 10*pt, % w } - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip @@ -219,7 +220,7 @@ Test number 7: vbars with spaced text, in three different rows: ga[52] = 71 % G ga[53] = 72 % H ga[54] = 0 - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip @@ -271,7 +272,7 @@ Test number 8: spaced text (checking the correct vertical alignment): ga[66] = 55 % 7 ga[67] = 56 % 8 ga[68] = 0 - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip @@ -323,7 +324,7 @@ Test number 9: spaced text, check correct vertical alignment: ga[66] = 55 % 7 ga[67] = 56 % 8 ga[68] = 0 - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip @@ -356,11 +357,11 @@ Test number 10: two centered texts aligned to the baseline: ga[23] = 56 % 8 ga[24] = 57 % 9 ga[25] = 0 - driver:ga_to_hbox({_data = ga}, [[mybox]]) + driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip -So far, we have manually build data for ga stream. Next we are going to +So far, we have manually build data for ga stream. For now on, we are going to use the ga-canvas library. \bigskip @@ -368,26 +369,22 @@ In fact, all the previous tests are rebuild with the ga-canvas library. Test 1: a vbar 2pt width, 20pt height: \directlua{ - gacanvas = require "lib-geo.brcd-gacanvas" - local ga = gacanvas:new() - local vbar = {_yline = {0.0, 2*pt}} - local err = ga:encode_Vbar(vbar, 0.0, 0.0, 20*pt) % x, w - assert(not err, err) + local ga = brcd:new_canvas() + local vbar = {0.0, 2*pt} + assert(ga:encode_vbar(vbar, 0.0, 0.0, 20*pt)) % x, w driver:ga_to_hbox(ga, [[mybox]]) }\box\mybox \bigskip Test 2: ten vbars equally spaced by 10pt: \directlua{ - local ga = gacanvas:new() - local data = {} + local ga = brcd:new_canvas() + local bars = {} for i = 0, 9 do - data[i*2 + 1] = 5*pt + i*20*pt % x - data[i*2 + 2] = 10*pt % w + bars[i*2 + 1] = 5*pt + i*20*pt % x + bars[i*2 + 2] = 10*pt % w end - local bars = {_yline = data} - local err = ga:encode_Vbar(bars, 0.0, 0.0, 10*pt) - assert(not err, err) + assert(ga:encode_vbar(bars, 0.0, 0.0, 10*pt)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -404,11 +401,9 @@ Test 3: two series of vbars 10pt and 5pt large: b2[i*2 + 1] = i*20*pt b2[i*2 + 2] = 5*pt end - local ga = gacanvas:new() - local err = ga:encode_Vbar({_yline=b1}, 0.0, 0.0, 10*pt) - assert(not err, err) - err = ga:encode_Vbar({_yline=b2}, 10.0*pt, 2.5*pt, 7.5*pt) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_vbar(b1, 0.0, 0.0, 10*pt)) + assert(ga:encode_vbar(b2, 10.0*pt, 2.5*pt, 7.5*pt)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -420,9 +415,8 @@ Test 4: a bunch of thin bars: b[i*2 + 1] = 1*pt + i*4*pt b[i*2 + 2] = 2*pt end - local ga = gacanvas:new() - local err = ga:encode_Vbar({_yline=b}, 0.0, 5*pt, 25*pt) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_vbar(b, 0.0, 5*pt, 25*pt)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule{ }\box\mybox{ }\vrule @@ -434,42 +428,34 @@ Test 5: two levels of a bunch of thin bars: b[i*2 + 1] = i*4*pt b[i*2 + 2] = 2*pt end - local b = {_yline=b} - local ga = gacanvas:new() - local err = ga:encode_Vbar(b, 0.0, 5*pt, 25*pt) - assert(not err, err) - err = ga:encode_Vbar(b, 2*pt, 25*pt, 45*pt, b) + local ga = brcd:new_canvas() + assert(ga:encode_vbar(b, 0.0, 5*pt, 25*pt)) + assert(ga:encode_vbar(b, 2*pt, 25*pt, 45*pt, b)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip Test number 6: staircase of bars (manual insertion of data): \directlua{ - local b = {_yline={0.0, 10*pt}} - local ga = gacanvas:new() - local err = ga:encode_Vbar(b, 0.0, 0.0, 20*pt) - assert(not err, err) - err = ga:encode_Vbar(b, 10*pt, 20*pt, 40*pt) - assert(not err, err) - err = ga:encode_Vbar(b, 20*pt, 40*pt, 60*pt) - assert(not err, err) + local b = {0.0, 10*pt} + local ga = brcd:new_canvas() + assert(ga:encode_vbar(b, 0.0, 0.0, 20*pt)) + assert(ga:encode_vbar(b, 10*pt, 20*pt, 40*pt)) + assert(ga:encode_vbar(b, 20*pt, 40*pt, 60*pt)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule \bigskip Test number 7: vbars with spaced text, all in three rows: \directlua{ - local b = {} + local vb = {} for i = 0,7 do - b[i*2+1] = i*10*pt - b[i*2+2] = 5*pt + vb[i*2+1] = i*10*pt + vb[i*2+2] = 5*pt end - local vb = {_yline=b} - local ga = gacanvas:new() - local err = ga:encode_Vbar(vb, 0.0, 0.0, 20*pt) - assert(not err, err) - local err = ga:encode_Vbar(vb, 0.0, 30*pt, 50*pt) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_vbar(vb, 0.0, 0.0, 20*pt)) + assert(ga:encode_vbar(vb, 0.0, 30*pt, 50*pt)) local txt = {codepoint = { 65, % A 66, % B @@ -480,8 +466,7 @@ Test number 7: vbars with spaced text, all in three rows: 71, % G 72, % H }} - err = ga:encode_Text_xspaced(txt, 0.0, 10*pt, 25*pt, 0.5) - assert(not err, err) + assert(ga:encode_Text_xspaced(txt, 0.0, 10*pt, 25*pt, 0.5)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -493,12 +478,9 @@ Test 8: spaced text, check correct vertical alignment: b[i*2+1] = i*10*pt b[i*2+2] = 2*pt end - b = {_yline=b} - local ga = gacanvas:new() - local err = ga:encode_Vbar(b, 0.0, 0.0, 20*pt) - assert(not err, err) - local err = ga:encode_Vbar(b, 0.0, 40*pt, 60*pt) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_vbar(b, 0.0, 0.0, 20*pt)) + assert(ga:encode_vbar(b, 0.0, 40*pt, 60*pt)) local c = { codepoint = { 65, % A 66, % B @@ -509,8 +491,7 @@ Test 8: spaced text, check correct vertical alignment: 71, % G 72, % H }} - err = ga:encode_Text_xspaced(c, 0.0, 10*pt, 30*pt, 0.0) - assert(not err, err) + assert(ga:encode_Text_xspaced(c, 0.0, 10*pt, 30*pt, 0.0)) local n = { codepoint = { 49, % 1 50, % 2 @@ -521,8 +502,7 @@ Test 8: spaced text, check correct vertical alignment: 55, % 7 56, % 8 }} - err = ga:encode_Text_xspaced(n, 0.0, 10*pt, 30*pt, 1.0) - assert(not err, err) + assert(ga:encode_Text_xspaced(n, 0.0, 10*pt, 30*pt, 1.0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -534,12 +514,9 @@ Test number 9: spaced text, check correct vertical alignment: b[i*2+1] = i*10*pt b[i*2+2] = 8*pt end - b = {_yline = b} - local ga = gacanvas:new() - local err = ga:encode_Vbar(b, 0.0, 0.0, 20*pt) - assert(not err, err) - local err = ga:encode_Vbar(b, 0.0, 40*pt, 60*pt) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_vbar(b, 0.0, 0.0, 20*pt)) + assert(ga:encode_vbar(b, 0.0, 40*pt, 60*pt)) local c = { codepoint = { 65, % A 66, % B @@ -550,8 +527,7 @@ Test number 9: spaced text, check correct vertical alignment: 71, % G 72, % H }} - err = ga:encode_Text_xspaced(c, 0.0, 10*pt, 20*pt, 0.0) - assert(not err, err) + assert(ga:encode_Text_xspaced(c, 0.0, 10*pt, 20*pt, 0.0)) local n = { codepoint = { 49, % 1 50, % 2 @@ -562,8 +538,7 @@ Test number 9: spaced text, check correct vertical alignment: 55, % 7 56, % 8 }} - err = ga:encode_Text_xspaced(n, 0.0, 10*pt, 40*pt, 1.0) - assert(not err, err) + assert(ga:encode_Text_xspaced(n, 0.0, 10*pt, 40*pt, 1.0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule{ }\box\mybox{ }\vrule @@ -582,16 +557,14 @@ Test number 10: two centered texts and baseline aligned: 56, % 8 57, % 9 }} - local ga = gacanvas:new() - local err = ga:encode_Text(n, 0, 0, 0.5, 0) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_Text(n, 0, 0, 0.5, 0)) local a = { codepoint = { 65, % A string.byte("Q"), % Q 67, % C }} - err = ga:encode_Text(a, 0, 0, 0.5, 1) - assert(not err, err) + assert(ga:encode_Text(a, 0, 0, 0.5, 1)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -610,16 +583,14 @@ Test number 11: two centered texts aligned: 56, % 8 57, % 9 }} - local ga = gacanvas:new() - local err = ga:encode_Text(n, 0, 0, 0.5, 1) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_Text(n, 0, 0, 0.5, 1)) local a = { codepoint = { 65, % A string.byte("Q"), % Q 67, % C }} - err = ga:encode_Text(a, 0, 0, 0.5, 0) - assert(not err, err) + assert(ga:encode_Text(a, 0, 0, 0.5, 0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -639,9 +610,8 @@ Test number 12: text\_xwidth opcode: 56, % 8 57, % 9 }} - local ga = gacanvas:new() - local err = ga:encode_Text_xwidth(n, 0, tex.sp "5cm", 0, 0) - assert(not err, err) + local ga = brcd:new_canvas() + assert(ga:encode_Text_xwidth(n, 0, tex.sp "5cm", 0, 0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -664,20 +634,14 @@ Test number 13: text\_xwidth with different size: 56, % 8 57, % 9 }} - local ga = gacanvas:new() - % (txt, x1, x2, ypos, ay) --> err - local err = ga:encode_Text_xwidth(n, tex.sp "0mm", tex.sp "50mm", 0, 0) - assert(not err, err) - local err = ga:encode_Text_xwidth(n, tex.sp "5mm", tex.sp "45mm", tex.sp "3mm", 0) - assert(not err, err) - local err = ga:encode_Text_xwidth(n, tex.sp "10mm", tex.sp "40mm", tex.sp "6mm", 0) - assert(not err, err) - local err = ga:encode_Text_xwidth(n, tex.sp "15mm", tex.sp "35mm", tex.sp "9mm", 0) - assert(not err, err) - local err = ga:encode_Text_xwidth(n, tex.sp "20mm", tex.sp "30mm", tex.sp "12mm", 0) - assert(not err, err) - local err = ga:encode_Text_xwidth(n, tex.sp "24mm", tex.sp "26mm", tex.sp "15mm", 0) - assert(not err, err) + local ga = brcd:new_canvas() + % (txt, x1, x2, ypos, ay) --> ok, err + assert(ga:encode_Text_xwidth(n, tex.sp "0mm", tex.sp "50mm", 0, 0)) + assert(ga:encode_Text_xwidth(n, tex.sp "5mm", tex.sp "45mm", tex.sp "3mm", 0)) + assert(ga:encode_Text_xwidth(n, tex.sp "10mm", tex.sp "40mm", tex.sp "6mm", 0)) + assert(ga:encode_Text_xwidth(n, tex.sp "15mm", tex.sp "35mm", tex.sp "9mm", 0)) + assert(ga:encode_Text_xwidth(n, tex.sp "20mm", tex.sp "30mm", tex.sp "12mm", 0)) + assert(ga:encode_Text_xwidth(n, tex.sp "24mm", tex.sp "26mm", tex.sp "15mm", 0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -691,16 +655,12 @@ Test number 14: place bars and text as text\_xwidth: b[i*2 + 1] = i*12*pt b[i*2 + 2] = 0.4*pt end - b = {_yline = b} local n = {codepoint = { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,}} - local ga = gacanvas:new() - % (vbar, x0, y1, y2) --> err - local err = ga:encode_Vbar(b, 0.0, 0*pt, 25*pt) - local err = ga:encode_Vbar(b, 0.0, 32*pt, 42*pt) - assert(not err, err) - % (txt, x1, x2, ypos, ay) --> err - local err = ga:encode_Text_xwidth(n, 0*pt, 108*pt, 25*pt, 0) - assert(not err, err) + local ga = brcd:new_canvas() + % (vbar, x0, y1, y2) --> ok, err + assert(ga:encode_vbar(b, 0.0, 0*pt, 25*pt)) + % (txt, x1, x2, ypos, ay) --> ok, err + assert(ga:encode_Text_xwidth(n, 0*pt, 108*pt, 25*pt, 0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -711,17 +671,14 @@ Test number 14: place bars and text as text\_xwidth: b[i*2 + 1] = i*12*pt b[i*2 + 2] = 0.2*pt end - b = {_yline = b} local n = { 48, 49, 50, 51, string.byte([[x]]), 53, 54, 55, 56,} n = {codepoint = n} - local ga = gacanvas:new() + local ga = brcd:new_canvas() % x0, y1, y2, bars - local err = ga:encode_Vbar(b, 0.0, 0*pt, 25*pt) - local err = ga:encode_Vbar(b, 0.0, 32*pt, 42*pt) - assert(not err, err) - % (txt, x1, x2, ypos, ay) --> err - local err = ga:encode_Text_xwidth(n, 0*pt, 96*pt, 25*pt, 0) - assert(not err, err) + assert(ga:encode_vbar(b, 0.0, 0*pt, 25*pt)) + assert(ga:encode_vbar(b, 0.0, 32*pt, 42*pt)) + % (txt, x1, x2, ypos, ay) --> ok, err + assert(ga:encode_Text_xwidth(n, 0*pt, 96*pt, 25*pt, 0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule @@ -730,10 +687,9 @@ Test number 15: place text\_xwidth when text is only two chars long: \directlua{ local n = {codepoint = { 48, 56,}} % 0 and 8 - local ga = gacanvas:new() - % (txt, x1, x2, ypos, ay) --> err - local err = ga:encode_Text_xwidth(n, 0*pt, 32*pt, 25*pt, 0) - assert(not err, err) + local ga = brcd:new_canvas() + % (txt, x1, x2, ypos, ay) --> ok, err + assert(ga:encode_Text_xwidth(n, 0*pt, 32*pt, 25*pt, 0)) driver:ga_to_hbox(ga, [[mybox]]) }\vrule\box\mybox\vrule diff --git a/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.pdf b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.pdf new file mode 100644 index 0000000000..72d4eddc05 Binary files /dev/null and b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.tex b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.tex new file mode 100644 index 0000000000..14a713dee9 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/002-polyline.tex @@ -0,0 +1,69 @@ +% !TeX program = LuaTeX + +\directlua{ + brcd = require "barracuda" +} +\newbox\mybox + +Test 1: a simple polyline: +\directlua{ + local Polyline = brcd._libgeo.Polyline + local p = Polyline:new() + p:add_point(0, 0) + p:add_point(tex.sp "32pt", 0) + p:add_relpoint(tex.sp "16pt", tex.sp "16pt") + + local gaCanvas = brcd._gacanvas + local ga = gaCanvas:new() + assert(ga:encode_polyline(p)) + + local driver = brcd:get_driver() + driver:ga_to_hbox(ga, [[mybox]]) +}\vrule\box\mybox\vrule + + +Test 2: a staircase: +\directlua{ + local h = tex.sp "18pt" + local b = tex.sp "36pt" + local Polyline = brcd._libgeo.Polyline + local p = Polyline:new() + p:add_point(0, 0) + for _ = 1, 5 do + p:add_relpoint(0, h) + p:add_relpoint(b, 0) + end + + local gaCanvas = brcd._gacanvas + local ga = gaCanvas:new() + assert(ga:encode_polyline(p)) + + local driver = brcd:get_driver() + driver:ga_to_hbox(ga, [[mybox]]) +}\vrule\box\mybox\vrule + +Test 3: several regular polygons: +\directlua{ + local Polyline = brcd._libgeo.Polyline + local l = tex.sp "36pt" % side length + local gaCanvas = brcd._gacanvas + local ga = gaCanvas:new() + ga:encode_linewidth(tex.sp "0.4pt") + for n = 3, 13 do + local p = Polyline:new() + p:add_point(0, 0) + local alpha = 2*math.pi/n % angle + local a = alpha/2 % regular angles sum + for _ = 1, n do + local x, y = l * math.cos(a), l * math.sin(a) + a = a + alpha + p:add_relpoint(x, y) + end + assert(ga:encode_polyline(p)) + end + local driver = brcd:get_driver() + driver:ga_to_hbox(ga, [[mybox]]) + driver:save("svg", ga, "polygon") +}\vrule\box\mybox\vrule + +\bye diff --git a/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/polygon.svg b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/polygon.svg new file mode 100644 index 0000000000..fd00ed2912 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-ga-pdfliteral/polygon.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macros/luatex/generic/barracuda/test/test-ga-svg/002-ga-svg-test.lua b/macros/luatex/generic/barracuda/test/test-ga-svg/002-ga-svg-test.lua index b5a2e3c4ae..e116fe75f4 100644 --- a/macros/luatex/generic/barracuda/test/test-ga-svg/002-ga-svg-test.lua +++ b/macros/luatex/generic/barracuda/test/test-ga-svg/002-ga-svg-test.lua @@ -13,6 +13,6 @@ local symbol, err = c39:from_string("ABC000Z") assert(not err, err) local canvas = barracuda:new_canvas() -symbol:append_ga(canvas) +symbol:draw(canvas) driver:save("svg", canvas, "test-code39") \ No newline at end of file diff --git a/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.pdf b/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.pdf index f2dbd6f9ea..5bf43e574b 100644 Binary files a/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.pdf and b/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.tex b/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.tex index 0062b74d3e..3f5a4dff75 100644 --- a/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.tex +++ b/macros/luatex/generic/barracuda/test/test-i2of5/001-i2of5-test.tex @@ -1,10 +1,14 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \newbox\mybox \nopagenumbers -\directlua{barracuda = require "barracuda"} +\directlua{ +barracuda = require "barracuda" +local barcode = barracuda:barcode() +barcode:set_param("debug_bbox", "symb") +} Interleaved 2 of 5 encoder test. @@ -12,14 +16,13 @@ Test 1: one simple barcode with default parameters: \directlua{ local barcode = barracuda:barcode() - local enc, err = barcode:new_encoder("i2of5"); assert(not err, err) local symbo, err = enc:from_uint(54654681); assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input code 54654681: \vrule A\vrule\box\mybox \vrule A\vrule \bigskip Test 2: one simple barcode with default parameter: @@ -28,11 +31,11 @@ Test 2: one simple barcode with default parameter: local barcode = barracuda:barcode() local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) local symbo, err = enc:from_uint(1234567895); assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input code 1234567895: \vrule A\vrule\box\mybox \vrule A\vrule % check digit tests @@ -104,11 +107,11 @@ local barcode = barracuda:barcode() local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) local symbo, err = enc:from_uint(454473, {check_digit_policy="add"}) assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input code 454473: \vrule A\vrule\box\mybox \vrule A\vrule \bigskip Test 4: a second simple barcode with check digit automatically added: @@ -118,11 +121,11 @@ local barcode = barracuda:barcode() local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) local symbo, err = enc:from_uint(74223, {check_digit_policy="add"}) assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input code 74223: \vrule A\vrule\box\mybox \vrule A\vrule \bigskip Test 5: a symbol with native check digits: @@ -132,11 +135,11 @@ local barcode = barracuda:barcode() local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) local symbo, err = enc:from_uint(121891259, {check_digit_policy="verify"}) assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input code 121891259: \vrule A\vrule\box\mybox \vrule A\vrule \bigskip Test 6: bearer bars please: @@ -144,13 +147,13 @@ Test 6: bearer bars please: \directlua{ local barcode = barracuda:barcode() local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) -local symbo, err = enc:from_uint(747867239, {bearer_bars_enabled = true}) +local symbo, err = enc:from_string("747867239", {bearer_bars_enabled = true}) assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input string "747867239": \vrule A\vrule\box\mybox \vrule A\vrule \bigskip Test 7: bearer bars all around the symbol: @@ -160,11 +163,11 @@ local barcode = barracuda:barcode() local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) local symbo, err = enc:from_uint(986790868, {bearer_bars_enabled = true, bearer_bars_layout="frame"}) assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input code 986790868: \vrule A\vrule\box\mybox \vrule A\vrule \bigskip Test 8: bearer bars all around the symbol (with string costructor): @@ -174,11 +177,11 @@ local barcode = barracuda:barcode() local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) local symbo, err = enc:from_string("986790868", {bearer_bars_enabled = true, bearer_bars_layout="frame"}) assert(not err, err) -local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local canvas = barracuda:new_canvas(); symbo:draw(canvas) local drv = barracuda:get_driver() drv:ga_to_hbox(canvas, "mybox") -} -\vrule A\vrule\box\mybox \vrule A\vrule +}% +input string "986790868": \vrule A\vrule\box\mybox \vrule A\vrule That's all folks! diff --git a/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.pdf b/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.pdf index 79a05eca42..449a7b63a8 100644 Binary files a/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.pdf and b/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.tex b/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.tex index 52784b66bb..7b6229b483 100644 --- a/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.tex +++ b/macros/luatex/generic/barracuda/test/test-i2of5/002-ITF14-test.tex @@ -1,5 +1,5 @@ % !TeX program = LuaTeX -% Copyright (C) 2020 Roberto Giacomelli +% Copyright (C) 2019-2022 Roberto Giacomelli \newbox\mybox \nopagenumbers @@ -15,9 +15,8 @@ local enc = assert(barcode:new_encoder("i2of5-ITF14")) local s1 = assert(enc:from_uint(1234567890123)) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) -local drv = barracuda:get_driver() -drv:ga_to_hbox(canvas, "mybox") +s1:draw(canvas) +canvas:ga_to_hbox("mybox") } \vskip 10pt 12345678901231 is \vrule A\vrule\box\mybox \vrule A\vrule @@ -28,9 +27,8 @@ local enc = assert(barcode:enc_by_name("i2of5-ITF14")) local s1 = assert(enc:from_string("1234567890123")) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) -local drv = barracuda:get_driver() -drv:ga_to_hbox(canvas, "mybox") +s1:draw(canvas) +canvas:ga_to_hbox("mybox") } \vskip 10pt 12345678901231 is \vrule A\vrule\box\mybox \vrule A\vrule @@ -39,15 +37,12 @@ drv:ga_to_hbox(canvas, "mybox") local barcode = barracuda:barcode() local enc = assert(barcode:enc_by_name("i2of5-ITF14")) local s1 = assert(enc:from_string("(12) 34 56 78 90 12 3")) - +s1:set_param("debug_bbox_on", true) local canvas = barracuda:new_canvas() -s1:append_ga(canvas) -local drv = barracuda:get_driver() -drv:ga_to_hbox(canvas, "mybox") +s1:draw(canvas) +canvas:ga_to_hbox("mybox") +canvas:save("svg", "02-itf14") } \vskip 10pt 12345678901231 is \vrule A\vrule\box\mybox \vrule A\vrule - \bye - - diff --git a/macros/luatex/generic/barracuda/test/test-i2of5/02-itf14.svg b/macros/luatex/generic/barracuda/test/test-i2of5/02-itf14.svg new file mode 100644 index 0000000000..2f8ee06996 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-i2of5/02-itf14.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (12) 34 56 78 90 12 31 + + + diff --git a/macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.pdf b/macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.pdf new file mode 100644 index 0000000000..46c326513a Binary files /dev/null and b/macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.tex b/macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.tex new file mode 100644 index 0000000000..ec43ad0091 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-libgeo/001-libgeo-test.tex @@ -0,0 +1,48 @@ +% !TeX program = LuaTeX +% test for ga-canvas pdfliteral driver +% +% Copyright (C) 2019-2022 Roberto Giacomelli +% see LICENSE.txt file + +\newbox\mybox +\directlua{ + barracuda = require [[barracuda]] + pt = tex.sp [[1pt]] % 1pt = 65536sp +} + +Test 1: test Archive class and Vbar arithmetic: + +\medskip +\directlua{ + % retrive the Vbar class + local libgeo = barracuda:libgeo() + local Vbar = libgeo.Vbar + % create three Vbar objects + local b1 = Vbar:from_int(22556, 2*pt) + local b2 = Vbar:from_int(3134563, 2*pt) + local b3 = Vbar:from_int(1111111, 2*pt) + % retrive the Archive class + local Archive = libgeo.Archive + % create a new instance of an archive and insert vbars + local archive = Archive:new() + assert(archive:insert(b1, 1)) + assert(archive:insert(b2, 2)) + assert(archive:insert(b3, 3)) + % fill a queue (an array) two times + local queue = assert(archive:get(1)) + 20*pt + queue = queue + assert(archive:get(2)) + 20*pt + queue = queue + assert(archive:get(3)) + 20*pt + queue = queue + assert(archive:get(1)) + 20*pt + queue = queue + assert(archive:get(2)) + 20*pt + queue = queue + assert(archive:get(3)) + % retrive a canvas instance + local ga = barracuda:new_canvas() + % draw the canvas with the driver component + assert(ga:encode_vbar_queue(queue, 0, 0, 30*pt)) + local driver = barracuda:get_driver() + driver:ga_to_hbox(ga, [[mybox]]) +}A\box\mybox A + +\bye + + \ No newline at end of file diff --git a/macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.pdf b/macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.pdf new file mode 100644 index 0000000000..1465413c8a Binary files /dev/null and b/macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.tex b/macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.tex new file mode 100644 index 0000000000..c3692c282e --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-libgeo/003-ga-svg-test.tex @@ -0,0 +1,41 @@ +% !TeX program = LuaTeX + +\newbox\mybox +\nopagenumbers +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:barcode() +local driver = barracuda:get_driver() +local mm = driver.mm + +local canvas = barracuda:new_canvas() +canvas:encode_linewidth(1*mm) + +canvas:encode_dash_pattern(0, 2*mm) +canvas:encode_hline(0, 30*mm, 5*mm) + +canvas:encode_dash_pattern(0, 2*mm, 4*mm) +canvas:encode_hline(0, 30*mm, 10*mm) + +canvas:encode_dash_pattern(1*mm, 2*mm, 2*mm, 4*mm) +canvas:encode_hline(0, 30*mm, 15*mm) + +canvas:encode_linewidth(0.05*mm) +canvas:encode_reset_pattern() +for i=0, 15 do + canvas:encode_vline(0, 20*mm, i*2*mm) +end + +canvas:encode_dash_pattern(0.5*mm, 1*mm) +canvas:encode_polyline{ + 1*mm, 1*mm, + 29*mm, 1*mm, + 29*mm, 19*mm, + 1*mm, 19*mm, + 1*mm, 1*mm +} + +driver:save("svg", canvas, "test") +assert(driver:ga_to_hbox(canvas, [[mybox]])) +}\leavevmode\box\mybox +\bye \ No newline at end of file diff --git a/macros/luatex/generic/barracuda/test/test-libgeo/test.svg b/macros/luatex/generic/barracuda/test/test-libgeo/test.svg new file mode 100644 index 0000000000..d9614096c4 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-libgeo/test.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macros/luatex/generic/barracuda/test/test-upc/001-upca-test.pdf b/macros/luatex/generic/barracuda/test/test-upc/001-upca-test.pdf new file mode 100644 index 0000000000..c4637e681a Binary files /dev/null and b/macros/luatex/generic/barracuda/test/test-upc/001-upca-test.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-upc/001-upca-test.tex b/macros/luatex/generic/barracuda/test/test-upc/001-upca-test.tex new file mode 100644 index 0000000000..3be12aa502 --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-upc/001-upca-test.tex @@ -0,0 +1,41 @@ +% !TeX program = LuaTeX +% Copyright (C) 2019-2022 Roberto Giacomelli + +\newbox\mybox +\nopagenumbers + +UPC encoder test. + +Test 1: one simple barcode UPC-A with default parameter: + +\directlua{ +barracuda = require "barracuda" +local barcode = barracuda:barcode() +barcode:set_param("debug_bbox", "qz") +local upca, err = barcode:new_encoder("upc-A") +assert(not err, err) + +local symbo, err = upca:from_string("042100005264") +assert(not err, err) + +local canvas = barracuda:new_canvas() +symbo:draw(canvas) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\box\mybox A\vrule + +\bigskip\directlua{ +local barcode = barracuda:barcode() +barcode:set_param("debug_bbox", "none") +local upca = assert(barcode:enc_by_name("upc-A")) + +local symbo = assert(upca:new("012345678905")) +local canvas = barracuda:new_canvas() +symbo:draw(canvas) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +}\leavevmode\box\mybox +\bye diff --git a/macros/luatex/generic/barracuda/test/test-upc/002-upca.pdf b/macros/luatex/generic/barracuda/test/test-upc/002-upca.pdf new file mode 100644 index 0000000000..ed5363d1de Binary files /dev/null and b/macros/luatex/generic/barracuda/test/test-upc/002-upca.pdf differ diff --git a/macros/luatex/generic/barracuda/test/test-upc/002-upca.tex b/macros/luatex/generic/barracuda/test/test-upc/002-upca.tex new file mode 100644 index 0000000000..5196ecbc7a --- /dev/null +++ b/macros/luatex/generic/barracuda/test/test-upc/002-upca.tex @@ -0,0 +1,9 @@ +% !TeX program = LuaLaTeX +% Copyright (C) 2019-2022 Roberto Giacomelli + +\documentclass[border=5pt]{standalone} +\usepackage{barracuda} + +\begin{document} +\barracuda[debug_bbox="qz"]{upc-A}{121212343430} +\end{document} \ No newline at end of file -- cgit v1.2.3