From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/gs1/GS1.dtx | 1029 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1029 insertions(+) create mode 100644 macros/latex/contrib/gs1/GS1.dtx (limited to 'macros/latex/contrib/gs1/GS1.dtx') diff --git a/macros/latex/contrib/gs1/GS1.dtx b/macros/latex/contrib/gs1/GS1.dtx new file mode 100644 index 0000000000..0f6508d9ce --- /dev/null +++ b/macros/latex/contrib/gs1/GS1.dtx @@ -0,0 +1,1029 @@ +% \iffalse meta-comment +% +%% File: GS1.dtx Copyright (C) 2012-2017 Markus Kohm +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "GS1 bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ------------------------------------------------------------------------- +% +%<*driver|package|test> +\RequirePackage{expl3}[2017/05/29] +\GetIdInfo$Id: GS1.dtx 22 2017-07-15 18:03:18Z mjk $ + {GS1 code handler and barcode generator} +% +%<*driver> +\documentclass{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +% +%<*test> +\documentclass{article} +\usepackage{GS1} +\ExplSyntaxOn +\msg_new:nnn { GS1/test } { function } + { + Something~is~wrong~with~function~#1 + \msg_line_context:~~of~\c_sys_jobname_str.tex. + } +\ExplSyntaxOff +\begin{document} +% +% \fi +% +% \title{^^A +% The \pkg{GS1}\thanks +% {^^A +% GS1 is a registered trademark of GS1 AISBL. Nevertheless, GS1 AISBL +% neither has any rights on this package, nor is responsible for it in +% any kind. The package's name should indicate only, that the package +% implements some aspects of GS1 codes.^^A +% } +% package\\ +% GS1 Code Handler and Barcode Generator\thanks +% {^^A +% This file describes v\ExplFileVersion, +% last revised \ExplFileDate.^^A +% }^^A +% } +% +% \author{^^A +% Markus Kohm\thanks +% {^^A +% E-mail: \href{mailto:komascript@gmx.info}{komascript@gmx.info}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% \begin{abstract} +% There are several barcode packages out in the world, but they either need +% PStricks, or are restricted to EAN-13 barcodes. And most of all, they are +% all \LaTeXe. I've decided to write a package, that supports several GS1 +% codes, and at almost the same time, I've decided to give L3 a chance. So +% I've started an experimental GS1 package using \pkg{expl3}. Using +% \pkg{expl3} was the main reason writing this package. +% \end{abstract} +% +% \tableofcontents +% +% \section*{Preface} +% +% Design and implementation of this package based on +% \begin{quote}\begin{description} +% \item[GS1:] ``Allgemeine GS1 Spezifikation'', Version~12.0, Januar~2012, +% Ausgabe~1. +% \end{description}\end{quote} +% This is the official GS1 specification for Germany, Austria and Switzerland. +% +% Currently only EAN-8 and EAN-13 codes and bar codes without extension have +% been implemented. Others may follow in future. +% +% +% \section{L3 Functions and Variables for GS1 Codes} +% \label{sec:doc:functions.and.variables} +% +% First of all: Please note, that the concept of private functions and +% variables is not well defined in \TeX. Several variables, that I'd have +% made private in C++, haven't been declared to be private in this +% implementation. Maybe I should change this. +% +% You should also know, that several test files may be created from the +% package source, and each of those may be used as an example for using the +% code. Nevertheless, \LaTeXe{} users will not need the following functions +% and should continue reading with \autoref{sec:doc:latex2e}. +% +% \begin{function}{\GS_set_code_digit_seq:Nn} +% \begin{syntax} +% "\GS_set_code_digit_seq:Nn" \meta{GS1 sequence variable} \Arg{token list} +% \end{syntax} +% Makes a GS1 sequence, that consist in digits only, from a \meta{token +% list}. To do so, only the tokens from 0 up to 9 of the \meta{token list} +% are set to the \meta{GS1 sequence variable}. All other tokens are +% ignored. So may, e.g., convert the string ``ISBN 978-3-86541-459-5'' into +% a GS1 sequence with the digits ``9783865414595'', where each digit is one +% item of the sequence. +% \end{function} +% +% \begin{function}{\GS_cut_EAN_control_digit:N} +% \begin{syntax} +% "\GS_cut_EAN_control_digit:N" \meta{GS1 sequence variable} +% \end{syntax} +% The \meta{GS1 sequence variable} should store either a EAN-8 or EAN-13 +% code with or without control digit. If the code has seven or twelve +% digits, nothing happens. If the code has eight or 13 digits, the last one +% will be removed. All other cases result in an error message. +% \end{function} +% +% \begin{function}{\GS_set_EAN_control_digit:N} +% \begin{syntax} +% "\GS_set_EAN_control_digit:N" \meta{GS1 sequence variable} +% \end{syntax} +% The \meta{GS1 sequence variable} should store either a EAN-8 or EAN-13 +% code with or without control digit. A new control digit will be +% calculated. If the code has seven or twelve digits the new control digit +% will be added. If the code has eight or 13 digits, the old control digit +% will be replaced by the new one. All other cases result in an error +% message. +% \end{function} +% +% \begin{function}{\int_set_to_EAN_control_digit:NN} +% \begin{syntax} +% "\int_set_to_EAN_control_digit:NN" \meta{integer variable} \meta{GS1 sequence variable} +% \end{syntax} +% Calculates the control digit of the \meta{GS1 sequence variable} using the +% EAN control digit algorithm and stores it into the \meta{integer +% variable}. Note, that the \meta{GS1 sequence variable} may be a sequence +% of digits of any length not only seven digits for EAN-8 or twelve digits +% for EAN-13. +% \end{function} +% +% \begin{function}{\GS_use_as_EAN_barcode:N} +% \begin{syntax} +% "\GS_use_as_EAN_barcode:N" \meta{GS1 sequence variable} +% \end{syntax} +% Prints an EAN-8 or EAN-13 bar code depending on +% \cs{l_GS_code_size_int}. Note, that the \meta{GS1 sequence variable} may +% have more than 8 resp. 13 items but not less! Use \cs{EANBarcode} if you +% need a more save function. +% \end{function} +% +% +% \section{\LaTeXe{} User Interface for GS1 Codes} +% \label{sec:doc:latex2e} +% +% This section describes the \LaTeXe-compatible user interface. Note, that +% the test files \file{EANControlDigit.tex}, \file{EANBarcode.tex}, +% \file{GSSetup.tex}, and the resulting PDF files may be used as examples of +% the following commands. +% +% \begin{function}{\EANControlDigit} +% \begin{syntax} +% "\EANControlDigit"\Arg{string} +% \end{syntax} +% Only the digits of the \meta{string} will be used. All other tokens +% will be ignored. If the \meta{string} has 7 or 8 digits, the control +% digit of an EAN-8 code will be calculated and output. If the +% \meta{string} has 12 or 13 digits, the control digit of an EAN-13 code +% will be calculated and output. If the \meta{string} has 8 or 13 digits +% the last digit will be ignored. Any other number of digits will result in +% an error message. +% \end{function} +% +% \begin{function}{\EANBarcode} +% \begin{syntax} +% "\EANBarcode"\oarg{options}\Arg{string} +% \end{syntax} +% Creates the EAN bar code corresponding with \meta{string}. The optional +% argument \meta{options} may be used to use different settings from the +% defaults set by \cmd{\GSSetup}. +% +% Each digit of a EAN bar code is represented by seven modules. Each module +% is either black or white. A black module is a black, vertical line. A +% white module is just a gap. The seven modules start either with a black +% sequence of up to four modules, followed by a white sequence of up to four +% modules, followed by a black sequence of up to four modules, finished by a +% white sequence of up to four modules, or they start with a white sequence +% of up to four modules, followed by a black sequence of up to four modules, +% followed by a white sequence of up to four modules, finished by a black +% sequence of up to four modules. +% \end{function} +% +% \begin{function}{\GSSetup} +% \begin{syntax} +% "\GSSetup" \Arg{options} +% \end{syntax} +% \meta{options} is a list of \meta{key}=\meta{value} pairs. They are used +% to setup the default of several settings: +% \begin{description} +% \item[\texttt{ocrb=}\meta{boolean}]\hfill\\ +% If \meta{boolean} is \texttt{true} the digits at the bottom of the bar +% code will be printed using OCR-b font ocrb/T1/m/n in 9pt. Predefined +% default is |ocrb=true|. +% \item[\texttt{module\_width=}\meta{dimension expression}]\hfill\\ +% This is the width of one module. GS1 specifies a minimum module width +% of 0.264\,mm and a normal width of 0.33\,mm. You should not set a +% width below the minimum! +% \item[\texttt{module\_height=}\meta{dimension expression}]\hfill\\ +% This is the height of a black module. GS1 specifies a normal bar code +% height of 21.31\,mm for EAN-8 and 25.01\,mm for EAN-13. Both values +% are inclusive the digits at the bottom of the bar code. Some marker +% modules are higher than the digit modules. +% \item[\texttt{code=}\meta{string}]\hfill\\ +% The \meta{string} should either be \texttt{EAN-8} or \texttt{EAN-13}. +% The predefined default is |EAN-13|. More types will be +% supported in future. +% \item[\texttt{scale=}\meta{floating point}]\hfill\\ +% This is the scale factor for the bar code. GS1 specifies scale classes +% from 0.8 up to 2.0 with steps of 0.05. Factors less than 0.8 +% shouldn't be used. \emph{Currently \texttt{scale} won't be used!} +% \item[\texttt{scale\_to\_font=}\meta{boolean}]\hfill\\ +% Ignore \texttt{module_width} and instead set the module width +% depending on the width of digit 0 of the current font. Note, that +% this will not scale the whole bar code but only the module width. To +% scale the whole bar code, you should use \texttt{scale}. +% \item[\texttt{add\_control=}\meta{boolean}]\hfill\\ +% Add the control digit to the GS1 code. If there's already a control +% digit, replace it by the calculated one. The predefined default is +% |add_control=false|. +% \end{description} +% \end{function} +% +% +% \section{Internal Functions and Variables} +% \label{sec:doc:internal} +% +% You should not use or manipulate these! So, maybe it's better to stop +% reading now. +% +% \begin{function}{\__GS_set_key_code:nn} +% \begin{syntax} +% "\__GS_set_key_code:nn" \Arg{token list} \Arg{integer expression} +% \end{syntax} +% Sets \cs{l_GS_code_type_tl} to \meta{token list} and +% \cs{l_GS_code_size_int} to value of \Arg{integer expression}. +% \end{function} +% +% \begin{function}{\__GS_new_seq_c:cn} +% \begin{syntax} +% "\__GS_new_seq_c:cn" \Arg{sequence name} \Arg{token list} +% \end{syntax} +% Creates a sequence constant \cs{c__GS_\meta{sequence name}_seq}. The +% value of the constant will be build by the tokens of the \meta{token +% list}. These tokens should be either characters ``A'' or ``B'' for +% selection constants or digits 1--4 for module constants. +% \end{function} +% +% \begin{function}{\__GS_modules:Nn, \__GS_modules:cn, \__GS_modules:NnN} +% \begin{syntax} +% "\__GS_modules:Nn" \meta{sequence variable} \Arg{dimension expression} +% "\__GS_modules:cn" \Arg{sequence variable name} \Arg{dimension expression} +% "\__GS_modules:NnN" \meta{sequence variable} \Arg{dimension expression} \meta{boolean variable} +% \end{syntax} +% Draws the modules given by the \meta{sequence variable} with height +% \Arg{dimension expression}. The arguments are: +% \begin{arguments} +% \item \meta{sequence variable} or \meta{sequence variable name}, each item +% of the sequence stays for a number of modules with the same color. +% \cs{l__GS_black_bool} signals, whether the (first) modules are black or +% white and will be reversed after every item. Each module has the width +% \cs{l_GS_module_wd_dim}. +% \item \meta{dimension expression}, the height of the black modules. The +% modules will be raised by \cs{l_GS_module_ht_dim}. +% \item \meta{boolean variable}, \texttt{true} indicates, that the first +% module should be black. With \texttt{false}, the first module will be +% white. +% \end{arguments} +% \end{function} +% +% \begin{function}{\__GS_modules_start_black:Nn} +% \begin{syntax} +% "\__GS_modules_start_black:Nn" \meta{sequence variable} \Arg{dimension expression} +% \end{syntax} +% Same like \cs{__GS_modules:NnN} \meta{sequence variable} \Arg{dimension +% expression} \cs{c_true_bool}. +% \end{function} +% +% \begin{function}{\__GS_modules_start_white:Nn} +% \begin{syntax} +% "\__GS_modules_start_white:Nn" \meta{sequence variable} \Arg{dimension expression} +% \end{syntax} +% Same like \cs{__GS_modules:NnN} \meta{sequence variable} \Arg{dimension +% expression} \cs{c_false_bool}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{GS1} implementation} +% \label{sec:implementation} +% \iffalse +%<*package> +%<@@=GS> +% \fi +% +% The implementation has been done in two parts. The first part is the L3 +% code with all the functions and variables. The second part is the +% \LaTeXe{} lookalike user interface. +% +% But before this, we just declare, what this is: +% \begin{macrocode} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +% \end{macrocode} +% and what it requires: +% \begin{macrocode} +\RequirePackage{rule-D} +% \end{macrocode} +% +% \subsection{Implementation of Functions and Variables} +% \label{sec:impl:functions.and.variables} +% +% \subsubsection{Constants} +% \label{sec:impl:constants} +% +% \begin{macro}{\__GS_new_seq_c:cn} +% While this is an internal function, that should allow only some tokens at +% the arguments, it is declared \texttt{nopar}. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_new_seq_c:cn #1#2 + { + \seq_new:c {c@@_ #1 _seq} + \seq_set_split:Nnn \l_tmpa_seq {} {#2} + \seq_gset_eq:cN {c@@_ #1 _seq} \l_tmpa_seq + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\c__GS_AB0_seq, \c__GS_AB1_seq, \c__GS_AB2_seq, +% \c__GS_AB3_seq, \c__GS_AB4_seq, \c__GS_AB5_seq, \c__GS_AB6_seq, +% \c__GS_AB7_seq, \c__GS_AB8_seq, \c__GS_AB9_seq} +% These constants represent the generation rules of the left side of an EAN-13 +% barcode. See figure~5.2.1.3.1-1 of the GS1 specification. +% \begin{macrocode} +\@@_new_seq_c:cn {AB0} {AAAAAA} +\@@_new_seq_c:cn {AB1} {AABABB} +\@@_new_seq_c:cn {AB2} {AABBAB} +\@@_new_seq_c:cn {AB3} {AABBBA} +\@@_new_seq_c:cn {AB4} {ABAABB} +\@@_new_seq_c:cn {AB5} {ABBAAB} +\@@_new_seq_c:cn {AB6} {ABBBAA} +\@@_new_seq_c:cn {AB7} {ABABAB} +\@@_new_seq_c:cn {AB8} {ABABBA} +\@@_new_seq_c:cn {AB9} {ABBABA} +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c__GS_A0_seq, \c__GS_A1_seq, \c__GS_A2_seq, \c__GS_A3_seq, +% \c__GS_A4_seq, \c__GS_A5_seq, \c__GS_A6_seq, \c__GS_A7_seq, \c__GS_A8_seq, +% \c__GS_A9_seq, \c__GS_B0_seq, \c__GS_B1_seq, \c__GS_B2_seq, \c__GS_B3_seq, +% \c__GS_B4_seq, \c__GS_B5_seq, \c__GS_B6_seq, \c__GS_B7_seq, \c__GS_B8_seq, +% \c__GS_B9_seq, \c__GS_margin_seq, \c__GS_separator_seq, \c__GS_special_seq, +% \c__GS_extra_margin_seq, \c__GS_extra_separator_seq} +% These constants represent the module sequences of digits and markers. See +% figure~5.2.1.2.1-1 and 5.2.1.2.2-1 of the GS1 specification. Note, that +% the module sequences of type C are same like type A but start with a black +% module instead of a white one. +% \begin{macrocode} +\@@_new_seq_c:cn {A0} {3211} % start white (C0 same but start with black) +\@@_new_seq_c:cn {A1} {2221} +\@@_new_seq_c:cn {A2} {2122} +\@@_new_seq_c:cn {A3} {1411} +\@@_new_seq_c:cn {A4} {1132} +\@@_new_seq_c:cn {A5} {1231} +\@@_new_seq_c:cn {A6} {1114} +\@@_new_seq_c:cn {A7} {1312} +\@@_new_seq_c:cn {A8} {1213} +\@@_new_seq_c:cn {A9} {3112} +\@@_new_seq_c:cn {B0} {1123} % start white +\@@_new_seq_c:cn {B1} {1222} +\@@_new_seq_c:cn {B2} {2212} +\@@_new_seq_c:cn {B3} {1141} +\@@_new_seq_c:cn {B4} {2311} +\@@_new_seq_c:cn {B5} {1321} +\@@_new_seq_c:cn {B6} {4111} +\@@_new_seq_c:cn {B7} {2131} +\@@_new_seq_c:cn {B8} {3121} +\@@_new_seq_c:cn {B9} {2113} +\@@_new_seq_c:cn {margin} {111} % start black +\@@_new_seq_c:cn {separator} {11111} % start white +\@@_new_seq_c:cn {special} {111111} % start white +\@@_new_seq_c:cn {extra_margin} {112} % start black +\@@_new_seq_c:cn {extra_separator} {11} % start white +% \end{macrocode} +% \end{variable} +% +% There are some basic dimensions for the modules at the specification: +% \begin{variable}{\c__GS_module_min_width_dim, \c__GS_module_norm_width_dim} +% \begin{macrocode} +\dim_const:Nn \c_@@_module_min_width_dim {0.264mm} +\dim_const:Nn \c_@@_module_norm_width_dim {0.33mm} +% \end{macrocode} +% \end{variable} +% +% \subsubsection{Settings and Variables} +% \label{seq:impl.settings} +% +% These settings will influence the work of several of the user functions. +% They are defined as keys of family \texttt{GS1}. +% +% \begin{variable}{ \l_GS_use_ocrb_bool, \l_GS_module_wd_dim, +% \l_GS_module_ht_dim, \l_GS_scale_fp, \l_GS_scale_to_font_bool, +% \l_GS_add_control_bool, \l_GS_code_type_tl, \l_GS_code_size_int } +% \begin{macro}{\__GS_set_key_code:nn} +% Needed to set both \cmd{\l_GS_code_type_tl} and \cmd{\l_GS_code_size_int} +% with one key. Together they are the type of code, to be handled. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_set_key_code:nn #1#2 + { + \tl_if_exist:NF \l_GS_code_type_tl { \tl_new:N \l_GS_code_type_tl } + \tl_set:Nn \l_GS_code_type_tl { #1 } + \int_if_exist:NF \l_GS_code_size_int { \int_new:N \l_GS_code_size_int } + \int_set:Nn \l_GS_code_size_int { #2 } + } +% \end{macrocode} +% \end{macro} +% \begin{macrocode} +\keys_define:nn { GS1 } + { + ocrb .bool_set:N = \l_GS_use_ocrb_bool, + ocrb .initial:n = true, + module_width .dim_set:N = \l_GS_module_wd_dim, + module_width .initial:V = \c_@@_module_norm_width_dim, + module_height .dim_set:N = \l_GS_module_ht_dim, + module_height .initial:V = \c_zero_dim, + code .choice:, + code / EAN-8 .code:n = { \@@_set_key_code:nn { EAN } { 8 } }, + code / EAN8 .code:n = { \@@_set_key_code:nn { EAN } { 8 } }, + code / EAN-13 .code:n = { \@@_set_key_code:nn { EAN } { 13 } }, + code / EAN13 .code:n = { \@@_set_key_code:nn { EAN } { 13 } }, + code .initial:n = EAN-13, + scale .fp_set:N = \l_GS_scale_fp, + scale .initial:n = 1.0, + scale_to_font .bool_set:N = \l_GS_scale_to_font_bool, + scale_to_font .initial:n = false, + add_control .bool_set:N = \l_GS_add_control_bool, + add_control .initial:n = false, + } +% \end{macrocode} +% \end{variable} +% +% Note: Later I'll define a \LaTeXe{} command to change the defaults of those +% keys. Additionally local changes of those keys may be done using the +% optional argument of the \LaTeXe{} user commands. See +% \autoref{sec:impl:user.interface} for more information. +% +% \begin{variable}{\l__GS_code_seq} +% This will be used later for several local GS1 sequences. It is private +% and also shouldn't be used in global context. +% \begin{macrocode} +\seq_new:N \l_@@_code_seq +% \end{macrocode} +% \end{variable} +% +% \subsubsection{Messages} +% \label{seq:impl.messages} +% +% We need a message for not supported lengths of EAN codes, because currently +% only EAN-8 and EAN-13 are supported, both with or without control +% digit. This message will be used as an error message. +% \begin{macrocode} +\msg_new:nnnn { GS1 } { EAN-code-size } + { + #1~isn't~a~valid~EAN~code~\msg_line_context:. + } + { + The~given~code~is~neither~a~EAN-8~with~or~without~control~digit,\\ + nor~a~EAN-13~with~or~without~control~digit.\\\\ + The~GS1~module~currently~only~supports~EAN-8~and~EAN~13. + } +% \end{macrocode} +% +% Another message is only a warning message. It will be used whenever the used +% module width would be less than the minimum module width given by the GS1 +% specification. +% \begin{macrocode} +\msg_new:nnn { GS1 } { module/minwidth } + { + Resulting~module~width~is~less~than~allowed~minimum~\msg_line_context:.\\\\ + GS1~specification~declares~a~minimum~module~width~of~#2.\\ + Currently~the~module~with~would~be~#1.\\ + To~avoid~problems,~I'll~increase~module~width~to~#2. + } +% \end{macrocode} +% +% \subsubsection{Functions} +% \label{seq:impl.functions} +% +% \begin{macro}{\GS_set_code_digit_seq:Nn} +% Convert a string into a code sequence ignoring all but digits. +% \begin{macrocode} +\cs_new_nopar:Npn \GS_set_code_digit_seq:Nn #1#2 + { + \seq_set_eq:NN #1 \c_empty_seq + \tl_map_inline:nn + { #2 } + { + \tl_if_in:nnT + {0123456789} + {##1} + { + \seq_put_right:Nn #1 { ##1 } + } + } + } +% \end{macrocode} +% +% \TestFiles{GS_set_code_digit.tex}\UnitTested +% \iffalse meta-comment +% +%<*test&GS.set.code.digit.seq> +% \begin{macrocode} +\ExplSyntaxOn +\seq_new:N \l_testa_seq +\seq_new:N \l_testb_seq + +\GS_set_code_digit_seq:Nn \l_testa_seq {ISBN 978-3-86541-459-5} +Sequence~for~ISBN~978-3-86541-459-5~is:~ +\seq_use:Nnnn \l_testa_seq { ,~ } { ,~} { ,~ } + +\GS_set_code_digit_seq:Nn \l_testb_seq {9783865414595} +\seq_map_inline:Nn \l_testa_seq + { + \seq_pop_left:NN \l_testb_seq \l_tmpa_tl + \tl_set:Nn \l_tmpb_tl { #1 } + \tl_if_eq:NNF \l_tmpa_tl \l_tmpb_tl + { + \tl_show:N l_testa_seq + \tl_show:N l_testb_seq + \msg_fatal:nnn { GS1/test } { function } { \GS_set_code_digit_seq:Nn } + } + } + +\GS_set_code_digit_seq:Nn \l_testa_seq {ISBN 978-3-86541-459-5} +\seq_set_split:Nnn \l_testb_seq {,} {9,7,8,3,8,6,5,4,1,4,5,9,5} +\seq_map_inline:Nn \l_testa_seq + { + \seq_pop_left:NN \l_testb_seq \l_tmpa_tl + \tl_set:Nn \l_tmpb_tl { #1 } + \tl_if_eq:NNF \l_tmpa_tl \l_tmpb_tl + { + \tl_show:N \l_testa_seq + \tl_show:N \l_testb_seq + \msg_fatal:nnn { GS1/test } { function } { \GS_set_code_digit_seq:Nn } + } + } + +\ExplSyntaxOff +% \end{macrocode} +% +%<*package> +% \fi +% \end{macro} +% +% \begin{macro}[updated = 2017-07-15]{\GS_cut_EAN_control_digit:N} +% \changes{v18}{2017/07/15}{replaced removed \cs{int_case:nnn} by +% \cs{int_case:nnF}}^^A +% EAN code sequences with control digit are either 8 or 13 digits. To +% remove the control digit we just have to remove the right most digit from +% a 8 or 13 digits sequence. 7 or 12 digit sequences are already without +% control digit. All other sequences are not supported. +% \begin{macrocode} +\cs_new_nopar:Npn \GS_cut_EAN_control_digit:N #1 + { + \int_case:nnF + { \seq_count:N #1 } + { + { 7 } { } + { 8 } { \seq_pop_right:NN #1 \l_tempa_tl } + { 12 } { } + { 13 } { \seq_pop_right:NN #1 \l_tempa_tl } + } + { + \msg_error:nnn { GS1 } { EAN-code-size } { #1 } + } + } +% \end{macrocode} +% \TestFiles{GS_cut_EAN_control_digit.tex}\UnitTested +% +% \iffalse meta-comment +% +%<*test&GS.cut.EAN.control.digit> +% \begin{macrocode} +\raggedright +\ExplSyntaxOn +\seq_new:N \l_testa_seq +\GS_set_code_digit_seq:Nn \l_testa_seq {ISBN 978-3-86541-459-5} +With~control:~\seq_use:Nnnn \l_testa_seq { ,~ } { ,~} { ,~ }\\ +\GS_set_code_digit_seq:Nn \l_testb_seq {ISBN 978-3-86541-459} +\GS_cut_EAN_control_digit:N \l_testa_seq +\seq_map_inline:Nn \l_testa_seq + { + \seq_pop_left:NN \l_testb_seq \l_tmpa_tl + \tl_set:Nn \l_tmpb_tl { #1 } + \tl_if_eq:NNF \l_tmpa_tl \l_tmpb_tl + { + \tl_show:N \l_testa_seq + \tl_show:N \l_testb_seq + \msg_fatal:nnn { GS1/test } { function } + { \GS_cut_EAN_control_digit:N } + } + } +Without~control:~\seq_use:Nnnn \l_testa_seq { ,~ } { ,~} { ,~ }\\ +\ExplSyntaxOff +% \end{macrocode} +% +%<*package> +% \fi +% \end{macro} +% +% \begin{macro}{\int_set_to_EAN_control_digit:NN} +% Sets an integer to the control digit calculated with the EAN control digit +% algorithm for a given code sequence. Note, that the complete code +% sequence will be used to calculate the control digit. So, if you have a +% EAN-8 or EAN-13 code sequence, you should cut of the control digit first. +% \begin{macrocode} +\cs_new_nopar:Npn \int_set_to_EAN_control_digit:NN #1#2 + { + \int_zero:N #1 + \seq_set_eq:NN \l_tmpa_seq #2 + \bool_until_do:nn + { \seq_if_empty_p:N \l_tmpa_seq } + { + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_tl + \int_if_even:nTF + { \seq_count:N \l_tmpa_seq } + { + \int_add:Nn #1 { 3 * \l_tmpb_tl } + } + { + \int_add:Nn #1 { \l_tmpb_tl } + } + } + \int_set:Nn #1 { \int_mod:nn { 10 - \int_mod:nn { #1 } { 10 } } { 10 } } + } +% \end{macrocode} +% \TestFiles{int_set_to_EAN_control_digit.tex}\UnitTested +% +% \iffalse meta-comment +% +%<*test&int.set.to.EAN.control.digit> +% \begin{macrocode} +\ExplSyntaxOn +\seq_new:N \l_testa_seq +\tl_new:N \l_control_tl +\GS_set_code_digit_seq:Nn \l_testa_seq {ISBN 978-3-86541-459-5} +\seq_pop_right:NN \l_testa_seq \l_control_tl +\int_new:N \l_control_int +\int_set_to_EAN_control_digit:NN \l_control_int \l_testa_seq +Control~digit~should~be~\tl_use:N \l_control_tl{} ~ +\int_compare:nNnTF { \l_control_tl } { = } { \l_control_int } + { + ~and~is~\int_use:N \l_control_int . + } + { + ~but~it~\int_use:N \l_control_int . + \msg_error:nnn { GS1/test } { function } + { \int_set_to_EAN_control_digit:NN } + } +\ExplSyntaxOff +% \end{macrocode} +% +%<*package> +% \fi +% \end{macro} +% +% \begin{macro}{\GS_set_EAN_control_digit:N} +% Add a new control digit to a EAN sequence +% \begin{macrocode} +\cs_new_nopar:Npn \GS_set_EAN_control_digit:N #1 + { + \GS_cut_EAN_control_digit:N #1 + \int_set_to_EAN_control_digit:NN \l_tmpa_int #1 + \seq_put_right:NV #1 \l_tmpa_int + } +% \end{macrocode} +% \TestFiles{GS_set_EAN_control_digit.tex}\UnitTested +% +% \iffalse meta-comment +% +%<*test&GS.set.EAN.control.digit> +% \begin{macrocode} +\ExplSyntaxOn +\seq_new:N \l_testa_seq +\GS_set_code_digit_seq:Nn \l_testa_seq {ISBN 978-3-86541-459-5} +\seq_new:N \l_testb_tl +\seq_pop_right:NN \l_testa_seq \l_testb_tl +\GS_set_EAN_control_digit:N \l_testa_seq +\tl_new:N \l_testa_tl +\seq_get_right:NN \l_testa_seq \l_testa_tl +Control~digit~should~be~ \tl_use:N \l_testb_tl {} ~ +\int_compare:nNnTF { \l_testa_tl } { = } { \l_testb_tl } + { + ~and~is~\tl_use:N \l_testa_tl . + } + { + ~but~it~\tl_use:N \t_testa_tl . + \msg_error:nnn { GS1/test } { function } { \GS_set_EAN_control_digit:N } + } + +\ExplSyntaxOff +% \end{macrocode} +% +%<*package> +% \fi +% \end{macro} +% +% \begin{macro}{\__GS_modules:Nn, \__GS_modules:NnN, \__GS_modules:cn, +% \__GS_modules_start_black:Nn, \__GS_modules_start_white:Nn} +% \begin{macrocode} +\cs_new_nopar:Npn \@@_modules:Nn #1#2 + { + \seq_map_inline:Nn #1 + { + \bool_if:NTF \l_@@_black_bool + { + \bool_set_false:N \l_@@_black_bool + \hbox_set:Nn \l_tmpa_box { 0 } + \rule:nnn + { + \dim_eval:n + { + \box_ht:N \l_tmpa_box + \l_GS_module_wd_dim / 2 + - \dim_eval:n { #2 } + \l_GS_module_ht_dim + } + } + { \dim_eval:n { \l_GS_module_wd_dim * ##1 } } + { \dim_eval:n { #2 } } + } + { + \bool_set_true:N \l_@@_black_bool + \hbox_to_wd:nn { \l_GS_module_wd_dim * ##1 } { } + } + } + } + +\cs_new_nopar:Npn \@@_modules:NnN #1#2#3 + { + \bool_if_exist:NF \l_@@_black_bool { \bool_new:N \l_@@_black_bool } + \bool_set_eq:NN \l_@@_black_bool #3 + \@@_modules:Nn #1 { #2 } + } + +\cs_new_nopar:Npn \@@_modules_start_black:Nn #1#2 + { + \@@_modules:NnN #1 { #2 } \c_true_bool + } + +\cs_new_nopar:Npn \@@_modules_start_white:Nn #1#2 + { + \@@_modules:NnN #1 { #2 } \c_false_bool + } + +\cs_generate_variant:Nn \@@_modules:Nn { c } +% \end{macrocode} +% \TestFiles{EANBarcode.tex}\UnitTested +% \end{macro} +% +% \begin{macro}{\GS_use_as_EAN_barcode:N} +% Puts the digits, rules, and gaps for an EAN barcode into the input +% stream. +% \begin{macrocode} +\cs_new_nopar:Npn \GS_use_as_EAN_barcode:N #1 + { + \seq_set_eq:NN \l_@@_code_seq #1 + + \int_compare:nNnTF { \l_GS_code_size_int } { = } { 8 } + { + \hbox_to_wd:nn { \l_GS_module_wd_dim * 7 } { } + \seq_set_eq:Nc \l_GS_system_seq { c_@@_AB0_seq } + } + { + \hbox_to_wd:nn { \l_GS_module_wd_dim * 11 } { } + \seq_pop_left:NN \l_@@_code_seq \l_tmpa_tl + \seq_set_eq:Nc \l_GS_system_seq { c_@@_AB \l_tmpa_tl _seq } + \hbox_overlap_left:n { \l_tmpa_tl } + } + + \@@_modules_start_black:Nn \c_@@_margin_seq + { \l_GS_module_ht_dim + \l_GS_module_wd_dim * 5 } + + \int_step_inline:nnnn { 1 } { 1 } + { \int_div_truncate:nn { \l_GS_code_size_int } { 2 } } + { + \seq_pop_left:NN \l_@@_code_seq \l_tmpa_tl + \hbox_overlap_right:n { \l_tmpa_tl } + \seq_pop_left:NN \l_GS_system_seq \l_tmpb_tl + \@@_modules:cn { c_@@_ \l_tmpb_tl \l_tmpa_tl _seq } + { \l_GS_module_ht_dim } + } + + \@@_modules_start_white:Nn \c_@@_separator_seq + { \l_GS_module_ht_dim + \l_GS_module_wd_dim * 5 } + + \int_step_inline:nnnn { 1 } { 1 } + { \int_div_truncate:nn { \l_GS_code_size_int } { 2 } } + { + \seq_pop_left:NN \l_@@_code_seq \l_tmpa_tl + \hbox_overlap_right:n { \l_tmpa_tl } + \@@_modules:cn { c_@@_A \l_tmpa_tl _seq } + { \l_GS_module_ht_dim } + } + + \@@_modules_start_black:Nn \c__GS_margin_seq + { \l_GS_module_ht_dim + \l_GS_module_wd_dim * 5 } + + \hbox_to_wd:nn { \l_GS_module_wd_dim * 7 } { } + } +% \end{macrocode} +% \TestFiles{EANBarcode.tex}\UnitTested +% \end{macro} +% +% +% \subsection{Implementation of the User Interface} +% \label{sec:impl:user.interface} +% +% For this, additional packages are needed: +% \begin{macrocode} +\RequirePackage{xparse} +% \end{macrocode} +% +% \begin{macro}{\EANControlDigit} +% \begin{macrocode} +\NewDocumentCommand \EANControlDigit + { m } + { + \group_begin: + \GS_set_code_digit_seq:Nn \l_@@_code_seq { #1 } + \GS_cut_EAN_control_digit:N \l_@@_code_seq + \int_set_to_EAN_control_digit:NN \l_tmpa_int \l_@@_code_seq + \int_to_arabic:n { \l_tmpa_int } + \group_end: + } +% \end{macrocode} +% \TestFiles{EANControlDigit.tex}\UnitTested +% +% \iffalse meta-comment +% +%<*test&EANControlDigit> +% \begin{macrocode} +\begin{tabular}{ll} + \hline + Calculated & Known \\ + \hline + 501234567890-\EANControlDigit{501234567890} & 501234567890-0 \\ + ISBN 978-3-86541-459-\EANControlDigit{ISBN 978-3-86541-459} & ISBN + 978-3-86541-459-5 \\ + EAN-8: 2012345\EANControlDigit{2012345} & EAN-8: 20123451 \\ + \hline +\end{tabular} +% \end{macrocode} +% +%<*package> +% \fi +% \end{macro} +% +% \begin{macro}{\EANBarcode} +% \begin{macrocode} +\NewDocumentCommand \EANBarcode + { o m } + { + \group_begin: + \IfNoValueF{#1}{ \keys_set:nn { GS1 } { #1 } } + \dim_compare:nNnT { \l_GS_module_ht_dim } { = } { \c_zero_dim } + { + \int_compare:nNnTF { \l_GS_code_size_int } { = } { 8 } + { \dim_set:Nn \l_GS_module_ht_dim { 21.31 mm } } + { \dim_set:Nn \l_GS_module_ht_dim { 25.01 mm } } + } + \bool_if:nT \l_GS_use_ocrb_bool + { +% \end{macrocode} +% \textsc{ToDo:} Use \pkg{fontspec} if available. +% \begin{macrocode} + \usefont{OT1}{ocrb}{m}{n}\fontsize{9}{9}\selectfont + } + + \GS_set_code_digit_seq:Nn \l_@@_code_seq { #2 } + + \bool_if:NT \l_GS_add_control_bool + { + \GS_set_EAN_control_digit:N \l_@@_code_seq + } + + \int_compare:nNnT + { \seq_count:N \l__GS_code_seq } + { > } + { \l_GS_code_size_int } + { + \msg_error:nnn { GS1 } { EAN-code-size } { #2 } + } + \int_while_do:nNnn + { \seq_count:N \l_@@_code_seq } + { < } + { \l_GS_code_size_int } + { + \seq_put_left:Nn \l_@@_code_seq { 0 } + } + + \bool_if:NT \l_GS_scale_to_font_bool { + \hbox_set:Nn \l_tmpa_box { 0 } + \dim_set:Nn \l_GS_module_wd_dim { \box_wd:N \l_tmpa_box / 7 } + } + + \dim_set:Nn \l_tmpa_dim + { \fp_to_decimal:N \l_GS_scale_fp \l_GS_module_wd_dim } + + \dim_compare:nNnT + { \l_tmpa_dim } + { < } + { \c_@@_module_min_width_dim } + { + \msg_warning:nnxx { GS1 } { module/minwidth } + { \dim_use:N \l_GS_module_wd_dim } + { \dim_use:N \c_@@_module_min_width_dim } + \dim_set:Nn \l_GS_module_wd_dim + { + \c_@@_module_min_width_dim * + 100 / \fp_to_int:n { 100 * \l_GS_scale_fp } + } + } + + \hbox_set:Nn \l_tmpa_box { \GS_use_as_EAN_barcode:N \l_@@_code_seq } + \box_scale:Nnn \l_tmpa_box + { \fp_to_int:n { 100 * \l_GS_scale_fp } / 100 } + { \fp_to_int:n { 100 * \l_GS_scale_fp } / 100 } + \box_use:N \l_tmpa_box + \group_end: + } +% \end{macrocode} +% \TestFiles{EANBarcode.tex}\UnitTested +% +% \iffalse meta-comment +% +%<*test&EANBarcode|GSSetup> +% \begin{macrocode} +\raggedright +\verb|\EANBarcode{ISBN 978-3-86541-459-5}|: + \EANBarcode{ISBN 978-3-86541-459-5} + +\verb|\EANBarcode[add_control]{ISBN 978-3-86541-459-}|: + \EANBarcode[add_control]{ISBN 978-3-86541-459-} + +\verb|\EANBarcode[ocrb=false]{ISBN 978-3-86541-459-5}|: +\EANBarcode[ocrb=false]{ISBN 978-3-86541-459-5} + +\verb|\EANBarcode[code=EAN-8]{20123451}|: + \EANBarcode[code=EAN-8]{20123451} + +\verb|\EANBarcode[code=EAN-8,ocrb=false,add_control]{2012345}|: + \EANBarcode[code=EAN-8,ocrb=false,add_control]{2012345} + +% \end{macrocode} +% +%<*package> +% \fi +% \end{macro} +% +% \begin{macro}{\GSSetup} +% \begin{macrocode} +\NewDocumentCommand \GSSetup + { m } + { \keys_set:nn { GS1 } { #1 } } +% \end{macrocode} +% \TestFiles{GSSetup.tex}\UnitTested +% +% \iffalse meta-comment +% +%<*test&GSSetup> +% \begin{macrocode} +After \verb|\GSSetup{ocrb=false,add_control}|: + \GSSetup{ocrb=false,add_control} + +\verb|\EANBarcode[code=EAN-8]{2012345}|: + \EANBarcode[code=EAN-8]{2012345} + +\verb|\EANBarcode[code=EAN-8,ocrb,add_control=false]{20123451}|: + \EANBarcode[code=EAN-8,ocrb,add_control=false]{20123451} + +% +%<*package> +% \fi +% \end{macro} +% +% +% \iffalse +% +%<*test> +% \begin{macrocode} +\end{document} +% \end{macrocode} +% +% \fi +% \end{implementation} +% +% \PrintIndex +% +\endinput +% +% end of file + +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: -- cgit v1.2.3