2022-07-25 14:25:38 +00:00
|
|
|
% \iffalse meta-comment
|
|
|
|
%
|
|
|
|
% qrcode.ins
|
|
|
|
% Copyright 2014 by Anders O.F. Hendrickson (anders.hendrickson@snc.edu)
|
|
|
|
%
|
|
|
|
% This work may be distributed and/or modified under the
|
|
|
|
% conditions of the LaTeX Project Public License, either version 1.3
|
|
|
|
% of this license or (at your option) any later version.
|
|
|
|
% The latest version of this license is in
|
|
|
|
% http://www.latex-project.org/lppl.txt
|
|
|
|
% and version 1.3 or later is part of all distributions of LaTeX
|
|
|
|
% version 2005/12/01 or later.
|
|
|
|
%
|
|
|
|
% This work has the LPPL maintenance status `maintained'.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% The Current Maintainer of this work is Anders O.F. Hendrickson.
|
|
|
|
%
|
|
|
|
% This work consists of the files qrcode.dtx and qrcode.ins
|
|
|
|
% and the derived file qrcode.sty.
|
|
|
|
%
|
|
|
|
% \fi
|
|
|
|
%
|
|
|
|
% \iffalse
|
|
|
|
%<*driver>
|
|
|
|
\ProvidesFile{qrcode.dtx}
|
|
|
|
%</driver>
|
|
|
|
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
|
|
|
|
%<package>\ProvidesPackage{qrcode}
|
|
|
|
%<*package>
|
|
|
|
[2015/01/08 v1.51 QR code generation]
|
|
|
|
%</package>
|
|
|
|
%
|
|
|
|
%<*driver>
|
|
|
|
\documentclass{ltxdoc}
|
|
|
|
\usepackage{hyperref}
|
|
|
|
\usepackage[nolinks]{qrcode}
|
2022-08-21 07:12:40 +00:00
|
|
|
\EnableCrossrefs
|
2022-07-25 14:25:38 +00:00
|
|
|
\CodelineIndex
|
|
|
|
\OnlyDescription
|
|
|
|
\RecordChanges
|
|
|
|
\begin{document}
|
|
|
|
\DocInput{qrcode.dtx}
|
|
|
|
\PrintChanges
|
|
|
|
%\PrintIndex
|
|
|
|
\end{document}
|
|
|
|
%</driver>
|
|
|
|
% \fi
|
|
|
|
%
|
|
|
|
% \CheckSum{0}
|
|
|
|
%
|
|
|
|
% \CharacterTable
|
|
|
|
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
|
|
|
|
% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
|
|
|
|
% Digits \0\1\2\3\4\5\6\7\8\9
|
|
|
|
% Exclamation \! Double quote \" Hash (number) \#
|
|
|
|
% Dollar \$ Percent \% Ampersand \&
|
|
|
|
% Acute accent \' Left paren \( Right paren \)
|
|
|
|
% Asterisk \* Plus \+ Comma \,
|
|
|
|
% Minus \- Point \. Solidus \/
|
|
|
|
% Colon \: Semicolon \; Less than \<
|
|
|
|
% Equals \= Greater than \> Question mark \?
|
|
|
|
% Commercial at \@ Left bracket \[ Backslash \\
|
|
|
|
% Right bracket \] Circumflex \^ Underscore \_
|
|
|
|
% Grave accent \` Left brace \{ Vertical bar \|
|
|
|
|
% Right brace \} Tilde \~}
|
|
|
|
%
|
|
|
|
%
|
|
|
|
% \changes{v1.0}{2014/09/26}{Initial version}
|
|
|
|
% \changes{v1.5}{2015/01/08}{Added support for new lines and hyperlinks.}
|
|
|
|
% \changes{v1.51}{2015/01/14}{Bug fix.}
|
|
|
|
%
|
|
|
|
% \GetFileInfo{qrcode.sty}
|
|
|
|
%
|
|
|
|
% \DoNotIndex{\newcommand,\newenvironment,\def}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \def\F{F}
|
|
|
|
%
|
|
|
|
% \title{The \textsf{qrcode} package: \\
|
|
|
|
% \makebox[0pt][r]{\raisebox{-0.3\height}[0pt][0pt]{\qrcode[hyperlink,tight]{http://ctan.org/pkg/qrcode}}\rule{0.75in}{0pt}}Quick Response code \\
|
|
|
|
% generation in \LaTeX\thanks{This document
|
|
|
|
% corresponds to \textsf{qrcode}~\fileversion, dated \filedate.}}
|
|
|
|
% \author{Anders Hendrickson\\ St.~Norbert College, De~Pere, WI, USA \\ \texttt{anders.hendrickson@snc.edu}}
|
|
|
|
% \date{January 8, 2015}
|
|
|
|
%
|
|
|
|
% \maketitle
|
|
|
|
%
|
|
|
|
%
|
|
|
|
% \section{Introduction}
|
|
|
|
%
|
|
|
|
% The proliferation of smartphones and tablets has led to the widespread
|
|
|
|
% use of Quick Response (QR) codes, which encode numeric, alphanumeric, kanji,
|
|
|
|
% or binary information into a square matrix of black and white pixels called modules.
|
|
|
|
% Although QR codes can encode any information up to almost three kilobytes,
|
|
|
|
% their most common use is as physical hyperlinks: a mobile device scans
|
|
|
|
% a printed QR code, decodes a URL, and automatically points a browser to that location.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% It is natural to want to include QR codes in certain \LaTeX\ documents;
|
2022-08-21 07:12:40 +00:00
|
|
|
% for example, one may want to direct the reader of a printed page to
|
2022-07-25 14:25:38 +00:00
|
|
|
% related interactive content online.
|
|
|
|
% Before now, the only \LaTeX\ package for producing QR codes was the
|
2022-08-21 07:12:40 +00:00
|
|
|
% immensely flexible {\tt pst-barcode}. As that package relies on
|
|
|
|
% {\tt pstricks}, however, it can be difficult to integrate with
|
2022-07-25 14:25:38 +00:00
|
|
|
% a pdf\LaTeX\ workflow,\footnote{%
|
|
|
|
% The {\tt auto-pst-pdf} or {\tt pstool} packages can make this possible
|
|
|
|
% by automatically running
|
2022-08-21 07:12:40 +00:00
|
|
|
% \LaTeX${}\rightarrow \tt dvips \rightarrow ps2pdf \rightarrow pdfcrop$
|
|
|
|
% for each barcode generated in {\tt pstricks},
|
2022-07-25 14:25:38 +00:00
|
|
|
% so long as the user is able and willing to enable {\tt\string\write18}
|
|
|
|
% in {\tt pdflatex} and install Perl.
|
|
|
|
% Judging by questions on {\tt tex.stackexchange.com} and {\tt latexcommunity.org},
|
|
|
|
% this is a significant hurdle for some users.
|
|
|
|
% Moreover, according to {\tt http://tex.stackexchange.com/questions/72876/}
|
|
|
|
% this workflow may have trouble if the QR code is in a header.}
|
|
|
|
% and a pdf\LaTeX\ user may not want the extra overhead just to produce a QR code.
|
|
|
|
% If one wants to avoid {\tt pstricks}, a Lua\TeX\ solution was proposed at
|
|
|
|
% {\tt http://tex.stackexchange.com/questions/89649/},
|
2022-08-21 07:12:40 +00:00
|
|
|
% and a plain\TeX\ solution can be found at
|
2022-07-25 14:25:38 +00:00
|
|
|
% {\catcode`\~=12\tt http://ktiml.mff.cuni.cz/~maj/QRcode.TeX},
|
|
|
|
% but until now no \LaTeX\ package had been available that did not call on outside machinery.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
|
|
|
% The {\tt qrcode} package, in contrast, implements the QR code algorithm using
|
2022-07-25 14:25:38 +00:00
|
|
|
% only \TeX\ and \LaTeX\ commands, so it should work with any \LaTeX\ workflow.
|
2022-08-21 07:12:40 +00:00
|
|
|
% Because it draws the squares constituting a QR code using the \TeX\ primitive
|
2022-07-25 14:25:38 +00:00
|
|
|
% |\rule|, there is no need to load any graphics package whatsoever.
|
|
|
|
% For a user who merely wants a QR code, this is the simplest solution.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \section{Usage}\label{sect:usage}
|
|
|
|
%
|
|
|
|
%
|
|
|
|
% \DescribeMacro{\qrcode}
|
|
|
|
% The package provides just one command, |\qrcode|, with the following syntax:
|
|
|
|
% \begin{center}
|
|
|
|
% |\qrcode|\oarg{options}\marg{text to be encoded}
|
|
|
|
% \end{center}
|
|
|
|
% For example, |\qrcode[hyperlink,height=0.5in]{http://www.ctan.org}| produces
|
|
|
|
% \begin{center}
|
|
|
|
% \qrcode[hyperlink,height=0.5in]{http://www.ctan.org}
|
|
|
|
% \end{center}
|
|
|
|
% Although the most common use of QR codes is as URLs,
|
|
|
|
% the \meta{text to be encoded} can be almost any typed text.
|
|
|
|
% The few exceptions to this are described in section \ref{sect:specialcharacters}.
|
|
|
|
%
|
|
|
|
% \subsection{Package Options}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \DescribeMacro{nolinks}
|
|
|
|
% When the |hyperref| package is loaded,
|
|
|
|
% by default |\qrcode| assumes its argument is a URL
|
|
|
|
% and makes the QR code produced a hyperlink to that URL.
|
|
|
|
% This default behavior may be changed by invoking the |nolinks| package option.
|
2022-08-21 07:12:40 +00:00
|
|
|
% For example, most of the QR codes in this document are not in fact URLs,
|
2022-07-25 14:25:38 +00:00
|
|
|
% so this documentation was typeset with |\usepackage[nolinks]{qrcode}|.
|
|
|
|
% The |hyperlinks| option is an antonym to |nolinks| and is the default.
|
|
|
|
% These options have no effect if hyperref is not loaded.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \DescribeMacro{draft}
|
|
|
|
% \DescribeMacro{final}
|
2022-08-21 07:12:40 +00:00
|
|
|
% Creating QR codes for short URLs takes relatively little time.\footnote{On
|
|
|
|
% this author's laptop, even a 60-character URL (version 4, level M) adds
|
2022-07-25 14:25:38 +00:00
|
|
|
% only about 0.7 seconds of compilation time.}
|
|
|
|
% Because \TeX\ was designed for typesetting, not for extensive computations,
|
|
|
|
% however, if many small QR codes or a single large one are required,
|
|
|
|
% the time spent can be quite noticeable. To save compilation
|
2022-08-21 07:12:40 +00:00
|
|
|
% time while working on a large document, calling the |draft| option
|
2022-07-25 14:25:38 +00:00
|
|
|
% causes the package not to compute QR codes, but merely to insert placeholder
|
|
|
|
% symbols with no data. The |final| option is an antonym to |draft|
|
|
|
|
% and is the default.
|
|
|
|
% \begin{quote}
|
|
|
|
% \begin{tabular}{p{1.25in}p{3.5in}}
|
|
|
|
% {\qrcode[draft,version=15]{http://www.tug.org}}
|
|
|
|
% &
|
|
|
|
% \begin{minipage}{3in}
|
2022-08-21 07:12:40 +00:00
|
|
|
% \tt
|
2022-07-25 14:25:38 +00:00
|
|
|
% |\documentclass{article}| \\
|
|
|
|
% |\usepackage[draft]{qrcode}| \\
|
|
|
|
% |\begin{document}| \\
|
|
|
|
% | \qrcode[version=15]{Dummy code}| \\
|
|
|
|
% |\end{document}|
|
|
|
|
% \end{minipage}
|
|
|
|
% \end{tabular}
|
|
|
|
% \end{quote}
|
|
|
|
% The placeholder symbol produced in {\tt draft} mode will have the same size
|
|
|
|
% and dimensions as the actual QR code.
|
|
|
|
%
|
|
|
|
% To conserve processing time, when |\qrcode| computes the binary matrix representing
|
|
|
|
% a QR code, it saves that binary data as a string of 1's and 0's
|
|
|
|
% both in a macro and in the {\tt .aux} file.
|
|
|
|
% Thus if the same QR code is desired later in the document, or upon the next
|
|
|
|
% run of \LaTeX, the QR symbol can be redrawn immediately from the saved binary data.
|
|
|
|
%
|
|
|
|
% \DescribeMacro{forget}
|
|
|
|
% There may be times when this is not desired; testing of this package is the chief
|
2022-08-21 07:12:40 +00:00
|
|
|
% example, but one might also have reason to believe that the {\tt .aux} file
|
2022-07-25 14:25:38 +00:00
|
|
|
% contains bad data.
|
|
|
|
% Invoking the |forget| package option causes |\qrcode| to calculate
|
|
|
|
% every QR code anew, even if a QR code for that \meta{text to be encoded}, level,
|
|
|
|
% and version
|
|
|
|
% was read from the {\tt .aux} file or was already computed earlier in the document.
|
|
|
|
%
|
|
|
|
% \subsection{Options}
|
|
|
|
% \DescribeMacro{\qrset}
|
|
|
|
% Several options affect the appearance and encoding of the QR code;
|
|
|
|
% {\tt qrcode} uses the {\tt xkeyval} package to handle the setting
|
|
|
|
% and processing of key-value pairs.
|
|
|
|
% The following options may either be given as optional arguments
|
|
|
|
% to |\qrcode| or changed within a \TeX-grouping using the
|
|
|
|
% macro |\qrset|.
|
|
|
|
% \begin{quote}
|
|
|
|
% \begin{tabular}{p{6cm}p{2in}}
|
|
|
|
% \qrcode{ABCD}
|
|
|
|
% {\qrset{height=1cm}%
|
|
|
|
% \qrcode{EFGH}}
|
|
|
|
% \qrcode{IJKL}
|
|
|
|
% &
|
|
|
|
% \begin{minipage}{3in}
|
|
|
|
% |\qrcode{ABCD}| \\
|
|
|
|
% |{\qrset{height=1cm}%| \\
|
|
|
|
% | \qrcode{EFGH}}| \\
|
|
|
|
% |\qrcode{IJKL}|
|
|
|
|
% \end{minipage}
|
|
|
|
% \end{tabular}
|
|
|
|
% \end{quote}
|
|
|
|
%
|
|
|
|
% \DescribeMacro{height}
|
2022-08-21 07:12:40 +00:00
|
|
|
% The |height=|\meta{dimen} key sets the printed height (and width) of the
|
2022-07-25 14:25:38 +00:00
|
|
|
% QR code. The default value is {\tt 2cm}.
|
|
|
|
% \begin{quote}
|
|
|
|
% \begin{tabular}{p{2in}p{2in}}
|
|
|
|
% \qrcode{ABCD} \qrcode[height=1cm]{ABCD}
|
|
|
|
% & |\qrcode{ABCD}| |\qrcode[height=1cm]{ABCD}|
|
|
|
|
% \end{tabular}
|
|
|
|
% \end{quote}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \DescribeMacro{level}
|
2022-08-21 07:12:40 +00:00
|
|
|
% The QR code specification (ISO 18004:2006) includes four
|
2022-07-25 14:25:38 +00:00
|
|
|
% levels of encoding: Low, Medium, Quality, and High, in
|
2022-08-21 07:12:40 +00:00
|
|
|
% increasing order of error-correction capabaility.
|
2022-07-25 14:25:38 +00:00
|
|
|
% In general, for a given text a higher error-correction
|
|
|
|
% level requires more bits of information in the QR code.
|
|
|
|
% The key |level=|\meta{level specification}
|
|
|
|
% selects the minimum acceptable level.
|
|
|
|
% The \meta{level specification} may be |L|, |M|, |Q|, or |H|;
|
|
|
|
% the default is |M|.
|
|
|
|
% It may happen that the smallest QR code able to encode
|
|
|
|
% the specified text at the desired level
|
2022-08-21 07:12:40 +00:00
|
|
|
% is in fact large enough to provide a higher level of
|
2022-07-25 14:25:38 +00:00
|
|
|
% error-correction. If so, {\tt qrcode} automatically upgrades to the higher
|
|
|
|
% error-correction level, and a message is printed in the log file.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \DescribeMacro{version}
|
2022-08-21 07:12:40 +00:00
|
|
|
% QR codes range in size from $21\times 21$ modules (``version 1'')
|
|
|
|
% to $177\times 177$ modules (``version 40''), in steps of 4 modules.
|
2022-07-25 14:25:38 +00:00
|
|
|
% The package automatically selects the smallest version large enough to encode
|
|
|
|
% the specified text at the desired error-correction level.
|
|
|
|
% Nevertheless, there might be occasions when a specific version is required;
|
2022-08-21 07:12:40 +00:00
|
|
|
% for example, perhaps a set of QR codes should have the same dimensions for
|
2022-07-25 14:25:38 +00:00
|
|
|
% aesthetic reasons, even though some encode shorter texts than others.
|
|
|
|
% For this reason, the key |version=|\meta{version specification} allows the user
|
|
|
|
% to specify a minimum version number, from 1 through 40, for the QR code.
|
|
|
|
% Setting |version=0| means ``as small as possible''; this is the default.
|
|
|
|
% If the desired version is not large enough to encode the text, the version
|
|
|
|
% will automatically be increased to accommodate the text, and a message will
|
|
|
|
% be placed in the log file.
|
|
|
|
% \begin{quote}
|
|
|
|
% \begin{tabular}{p{5.2cm}p{3in}}
|
|
|
|
% \raggedright
|
|
|
|
% \qrcode{ABCD}
|
2022-08-21 07:12:40 +00:00
|
|
|
% \qrcode[version=5]{ABCD}
|
2022-07-25 14:25:38 +00:00
|
|
|
% \medskip \\
|
|
|
|
% \qrcode[version=10]{ABCD}
|
|
|
|
% \qrcode[version=20]{ABCD}
|
|
|
|
% &
|
|
|
|
% \begin{minipage}{3in}
|
|
|
|
% |\qrcode{ABCD}| \\
|
|
|
|
% |\qrcode[version=5]{ABCD}| \\
|
|
|
|
% |\medskip \\| \\
|
|
|
|
% |\qrcode[version=10]{ABCD}| \\
|
|
|
|
% |\qrcode[version=20]{ABCD}|
|
|
|
|
% \end{minipage}
|
|
|
|
% \end{tabular}
|
|
|
|
% \end{quote}
|
|
|
|
%
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \DescribeMacro{tight}
|
|
|
|
% \DescribeMacro{padding}
|
|
|
|
% The QR specification states that a QR code should be surrounded by white\-space
|
|
|
|
% of a width equal to that of four modules. In many applications, a document
|
2022-08-21 07:12:40 +00:00
|
|
|
% author is likely to provide sufficient spacing anyway (e.g., by placing the
|
|
|
|
% QR code in a {\tt center} environment, header, or |\marginpar|), so by
|
|
|
|
% default the |qrcode| package adds no spacing. If the option |padding| is
|
2022-07-25 14:25:38 +00:00
|
|
|
% specified, however, the QR code will automatically be surrounded with 4 modules'
|
|
|
|
% worth of white\-space. The key |tight| is an antonym of |padding|; the default is |tight|.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \DescribeMacro{link}
|
|
|
|
% \DescribeMacro{nolink}
|
|
|
|
% \DescribeMacro{\qrcode*}
|
|
|
|
% As described above, if the |hyperref| package is loaded,
|
2022-08-21 07:12:40 +00:00
|
|
|
% then the QR codes produced in a PDF document can be made
|
|
|
|
% into hyperlinks to their text. The default behavior
|
2022-07-25 14:25:38 +00:00
|
|
|
% can be controlled with the options |nolinks| and |hyperlinks|,
|
|
|
|
% but this default can be overridden for individual QR codes by invoking
|
2022-08-21 07:12:40 +00:00
|
|
|
% the options |link| or |nolink|.
|
|
|
|
% Moreover, the starred version of the macro, |\qrcode*|, is a shorthand
|
2022-07-25 14:25:38 +00:00
|
|
|
% equivalent to |\qrcode[nolink]|.
|
|
|
|
% \begin{quote}
|
|
|
|
% \begin{tabular}{p{5.2cm}p{3in}}
|
|
|
|
% \raggedright
|
|
|
|
% \qrset{link, height=1.5cm}
|
|
|
|
% \qrcode{http://www.ctan.org}
|
|
|
|
% \qrcode[nolink]{This is not a URL.}
|
2022-08-21 07:12:40 +00:00
|
|
|
% \qrcode*{Neither is this.}
|
2022-07-25 14:25:38 +00:00
|
|
|
% &
|
|
|
|
% \begin{minipage}{3in}
|
|
|
|
% |\qrset{link, height=1.5cm}| \\
|
|
|
|
% |\qrcode{http://www.ctan.org}| \\
|
|
|
|
% |\qrcode[nolink]{This is not a URL.}| \\
|
|
|
|
% |\qrcode*{Neither is this.}|
|
|
|
|
% \end{minipage}
|
|
|
|
% \end{tabular}
|
|
|
|
% \end{quote}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \subsection{Special characters}\label{sect:specialcharacters}
|
|
|
|
% Many URLs can be processed by \TeX\ with no hiccups,
|
|
|
|
% but not infrequently a URL may contain the symbols |%|, |#|,
|
|
|
|
% |~|, |_|, and |&|. Moreover, QR codes need not just contain
|
|
|
|
% URL's, so a user may wish to encode text containing |^|, |$|, or spaces.
|
|
|
|
% The |qrcode| package offers two ways of coping with these special characters.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
|
|
|
% First, the |\qrcode| command itself processes its \meta{text to be encoded}
|
2022-07-25 14:25:38 +00:00
|
|
|
% in a limited verbatim mode. The following characters will be encoded into
|
|
|
|
% the QR code as typed:
|
|
|
|
% \begin{center}
|
|
|
|
% |#| |$| |&| |^| |_| |~| |%| {\tt\char32}
|
|
|
|
% \end{center}
|
2022-08-21 07:12:40 +00:00
|
|
|
% and line breaks as well.\footnote{Technically, when the input character
|
2022-07-25 14:25:38 +00:00
|
|
|
% {\tt\char`\^\char`\^M} (CR, charcode 13) is encountered,
|
|
|
|
% the character {\tt\char`\^\char`\^J} (LF, charcode 10) is placed into the QR code.}
|
|
|
|
% Conspicuously absent from this list are |\|, |{|, and |}|.
|
|
|
|
% This is intentional, so that macros may be used within |\qrcode|
|
|
|
|
% to generate the \meta{text to be encoded} automatically.
|
|
|
|
% If these characters are desired, they may be obtained by ``escaping'' them
|
|
|
|
% with an extra backslash.
|
|
|
|
% \begin{quote}
|
|
|
|
% \begin{tabular}{p{2in}p{3in}}
|
|
|
|
% \qrset{height=1.5cm}%
|
|
|
|
% \qrcode{We can include #$&^_~%.}
|
|
|
|
% \def\foo{bar}%
|
|
|
|
% \qrcode{Set the \foo\ high.}
|
|
|
|
% \qrcode{We must escape \\emph\{this\}.}
|
|
|
|
% & \begin{minipage}{3in}
|
|
|
|
% |\qrset{height=1.5cm}%| \\
|
|
|
|
% |\qrcode{We can include #$&^_~%.}| \\
|
|
|
|
% |\def\foo{bar}%| \\
|
|
|
|
% |\qrcode{Set the \foo\ high.}| \\
|
|
|
|
% |\qrcode{We must escape \\emph\{this\}.}|
|
|
|
|
% \end{minipage}
|
|
|
|
% \end{tabular}
|
|
|
|
% \end{quote}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
|
|
|
% As with all verbatim modes, however, because \TeX\ irrevocably sets catcodes
|
2022-07-25 14:25:38 +00:00
|
|
|
% when it first encounters characters, this will not work if the |\qrcode| macro
|
|
|
|
% is contained in another macro. If you call |\qrcode| inside an
|
|
|
|
% |\fbox| or a |\marginpar|, for example, and if your URL contains one of those
|
|
|
|
% special characters, you will either encounter error messages or (worse, because
|
|
|
|
% it is undetectable to the naked eye) have the wrong QR code typeset.
|
|
|
|
% In this scenario, you can still include any of the characters
|
|
|
|
% |#$&^_~%|{\tt\char32}|\{}|
|
|
|
|
% by escaping them with an extra backslash;
|
|
|
|
% so long as they eventually pass unexpanded to |\qrcode|,
|
|
|
|
% they will produce the correct QR code.
|
|
|
|
% A line break may be obtained with |\?|.
|
|
|
|
% \begin{quote}
|
|
|
|
% \begin{tabular}{p{1.5cm}p{2in}}
|
2022-08-21 07:12:40 +00:00
|
|
|
% \fbox{\qrcode[height=1cm]{\#\$\&\^\_\~\?\%\ \\\{\}}}
|
|
|
|
% & |\fbox{qrcode[height=1cm]{\#\$\&\^\_\~\?\%\ \\\{\}}}|
|
2022-07-25 14:25:38 +00:00
|
|
|
% \end{tabular}
|
|
|
|
% \end{quote}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \section{Limitations and Cautions}
|
|
|
|
%
|
|
|
|
% \begin{itemize}
|
|
|
|
% \item The QR specification includes modes for encoding numeric, alphanumeric,
|
|
|
|
% or Kanji data more efficiently. This package does not (yet) offer
|
|
|
|
% those options.
|
|
|
|
% \item The QR specification offers ways to string lengthy data across multiple
|
|
|
|
% QR codes. This package does not implement that possibility.
|
|
|
|
% \end{itemize}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \StopEventually{}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \section{Implementation}
|
|
|
|
% \subsection{Key handling and options}
|
|
|
|
% \begin{macrocode}
|
|
|
|
%%PACKAGE LOADING
|
|
|
|
\RequirePackage{xcolor}%
|
|
|
|
\RequirePackage{xkeyval}%
|
|
|
|
|
|
|
|
%%INITIAL CODE
|
|
|
|
\newif\ifqr@draft@mode
|
|
|
|
\newif\ifqr@forget@mode
|
|
|
|
|
|
|
|
%%DECLARATION OF OPTIONS
|
|
|
|
\define@boolkey{qr}[qr@]{draft}[true]{\ifqr@draft\qr@draft@modetrue\else\qr@draft@modefalse\fi}%
|
|
|
|
\define@boolkey{qr}[qr@]{final}[true]{\ifqr@final\qr@draft@modefalse\else\qr@draft@modetrue\fi}%
|
|
|
|
\define@boolkey{qr}[qr@]{forget}[true]{\ifqr@forget\qr@forget@modetrue\else\qr@forget@modefalse\fi}%
|
|
|
|
\define@boolkey{qr}[qr@]{hyperlink}[true]{}% %This creates \ifqr@hyperlink.
|
|
|
|
\define@boolkey{qr}[qr@]{hyperlinks}[true]{\ifqr@hyperlinks\qr@hyperlinktrue\else\qr@hyperlinkfalse\fi}%
|
|
|
|
\define@boolkey{qr}[qr@]{link}[true]{\ifqr@link\qr@hyperlinktrue\else\qr@hyperlinkfalse\fi}%
|
|
|
|
\define@boolkey{qr}[qr@]{nolink}[true]{\ifqr@nolink\qr@hyperlinkfalse\else\qr@hyperlinktrue\fi}% %Make nolink an antonym.
|
|
|
|
\define@boolkey{qr}[qr@]{links}[true]{\ifqr@links\qr@hyperlinktrue\else\qr@hyperlinkfalse\fi}%
|
|
|
|
\define@boolkey{qr}[qr@]{nolinks}[true]{\ifqr@nolinks\qr@hyperlinkfalse\else\qr@hyperlinktrue\fi}% %Make nolinks an antonym.
|
|
|
|
|
|
|
|
%%EXECUTION OF OPTIONS
|
|
|
|
\qr@draft@modefalse
|
|
|
|
\qr@forget@modefalse
|
|
|
|
\qr@hyperlinktrue
|
|
|
|
|
|
|
|
\ProcessOptionsX<qr>
|
|
|
|
|
|
|
|
% \end{macrocode}
|
|
|
|
% \subsection{Utilities}
|
|
|
|
% \begin{macrocode}
|
|
|
|
%COUNTERS
|
|
|
|
\newcounter{qr@i}%
|
|
|
|
\newcounter{qr@j}%
|
|
|
|
\newcount\qr@a
|
|
|
|
\newcount\qr@b
|
|
|
|
\newcount\qr@c
|
|
|
|
|
|
|
|
%BASICS
|
|
|
|
\let\xa=\expandafter
|
|
|
|
|
|
|
|
%This is for messages.
|
|
|
|
\newlinechar=`\^^J
|
|
|
|
|
|
|
|
|
|
|
|
%Tests
|
|
|
|
\def\qr@relax{\relax}%
|
|
|
|
|
|
|
|
%Manipulating macros
|
|
|
|
\def\qr@preface@macro#1#2{%
|
|
|
|
% #1 = macro name
|
|
|
|
% #2 = text to add to front of macro
|
|
|
|
\def\qr@tempb{#2}%
|
|
|
|
\xa\xa\xa\def\xa\xa\xa#1\xa\xa\xa{\xa\qr@tempb #1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@g@preface@macro#1#2{%
|
|
|
|
% #1 = macro to be appended to
|
|
|
|
% #2 = code to add
|
|
|
|
\edef\qr@tempb{#2}%
|
|
|
|
\xa\xa\xa\gdef\xa\xa\xa#1\xa\xa\xa{\xa\qr@tempb#1}%
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@getstringlength#1{%
|
|
|
|
\bgroup
|
|
|
|
\qr@a=0%
|
|
|
|
\xdef\qr@thestring{#1}%
|
|
|
|
\xa\qr@stringlength@recursive\xa(\qr@thestring\relax\relax)%
|
|
|
|
\xdef\qr@stringlength{\the\qr@a}%
|
|
|
|
\egroup
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@stringlength@recursive(#1#2){%
|
|
|
|
\def\qr@testi{#1}%
|
|
|
|
\ifx\qr@testi\qr@relax
|
|
|
|
%we are done.
|
|
|
|
\let\qr@next=\relax%
|
2022-08-21 07:12:40 +00:00
|
|
|
\else
|
2022-07-25 14:25:38 +00:00
|
|
|
\advance\qr@a by 1%
|
|
|
|
\def\qr@next{\qr@stringlength@recursive(#2)}%
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
|
|
|
% \subsubsection{For-loop macro}
|
|
|
|
% We implement a macro |\qr@for| with the syntax
|
|
|
|
% \begin{center}
|
|
|
|
% |\qr@for| \meta{control sequence}=\meta{number} to \meta{number} by \meta{number} \marg{loop body}
|
|
|
|
% \end{center}
|
|
|
|
% The \meta{control sequence} becomes the loop variable,
|
|
|
|
% which is a \TeX\ counter.
|
|
|
|
% For example, |\qr@for \i=1 to 8 by 2 {\fbox{\number\i}}|
|
|
|
|
% produces {\makeatletter\qr@for \i=1 to 8 by 2 {\fbox{\number\i}}}.
|
|
|
|
% \begin{macrocode}
|
2022-08-21 07:12:40 +00:00
|
|
|
%The \qr@for@depth counter measures the depth of our loop.
|
2022-07-25 14:25:38 +00:00
|
|
|
%The outermost loop has depth zero.
|
|
|
|
\newcount\qr@for@depth%
|
|
|
|
\newcount\qr@for@maxdepth%
|
|
|
|
\qr@for@depth=0%
|
|
|
|
\qr@for@maxdepth=0%
|
|
|
|
%These counters are used in the qr@for loop.
|
|
|
|
\newcount\qr@for@start%
|
|
|
|
\newcount\qr@for@end%
|
|
|
|
\newcount\qr@for@step%
|
|
|
|
%Now a macro to get a new count for every depth as needed.
|
|
|
|
\def\qr@allocate@new@for@counter{%
|
|
|
|
\global\advance\qr@for@maxdepth by 1%
|
|
|
|
\newcount\qr@newforcount%
|
|
|
|
\xa\global\xa\let\csname qr@for@var@\the\qr@for@maxdepth\endcsname=\qr@newforcount%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifqr@loopshouldrun
|
|
|
|
%The extra # in the following definition makes sure #4 scoops up everything up to the next opening brace.
|
|
|
|
%This is needed so the step can include more than one character without being enclosed in braces itself.
|
|
|
|
\def\qr@for #1=#2to#3by#4#{%
|
|
|
|
\qr@for@int{#1}{#2}{#3}{#4}%
|
|
|
|
}%
|
|
|
|
\long\def\qr@for@int#1#2#3#4#5{%
|
|
|
|
\bgroup
|
2022-08-21 07:12:40 +00:00
|
|
|
%Because we're working within a TeX group,
|
2022-07-25 14:25:38 +00:00
|
|
|
%any values of \qr@for@start, \qr@for@end, and \qr@for@step from an outer loop
|
|
|
|
%will be restored after the \egroup.
|
|
|
|
%
|
|
|
|
%For the \qr@for@var itself, however, we need a different counter,
|
|
|
|
%because the user's text within the loop might need to access the variable from the outer loop.
|
|
|
|
\advance\qr@for@depth by 1\relax% This is a local change.
|
|
|
|
\ifnum\qr@for@depth>\qr@for@maxdepth%
|
|
|
|
%This is the first time we have gone to this depth of nesting!
|
|
|
|
%We should only be over by one.
|
|
|
|
\qr@allocate@new@for@counter%
|
|
|
|
\fi
|
|
|
|
% \showthe\qr@for@depth%
|
|
|
|
\xa\let\xa\qr@for@var\xa=\csname qr@for@var@\the\qr@for@depth\endcsname%
|
|
|
|
%Now \qr@for@var points to the same register as \qr@for@var@3 or something.
|
|
|
|
%The next line lets the user-level variable (e.g., \i or \j) point to the same count register.
|
|
|
|
\let#1=\qr@for@var%
|
|
|
|
%Now establish the looping parameters.
|
|
|
|
\edef\qr@for@start@text{#2}%
|
|
|
|
\edef\qr@for@end@text{#3}%
|
|
|
|
\edef\qr@for@step@text{#4}%
|
|
|
|
\def\qr@for@body{\bgroup #5\egroup}%
|
|
|
|
\xa\qr@for@start\qr@for@start@text\relax%
|
|
|
|
\xa\qr@for@end \qr@for@end@text\relax%
|
|
|
|
\xa\qr@for@step \qr@for@step@text\relax%
|
|
|
|
%
|
|
|
|
%Next, test whether the loop should run at all.
|
|
|
|
% * "\qr@for \i = 1 to 0 by 1" should fail.
|
|
|
|
% * "\qr@for \i = 3 to 5 by -1" should fail.
|
|
|
|
% * "\qr@for \i = 6 to 2 by 1" should fail.
|
|
|
|
% * "\qr@for \i = 4 to 4 by -1" should run.
|
|
|
|
% * "\qr@for \i = 4 to 4 by 1" should run.
|
|
|
|
% * "\qr@for \i = 5 to 7 by 0" should fail.
|
|
|
|
%The loop should fail if (step)=0 or if (step) and (end-start) have opposite signs.
|
|
|
|
%The loop will fail if (step=0) or (step)*(end-start)<0.
|
|
|
|
% TODO: "\qr@for \i = 5 to 5 by 0" should run (just one iteration).
|
|
|
|
\qr@loopshouldruntrue
|
|
|
|
\ifnum\qr@for@step=0\relax
|
|
|
|
\qr@loopshouldrunfalse
|
|
|
|
\fi
|
|
|
|
\qr@a=\qr@for@end%
|
|
|
|
\advance\qr@a by -\qr@for@start%
|
|
|
|
\multiply\qr@a by \qr@for@step%
|
|
|
|
\ifnum\qr@a<0\relax
|
|
|
|
\qr@loopshouldrunfalse
|
|
|
|
\fi
|
|
|
|
\ifqr@loopshouldrun
|
|
|
|
\qr@for@var=\qr@for@start%
|
|
|
|
\ifnum\qr@for@step>0\relax
|
|
|
|
\def\qr@for@recursive{%
|
|
|
|
\qr@for@body%
|
|
|
|
\advance\qr@for@var by \qr@for@step%
|
|
|
|
\ifnum\qr@for@var>\qr@for@end%
|
|
|
|
\let\qr@for@next=\relax%
|
|
|
|
\else%
|
|
|
|
\let\qr@for@next=\qr@for@recursive%
|
|
|
|
\fi%
|
|
|
|
\qr@for@next%
|
|
|
|
}%
|
|
|
|
\else
|
|
|
|
\def\qr@for@recursive{%
|
|
|
|
\qr@for@body%
|
|
|
|
\advance\qr@for@var by \qr@for@step%
|
|
|
|
\ifnum\qr@for@var<\qr@for@end%
|
|
|
|
\let\qr@for@next=\relax%
|
|
|
|
\else%
|
|
|
|
\let\qr@for@next=\qr@for@recursive%
|
|
|
|
\fi%
|
|
|
|
\qr@for@next%
|
|
|
|
}%
|
|
|
|
\fi
|
|
|
|
\qr@for@recursive%
|
|
|
|
\fi
|
|
|
|
\egroup
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
|
|
|
% \subsubsection{Base conversions}
|
|
|
|
% \begin{macrocode}
|
|
|
|
\def\qr@padatfront#1#2{%
|
|
|
|
% #1 = macro containing text to pad
|
|
|
|
% #2 = desired number of characters
|
|
|
|
% Pads a number with initial zeros.
|
|
|
|
\qr@getstringlength{#1}%
|
|
|
|
\qr@a=\qr@stringlength\relax%
|
|
|
|
\advance\qr@a by 1\relax%
|
|
|
|
\qr@for \i = \qr@a to #2 by 1\relax%
|
|
|
|
{\qr@g@preface@macro{#1}{0}}%
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
\qr@a=-1\relax%
|
|
|
|
\def\qr@savehexsymbols(#1#2){%
|
|
|
|
\advance\qr@a by 1\relax%
|
|
|
|
\xa\def\csname qr@hexchar@\the\qr@a\endcsname{#1}%
|
|
|
|
\xa\edef\csname qr@hextodecimal@#1\endcsname{\the\qr@a}%
|
|
|
|
\ifnum\qr@a=15\relax
|
|
|
|
%Done.
|
|
|
|
\let\qr@next=\relax%
|
|
|
|
\else
|
|
|
|
\def\qr@next{\qr@savehexsymbols(#2)}%
|
|
|
|
\fi%
|
|
|
|
\qr@next%
|
|
|
|
}%
|
|
|
|
\qr@savehexsymbols(0123456789abcdef\relax\relax)%
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@decimaltobase#1#2#3{%
|
|
|
|
% #1 = macro to store result
|
|
|
|
% #2 = decimal representation of a positive integer
|
|
|
|
% #3 = new base
|
|
|
|
\bgroup
|
|
|
|
\edef\qr@newbase{#3}%
|
|
|
|
\gdef\qr@base@result{}%
|
|
|
|
\qr@a=#2\relax%
|
|
|
|
\qr@decimaltobase@recursive%
|
|
|
|
\xdef#1{\qr@base@result}%
|
|
|
|
\egroup
|
|
|
|
}
|
|
|
|
\def\qr@decimaltobase@recursive{%
|
|
|
|
\qr@b=\qr@a%
|
|
|
|
\divide\qr@b by \qr@newbase\relax
|
|
|
|
\multiply\qr@b by -\qr@newbase\relax
|
|
|
|
\advance\qr@b by \qr@a\relax%
|
|
|
|
\divide\qr@a by \qr@newbase\relax%
|
|
|
|
\ifnum\qr@b<10\relax
|
|
|
|
\edef\qr@newdigit{\the\qr@b}%
|
|
|
|
\else
|
|
|
|
\edef\qr@newdigit{\csname qr@hexchar@\the\qr@b\endcsname}%
|
|
|
|
\fi
|
|
|
|
\edef\qr@argument{{\noexpand\qr@base@result}{\qr@newdigit}}%
|
|
|
|
\xa\qr@g@preface@macro\qr@argument%
|
|
|
|
\ifnum\qr@a=0\relax
|
|
|
|
\relax
|
|
|
|
\else
|
|
|
|
\xa\qr@decimaltobase@recursive
|
|
|
|
\fi
|
|
|
|
}
|
|
|
|
|
|
|
|
\newcommand\qr@decimaltohex[3][0]{%
|
|
|
|
% #1 (opt.) = number of hex digits to create
|
|
|
|
% #2 = macro to store result
|
|
|
|
% #3 = decimal digits to convert
|
|
|
|
\qr@decimaltobase{#2}{#3}{16}%
|
|
|
|
\qr@padatfront{#2}{#1}%
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
\newcommand\qr@decimaltobinary[3][0]{%
|
|
|
|
% #1 (opt.) = number of bits to create
|
|
|
|
% #2 = macro to store result
|
|
|
|
% #3 = decimal digits to convert
|
|
|
|
\qr@decimaltobase{#2}{#3}{2}%
|
|
|
|
\qr@padatfront{#2}{#1}%
|
|
|
|
}
|
|
|
|
|
|
|
|
\qr@for \i = 0 to 15 by 1%
|
|
|
|
{%
|
|
|
|
\qr@decimaltohex[1]{\qr@hexchar}{\the\i}%
|
|
|
|
\qr@decimaltobinary[4]{\qr@bits}{\the\i}%
|
|
|
|
\xa\xdef\csname qr@b2h@\qr@bits\endcsname{\qr@hexchar}%
|
|
|
|
\xa\xdef\csname qr@h2b@\qr@hexchar\endcsname{\qr@bits}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\newcommand\qr@binarytohex[3][\relax]{%
|
|
|
|
% #1 (optional) = # digits desired
|
|
|
|
% #2 = macro to save to
|
|
|
|
% #3 = binary string (must be multiple of 4 bits)
|
|
|
|
\def\qr@test@i{#1}%
|
|
|
|
\ifx\qr@test@i\qr@relax%
|
|
|
|
%No argument specified
|
|
|
|
\def\qr@desireddigits{0}%
|
|
|
|
\else
|
|
|
|
\def\qr@desireddigits{#1}%
|
|
|
|
\fi
|
|
|
|
\gdef\qr@base@result{}%
|
|
|
|
\edef\qr@argument{(#3\relax\relax\relax\relax\relax)}%
|
|
|
|
\xa\qr@binarytohex@int\qr@argument%
|
|
|
|
\qr@padatfront{\qr@base@result}{\qr@desireddigits}%
|
|
|
|
\xdef#2{\qr@base@result}%
|
|
|
|
}
|
|
|
|
\def\qr@binarytohex@int(#1#2#3#4#5){%
|
|
|
|
% #1#2#3#4 = 4 bits
|
|
|
|
% #5 = remainder, including \relax\relax\relax\relax\relax terminator
|
|
|
|
\def\qr@test@i{#1}%
|
|
|
|
\ifx\qr@test@i\qr@relax%
|
|
|
|
%Done.
|
|
|
|
\def\qr@next{\relax}%
|
|
|
|
\else%
|
|
|
|
\xdef\qr@base@result{\qr@base@result\csname qr@b2h@#1#2#3#4\endcsname}%
|
|
|
|
\def\qr@next{\qr@binarytohex@int(#5)}%
|
|
|
|
\fi%
|
|
|
|
\qr@next%
|
|
|
|
}
|
|
|
|
|
|
|
|
\newcommand\qr@hextobinary[3][\relax]{%
|
|
|
|
% #1 (optional) = # bits desired
|
|
|
|
% #2 = macro to save to
|
|
|
|
% #3 = hexadecimal string
|
|
|
|
\bgroup
|
|
|
|
\def\qr@test@i{#1}%
|
|
|
|
\ifx\qr@test@i\qr@relax%
|
|
|
|
%No argument specified
|
|
|
|
\def\qr@desireddigits{0}%
|
|
|
|
\else
|
|
|
|
\def\qr@desireddigits{#1}%
|
|
|
|
\fi
|
|
|
|
\gdef\qr@base@result{}%
|
|
|
|
\edef\qr@argument{(#3\relax\relax)}%
|
|
|
|
\xa\qr@hextobinary@int\qr@argument%
|
|
|
|
\qr@padatfront{\qr@base@result}{\qr@desireddigits}%
|
|
|
|
\xdef#2{\qr@base@result}%
|
|
|
|
\egroup
|
|
|
|
}
|
|
|
|
\def\qr@hextobinary@int(#1#2){%
|
|
|
|
% #1 = hexadecimal character
|
|
|
|
% #2 = remainder, including \relax\relax terminator
|
|
|
|
\def\qr@test@@i{#1}%
|
|
|
|
\ifx\qr@test@@i\qr@relax%
|
|
|
|
%Done.
|
|
|
|
\def\qr@next{\relax}%
|
|
|
|
\else%
|
|
|
|
\xdef\qr@base@result{\qr@base@result\csname qr@h2b@#1\endcsname}%
|
|
|
|
\def\qr@next{\qr@hextobinary@int(#2)}%
|
|
|
|
\fi%
|
|
|
|
\qr@next%
|
|
|
|
}
|
|
|
|
|
|
|
|
\def\qr@hextodecimal#1#2{%
|
|
|
|
\edef\qr@argument{#2}%
|
|
|
|
\xa\qr@a\xa=\xa\number\xa"\qr@argument\relax%
|
|
|
|
\edef#1{\the\qr@a}%
|
|
|
|
}
|
|
|
|
|
|
|
|
\def\qr@hextodecimal#1#2{%
|
|
|
|
% #1 = macro to store result
|
|
|
|
% #2 = hexadecimal representation of a positive integer
|
|
|
|
\bgroup
|
|
|
|
\qr@a=0\relax%
|
|
|
|
\edef\qr@argument{(#2\relax)}%
|
|
|
|
\xa\qr@hextodecimal@recursive\qr@argument%
|
|
|
|
\xdef#1{\the\qr@a}%
|
|
|
|
\egroup
|
|
|
|
}
|
|
|
|
\def\qr@hextodecimal@recursive(#1#2){%
|
|
|
|
% #1 = first hex char
|
|
|
|
% #2 = remainder
|
|
|
|
\advance \qr@a by \csname qr@hextodecimal@#1\endcsname\relax%
|
|
|
|
\edef\qr@testii{#2}%
|
|
|
|
\ifx\qr@testii\qr@relax%
|
|
|
|
%Done.
|
|
|
|
\let\qr@next=\relax%
|
|
|
|
\else
|
|
|
|
%There's at least one more digit.
|
|
|
|
\multiply\qr@a by 16\relax
|
|
|
|
\edef\qr@next{\noexpand\qr@hextodecimal@recursive(#2)}%
|
|
|
|
\fi%
|
|
|
|
\qr@next%
|
|
|
|
}
|
|
|
|
% \end{macrocode}
|
|
|
|
% \subsubsection{Catcode setup}
|
|
|
|
% \begin{macrocode}
|
|
|
|
%The following catcode trickery creates special characters
|
|
|
|
%with catcode 12 (other) for use in our verbatim handling.
|
|
|
|
{\catcode`\ =12\relax\gdef\qr@otherspace{ }}%
|
|
|
|
{\catcode`\%=12\relax\gdef\qr@otherpercent{%}}%
|
|
|
|
{\catcode`\#=12\relax\gdef\qr@otherpound{#}}%
|
|
|
|
{\catcode`\|=0\relax|catcode`|\=12|relax|gdef|qr@otherbackslash{\}}%
|
|
|
|
{\catcode`\^^J=12\relax\gdef\qr@otherlf{^^J}}%
|
|
|
|
\bgroup
|
|
|
|
\catcode`\<=1\relax
|
|
|
|
\catcode`\>=2\relax
|
|
|
|
\catcode`\{=12\relax\gdef\qr@otherleftbrace<{>%
|
|
|
|
\catcode`\}=12\relax\gdef\qr@otherrightbrace<}>%
|
|
|
|
\egroup%
|
|
|
|
{\catcode`\&=12\relax\gdef\qr@otherampersand{&}}%
|
|
|
|
{\catcode`\~=12\relax\gdef\qr@othertilde{~}}%
|
|
|
|
{\catcode`\^=12\relax\gdef\qr@othercaret{^}}%
|
|
|
|
{\catcode`\_=12\relax\gdef\qr@otherunderscore{_}}%
|
|
|
|
{\catcode`\$=12\relax\gdef\qr@otherdollar{$}}%
|
|
|
|
|
2022-08-21 07:12:40 +00:00
|
|
|
%Line feeds require some special handling. \TeX\ reads a line feed in the input
|
2022-07-25 14:25:38 +00:00
|
|
|
%as |^^M| (carriage return, character code 13), but it should be encoded in a
|
|
|
|
%QR code as |^^J| (line feed, character code 10).
|
|
|
|
%To do this, we make |^^M| an active character and a synonym for a |^^J| with catcode 12.
|
|
|
|
%Note that the macro |\qr@verbatimlinefeeds| must itself be processed with |^^M| active.
|
|
|
|
{\catcode`\^^M=13\relax\gdef\qr@verbatimlinefeeds{\let^^M=\qr@otherlf}}
|
|
|
|
\def\qr@verbatimcatcodes{%
|
|
|
|
\catcode`\#=12\relax
|
|
|
|
\catcode`\$=12\relax
|
|
|
|
\catcode`\&=12\relax
|
|
|
|
\catcode`\^=12\relax
|
|
|
|
\catcode`\_=12\relax
|
|
|
|
\catcode`\~=12\relax
|
|
|
|
\catcode`\%=12\relax
|
|
|
|
\catcode`\ =12\relax
|
|
|
|
\catcode`\^^M=13\relax\qr@verbatimlinefeeds}%
|
|
|
|
|
|
|
|
\def\qr@setescapedspecials{%
|
|
|
|
\let\ =\qr@otherspace%
|
|
|
|
\let\%=\qr@otherpercent%
|
|
|
|
\let\#=\qr@otherpound%
|
|
|
|
\let\&=\qr@otherampersand%
|
|
|
|
\let\^=\qr@othercaret%
|
|
|
|
\let\_=\qr@otherunderscore%
|
|
|
|
\let\~=\qr@othertilde%
|
|
|
|
\let\$=\qr@otherdollar%
|
|
|
|
\let\\=\qr@otherbackslash%
|
|
|
|
\let\{=\qr@otherleftbrace%
|
|
|
|
\let\}=\qr@otherrightbrace%
|
|
|
|
\let\?=\qr@otherlf%
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
|
|
|
% \subsection{Plotting}
|
|
|
|
% \begin{macrocode}
|
|
|
|
\def\qr@creatematrix#1{%
|
|
|
|
\xa\gdef\csname #1\endcsname##1##2{%
|
|
|
|
\csname #1@##1@##2\endcsname
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@storetomatrix#1#2#3#4{%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = row number
|
|
|
|
% #3 = column number
|
|
|
|
% #4 = value of matrix entry
|
|
|
|
\xa\gdef\csname #1@#2@#3\endcsname{#4}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@estoretomatrix#1#2#3#4{%
|
|
|
|
% This version performs exactly one expansion on #4.
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = row number
|
|
|
|
% #3 = column number
|
|
|
|
% #4 = value of matrix
|
|
|
|
\xa\xa\xa\gdef\xa\xa\csname #1@#2@#3\endcsname\xa{#4}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@matrixentry#1#2#3{%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = row number
|
|
|
|
% #3 = column number
|
|
|
|
\csname #1@#2@#3\endcsname%
|
|
|
|
}%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@createsquareblankmatrix#1#2{%
|
|
|
|
\qr@creatematrix{#1}%
|
|
|
|
\xa\gdef\csname #1@numrows\endcsname{#2}%
|
|
|
|
\xa\gdef\csname #1@numcols\endcsname{#2}%
|
|
|
|
\qr@for \i = 1 to #2 by 1%
|
|
|
|
{\qr@for \j = 1 to #2 by 1%
|
|
|
|
{\qr@storetomatrix{#1}{\the\i}{\the\j}{\qr@blank}}}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@numberofrowsinmatrix#1{%
|
|
|
|
\csname #1@numrows\endcsname%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@numberofcolsinmatrix#1{%
|
|
|
|
\csname #1@numcols\endcsname%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@setnumberofrows#1#2{%
|
|
|
|
\xa\xdef\csname #1@numrows\endcsname{#2}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@setnumberofcols#1#2{%
|
|
|
|
\xa\xdef\csname #1@numcols\endcsname{#2}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newlength\qr@desiredheight
|
|
|
|
\setlength\qr@desiredheight{2cm}%
|
|
|
|
\newlength\qr@modulesize
|
|
|
|
\newlength\qr@minipagewidth
|
|
|
|
|
|
|
|
\def\qr@printmatrix#1{%
|
|
|
|
\def\qr@black{\rule{\qr@modulesize}{\qr@modulesize}}%
|
|
|
|
\def\qr@white{\rule{\qr@modulesize}{0pt}}%
|
|
|
|
\def\qr@black@fixed{\rule{\qr@modulesize}{\qr@modulesize}}%
|
|
|
|
\def\qr@white@fixed{\rule{\qr@modulesize}{0pt}}%
|
|
|
|
\def\qr@black@format{\rule{\qr@modulesize}{\qr@modulesize}}%
|
|
|
|
\def\qr@white@format{\rule{\qr@modulesize}{0pt}}%
|
|
|
|
%Set module size
|
|
|
|
\setlength{\qr@modulesize}{\qr@desiredheight}%
|
|
|
|
\divide\qr@modulesize by \qr@size\relax%
|
|
|
|
%
|
|
|
|
\setlength{\qr@minipagewidth}{\qr@modulesize}%
|
|
|
|
\multiply\qr@minipagewidth by \qr@size\relax%
|
|
|
|
\ifqr@tight
|
|
|
|
\else
|
|
|
|
\advance\qr@minipagewidth by 8\qr@modulesize%
|
|
|
|
\fi
|
|
|
|
\begin{minipage}{\qr@minipagewidth}%
|
|
|
|
\baselineskip=\qr@modulesize%
|
|
|
|
\ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi% %Blank space at top.
|
|
|
|
\qr@for \i = 1 to \qr@numberofrowsinmatrix{#1} by 1%
|
|
|
|
{\ifqr@tight\else\rule{4\qr@modulesize}{0pt}\fi% %Blank space at left.
|
|
|
|
\qr@for \j = 1 to \qr@numberofcolsinmatrix{#1} by 1%
|
|
|
|
{\qr@matrixentry{#1}{\the\i}{\the\j}}%
|
|
|
|
\par}%
|
|
|
|
\ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi%
|
|
|
|
\end{minipage}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@printsavedbinarymatrix#1{%
|
|
|
|
\edef\qr@binarystring{#1\relax\relax}%
|
|
|
|
%Set module size
|
|
|
|
\setlength{\qr@modulesize}{\qr@desiredheight}%
|
|
|
|
\divide\qr@modulesize by \qr@size\relax%
|
|
|
|
%
|
|
|
|
\setlength{\qr@minipagewidth}{\qr@modulesize}%
|
|
|
|
\multiply\qr@minipagewidth by \qr@size\relax%
|
|
|
|
\ifqr@tight
|
|
|
|
\else
|
|
|
|
\advance\qr@minipagewidth by 8\qr@modulesize%
|
|
|
|
\fi
|
|
|
|
\begin{minipage}{\qr@minipagewidth}%
|
|
|
|
\baselineskip=\qr@modulesize%
|
|
|
|
\ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi% %Blank space at top.
|
|
|
|
\qr@for \i = 1 to \qr@size by 1%
|
|
|
|
{\ifqr@tight\else\rule{4\qr@modulesize}{0pt}\fi% %Blank space at left.
|
|
|
|
\qr@for \j = 1 to \qr@size by 1%
|
|
|
|
{\edef\qr@theargument{(\qr@binarystring)}%
|
|
|
|
\xa\qr@printsavedbinarymatrix@int\qr@theargument
|
|
|
|
}%
|
|
|
|
\par}%
|
|
|
|
\ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi%
|
|
|
|
\end{minipage}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@printsavedbinarymatrix@int(#1#2){%
|
|
|
|
% #1 = first bit, either 1 or 0.
|
|
|
|
% #2 = remainder of string, terminating with \relax\relax
|
|
|
|
% There's no need to check for EOF here, because
|
|
|
|
% we'll only call this n^2 times.
|
|
|
|
\ifcase #1\relax
|
|
|
|
\rule{\qr@modulesize}{0pt}% % 0: white square
|
|
|
|
\or
|
|
|
|
\rule{\qr@modulesize}{\qr@modulesize}% % 1: black square
|
|
|
|
\fi
|
|
|
|
\xdef\qr@binarystring{#2}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@createliteralmatrix#1#2#3{%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = m, the number of rows and columns in the square matrix
|
|
|
|
% #3 = a string of m^2 tokens to be written into the matrix
|
|
|
|
\qr@creatematrix{#1}%
|
|
|
|
\xa\xdef\csname #1@numrows\endcsname{#2}%
|
|
|
|
\xa\xdef\csname #1@numcols\endcsname{#2}%
|
|
|
|
\gdef\qr@literalmatrix@tokens{#3}%
|
|
|
|
\qr@for \i = 1 to #2 by 1%
|
|
|
|
{\qr@for \j = 1 to #2 by 1%
|
|
|
|
{\xa\qr@createliteralmatrix@int\xa(\qr@literalmatrix@tokens)%
|
|
|
|
\qr@estoretomatrix{#1}{\the\i}{\the\j}{\qr@entrytext}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
}
|
|
|
|
\def\qr@createliteralmatrix@int(#1#2){%
|
|
|
|
\def\qr@entrytext{#1}%
|
|
|
|
\gdef\qr@literalmatrix@tokens{#2}%
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
\qr@createliteralmatrix{finderpattern}{8}{%
|
|
|
|
\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed%
|
|
|
|
\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed%
|
|
|
|
\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\qr@createliteralmatrix{alignmentpattern}{5}{%
|
|
|
|
\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed%
|
|
|
|
\qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed%
|
|
|
|
\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed%
|
|
|
|
}%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@copymatrixentry#1#2#3#4#5#6{%
|
|
|
|
% Copy the (#2,#3) entry of matrix #1
|
|
|
|
% to the (#5,#6) position of matrix #4.
|
|
|
|
\xa\xa\xa\global%
|
|
|
|
\xa\xa\xa\let\xa\xa\csname #4@#5@#6\endcsname%
|
2022-08-21 07:12:40 +00:00
|
|
|
\csname #1@#2@#3\endcsname%
|
2022-07-25 14:25:38 +00:00
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@createduplicatematrix#1#2{%
|
|
|
|
% #1 = name of copy
|
|
|
|
% #2 = original matrix to be copied
|
|
|
|
\qr@creatematrix{#1}%
|
|
|
|
\qr@for \i = 1 to \qr@numberofrowsinmatrix{#2} by 1%
|
|
|
|
{\qr@for \j = 1 to \qr@numberofcolsinmatrix{#2} by 1%
|
|
|
|
{\qr@copymatrixentry{#2}{\the\i}{\the\j}{#1}{\the\i}{\the\j}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
\qr@setnumberofrows{#1}{\qr@numberofrowsinmatrix{#2}}%
|
|
|
|
\qr@setnumberofcols{#1}{\qr@numberofcolsinmatrix{#2}}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@placefinderpattern@int#1#2#3#4#5{%
|
|
|
|
% Work on matrix #1.
|
|
|
|
% Start in position (#2, #3) -- should be a corner
|
|
|
|
% #4 indicates horizontal direction (1=right, -1=left)
|
|
|
|
% #5 indicates vertical direction (1=down, -1=up)
|
|
|
|
%
|
|
|
|
% In this code, \sourcei and \sourcej are TeX counts working through the finderpattern matrix,
|
|
|
|
% and i and j are LaTeX counters indicating positions in the big matrix.
|
|
|
|
\setcounter{qr@i}{#2}%
|
|
|
|
\qr@for \sourcei=1 to 8 by 1%
|
|
|
|
{\setcounter{qr@j}{#3}%
|
|
|
|
\qr@for \sourcej=1 to 8 by 1%
|
|
|
|
{\qr@copymatrixentry{finderpattern}{\the\sourcei}{\the\sourcej}%
|
|
|
|
{#1}{\theqr@i}{\theqr@j}%
|
|
|
|
\addtocounter{qr@j}{#5}%
|
|
|
|
}%
|
|
|
|
\addtocounter{qr@i}{#4}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@placefinderpatterns#1{%
|
|
|
|
% #1=matrix name
|
|
|
|
\qr@placefinderpattern@int{#1}{1}{1}{1}{1}%
|
|
|
|
\qr@placefinderpattern@int{#1}{\qr@numberofrowsinmatrix{#1}}{1}{-1}{1}%
|
|
|
|
\qr@placefinderpattern@int{#1}{1}{\qr@numberofcolsinmatrix{#1}}{1}{-1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@placetimingpatterns#1{%
|
|
|
|
%Set \qr@endingcol to n-8.
|
|
|
|
\qr@a=\qr@size\relax%
|
|
|
|
\advance\qr@a by -8\relax%
|
|
|
|
\edef\qr@endingcol{\the\qr@a}%
|
|
|
|
\qr@for \j = 9 to \qr@endingcol by 1%
|
|
|
|
{\ifodd\j\relax%
|
|
|
|
\qr@storetomatrix{#1}{7}{\the\j}{\qr@black@fixed}%
|
|
|
|
\qr@storetomatrix{#1}{\the\j}{7}{\qr@black@fixed}%
|
|
|
|
\else%
|
|
|
|
\qr@storetomatrix{#1}{7}{\the\j}{\qr@white@fixed}%
|
|
|
|
\qr@storetomatrix{#1}{\the\j}{7}{\qr@white@fixed}%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@placealignmentpattern@int#1#2#3{%
|
|
|
|
% Work on matrix #1.
|
|
|
|
% Write an alignment pattern into the matrix, centered on (#2,#3).
|
|
|
|
\qr@a=#2\relax%
|
|
|
|
\advance\qr@a by -2\relax%
|
|
|
|
\qr@b=#3\relax%
|
|
|
|
\advance\qr@b by -2\relax%
|
|
|
|
\setcounter{qr@i}{\the\qr@a}%
|
|
|
|
\qr@for \i=1 to 5 by 1%
|
|
|
|
{\setcounter{qr@j}{\the\qr@b}%
|
|
|
|
\qr@for \j=1 to 5 by 1%
|
|
|
|
{\qr@copymatrixentry{alignmentpattern}{\the\i}{\the\j}%
|
|
|
|
{#1}{\theqr@i}{\theqr@j}%
|
|
|
|
\stepcounter{qr@j}%
|
|
|
|
}%
|
|
|
|
\stepcounter{qr@i}%
|
2022-08-21 07:12:40 +00:00
|
|
|
}%
|
2022-07-25 14:25:38 +00:00
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifqr@incorner%
|
|
|
|
\def\qr@placealignmentpatterns#1{%
|
|
|
|
%There are k^2-3 alignment patterns,
|
|
|
|
%arranged in a (k x k) grid within the matrix.
|
|
|
|
%They begin in row 7, column 7,
|
|
|
|
%except that the ones in the NW, NE, and SW corners
|
|
|
|
%are omitted because of the finder patterns.
|
2022-08-21 07:12:40 +00:00
|
|
|
%Recall that
|
2022-07-25 14:25:38 +00:00
|
|
|
% * \qr@k stores k,
|
|
|
|
% * \qr@alignment@firstskip stores how far between the 1st and 2nd row/col, &
|
|
|
|
% * \qr@alignment@generalskip stores how far between each subsequent row/col.
|
|
|
|
\xa\ifnum\qr@k>0\relax
|
|
|
|
%There will be at least one alignment pattern.
|
|
|
|
%N.B. k cannot equal 1.
|
|
|
|
\xa\ifnum\qr@k=2\relax
|
|
|
|
% 2*2-3 = exactly 1 alignment pattern.
|
|
|
|
\qr@a=7\relax
|
|
|
|
\advance\qr@a by \qr@alignment@firstskip\relax
|
|
|
|
\xdef\qr@target@ii{\the\qr@a}%
|
|
|
|
\qr@placealignmentpattern@int{#1}{\qr@target@ii}{\qr@target@ii}%
|
|
|
|
\else
|
|
|
|
% k is at least 3, so the following loops should be safe.
|
|
|
|
\xdef\qr@target@ii{7}%
|
|
|
|
\qr@for \ii = 1 to \qr@k by 1%
|
|
|
|
{\ifcase\ii\relax%
|
|
|
|
\relax% \ii should never equal 0.
|
|
|
|
\or
|
|
|
|
\xdef\qr@target@ii{7}% If \ii = 1, we start in row 7.
|
|
|
|
\or
|
|
|
|
%If \ii = 2, we add the firstskip.
|
|
|
|
\qr@a=\qr@target@ii\relax%
|
|
|
|
\advance\qr@a by \qr@alignment@firstskip\relax%
|
|
|
|
\xdef\qr@target@ii{\the\qr@a}%
|
|
|
|
\else
|
|
|
|
%If \ii>2, we add the generalskip.
|
|
|
|
\qr@a=\qr@target@ii\relax%
|
|
|
|
\advance\qr@a by \qr@alignment@generalskip\relax%
|
|
|
|
\xdef\qr@target@ii{\the\qr@a}%
|
|
|
|
\fi
|
|
|
|
\qr@for \jj = 1 to \qr@k by 1%
|
|
|
|
{\ifcase\jj\relax%
|
|
|
|
\relax% \jj should never equal 0.
|
|
|
|
\or
|
|
|
|
\xdef\qr@target@jj{7}% If \jj=1, we start in row 7.
|
|
|
|
\or
|
|
|
|
%If \jj=2, we add the firstskip.
|
|
|
|
\qr@a=\qr@target@jj\relax%
|
|
|
|
\advance\qr@a by \qr@alignment@firstskip%
|
|
|
|
\xdef\qr@target@jj{\the\qr@a}%
|
|
|
|
\else
|
|
|
|
%If \jj>2, we add the generalskip.
|
|
|
|
\qr@a=\qr@target@jj\relax%
|
|
|
|
\advance\qr@a by \qr@alignment@generalskip%
|
|
|
|
\xdef\qr@target@jj{\the\qr@a}%
|
|
|
|
\fi
|
|
|
|
\qr@incornerfalse%
|
|
|
|
\ifnum\ii=1\relax
|
|
|
|
\ifnum\jj=1\relax
|
|
|
|
\qr@incornertrue
|
|
|
|
\else
|
|
|
|
\ifnum\qr@k=\jj\relax
|
|
|
|
\qr@incornertrue
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
\xa\ifnum\qr@k=\ii\relax
|
|
|
|
\ifnum\jj=1\relax
|
|
|
|
\qr@incornertrue
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\ifqr@incorner
|
|
|
|
\relax
|
|
|
|
\else
|
|
|
|
\qr@placealignmentpattern@int{#1}{\qr@target@ii}{\qr@target@jj}%
|
|
|
|
\fi
|
|
|
|
}% ends \qr@for \jj
|
|
|
|
}% ends \qr@for \ii
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@placedummyformatpatterns#1{%
|
|
|
|
\qr@for \j = 1 to 9 by 1%
|
|
|
|
{\ifnum\j=7\relax%
|
|
|
|
\else%
|
|
|
|
\qr@storetomatrix{#1}{9}{\the\j}{\qr@format@square}%
|
|
|
|
\qr@storetomatrix{#1}{\the\j}{9}{\qr@format@square}%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
\setcounter{qr@j}{\qr@size}%
|
|
|
|
\qr@for \j = 1 to 8 by 1%
|
|
|
|
{\qr@storetomatrix{#1}{9}{\theqr@j}{\qr@format@square}%
|
|
|
|
\qr@storetomatrix{#1}{\theqr@j}{9}{\qr@format@square}%
|
|
|
|
\addtocounter{qr@j}{-1}%
|
|
|
|
}%
|
|
|
|
%Now go back and change the \qr@format@square in (n-8,9) to \qr@black@fixed.
|
|
|
|
\addtocounter{qr@j}{1}%
|
|
|
|
\qr@storetomatrix{#1}{\theqr@j}{9}{\qr@black@fixed}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@placedummyversionpatterns#1{%
|
|
|
|
\xa\ifnum\qr@version>6\relax
|
|
|
|
%Must include version information.
|
|
|
|
\global\c@qr@i=\qr@size%
|
|
|
|
\global\advance\c@qr@i by -10\relax%
|
|
|
|
\qr@for \i = 1 to 3 by 1%
|
|
|
|
{\qr@for \j = 1 to 6 by 1%
|
|
|
|
{\qr@storetomatrix{#1}{\theqr@i}{\the\j}{\qr@format@square}%
|
|
|
|
\qr@storetomatrix{#1}{\the\j}{\theqr@i}{\qr@format@square}%
|
|
|
|
}%
|
|
|
|
\stepcounter{qr@i}%
|
|
|
|
}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writebit(#1#2)#3{%
|
|
|
|
% #3 = matrix name
|
|
|
|
% (qr@i,qr@j) = position to write in (LaTeX counters)
|
|
|
|
% #1 = bit to be written
|
|
|
|
% #2 = remaining bits plus '\relax' as an end-of-file marker
|
|
|
|
\edef\qr@datatowrite{#2}%
|
|
|
|
\ifnum#1=1
|
|
|
|
\qr@storetomatrix{#3}{\theqr@i}{\theqr@j}{\qr@black}%
|
|
|
|
\else
|
|
|
|
\qr@storetomatrix{#3}{\theqr@i}{\theqr@j}{\qr@white}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifqr@rightcol
|
|
|
|
\newif\ifqr@goingup
|
|
|
|
|
|
|
|
\def\qr@writedata@hex#1#2{%
|
|
|
|
% #1 = name of a matrix that has been prepared with finder patterns, timing patterns, etc.
|
|
|
|
% #2 = a string consisting of bytes to write into the matrix, in two-char hex format.
|
|
|
|
\setcounter{qr@i}{\qr@numberofrowsinmatrix{#1}}%
|
|
|
|
\setcounter{qr@j}{\qr@numberofcolsinmatrix{#1}}%
|
|
|
|
\qr@rightcoltrue%
|
|
|
|
\qr@goinguptrue%
|
|
|
|
\edef\qr@argument{{#1}(#2\relax\relax\relax)}%
|
|
|
|
\xa\qr@writedata@hex@recursive\qr@argument%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writedata@hex@recursive#1(#2#3#4){%
|
|
|
|
% #1 = name of a matrix that has been prepared with finder patterns, timing patterns, etc.
|
|
|
|
% (qr@i,qr@j) = position to write in LaTeX counters
|
|
|
|
% #2#3#4 contains the hex codes of the bytes to be written, plus \relax\relax\relax
|
|
|
|
% as an end-of-file marker
|
|
|
|
\edef\qr@testii{#2}%
|
|
|
|
\ifx\qr@testii\qr@relax%
|
|
|
|
% #2 is \relax, so there is nothing more to write.
|
|
|
|
\relax
|
|
|
|
\let\qr@next=\relax
|
|
|
|
\else
|
|
|
|
% #2 is not \relax, so there is another byte to write.
|
|
|
|
\qr@hextobinary[8]{\bytetowrite}{#2#3}%
|
|
|
|
\xdef\qr@datatowrite{\bytetowrite\relax}% %Add terminating "\relax"
|
|
|
|
\qr@writedata@recursive{#1}% %This function actually writes the 8 bits.
|
|
|
|
\edef\qr@argument{{#1}(#4)}%
|
|
|
|
\xa\def\xa\qr@next\xa{\xa\qr@writedata@hex@recursive\qr@argument}% %Call self to write the next bit.
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writedata#1#2{%
|
|
|
|
% #1 = name of a matrix that has been prepared with finder patterns, timing patterns, etc.
|
|
|
|
% #2 = a string consisting of 0's and 1's to write into the matrix.
|
|
|
|
\setcounter{qr@i}{\qr@numberofrowsinmatrix{#1}}%
|
|
|
|
\setcounter{qr@j}{\qr@numberofcolsinmatrix{#1}}%
|
|
|
|
\qr@rightcoltrue
|
|
|
|
\qr@goinguptrue
|
|
|
|
\edef\qr@datatowrite{#2\relax}%
|
|
|
|
\qr@writedata@recursive{#1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@@blank{\qr@blank}%
|
|
|
|
|
|
|
|
\def\qr@writedata@recursive#1{%
|
|
|
|
% #1 = matrix name
|
|
|
|
% (qr@i,qr@j) = position to write in (LaTeX counters)
|
|
|
|
% \qr@datatowrite contains the bits to be written, plus '\relax' as an end-of-file marker
|
|
|
|
\xa\let\xa\squarevalue\csname #1@\theqr@i @\theqr@j\endcsname%
|
|
|
|
\ifx\squarevalue\qr@@blank
|
|
|
|
%Square is blank, so write data in it.
|
|
|
|
\xa\qr@writebit\xa(\qr@datatowrite){#1}%
|
|
|
|
%The \qr@writebit macro not only writes the first bit of \qr@datatowrite into the matrix,
|
|
|
|
%but also removes the bit from the 'bitstream' of \qr@datatowrite.
|
|
|
|
\fi
|
|
|
|
%Now adjust our position in the matrix.
|
|
|
|
\ifqr@rightcol
|
|
|
|
%From the right-hand half of the two-bit column, we always move left. Easy peasy.
|
|
|
|
\addtocounter{qr@j}{-1}%
|
|
|
|
\qr@rightcolfalse
|
|
|
|
\else
|
|
|
|
%If we're in the left-hand column, things are harder.
|
|
|
|
\ifqr@goingup
|
|
|
|
%First, suppose we're going upwards.
|
|
|
|
\ifnum\c@qr@i>1\relax%
|
|
|
|
%If we're not in the first row, things are easy.
|
|
|
|
%We move one to the right and one up.
|
|
|
|
\addtocounter{qr@j}{1}%
|
|
|
|
\addtocounter{qr@i}{-1}%
|
|
|
|
\qr@rightcoltrue
|
|
|
|
\else
|
|
|
|
%If we are in the first row, then we move to the left,
|
|
|
|
%and we are now in the right-hand column on a downward pass.
|
|
|
|
\addtocounter{qr@j}{-1}%
|
|
|
|
\qr@goingupfalse
|
|
|
|
\qr@rightcoltrue
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
%Now, suppose we're going downwards.
|
|
|
|
\xa\ifnum\qr@size>\c@qr@i\relax%
|
|
|
|
%If we're not yet in the bottom row, things are easy.
|
|
|
|
%We move one to the right and one down.
|
|
|
|
\addtocounter{qr@j}{1}%
|
|
|
|
\addtocounter{qr@i}{1}%
|
|
|
|
\qr@rightcoltrue
|
|
|
|
\else
|
|
|
|
%If we are in the bottom row, then we move to the left,
|
|
|
|
%and we are now in the right-hand column on an upward pass.
|
|
|
|
\addtocounter{qr@j}{-1}%
|
|
|
|
\qr@rightcoltrue
|
|
|
|
\qr@goinguptrue
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%One problem: what if we just moved into the 7th column?
|
|
|
|
%Das ist verboten.
|
|
|
|
%If we just moved (left) into the 7th column, we should move on into the 6th column.
|
|
|
|
\ifnum\c@qr@j=7\relax%
|
|
|
|
\setcounter{qr@j}{6}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%Now check whether there are any more bits to write.
|
|
|
|
\ifx\qr@datatowrite\qr@relax
|
|
|
|
% \qr@datatowrite is just `\relax', so we're done.
|
|
|
|
\let\qr@next=\relax
|
|
|
|
\relax
|
|
|
|
\else
|
|
|
|
% Write some more!
|
|
|
|
\def\qr@next{\qr@writedata@recursive{#1}}%
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writeremainderbits#1{%
|
|
|
|
% #1 = name of a matrix that has been prepared and partly filled.
|
|
|
|
% (qr@i,qr@j) = position to write in LaTeX counters
|
|
|
|
\xa\ifnum\qr@numremainderbits>0\relax
|
|
|
|
\def\qr@datatowrite{}%
|
|
|
|
\qr@for \i = 1 to \qr@numremainderbits by 1%
|
|
|
|
{\g@addto@macro{\qr@datatowrite}{0}}%
|
|
|
|
\g@addto@macro{\qr@datatowrite}{\relax}% terminator
|
|
|
|
\qr@writedata@recursive{#1}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifqr@cellinmask
|
|
|
|
|
|
|
|
\def\qr@setmaskingfunction#1{%
|
2022-08-21 07:12:40 +00:00
|
|
|
% #1 = 1 decimal digit for the mask. (I see no reason to use the 3-bit binary code.)
|
2022-07-25 14:25:38 +00:00
|
|
|
% The current position is (\themaski,\themaskj), with indexing starting at 0.
|
|
|
|
\edef\qr@maskselection{#1}%
|
|
|
|
\xa\ifcase\qr@maskselection\relax
|
|
|
|
%Case 0: checkerboard
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod(\themaski+\themaskj,2)%
|
|
|
|
\qr@a=\c@maski%
|
|
|
|
\advance\qr@a by \c@maskj%
|
|
|
|
\qr@b=\qr@a%
|
|
|
|
\divide\qr@b by 2%
|
|
|
|
\multiply\qr@b by 2%
|
|
|
|
\advance\qr@a by -\qr@b%
|
|
|
|
\edef\qr@maskfunctionresult{\the\qr@a}%
|
|
|
|
}%
|
|
|
|
\or
|
|
|
|
%Case 1: horizontal stripes
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod(\themaski,2)%
|
|
|
|
\ifodd\c@maski\relax%
|
|
|
|
\def\qr@maskfunctionresult{1}%
|
|
|
|
\else%
|
|
|
|
\def\qr@maskfunctionresult{0}%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
\or
|
|
|
|
%Case 2: vertical stripes
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod(\themaskj,3)%
|
|
|
|
\qr@a=\c@maskj%
|
|
|
|
\divide\qr@a by 3%
|
|
|
|
\multiply\qr@a by 3%
|
|
|
|
\advance\qr@a by -\c@maskj%
|
|
|
|
\edef\qr@maskfunctionresult{\the\qr@a}%
|
|
|
|
}%
|
|
|
|
\or
|
|
|
|
%Case 3: diagonal stripes
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod(\themaski+\themaskj,3)%
|
|
|
|
\qr@a=\c@maski%
|
|
|
|
\advance\qr@a by \c@maskj%
|
|
|
|
\qr@b=\qr@a%
|
|
|
|
\divide\qr@b by 3%
|
|
|
|
\multiply\qr@b by 3%
|
|
|
|
\advance\qr@b by -\qr@a%
|
|
|
|
\edef\qr@maskfunctionresult{\the\qr@b}%
|
|
|
|
}%
|
|
|
|
\or
|
|
|
|
%Case 4: wide checkerboard
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod(floor(\themaski/2) + floor(\themaskj/3),2) %
|
|
|
|
\qr@a=\c@maski%
|
|
|
|
\divide\qr@a by 2%
|
|
|
|
\qr@b=\c@maskj%
|
|
|
|
\divide\qr@b by 3%
|
|
|
|
\advance\qr@a by \qr@b%
|
|
|
|
\qr@b=\qr@a%
|
|
|
|
\divide\qr@a by 2%
|
|
|
|
\multiply\qr@a by 2%
|
|
|
|
\advance\qr@a by -\qr@b%
|
|
|
|
\edef\qr@maskfunctionresult{\the\qr@a}%
|
|
|
|
}%
|
|
|
|
\or
|
|
|
|
%Case 5: quilt
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod(\themaski*\themaskj,2) + mod(\themaski*\themaskj,3) %
|
|
|
|
\qr@a=\c@maski%
|
|
|
|
\multiply\qr@a by \c@maskj%
|
|
|
|
\qr@b=\qr@a%
|
|
|
|
\qr@c=\qr@a%
|
|
|
|
\divide\qr@a by 2%
|
|
|
|
\multiply\qr@a by 2%
|
|
|
|
\advance\qr@a by -\qr@c% (result will be -mod(i*j,2), which is negative.)
|
|
|
|
\divide\qr@b by 3%
|
|
|
|
\multiply\qr@b by 3%
|
|
|
|
\advance\qr@b by -\qr@c% (result will be -mod(i*j,3), which is negative.)
|
|
|
|
\advance\qr@a by \qr@b% (result is negative of what's in the spec.)
|
|
|
|
\edef\qr@maskfunctionresult{\the\qr@a}%
|
|
|
|
}%
|
|
|
|
\or
|
|
|
|
%Case 6: arrows
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod( mod(\themaski*\themaskj,2) + mod(\themaski*\themaskj,3) , 2 ) %
|
|
|
|
\qr@a=\c@maski%
|
|
|
|
\multiply\qr@a by \c@maskj%
|
|
|
|
\qr@b=\qr@a%
|
|
|
|
\qr@c=\qr@a%
|
|
|
|
\multiply\qr@c by 2% % \qr@c equals 2*i*j.
|
|
|
|
\divide\qr@a by 2%
|
|
|
|
\multiply\qr@a by 2%
|
|
|
|
\advance\qr@c by -\qr@a% Now \qr@c equals i*j + mod(i*j,2).
|
|
|
|
\divide\qr@b by 3%
|
|
|
|
\multiply\qr@b by 3%
|
|
|
|
\advance\qr@c by -\qr@b% (Now \qr@c equals mod(i*j,2) + mod(i*j,3).
|
|
|
|
\qr@a=\qr@c%
|
|
|
|
\divide\qr@a by 2%
|
|
|
|
\multiply\qr@a by 2%
|
|
|
|
\advance\qr@c by-\qr@a%
|
|
|
|
\edef\qr@maskfunctionresult{\the\qr@c}%
|
|
|
|
}%
|
|
|
|
\or
|
|
|
|
%Case 7: shotgun
|
|
|
|
\def\qr@parsemaskingfunction{%
|
|
|
|
% Compute mod( mod(\themaski+\themaskj,2) + mod(\themaski*\themaskj,3) , 2 ) %
|
|
|
|
\qr@a=\c@maski%
|
|
|
|
\advance\qr@a by \c@maskj% %So \qr@a = i+j
|
|
|
|
\qr@b=\c@maski%
|
|
|
|
\multiply\qr@b by \c@maskj% %So \qr@b = i*j
|
|
|
|
\qr@c=\qr@a%
|
|
|
|
\advance\qr@c by \qr@b% So \qr@c = i+j+i*j
|
|
|
|
\divide\qr@a by 2%
|
|
|
|
\multiply\qr@a by 2%
|
|
|
|
\advance\qr@c by -\qr@a% So \qr@c = mod(i+j,2) + i*j
|
|
|
|
\divide\qr@b by 3%
|
|
|
|
\multiply\qr@b by 3%
|
|
|
|
\advance\qr@c by -\qr@b% So \qr@c = mod(i+j,2) + mod(i*j,3)
|
|
|
|
\qr@a=\qr@c%
|
|
|
|
\divide\qr@c by 2%
|
|
|
|
\multiply\qr@c by 2%
|
|
|
|
\advance\qr@a by -\qr@c%
|
|
|
|
\edef\qr@maskfunctionresult{\the\qr@a}%
|
|
|
|
}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@checkifcellisinmask{%
|
|
|
|
% The current position is (\i,\j), in TeX counts,
|
|
|
|
% but the LaTeX counters (maski,maskj) should contain
|
|
|
|
% the current position with indexing starting at 0.
|
|
|
|
% That is, maski = \i-1 and maskj = \j-1.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \qr@parsemaskingfunction must have been set by a call to \qr@setmaskingfunction
|
|
|
|
\qr@parsemaskingfunction
|
|
|
|
\xa\ifnum\qr@maskfunctionresult=0\relax
|
|
|
|
\qr@cellinmasktrue
|
|
|
|
\else
|
|
|
|
\qr@cellinmaskfalse
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newcounter{maski}%
|
|
|
|
\newcounter{maskj}%
|
|
|
|
|
|
|
|
\def\qr@applymask#1#2#3{%
|
|
|
|
% #1 = name of a matrix that should be filled out completely
|
|
|
|
% except for the format and/or version information.
|
|
|
|
% #2 = name of a new matrix to contain the masked version
|
|
|
|
% #3 = 1 decimal digit naming the mask
|
|
|
|
\qr@createduplicatematrix{#2}{#1}%
|
|
|
|
\qr@setmaskingfunction{#3}%
|
|
|
|
\setcounter{maski}{-1}%
|
|
|
|
\qr@for \i = 1 to \qr@size by 1%
|
|
|
|
{\stepcounter{maski}%
|
|
|
|
\setcounter{maskj}{-1}%
|
|
|
|
\qr@for \j = 1 to \qr@size by 1%
|
|
|
|
{\stepcounter{maskj}%
|
|
|
|
\qr@checkifcellisinmask
|
|
|
|
\ifqr@cellinmask
|
|
|
|
\qr@checkifcurrentcellcontainsdata{#2}%
|
|
|
|
\ifqr@currentcellcontainsdata
|
|
|
|
\qr@flipcurrentcell{#2}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifqr@currentcellcontainsdata
|
|
|
|
\qr@currentcellcontainsdatafalse
|
|
|
|
|
|
|
|
\def\qr@@white{\qr@white}%
|
|
|
|
\def\qr@@black{\qr@black}%
|
|
|
|
|
|
|
|
\def\qr@checkifcurrentcellcontainsdata#1{%
|
|
|
|
% #1 = name of matrix
|
|
|
|
\qr@currentcellcontainsdatafalse
|
|
|
|
\xa\ifx\csname #1@\the\i @\the\j\endcsname\qr@@white
|
|
|
|
\qr@currentcellcontainsdatatrue
|
|
|
|
\fi
|
|
|
|
\xa\ifx\csname #1@\the\i @\the\j\endcsname\qr@@black
|
|
|
|
\qr@currentcellcontainsdatatrue
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@flipped@black{\qr@black}%
|
|
|
|
\def\qr@flipped@white{\qr@white}%
|
|
|
|
|
|
|
|
\def\qr@flipcurrentcell#1{%
|
|
|
|
% #1 = name of matrix
|
|
|
|
% (\i, \j) = current position, in TeX counts.
|
|
|
|
% This assumes the cell contains data, either black or white!
|
|
|
|
\xa\ifx\csname #1@\the\i @\the\j\endcsname\qr@@white
|
|
|
|
\qr@storetomatrix{#1}{\the\i}{\the\j}{\qr@flipped@black}%
|
|
|
|
\else
|
|
|
|
\qr@storetomatrix{#1}{\the\i}{\the\j}{\qr@flipped@white}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@chooseandapplybestmask#1{%
|
|
|
|
% #1 = name of a matrix that should be filled out completely
|
|
|
|
% except for the format and/or version information.
|
|
|
|
% This function applies all eight masks in succession,
|
|
|
|
% calculates their penalties, and remembers the best.
|
|
|
|
% The number indicating which mask was used is saved in \qr@mask@selected.
|
|
|
|
\qr@createduplicatematrix{originalmatrix}{#1}%
|
|
|
|
\message{<Applying Mask 0...}%
|
|
|
|
\qr@applymask{originalmatrix}{#1}{0}%
|
|
|
|
\message{done. Calculating penalty...}%
|
|
|
|
\qr@evaluatemaskpenalty{#1}%
|
|
|
|
\xdef\qr@currentbestpenalty{\qr@penalty}%
|
|
|
|
\message{penalty is \qr@penalty>^^J}%
|
|
|
|
\gdef\qr@currentbestmask{0}%
|
|
|
|
\qr@for \i = 1 to 7 by 1%
|
|
|
|
{\message{<Applying Mask \the\i...}%
|
|
|
|
\qr@applymask{originalmatrix}{currentmasked}{\the\i}%
|
|
|
|
\message{done. Calculating penalty...}%
|
|
|
|
\qr@evaluatemaskpenalty{currentmasked}%
|
|
|
|
\message{penalty is \qr@penalty>^^J}%
|
|
|
|
\xa\xa\xa\ifnum\xa\qr@penalty\xa<\qr@currentbestpenalty\relax
|
|
|
|
%We found a better mask.
|
|
|
|
\xdef\qr@currentbestmask{\the\i}%
|
|
|
|
\qr@createduplicatematrix{#1}{currentmasked}%
|
|
|
|
\xdef\qr@currentbestpenalty{\qr@penalty}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
\xdef\qr@mask@selected{\qr@currentbestmask}%
|
|
|
|
\message{<Selected Mask \qr@mask@selected>^^J}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@Ni{3}%
|
|
|
|
\def\qr@Nii{3}%
|
|
|
|
\def\qr@Niii{40}%
|
|
|
|
\def\qr@Niv{10}%
|
|
|
|
\def\qr@fiveones{11111}%
|
|
|
|
\def\qr@fivezeros{11111}%
|
|
|
|
\def\qr@twoones{11}%
|
|
|
|
\def\qr@twozeros{00}%
|
|
|
|
\def\qr@finderA{00001011101}%
|
|
|
|
\def\qr@finderB{10111010000}%
|
|
|
|
\def\qr@finderB@three{1011101000}%
|
|
|
|
\def\qr@finderB@two{101110100}%
|
|
|
|
\def\qr@finderB@one{10111010}%
|
|
|
|
\def\qr@finderB@zero{1011101}%
|
|
|
|
\newif\ifqr@stringoffive
|
|
|
|
\def\qr@addpenaltyiii{%
|
|
|
|
\addtocounter{penaltyiii}{\qr@Niii}%
|
|
|
|
}%
|
|
|
|
\newcounter{totalones}%
|
|
|
|
\newcounter{penaltyi}%
|
|
|
|
\newcounter{penaltyii}%
|
|
|
|
\newcounter{penaltyiii}%
|
|
|
|
\newcounter{penaltyiv}%
|
|
|
|
\def\qr@evaluatemaskpenalty#1{%
|
|
|
|
% #1 = name of a matrix that we will test for the penalty
|
|
|
|
% according to the specs.
|
|
|
|
\setcounter{penaltyi}{0}%
|
|
|
|
\setcounter{penaltyii}{0}%
|
|
|
|
\setcounter{penaltyiii}{0}%
|
|
|
|
\setcounter{penaltyiv}{0}%
|
|
|
|
\bgroup%localize the meanings we give to the symbols
|
|
|
|
\def\qr@black{1}\def\qr@white{0}%
|
|
|
|
\def\qr@black@fixed{1}\def\qr@white@fixed{0}%
|
|
|
|
\def\qr@format@square{0}% This is not stated in the specs, but seems
|
|
|
|
% to be the standard implementation.
|
|
|
|
\def\qr@blank{0}% These would be any bits at the end.
|
|
|
|
%
|
|
|
|
\setcounter{totalones}{0}%
|
|
|
|
\qr@for \i=1 to \qr@size by 1%
|
|
|
|
{\def\qr@lastfive{z}% %The z is a dummy, that will be removed before any testing.
|
|
|
|
\qr@stringoffivefalse
|
|
|
|
\def\qr@lasttwo@thisrow{z}% %The z is a dummy.
|
|
|
|
\def\qr@lasttwo@nextrow{z}% %The z is a dummy.
|
|
|
|
\def\qr@lastnine{z0000}% %The 0000 stands for the white space to the left. The z is a dummy.
|
|
|
|
\def\qr@ignore@finderB@at{0}%
|
|
|
|
\qr@for \j=1 to \qr@size by 1%
|
|
|
|
{\edef\qr@newbit{\qr@matrixentry{#1}{\the\i}{\the\j}}%
|
|
|
|
%
|
|
|
|
% LASTFIVE CODE FOR PENALTY 1
|
|
|
|
% First, add the new bit to the end.
|
|
|
|
\xa\g@addto@macro\xa\qr@lastfive\xa{\qr@newbit}%
|
2022-08-21 07:12:40 +00:00
|
|
|
\ifnum\j<5\relax%
|
2022-07-25 14:25:38 +00:00
|
|
|
%Not yet on the 5th entry.
|
|
|
|
%Don't do any testing.
|
|
|
|
\else
|
|
|
|
% 5th entry or later.
|
|
|
|
% Remove the old one, and then test.
|
|
|
|
\qr@removefirsttoken\qr@lastfive%
|
|
|
|
\ifx\qr@lastfive\qr@fiveones%
|
|
|
|
\ifqr@stringoffive%
|
|
|
|
%This is a continuation of a previous block of five or more 1's.
|
|
|
|
\stepcounter{penaltyi}%
|
|
|
|
\else
|
|
|
|
%This is a new string of five 1's.
|
|
|
|
\addtocounter{penaltyi}{\qr@Ni}%
|
|
|
|
\global\qr@stringoffivetrue
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
\ifx\qr@lastfive\qr@fivezeros%
|
|
|
|
\ifqr@stringoffive
|
|
|
|
%This is a continuation of a previous block of five or more 0's.
|
|
|
|
\stepcounter{penaltyi}%
|
|
|
|
\else
|
|
|
|
%This is a new string of five 0's.
|
|
|
|
\addtocounter{penaltyi}{\qr@Ni}%
|
|
|
|
\global\qr@stringoffivetrue
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
%This is not a string of five 1's or five 0's.
|
|
|
|
\global\qr@stringoffivefalse
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%
|
|
|
|
% 2x2 BLOCKS FOR PENALTY 2
|
|
|
|
% Every 2x2 block of all 1's counts for \qr@Nii penalty points.
|
|
|
|
% We do not need to run this test in the last row.
|
|
|
|
\xa\ifnum\xa\i\xa<\qr@size\relax
|
|
|
|
\xa\g@addto@macro\xa\qr@lasttwo@thisrow\xa{\qr@newbit}%
|
|
|
|
%Compute \qr@iplusone
|
|
|
|
\qr@a=\i\relax%
|
|
|
|
\advance\qr@a by 1%
|
|
|
|
\edef\qr@iplusone{\the\qr@a}%
|
|
|
|
%
|
|
|
|
\edef\qr@nextrowbit{\qr@matrixentry{#1}{\qr@iplusone}{\the\j}}%
|
|
|
|
\xa\g@addto@macro\xa\qr@lasttwo@nextrow\xa{\qr@nextrowbit}%
|
|
|
|
\ifnum\j<2\relax%
|
|
|
|
%Still in the first column; no check.
|
|
|
|
\else
|
|
|
|
%Second column or later. Remove the old bits, and then test.
|
|
|
|
\qr@removefirsttoken\qr@lasttwo@thisrow
|
|
|
|
\qr@removefirsttoken\qr@lasttwo@nextrow
|
|
|
|
\ifx\qr@lasttwo@thisrow\qr@twoones
|
|
|
|
\ifx\qr@lasttwo@nextrow\qr@twoones
|
|
|
|
\addtocounter{penaltyii}{\qr@Nii}%
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
\ifx\qr@lasttwo@thisrow\qr@twozeros
|
|
|
|
\ifx\qr@lasttwo@nextrow\qr@twozeros
|
|
|
|
\addtocounter{penaltyii}{\qr@Nii}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%
|
|
|
|
% LASTNINE CODE FOR PENALTY 3
|
|
|
|
% First, add the new bit to the end.
|
|
|
|
\xa\g@addto@macro\xa\qr@lastnine\xa{\qr@newbit}%
|
2022-08-21 07:12:40 +00:00
|
|
|
\ifnum\j<7\relax%
|
2022-07-25 14:25:38 +00:00
|
|
|
%Not yet on the 7th entry.
|
|
|
|
%Don't do any testing.
|
|
|
|
\else
|
|
|
|
% 7th entry or later.
|
|
|
|
% Remove the old one, and then test.
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\xa\ifnum\qr@size=\j\relax%
|
|
|
|
% Last column. Any of the following should count:
|
|
|
|
% 1011101 (\qr@finderB@zero)
|
|
|
|
% 10111010 (\qr@finderB@one)
|
|
|
|
% 101110100 (\qr@finderB@two)
|
|
|
|
% 1011101000 (\qr@finderB@three)
|
|
|
|
% 10111010000 (\qr@finderB)
|
|
|
|
\ifx\qr@lastnine\qr@finderB
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@three
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@two
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@one
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@zero
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
\ifx\qr@lastnine\qr@finderA% %Matches 0000 1011101
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
%Also, we record our discovery, so that we can't count this pattern again
|
|
|
|
%if it shows up four columns later as 1011101 0000.
|
|
|
|
%
|
|
|
|
%Set \qr@ignore@finderB@at to \j+4.
|
|
|
|
\qr@a=\j\relax%
|
|
|
|
\advance\qr@a by 4%
|
|
|
|
\xdef\qr@ignore@finderB@at{\the\qr@a}%
|
|
|
|
\else
|
|
|
|
\ifx\qr@lastfive\qr@finderB% %Matches 1011101 0000.
|
|
|
|
\xa\ifnum\qr@ignore@finderB@at=\j\relax
|
|
|
|
%This pattern was *not* counted already earlier.
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%
|
|
|
|
%COUNT 1's FOR PENALTY 4
|
|
|
|
\xa\ifnum\qr@newbit=1\relax%
|
|
|
|
\stepcounter{totalones}%
|
|
|
|
\fi
|
|
|
|
}% end of j-loop
|
|
|
|
}% end of i-loop
|
|
|
|
%
|
|
|
|
%NOW WE ALSO NEED TO RUN DOWN THE COLUMNS TO FINISH CALCULATING PENALTIES 1 AND 3.
|
|
|
|
\qr@for \j=1 to \qr@size by 1%
|
|
|
|
{\def\qr@lastfive{z}% %The z is a dummy, that will be removed before any testing.
|
|
|
|
\qr@stringoffivefalse
|
|
|
|
\def\qr@lastnine{z0000}% %The 0000 stands for the white space to the left. The z is a dummy.
|
|
|
|
\def\qr@ignore@finderB@at{0}%
|
|
|
|
\qr@for \i=1 to \qr@size by 1%
|
|
|
|
{\edef\qr@newbit{\qr@matrixentry{#1}{\the\i}{\the\j}}%
|
|
|
|
%
|
|
|
|
% LASTFIVE CODE FOR PENALTY 1
|
|
|
|
% First, add the new bit to the end.
|
|
|
|
\xa\g@addto@macro\xa\qr@lastfive\xa{\qr@newbit}%
|
2022-08-21 07:12:40 +00:00
|
|
|
\ifnum\i<5\relax%
|
2022-07-25 14:25:38 +00:00
|
|
|
%Not yet on the 5th entry.
|
|
|
|
%Don't do any testing.
|
|
|
|
\else
|
|
|
|
% 5th entry or later.
|
|
|
|
% Remove the old one, and then test.
|
|
|
|
\qr@removefirsttoken\qr@lastfive%
|
|
|
|
\ifx\qr@lastfive\qr@fiveones%
|
|
|
|
\ifqr@stringoffive%
|
|
|
|
%This is a continuation of a previous block of five or more 1's.
|
|
|
|
\stepcounter{penaltyi}%
|
|
|
|
\else
|
|
|
|
%This is a new string of five 1's.
|
|
|
|
\addtocounter{penaltyi}{\qr@Ni}%
|
|
|
|
\global\qr@stringoffivetrue
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
\ifx\qr@lastfive\qr@fivezeros%
|
|
|
|
\ifqr@stringoffive
|
|
|
|
%This is a continuation of a previous block of five or more 0's.
|
|
|
|
\stepcounter{penaltyi}%
|
|
|
|
\else
|
|
|
|
%This is a new string of five 0's.
|
|
|
|
\addtocounter{penaltyi}{\qr@Ni}%
|
|
|
|
\global\qr@stringoffivetrue
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
%This is not a string of five 1's or five 0's.
|
|
|
|
\global\qr@stringoffivefalse
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%
|
|
|
|
% HAPPILY, WE DON'T NEED TO CALCULATE PENALTY 2 AGAIN.
|
|
|
|
%
|
|
|
|
% LASTNINE CODE FOR PENALTY 3
|
|
|
|
% First, add the new bit to the end.
|
|
|
|
\xa\g@addto@macro\xa\qr@lastnine\xa{\qr@newbit}%
|
2022-08-21 07:12:40 +00:00
|
|
|
\ifnum\i<7\relax%
|
2022-07-25 14:25:38 +00:00
|
|
|
%Not yet on the 7th entry.
|
|
|
|
%Don't do any testing.
|
|
|
|
\else
|
|
|
|
% 7th entry or later.
|
|
|
|
% Remove the old one, and then test.
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\xa\ifnum\qr@size=\i\relax%
|
|
|
|
% Last column. Any of the following should count:
|
|
|
|
% 1011101 (\qr@finderB@zero)
|
|
|
|
% 10111010 (\qr@finderB@one)
|
|
|
|
% 101110100 (\qr@finderB@two)
|
|
|
|
% 1011101000 (\qr@finderB@three)
|
|
|
|
% 10111010000 (\qr@finderB)
|
|
|
|
\ifx\qr@lastnine\qr@finderB
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@three
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@two
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@one
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\else
|
|
|
|
\qr@removefirsttoken\qr@lastnine
|
|
|
|
\ifx\qr@lastnine\qr@finderB@zero
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
\ifx\qr@lastnine\qr@finderA% %Matches 0000 1011101
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
%Also, we record our discovery, so that we can't count this pattern again
|
|
|
|
%if it shows up four columns later as 1011101 0000.
|
|
|
|
%
|
|
|
|
%Set \qr@ignore@finderB@at to \i+4.
|
|
|
|
\qr@a=\i\relax%
|
|
|
|
\advance\qr@a by 4%
|
|
|
|
\xdef\qr@ignore@finderB@at{\the\qr@a}%
|
|
|
|
\else
|
|
|
|
\ifx\qr@lastfive\qr@finderB% %Matches 1011101 0000.
|
|
|
|
\xa\ifnum\qr@ignore@finderB@at=\i\relax
|
|
|
|
%This pattern was *not* counted already earlier.
|
|
|
|
\qr@addpenaltyiii
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%
|
|
|
|
}% end of i-loop
|
|
|
|
}% end of j-loop
|
|
|
|
\egroup%
|
|
|
|
%
|
|
|
|
%CALCULATE PENALTY 4
|
|
|
|
%According to the spec, penalty #4 is computed as
|
|
|
|
% floor( |(i/n^2)-0.5|/0.05 )
|
|
|
|
% where i is the total number of 1's in the matrix.
|
|
|
|
% This is equal to abs(20*i-10n^2) div n^2.
|
|
|
|
%
|
|
|
|
\qr@a=\c@totalones\relax
|
|
|
|
\multiply\qr@a by 20\relax
|
|
|
|
\qr@b=\qr@size\relax
|
|
|
|
\multiply\qr@b by \qr@size\relax
|
|
|
|
\qr@c=10\relax
|
|
|
|
\multiply\qr@c by \qr@b\relax
|
|
|
|
\advance\qr@a by -\qr@c\relax
|
|
|
|
\ifnum\qr@a<0\relax
|
|
|
|
\multiply\qr@a by -1\relax
|
|
|
|
\fi
|
|
|
|
\divide\qr@a by \qr@b\relax
|
|
|
|
\setcounter{penaltyiv}{\the\qr@a}%
|
|
|
|
%
|
|
|
|
%CALCULATE TOTAL PENALTY
|
|
|
|
\qr@a=\thepenaltyi\relax%
|
|
|
|
\advance\qr@a by \thepenaltyii\relax%
|
|
|
|
\advance\qr@a by \thepenaltyiii\relax%
|
|
|
|
\advance\qr@a by \thepenaltyiv\relax%
|
|
|
|
\edef\qr@penalty{\the\qr@a}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@removefirsttoken#1{%
|
|
|
|
%Removes the first token from the macro named in #1.
|
|
|
|
\edef\qr@argument{(#1)}%
|
|
|
|
\xa\qr@removefirsttoken@int\qr@argument%
|
|
|
|
\xdef#1{\qr@removefirsttoken@result}%
|
|
|
|
}%
|
|
|
|
\def\qr@removefirsttoken@int(#1#2){%
|
|
|
|
\def\qr@removefirsttoken@result{#2}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writeformatstring#1#2{%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = binary string representing the encoded and masked format information
|
|
|
|
\setcounter{qr@i}{9}%
|
|
|
|
\setcounter{qr@j}{1}%
|
|
|
|
\edef\qr@argument{{#1}(#2\relax)}%
|
|
|
|
\xa\qr@writeformatA@recursive\qr@argument
|
|
|
|
%
|
|
|
|
\setcounter{qr@i}{\qr@numberofrowsinmatrix{#1}}%
|
|
|
|
\setcounter{qr@j}{9}%
|
|
|
|
\xa\qr@writeformatB@recursive\qr@argument
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writeformatA@recursive#1(#2#3){%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = first bit of string
|
|
|
|
% #3 = rest of bitstream
|
|
|
|
% (qr@i,qr@j) = current (valid) position to write (in LaTeX counters)
|
|
|
|
\ifnum#2=1\relax
|
|
|
|
\qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@black@format}%
|
|
|
|
\else
|
|
|
|
\qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@white@format}%
|
|
|
|
\fi
|
|
|
|
% Now the tricky part--moving \i and \j to their next positions.
|
|
|
|
\ifnum\c@qr@j<9\relax
|
|
|
|
%If we're not yet in column 9, move right.
|
|
|
|
\stepcounter{qr@j}%
|
|
|
|
\ifnum\c@qr@j=7\relax
|
|
|
|
%But we skip column 7!
|
|
|
|
\stepcounter{qr@j}%
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
%If we're in column 9, we move up.
|
|
|
|
\addtocounter{qr@i}{-1}%
|
|
|
|
\ifnum\c@qr@i=7\relax
|
|
|
|
%But we skip row 7!
|
|
|
|
\addtocounter{qr@i}{-1}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%N.B. that at the end of time, this will leave us at invalid position (0,9).
|
|
|
|
%That makes for an easy test to know when we are done.
|
|
|
|
\ifnum\c@qr@i<1
|
|
|
|
\let\qr@next=\relax
|
|
|
|
\else
|
|
|
|
\def\qr@next{\qr@writeformatA@recursive{#1}(#3)}%
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writeformatB@recursive#1(#2#3){%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = first bit of string
|
|
|
|
% #3 = rest of bitstream
|
|
|
|
% (qr@i,qr@j) = current (valid) position to write (in LaTeX counters)
|
|
|
|
\ifnum#2=1\relax
|
|
|
|
\qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@black@format}%
|
|
|
|
\else
|
|
|
|
\qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@white@format}%
|
|
|
|
\fi
|
|
|
|
% Now the tricky part--moving counters i and j to their next positions.
|
|
|
|
\qr@a=\qr@size%
|
|
|
|
\advance\qr@a by -6\relax%
|
|
|
|
\ifnum\qr@a<\c@qr@i\relax
|
|
|
|
%If we're not yet in row n-6, move up.
|
|
|
|
\addtocounter{qr@i}{-1}%
|
|
|
|
\else
|
|
|
|
\ifnum\qr@a=\c@qr@i\relax
|
|
|
|
%If we're actually in row n-6, we jump to position (9,n-7).
|
|
|
|
\setcounter{qr@i}{9}%
|
|
|
|
%Set counter j equal to \qr@size-7.
|
|
|
|
\global\c@qr@j=\qr@size\relax%
|
|
|
|
\global\advance\c@qr@j by -7\relax%
|
|
|
|
\else
|
|
|
|
%Otherwise, we must be in row 9.
|
|
|
|
%In this case, we move right.
|
|
|
|
\stepcounter{qr@j}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
%N.B. that at the end of time, this will leave us at invalid position (9,n+1).
|
|
|
|
%That makes for an easy test to know when we are done.
|
|
|
|
\xa\ifnum\qr@size<\c@qr@j\relax
|
|
|
|
\let\qr@next=\relax
|
|
|
|
\else
|
|
|
|
\def\qr@next{\qr@writeformatB@recursive{#1}(#3)}%
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writeversionstring#1#2{%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = binary string representing the encoded version information
|
|
|
|
%
|
|
|
|
% Plot the encoded version string into the matrix.
|
|
|
|
% This is only done for versions 7 and higher.
|
|
|
|
\xa\ifnum\qr@version>6\relax
|
|
|
|
%Move to position (n-8,6).
|
|
|
|
\setcounter{qr@i}{\qr@size}\relax%
|
|
|
|
\addtocounter{qr@i}{-8}\relax%
|
|
|
|
\setcounter{qr@j}{6}%
|
|
|
|
\edef\qr@argument{{#1}(#2\relax)}%
|
|
|
|
\xa\qr@writeversion@recursive\qr@argument
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writeversion@recursive#1(#2#3){%
|
|
|
|
% #1 = matrix name
|
|
|
|
% #2 = first bit of string
|
|
|
|
% #3 = rest of bitstream
|
|
|
|
% (qr@i,qr@j) = current (valid) position to write (in LaTeX counters)
|
|
|
|
%
|
|
|
|
% The version information is stored symmetrically in the matrix
|
|
|
|
% In two transposed regions, so we can write both at the same time.
|
|
|
|
% In the comments, we describe what happens in the lower-left region,
|
|
|
|
% not the upper-right.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
%Set \qr@topline equal to n-10.
|
|
|
|
\qr@a=\qr@size\relax%
|
|
|
|
\advance\qr@a by -10\relax%
|
|
|
|
\edef\qr@topline{\the\qr@a}%
|
|
|
|
%
|
|
|
|
\ifnum#2=1\relax
|
|
|
|
\qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@black@format}%
|
|
|
|
\qr@storetomatrix{#1}{\theqr@j}{\theqr@i}{\qr@black@format}%
|
|
|
|
\else
|
|
|
|
\qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@white@format}%
|
|
|
|
\qr@storetomatrix{#1}{\theqr@j}{\theqr@i}{\qr@white@format}%
|
|
|
|
\fi
|
|
|
|
% Now the tricky part--moving counters i and j to their next positions.
|
|
|
|
\addtocounter{qr@i}{-1}%
|
|
|
|
\xa\ifnum\qr@topline>\c@qr@i\relax
|
|
|
|
%We've overshot the top of the region.
|
|
|
|
%We need to move left one column and down three.
|
|
|
|
\addtocounter{qr@j}{-1}%
|
|
|
|
\addtocounter{qr@i}{3}%
|
|
|
|
\fi
|
|
|
|
%N.B. that at the end of time, this will leave us at invalid position (n-8,0).
|
|
|
|
%That makes for an easy test to know when we are done.
|
|
|
|
\ifnum\c@qr@j<1\relax
|
|
|
|
\let\qr@next=\relax
|
|
|
|
\else
|
|
|
|
\def\qr@next{\qr@writeversion@recursive{#1}(#3)}%
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \subsection{Encoding and error correction}
|
|
|
|
% \begin{macrocode}
|
|
|
|
\newcounter{qr@hexchars}%
|
|
|
|
|
|
|
|
\def\qr@string@binarytohex#1{%
|
|
|
|
\qr@binarytohex{\qr@hex@result}{#1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@encode@binary#1{%
|
|
|
|
% #1 = string of ascii characters, to be converted into bitstream
|
|
|
|
%
|
|
|
|
% We do this one entirely in hex, rather than binary, because we can.
|
|
|
|
\edef\qr@plaintext{#1}%
|
|
|
|
%
|
|
|
|
%First, the mode indicator.
|
|
|
|
\def\qr@codetext{4}% %This means `binary'
|
|
|
|
%
|
|
|
|
%Next, the character count.
|
|
|
|
\qr@getstringlength{\qr@plaintext}%
|
|
|
|
%Set \qr@charactercountlengthinhex to \qr@charactercountbits@byte/4%
|
|
|
|
\qr@a=\qr@charactercountbits@byte\relax%
|
|
|
|
\divide \qr@a by 4\relax%
|
|
|
|
\edef\qr@charactercountlengthinhex{\the\qr@a}%
|
|
|
|
\qr@decimaltohex[\qr@charactercountlengthinhex]{\qr@charactercount}{\qr@stringlength}%
|
|
|
|
\xa\g@addto@macro\xa\qr@codetext\xa{\qr@charactercount}%
|
|
|
|
%
|
|
|
|
%Now comes the actual data.
|
|
|
|
\edef\qr@argument{(,\qr@plaintext\relax\relax\relax)}%
|
|
|
|
\xa\qr@encode@ascii@recursive\qr@argument%
|
|
|
|
%
|
|
|
|
%Now the terminator.
|
|
|
|
\g@addto@macro\qr@codetext{0}% %This is '0000' in binary.
|
|
|
|
%
|
|
|
|
%There is no need to pad bits to make a multiple of 8,
|
|
|
|
%because the data length is already 4 + 8 + 8n + 4.
|
|
|
|
%
|
|
|
|
%Now add padding codewords if needed.
|
|
|
|
\setcounter{qr@hexchars}{0}%
|
|
|
|
\qr@getstringlength{\qr@codetext}%
|
|
|
|
\setcounter{qr@hexchars}{\qr@stringlength}%
|
|
|
|
%Set \qr@numpaddingcodewords equal to \qr@totaldatacodewords - qr@hexchars/2.
|
|
|
|
\qr@a=-\c@qr@hexchars\relax
|
|
|
|
\divide\qr@a by 2\relax
|
|
|
|
\advance\qr@a by \qr@totaldatacodewords\relax
|
|
|
|
\edef\qr@numpaddingcodewords{\the\qr@a}%
|
|
|
|
%
|
|
|
|
\xa\ifnum\qr@numpaddingcodewords<0%
|
|
|
|
\edef\ds{ERROR: Too much data! Over by \qr@numpaddingcodewords bytes.}\show\ds%
|
|
|
|
\fi%
|
|
|
|
\xa\ifnum\qr@numpaddingcodewords>0%
|
|
|
|
\qr@for \i = 2 to \qr@numpaddingcodewords by 2%
|
|
|
|
{\g@addto@macro{\qr@codetext}{ec11}}%
|
|
|
|
\xa\ifodd\qr@numpaddingcodewords\relax%
|
|
|
|
\g@addto@macro{\qr@codetext}{ec}%
|
|
|
|
\fi%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@encode@ascii@recursive(#1,#2#3){%
|
|
|
|
% #1 = hex codes translated so far
|
|
|
|
% #2 = next plaintext character to translate
|
|
|
|
% #3 = remainder of plaintext
|
|
|
|
\edef\qr@testii{#2}%
|
|
|
|
\ifx\qr@testii\qr@relax%
|
|
|
|
% All done!
|
|
|
|
\g@addto@macro\qr@codetext{#1}%
|
|
|
|
\else%
|
|
|
|
% Another character to translate.
|
|
|
|
\edef\qr@asciicode{\number`#2}%
|
|
|
|
\qr@decimaltohex[2]{\qr@newhexcodes}{\qr@asciicode}%
|
|
|
|
\edef\qr@argument{(#1\qr@newhexcodes,#3)}%
|
|
|
|
%\show\qr@argument
|
|
|
|
\xa\qr@encode@ascii@recursive\qr@argument%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@splitcodetextintoblocks{%
|
|
|
|
\setcounter{qr@i}{0}%
|
|
|
|
\qr@for \j = 1 to \qr@numshortblocks by 1%
|
|
|
|
{\stepcounter{qr@i}%
|
|
|
|
\qr@splitoffblock{\qr@codetext}{\theqr@i}{\qr@shortblock@size}%
|
|
|
|
}%
|
|
|
|
\xa\ifnum\qr@numlongblocks>0\relax%
|
|
|
|
\qr@for \j = 1 to \qr@numlongblocks by 1%
|
|
|
|
{\stepcounter{qr@i}%
|
|
|
|
\qr@splitoffblock{\qr@codetext}{\theqr@i}{\qr@longblock@size}%
|
|
|
|
}%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@splitoffblock#1#2#3{%
|
|
|
|
% #1 = current codetext in hexadecimal
|
|
|
|
% #2 = number to use in csname "\datablock@#2".
|
|
|
|
% #3 = number of bytes to split off
|
|
|
|
\message{<Splitting off block #2>}%
|
|
|
|
\xa\gdef\csname datablock@#2\endcsname{}% %This line is important!
|
|
|
|
\qr@for \i = 1 to #3 by 1%
|
|
|
|
{\edef\qr@argument{{#2}(#1)}%
|
|
|
|
\xa\qr@splitoffblock@int\qr@argument%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@splitoffblock@int#1(#2#3#4){%
|
|
|
|
% #1 = number to use in csname "\datablock@#1".
|
|
|
|
% #2#3 = next byte to split off
|
|
|
|
% #4 = remaining text
|
|
|
|
%
|
|
|
|
% We add the next byte to "\datablock@#1",
|
|
|
|
% and we remove it from the codetext.
|
|
|
|
\xa\xdef\csname datablock@#1\endcsname{\csname datablock@#1\endcsname#2#3}%
|
|
|
|
\xdef\qr@codetext{#4}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@createerrorblocks{%
|
|
|
|
\qr@for \ii = 1 to \qr@numblocks by 1%
|
|
|
|
{\message{<Making error block \the\ii>}%
|
|
|
|
\FX@generate@errorbytes{\csname datablock@\the\ii\endcsname}{\qr@num@eccodewords}%
|
|
|
|
\xa\xdef\csname errorblock@\the\ii\endcsname{\FX@errorbytes}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@interleave{%
|
|
|
|
\setcounter{qr@i}{0}%
|
|
|
|
\def\qr@interleaved@text{}%
|
|
|
|
\message{<Interleaving datablocks of length \qr@shortblock@size\ and \qr@longblock@size: }%
|
|
|
|
\qr@for \ii = 1 to \qr@shortblock@size by 1%
|
|
|
|
{\qr@for \jj = 1 to \qr@numblocks by 1%
|
|
|
|
{\qr@writefromblock{datablock}{\the\jj}%
|
|
|
|
}%
|
|
|
|
\message{\the\ii,}%
|
|
|
|
}%
|
|
|
|
%The long blocks are numbered \qr@numshortblocks+1, \qr@numshortblocks+2, ..., \qr@numblocks.
|
|
|
|
\qr@a=\qr@numshortblocks\relax%
|
|
|
|
\advance\qr@a by 1\relax%
|
|
|
|
\qr@for \jj = \qr@a to \qr@numblocks by 1%
|
|
|
|
{\qr@writefromblock{datablock}{\the\jj}}%
|
|
|
|
\xa\ifnum\qr@numlongblocks>0\relax%
|
|
|
|
\message{\qr@longblock@size.>}%
|
|
|
|
\else
|
|
|
|
\message{.>}%
|
|
|
|
\fi
|
|
|
|
\message{<Interleaving errorblocks of length \qr@num@eccodewords: }%
|
|
|
|
\qr@for \ii = 1 to \qr@num@eccodewords by 1%
|
|
|
|
{\message{\the\ii,}%
|
|
|
|
\qr@for \jj = 1 to \qr@numblocks by 1%
|
|
|
|
{\qr@writefromblock{errorblock}{\the\jj}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
\message{.><Interleaving complete.>}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writefromblock#1#2{%
|
|
|
|
% #1 = either 'datablock' or 'errorblock'
|
|
|
|
% #2 = block number, in {1,...,\qr@numblocks}%
|
|
|
|
\edef\qr@argument{(\csname #1@#2\endcsname\relax\relax\relax)}%
|
|
|
|
\xa\qr@writefromblock@int\qr@argument
|
|
|
|
\xa\xdef\csname #1@#2\endcsname{\qr@writefromblock@remainder}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writefromblock@int(#1#2#3){%
|
|
|
|
% #1#2 = first byte (in hex) of text, which will be written to \qr@interleaved@text
|
|
|
|
% #3 = remainder, including \relax\relax\relax terminator.
|
|
|
|
\g@addto@macro{\qr@interleaved@text}{#1#2}%
|
|
|
|
\qr@writefromblock@intint(#3)%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@writefromblock@intint(#1\relax\relax\relax){%
|
|
|
|
\xdef\qr@writefromblock@remainder{#1}%
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \subsection{Encoding format and version information}
|
|
|
|
% \begin{macrocode}
|
|
|
|
\let\xa=\expandafter
|
|
|
|
\makeatletter
|
|
|
|
|
|
|
|
\def\qr@preface@macro#1#2{%
|
|
|
|
% #1 = macro name
|
|
|
|
% #2 = text to add to front of macro
|
|
|
|
\def\qr@tempb{#2}%
|
|
|
|
\xa\xa\xa\gdef\xa\xa\xa#1\xa\xa\xa{\xa\qr@tempb #1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifqr@leadingcoeff
|
|
|
|
\def\qr@testleadingcoeff(#1#2){%
|
|
|
|
% Tests whether the leading digit of #1#2 is 1.
|
|
|
|
\ifnum#1=1\relax
|
|
|
|
\qr@leadingcoefftrue
|
|
|
|
\else
|
|
|
|
\qr@leadingcoefffalse
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@polynomialdivide#1#2{%
|
|
|
|
\edef\qr@numerator{#1}%
|
|
|
|
\edef\qr@denominator{#2}%
|
|
|
|
\qr@divisiondonefalse%
|
|
|
|
\xa\xa\xa\qr@oneroundofdivision\xa\xa\xa{\xa\qr@numerator\xa}\xa{\qr@denominator}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\@qr@empty{}%
|
|
|
|
\def\qr@oneroundofdivision#1#2{%
|
|
|
|
% #1 = f(x), of degree n
|
|
|
|
% #2 = g(x), of degree m
|
|
|
|
% Obtains a new polynomial h(x), congruent to f(x) modulo g(x),
|
|
|
|
% but of degree at most n-1.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% If leading coefficient of f(x) is 1, subtracts off g(x) * x^(n-m).
|
|
|
|
% If leading coefficient of f(x) is 0, strips off that leading zero.
|
|
|
|
%
|
|
|
|
\qr@testleadingcoeff(#1)%
|
|
|
|
\ifqr@leadingcoeff
|
|
|
|
\qr@xorbitstrings{#1}{#2}%
|
|
|
|
\ifqr@xorfailed
|
|
|
|
%If xor failed, that means our #1 was already the remainder!
|
|
|
|
\qr@divisiondonetrue
|
|
|
|
\edef\qr@theremainder{#1}%
|
|
|
|
\else
|
|
|
|
%xor succeeded. We need to recurse.
|
|
|
|
\xa\xa\xa\edef\xa\xa\xa\qr@numerator\xa\xa\xa{\xa\qr@stripleadingzero\xa(\qr@xorresult)}%
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
\xa\def\xa\qr@numerator\xa{\qr@stripleadingzero(#1)}%
|
|
|
|
\ifx\qr@numerator\@qr@empty
|
|
|
|
\qr@divisiondonetrue
|
|
|
|
\def\qr@theremainder{0}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\ifqr@divisiondone
|
|
|
|
\relax
|
|
|
|
\else
|
|
|
|
\xa\qr@oneroundofdivision\xa{\qr@numerator}{#2}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@stripleadingzero(0#1){#1}%Strips off a leading zero.
|
|
|
|
|
|
|
|
\newif\ifqr@xorfailed% This flag will trigger when #2 is longer than #1.
|
|
|
|
|
|
|
|
\def\qr@xorbitstrings#1#2{%
|
|
|
|
% #1 = bitstring
|
|
|
|
% #2 = bitstring no longer than #1
|
|
|
|
\qr@xorfailedfalse
|
|
|
|
\edef\qr@argument{(,#1\relax\relax)(#2\relax\relax)}%
|
|
|
|
\xa\qr@xorbitstrings@recursive\qr@argument
|
|
|
|
%\qr@xorbitstrings@recursive(,#1\relax\relax)(#2\relax\relax)%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@xorbitstrings@recursive(#1,#2#3)(#4#5){%
|
|
|
|
% #1#2#3 is the first bitstring, xor'ed up through #1.
|
|
|
|
% #4#5 is the remaining portion of the second bitstring.
|
|
|
|
\def\qr@testii{#2}%
|
|
|
|
\def\qr@testiv{#4}%
|
|
|
|
\ifx\qr@testii\qr@relax
|
|
|
|
% #1 contains the whole string.
|
|
|
|
% Now if #4 is also \relax, that means the two strings started off with equal lengths.
|
|
|
|
% If, however, #4 is not \relax, that means the second string was longer than the first, a problem.
|
|
|
|
\ifx\qr@testiv\qr@relax
|
|
|
|
%No problem. We are done.
|
|
|
|
\qr@xorbit@saveresult(#1#2#3)%
|
|
|
|
\else
|
|
|
|
%Problem! The second string was longer than the first.
|
|
|
|
\qr@xorfailedtrue
|
|
|
|
\def\qr@xorresult{}%
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
% There is still a bit to manipulate in #2.
|
|
|
|
% Check whether #4 contains anything.
|
|
|
|
\ifx\qr@testiv\qr@relax
|
|
|
|
% No, #4 is empty. We are done. "#2#3" contains the remainder of the first string,
|
|
|
|
% which we append untouched and then strip off the two \relax-es.
|
|
|
|
\qr@xorbit@saveresult(#1#2#3)%
|
|
|
|
\else
|
|
|
|
% Yes, #4 still has something to XOR. Do the task.
|
|
|
|
\ifnum#2=#4\relax
|
|
|
|
\qr@xorbitstrings@recursive(#1%
|
|
|
|
0,#3)(#5)%
|
|
|
|
\else
|
|
|
|
\qr@xorbitstrings@recursive(#1%
|
|
|
|
1,#3)(#5)%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@xorbit@saveresult(#1\relax\relax){%
|
|
|
|
%Strips off the extra '\relax'es at the end.
|
|
|
|
\def\qr@xorresult{#1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifqr@divisiondone
|
|
|
|
|
|
|
|
\def\qr@BCHcode#1{%
|
|
|
|
\edef\qr@formatinfo{#1}%
|
|
|
|
\def\qr@formatinfopadded{\qr@formatinfo 0000000000}%
|
|
|
|
\def\qr@divisor{10100110111}%
|
|
|
|
\qr@divisiondonefalse
|
|
|
|
\qr@polynomialdivide{\qr@formatinfopadded}{\qr@divisor}%
|
|
|
|
%
|
|
|
|
\qr@getstringlength{\qr@theremainder}%
|
|
|
|
%Run loop from stringlength+1 to 10.
|
|
|
|
\qr@a=\qr@stringlength\relax%
|
|
|
|
\advance\qr@a by 1\relax%
|
|
|
|
\qr@for \i = \qr@a to 10 by 1%
|
|
|
|
{\qr@preface@macro{\qr@theremainder}{0}%
|
|
|
|
\xdef\qr@theremainder{\qr@theremainder}%
|
|
|
|
}%
|
|
|
|
\edef\qr@BCHresult{\qr@formatinfo\qr@theremainder}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@formatmask{101010000010010}%
|
|
|
|
|
|
|
|
\def\qr@encodeandmaskformat#1{%
|
|
|
|
\qr@BCHcode{#1}%
|
|
|
|
\qr@xorbitstrings{\qr@BCHresult}{\qr@formatmask}%
|
|
|
|
\edef\qr@format@bitstring{\qr@xorresult}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@Golaycode#1{%
|
|
|
|
% #1 = 6-bit version number
|
|
|
|
\edef\qr@versioninfo{#1}%
|
|
|
|
\def\qr@versioninfopadded{\qr@versioninfo 000000000000}% %Append 12 zeros.
|
|
|
|
\def\qr@divisor{1111100100101}%
|
|
|
|
\qr@divisiondonefalse
|
|
|
|
\qr@polynomialdivide{\qr@versioninfopadded}{\qr@divisor}%
|
|
|
|
%
|
|
|
|
\qr@getstringlength{\qr@theremainder}%
|
|
|
|
%Run loop from stringlength+1 to 12.
|
|
|
|
\qr@a=\qr@stringlength\relax%
|
|
|
|
\advance\qr@a by 1\relax%
|
|
|
|
\qr@for \i = \qr@a to 12 by 1%
|
|
|
|
{\qr@preface@macro{\qr@theremainder}{0}%
|
|
|
|
\xdef\qr@theremainder{\qr@theremainder}%
|
|
|
|
}%
|
|
|
|
\edef\qr@Golayresult{\qr@versioninfo\qr@theremainder}%
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \subsection{Error correction}
|
|
|
|
% The error-correction code is defined over $\F_{256}=GF(256)$,
|
|
|
|
% the finite field of order $256$.
|
|
|
|
% The QR specification encodes this field as $\F_2[X]/(X^8+X^4+X^3+X^2+1)$;
|
|
|
|
% in other words, each field element is an 8-bit binary string representing
|
|
|
|
% an integer between 0 and 255.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% We represent these 8-bit strings as two hexadecimal characters;
|
|
|
|
% for example, {\tt 5a} represents {\tt 01011010}.
|
|
|
|
% Because addition is done by xor-ing the bitstrings,
|
|
|
|
% we can define addition on hexadecimal characters.
|
|
|
|
% Since there are only $16^2$ possibilities,
|
|
|
|
% we create a lookup table.
|
|
|
|
% \begin{macrocode}
|
|
|
|
\def\F@result{}%
|
|
|
|
|
|
|
|
\def\qr@xorbitstring#1#2#3{%
|
|
|
|
% #1 = new macro to receive result
|
|
|
|
% #2, #3 = bitstrings to xor. The second can be shorter than the first.
|
|
|
|
\def\qr@xor@result{}%
|
|
|
|
\edef\qr@argument{(#2\relax\relax)(#3\relax\relax)}%
|
|
|
|
\xa\qr@xorbitstring@recursive\qr@argument%
|
|
|
|
\edef#1{\qr@xor@result}%
|
|
|
|
}%
|
|
|
|
\def\qr@xorbitstring@recursive(#1#2)(#3#4){%
|
|
|
|
\edef\qr@testi{#1}%
|
|
|
|
\ifx\qr@testi\qr@relax%
|
|
|
|
%Done.
|
|
|
|
\let\qr@next=\relax%
|
|
|
|
\else
|
|
|
|
\if#1#3\relax
|
|
|
|
\g@addto@macro{\qr@xor@result}{0}%
|
|
|
|
\else
|
|
|
|
\g@addto@macro{\qr@xor@result}{1}%
|
|
|
|
\fi
|
|
|
|
\edef\qr@next{\noexpand\qr@xorbitstring@recursive(#2)(#4)}%
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}
|
|
|
|
|
|
|
|
\def\F@addchar@raw#1#2{%
|
|
|
|
%Add two hexadecimal digits using bitwise xor
|
|
|
|
\qr@hextobinary[4]{\qr@summandA}{#1}%
|
|
|
|
\qr@hextobinary[4]{\qr@summandB}{#2}%
|
|
|
|
\qr@xorbitstring{\F@result}{\qr@summandA}{\qr@summandB}%
|
|
|
|
\qr@binarytohex[1]{\F@result}{\F@result}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@canceltwos#1{%
|
|
|
|
\edef\qr@argument{(#1\relax\relax)}%
|
|
|
|
\xa\qr@canceltwos@int\qr@argument%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@canceltwos@int(#1#2){%
|
|
|
|
\xa\qr@canceltwos@recursion(,#1#2)%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@canceltwos@recursion(#1,#2#3){%
|
|
|
|
\def\qr@testii{#2}%
|
|
|
|
\ifx\qr@testii\qr@relax
|
|
|
|
%Cancelling complete.
|
|
|
|
\qr@striptworelaxes(#1#2#3)%
|
|
|
|
%Now \F@result contains the answer.
|
|
|
|
\else
|
|
|
|
\relax
|
|
|
|
\ifnum#2=2\relax
|
|
|
|
\qr@canceltwos@recursion(#10,#3)%
|
|
|
|
\else
|
|
|
|
\qr@canceltwos@recursion(#1#2,#3)%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@striptworelaxes(#1\relax\relax){%
|
|
|
|
\gdef\F@result{#1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\qr@for \i = 0 to 15 by 1%
|
|
|
|
{\qr@decimaltohex[1]{\qr@tempa}{\the\i}%
|
|
|
|
\qr@for \j = 0 to 15 by 1%
|
|
|
|
{\qr@decimaltohex[1]{\qr@tempb}{\the\j}%
|
|
|
|
\F@addchar@raw\qr@tempa\qr@tempb
|
|
|
|
\xa\xdef\csname F@addchar@\qr@tempa\qr@tempb\endcsname{\F@result}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\F@addchar#1#2{%
|
|
|
|
\xa\def\xa\F@result\xa{\csname F@addchar@#1#2\endcsname}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\F@addstrings#1#2{%
|
|
|
|
\edef\qr@argument{(,#1\relax\relax)(#2\relax\relax)}%
|
|
|
|
\xa\F@addstrings@recursion\qr@argument%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\F@addstrings@recursion(#1,#2#3)(#4#5){%
|
|
|
|
%Adds two hexadecimal strings, bitwise, from left to right.
|
|
|
|
%The second string is allowed to be shorter than the first.
|
|
|
|
\def\qr@testii{#2}%
|
|
|
|
\def\qr@testiv{#4}%
|
|
|
|
\ifx\qr@testii\qr@relax
|
|
|
|
%The entire string has been processed.
|
|
|
|
\gdef\F@result{#1}%
|
|
|
|
\else
|
|
|
|
\ifx\qr@testiv\qr@relax
|
|
|
|
%The second string is over.
|
|
|
|
\qr@striptworelaxes(#1#2#3)%
|
|
|
|
%Now \F@result contains the answer.
|
|
|
|
\else
|
|
|
|
%We continue to add.
|
|
|
|
\F@addchar{#2}{#4}%
|
|
|
|
\edef\qr@argument{(#1\F@result,#3)(#5)}%
|
|
|
|
\xa\F@addstrings@recursion\qr@argument%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
|
|
|
% Now we handle multiplication.
|
|
|
|
% Our approach to multiplying $a,b\in\F_{256}$
|
|
|
|
% is to take discrete logarithms (with 2 as our base),
|
|
|
|
% add the logarithms, and then take the antilog.
|
|
|
|
% We first create a log table.
|
|
|
|
% \begin{macrocode}
|
|
|
|
\gdef\F@stripleadingzero(0#1){\edef\F@result{#1}}%
|
|
|
|
|
|
|
|
\setcounter{qr@i}{0}%
|
|
|
|
\def\qr@poweroftwo{1}%
|
|
|
|
\qr@for \i = 1 to 254 by 1%
|
|
|
|
{\stepcounter{qr@i}%
|
|
|
|
\qr@a=\qr@poweroftwo\relax
|
|
|
|
\multiply\qr@a by 2\relax
|
|
|
|
\edef\qr@poweroftwo{\the\qr@a}%
|
|
|
|
%\show\qr@poweroftwo
|
|
|
|
\qr@decimaltohex[2]{\qr@poweroftwo@hex}{\qr@poweroftwo}%
|
|
|
|
\xa\ifnum\qr@poweroftwo>255\relax
|
|
|
|
%We need to bitwise add the polynomial represented by 100011101, i.e. 0x11d.
|
|
|
|
\F@addstrings{\qr@poweroftwo@hex}{11d}% %Now it should start with 0.
|
|
|
|
\xa\F@stripleadingzero\xa(\F@result)% %Now it should be two hex digits.
|
|
|
|
\edef\qr@poweroftwo@hex{\F@result}% %Save the hex version.
|
|
|
|
\qr@hextodecimal{\qr@poweroftwo}{\F@result}%
|
|
|
|
\fi
|
|
|
|
\xdef\qr@poweroftwo{\qr@poweroftwo}%
|
|
|
|
\xa\xdef\csname F@twotothe@\theqr@i\endcsname{\qr@poweroftwo@hex}%
|
|
|
|
\xa\xdef\csname F@logtwo@\qr@poweroftwo@hex\endcsname{\theqr@i}%
|
|
|
|
}%
|
|
|
|
\xa\xdef\csname F@twotothe@0\endcsname{01}%
|
|
|
|
\xa\xdef\csname F@logtwo@01\endcsname{0}%
|
|
|
|
|
|
|
|
\def\F@twotothe#1{%
|
|
|
|
\xa\xdef\xa\F@result\xa{\csname F@twotothe@#1\endcsname}%
|
|
|
|
}%
|
|
|
|
\def\F@logtwo#1{%
|
|
|
|
\xa\xdef\xa\F@result\xa{\csname F@logtwo@#1\endcsname}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@zerozero{00}%
|
|
|
|
|
|
|
|
\def\F@multiply#1#2{%
|
|
|
|
% #1 and #2 are two elements of F_256,
|
|
|
|
% given as two-character hexadecimal strings.
|
|
|
|
% Multiply them within F_256, and place the answer in \F@result
|
|
|
|
\edef\qr@argA{#1}%
|
|
|
|
\edef\qr@argB{#2}%
|
|
|
|
\ifx\qr@argA\qr@zerozero
|
|
|
|
\def\F@result{00}%
|
|
|
|
\else
|
|
|
|
\ifx\qr@argB\qr@zerozero
|
|
|
|
\def\F@result{00}%
|
|
|
|
\else
|
|
|
|
\xa\F@logtwo\xa{\qr@argA}%
|
|
|
|
\edef\qr@logA{\F@result}%
|
|
|
|
\xa\F@logtwo\xa{\qr@argB}%
|
|
|
|
\edef\qr@logB{\F@result}%
|
|
|
|
\xa\qr@a\xa=\qr@logA\relax% \qr@a = \qr@logA
|
|
|
|
\xa\advance\xa\qr@a\qr@logB\relax% \advance \qr@a by \qr@logB
|
|
|
|
\ifnum\qr@a>254\relax%
|
|
|
|
\advance\qr@a by -255\relax%
|
|
|
|
\fi%
|
|
|
|
\xa\F@twotothe\xa{\the\qr@a}%
|
|
|
|
% Now \F@result contains the product, as desired.
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
|
|
|
|
\def\F@multiply#1#2{%
|
|
|
|
% #1 and #2 are two elements of F_256,
|
|
|
|
% given as two-character hexadecimal strings.
|
|
|
|
% Multiply them within F_256, and place the answer in \F@result
|
|
|
|
\edef\qr@argA{#1}%
|
|
|
|
\edef\qr@argB{#2}%
|
|
|
|
\ifx\qr@argA\qr@zerozero
|
|
|
|
\def\F@result{00}%
|
|
|
|
\else
|
|
|
|
\ifx\qr@argB\qr@zerozero
|
|
|
|
\def\F@result{00}%
|
|
|
|
\else
|
|
|
|
\xa\F@logtwo\xa{\qr@argA}%
|
|
|
|
\edef\qr@logA{\F@result}%
|
|
|
|
\xa\F@logtwo\xa{\qr@argB}%
|
|
|
|
\edef\qr@logB{\F@result}%
|
|
|
|
\xa\qr@a\xa=\qr@logA\relax% \qr@a = \qr@logA
|
|
|
|
\xa\advance\xa\qr@a\qr@logB\relax% \advance \qr@a by \qr@logB
|
|
|
|
\ifnum\qr@a>254\relax%
|
|
|
|
\advance\qr@a by -255\relax%
|
|
|
|
\fi%
|
|
|
|
\xa\F@twotothe\xa{\the\qr@a}%
|
|
|
|
% Now \F@result contains the product, as desired.
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
|
|
|
% Having developed $\F_{256}$, we now turn to the real task.
|
|
|
|
% Each byte of data is read as an element of $\F_{256}$,
|
|
|
|
% and a sequence of bytes corresponds a polynomial in
|
|
|
|
% $\F_{256}[X]$.
|
|
|
|
% The Reed-Solomon code takes that codeword $f(X)\in \F_{256}[X]$
|
|
|
|
% of degree $k$, divides $f(X)\cdot X^\ell$ by a fixed
|
|
|
|
% polynomial,
|
|
|
|
% and keeps the remainder $r(X)$ as the error-correction word.
|
|
|
|
% We therefore must implement polynomial division over $\F_{256}$.
|
|
|
|
% \begin{macrocode}
|
|
|
|
%These polynomials are represented as sequences of coefficients,
|
|
|
|
%from highest power to lowest,
|
|
|
|
%with each coefficient represented by two hexadecimal characters.
|
|
|
|
|
|
|
|
\def\FX@getstringlength#1{%
|
|
|
|
%Count number of two-character coefficients
|
|
|
|
\setcounter{qr@i}{0}%
|
|
|
|
\xdef\qr@argument{(#1\relax\relax\relax)}%
|
|
|
|
\xa\FX@stringlength@recursive\qr@argument%
|
|
|
|
\xdef\stringresult{\arabic{qr@i}}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@stringlength@recursive(#1#2#3){%
|
|
|
|
\def\qr@testi{#1}%
|
|
|
|
\ifx\qr@testi\qr@relax
|
|
|
|
%we are done.
|
2022-08-21 07:12:40 +00:00
|
|
|
\else
|
2022-07-25 14:25:38 +00:00
|
|
|
\stepcounter{qr@i}%
|
|
|
|
%\showthe\c@qr@i
|
|
|
|
\qr@stringlength@recursive(#3)%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifFX@leadingcoeff@zero
|
|
|
|
\def\FX@testleadingcoeff(#1#2#3){%
|
|
|
|
% Tests whether the leading coefficient of the hex-string #1#2#3 is '00'.
|
|
|
|
\edef\FX@leadingcoefficient{#1#2}%
|
|
|
|
\FX@leadingcoeff@zerofalse
|
|
|
|
\ifx\FX@leadingcoefficient\qr@zerozero
|
|
|
|
\FX@leadingcoeff@zerotrue
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newif\ifFX@divisiondone
|
|
|
|
|
|
|
|
\newcounter{qr@divisionsremaining} %Keep track of how many divisions to go!
|
|
|
|
\def\FX@polynomialdivide#1#2{%
|
|
|
|
\edef\FX@numerator{#1}%
|
|
|
|
\edef\FX@denominator{#2}%
|
|
|
|
\qr@getstringlength\FX@numerator%
|
|
|
|
\setcounter{qr@divisionsremaining}{\qr@stringlength}%
|
|
|
|
\qr@getstringlength\FX@denominator%
|
|
|
|
\addtocounter{qr@divisionsremaining}{-\qr@stringlength}%
|
|
|
|
\addtocounter{qr@divisionsremaining}{2}%
|
|
|
|
\divide\c@qr@divisionsremaining by 2\relax% %2 hex chars per number
|
|
|
|
\FX@divisiondonefalse%
|
|
|
|
\xa\xa\xa\FX@polynomialdivide@recursive\xa\xa\xa{\xa\FX@numerator\xa}\xa{\FX@denominator}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@polynomialdivide@recursive#1#2{%
|
|
|
|
% #1 = f(x), of degree n
|
|
|
|
% #2 = g(x), of degree m
|
|
|
|
% Obtains a new polynomial h(x), congruent to f(x) modulo g(x),
|
|
|
|
% but of degree at most n-1.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% If leading coefficient of f(x) is 0, strips off that leading zero.
|
|
|
|
% If leading coefficient of f(x) is a, subtracts off a * g(x) * x^(n-m).
|
|
|
|
% N.B. we assume g is monic.
|
|
|
|
%
|
|
|
|
\FX@testleadingcoeff(#1)%
|
|
|
|
\ifFX@leadingcoeff@zero%
|
|
|
|
%Leading coefficient is zero, so remove it.
|
|
|
|
\xa\def\xa\FX@numerator\xa{\FX@stripleadingzero(#1)}%
|
|
|
|
\else%
|
|
|
|
%Leading coefficient is nonzero, and contained in \FX@leadingcoefficient
|
|
|
|
\FX@subtractphase{#1}{#2}{\FX@leadingcoefficient}%
|
|
|
|
\ifFX@subtract@failed%
|
|
|
|
%If subtraction failed, that means our #1 was already the remainder!
|
|
|
|
\FX@divisiondonetrue%
|
|
|
|
\edef\qr@theremainder{#1}%
|
|
|
|
\else%
|
|
|
|
%xor succeeded. We need to recurse.
|
|
|
|
\xa\xa\xa\edef\xa\xa\xa\FX@numerator\xa\xa\xa{\xa\FX@stripleadingzero\xa(\FX@subtraction@result)}%
|
|
|
|
\fi%
|
|
|
|
\fi%
|
|
|
|
\addtocounter{qr@divisionsremaining}{-1}%
|
|
|
|
\ifnum\c@qr@divisionsremaining=0\relax
|
|
|
|
%Division is done!
|
|
|
|
\FX@divisiondonetrue%
|
|
|
|
\edef\qr@theremainder{\FX@numerator}%
|
|
|
|
\relax%
|
|
|
|
\else%
|
|
|
|
\xa\FX@polynomialdivide@recursive\xa{\FX@numerator}{#2}%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@stripleadingzero(00#1){#1}%Strips off a single leading zero of F_256.
|
|
|
|
|
|
|
|
\newif\ifFX@subtract@failed% This flag will trigger when #2 is longer than #1.
|
|
|
|
|
|
|
|
\def\FX@subtractphase#1#2#3{%
|
|
|
|
% #1 = bitstring
|
|
|
|
% #2 = bitstring no longer than #1
|
|
|
|
% #3 = leading coefficient
|
|
|
|
\FX@subtract@failedfalse%
|
|
|
|
\edef\qr@argument{(,#1\relax\relax\relax)(#2\relax\relax\relax)(#3)}%
|
|
|
|
\xa\FX@subtract@recursive\qr@argument%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@subtract@recursive(#1,#2#3#4)(#5#6#7)(#8){%
|
|
|
|
% This is a recursive way to compute f(x) - a*g(x)*x^k.
|
|
|
|
% #1#2#3#4 is the first bitstring, subtracted up through #1.
|
|
|
|
% Thus #2#3 constitutes the next two-character coefficient.
|
|
|
|
% #5#6#7 is the remaining portion of the second bitstring.
|
|
|
|
% Thus #5#6 constitutes the next two-character coefficient
|
|
|
|
% #8 is the element a of F_256. It should contain two characters.
|
|
|
|
\def\qr@testii{#2}%
|
|
|
|
\def\qr@testv{#5}%
|
|
|
|
\ifx\qr@testii\qr@relax
|
|
|
|
% #1 contains the whole string.
|
|
|
|
% Now if #5 is also \relax, that means the two strings started off with equal lengths.
|
|
|
|
% If, however, #5 is not \relax, that means the second string was longer than the first, a problem.
|
|
|
|
\ifx\qr@testv\qr@relax
|
|
|
|
%No problem. We are done.
|
|
|
|
\FX@subtract@saveresult(#1#2#3#4)% %We keep the #2#3#4 to be sure we have all three relax-es to strip off.
|
|
|
|
\else
|
|
|
|
%Problem! The second string was longer than the first.
|
|
|
|
%This usually indicates the end of the long division process.
|
|
|
|
\FX@subtract@failedtrue
|
|
|
|
\def\FX@subtraction@result{}%
|
|
|
|
\fi
|
|
|
|
\else
|
|
|
|
% There is still a coefficient to manipulate in #2#3.
|
|
|
|
% Check whether #5 contains anything.
|
|
|
|
\ifx\qr@testv\qr@relax
|
|
|
|
% No, #5 is empty. We are done. "#2#3#4" contains the remainder of the first string,
|
|
|
|
% which we append untouched and then strip off the three \relax-es.
|
|
|
|
\FX@subtract@saveresult(#1#2#3#4)%
|
|
|
|
\else
|
|
|
|
% Yes, #5#6 still has something to XOR. Do the task.
|
|
|
|
\F@multiply{#5#6}{#8}% Multiply by the factor 'a'.
|
|
|
|
\F@addstrings{#2#3}{\F@result}% Subtract. (We're in characteristic two, so adding works.)
|
|
|
|
\edef\qr@argument{(#1\F@result,#4)(#7)(#8)}%
|
|
|
|
\xa\FX@subtract@recursive\qr@argument%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@subtract@saveresult(#1\relax\relax\relax){%
|
|
|
|
%Strips off the three extra '\relax'es at the end.
|
|
|
|
\def\FX@subtraction@result{#1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@creategeneratorpolynomial#1{%
|
|
|
|
% #1 = n, the number of error codewords desired.
|
|
|
|
% We need to create \prod_{j=0}^{n-1} (x-2^j).
|
|
|
|
\edef\FX@generator@degree{#1}%
|
|
|
|
\def\FX@generatorpolynomial{01}% Initially, set it equal to 1.
|
|
|
|
\setcounter{qr@i}{0}%
|
|
|
|
\FX@creategenerator@recursive%
|
|
|
|
%The result is now stored in \FX@generatorpolynomial
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@creategenerator@recursive{%
|
|
|
|
% \c@qr@i contains the current value of i.
|
|
|
|
% \FX@generatorpolynomial contains the current polynomial f(x),
|
|
|
|
% which should be a degree-i polynomial
|
|
|
|
% equal to \prod_{j=0}^{i-1} (x-2^j).
|
|
|
|
% (If i=0, then \FX@generatorpolynomial should be 01.)
|
|
|
|
% This recursion step should multiply the existing polynomial by (x-2^i),
|
|
|
|
% increment i by 1, and check whether we're done or not.
|
|
|
|
\edef\qr@summandA{\FX@generatorpolynomial 00}% This is f(x) * x
|
|
|
|
\edef\qr@summandB{00\FX@generatorpolynomial}% This is f(x), with a 0x^{i+1} in front.
|
|
|
|
\F@twotothe{\theqr@i}%
|
|
|
|
\edef\qr@theconstant{\F@result}%
|
|
|
|
\FX@subtractphase{\qr@summandA}{\qr@summandB}{\qr@theconstant}%
|
|
|
|
%This calculates \qr@summandA + \qr@theconstant * \qr@summandB
|
|
|
|
%and stores the result in \FX@subtraction@result
|
|
|
|
\edef\FX@generatorpolynomial{\FX@subtraction@result}%
|
|
|
|
\stepcounter{qr@i}%
|
|
|
|
\xa\ifnum\FX@generator@degree=\c@qr@i\relax%
|
|
|
|
%We just multiplied by (x-2^{n-1}), so we're done.
|
|
|
|
\relax%
|
|
|
|
\else%
|
|
|
|
%We need to do this again!
|
|
|
|
\xa%
|
|
|
|
\FX@creategenerator@recursive%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\FX@generate@errorbytes#1#2{%
|
|
|
|
% #1 = datastream in hex
|
|
|
|
% #2 = number of error correction bytes requested
|
|
|
|
\edef\qr@numerrorbytes{#2}%
|
|
|
|
\xa\FX@creategeneratorpolynomial\xa{\qr@numerrorbytes}%
|
|
|
|
\edef\FX@numerator{#1}%
|
|
|
|
\qr@for \i = 1 to \qr@numerrorbytes by 1%
|
|
|
|
{\g@addto@macro\FX@numerator{00}}% %One error byte means two hex codes.
|
|
|
|
\FX@polynomialdivide{\FX@numerator}{\FX@generatorpolynomial}%
|
|
|
|
\edef\FX@errorbytes{\qr@theremainder}%
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
% \subsection{Version handling}
|
|
|
|
% \begin{macrocode}
|
|
|
|
\newif\ifqr@versionmodules
|
|
|
|
|
|
|
|
\def\qr@level@char#1{%
|
|
|
|
\xa\ifcase#1
|
|
|
|
M\or L\or H\or Q\fi}%
|
2022-08-21 07:12:40 +00:00
|
|
|
|
2022-07-25 14:25:38 +00:00
|
|
|
\newif\ifqr@versiongoodenough
|
|
|
|
\def\qr@choose@best@version#1{%
|
|
|
|
% \qr@desiredversion = user-requested version
|
|
|
|
% \qr@desiredlevel = user-requested error-correction level
|
|
|
|
\edef\qr@plaintext{#1}%
|
|
|
|
\qr@getstringlength{\qr@plaintext}%
|
|
|
|
%
|
2022-08-21 07:12:40 +00:00
|
|
|
%Run double loop over levels and versions, looking for
|
2022-07-25 14:25:38 +00:00
|
|
|
%the smallest version that can contain our data,
|
|
|
|
%and then choosing the best error-correcting level at that version,
|
|
|
|
%subject to the level being at least as good as the user desires.
|
|
|
|
\global\qr@versiongoodenoughfalse%
|
|
|
|
\gdef\qr@bestversion{0}%
|
|
|
|
\gdef\qr@bestlevel{0}%
|
|
|
|
\ifnum\qr@desiredversion=0\relax
|
|
|
|
\qr@a=1\relax
|
|
|
|
\else
|
|
|
|
\qr@a=\qr@desiredversion\relax
|
|
|
|
\fi
|
|
|
|
\qr@for \i=\qr@a to 40 by 1
|
|
|
|
{\edef\qr@version{\the\i}%
|
|
|
|
\global\qr@versiongoodenoughfalse
|
|
|
|
\qr@for \j=0 to 3 by 1%
|
2022-08-21 07:12:40 +00:00
|
|
|
{%First, we map {0,1,2,3} to {1,0,4,3}, so that we loop through {M,L,H,Q}
|
2022-07-25 14:25:38 +00:00
|
|
|
%in order of increasing error-correction capabilities.
|
|
|
|
\qr@a = \j\relax
|
|
|
|
\divide \qr@a by 2\relax
|
|
|
|
\multiply \qr@a by 4\relax
|
|
|
|
\advance \qr@a by 1\relax
|
|
|
|
\advance \qr@a by -\j\relax
|
|
|
|
\edef\qr@level{\the\qr@a}%
|
|
|
|
\ifnum\qr@desiredlevel=\qr@a\relax
|
|
|
|
\global\qr@versiongoodenoughtrue
|
|
|
|
\fi
|
|
|
|
\ifqr@versiongoodenough
|
|
|
|
\qr@calculate@capacity{\qr@version}{\qr@level}%
|
|
|
|
\xa\xa\xa\ifnum\xa\qr@truecapacity\xa<\qr@stringlength\relax
|
|
|
|
%Too short
|
|
|
|
\relax
|
|
|
|
\else
|
|
|
|
%Long enough!
|
|
|
|
\xdef\qr@bestversion{\qr@version}%
|
|
|
|
\xdef\qr@bestlevel{\qr@level}%
|
|
|
|
\global\i=40%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
\edef\qr@version{\qr@bestversion}%
|
|
|
|
\edef\qr@level{\qr@bestlevel}%
|
|
|
|
\xa\ifnum\qr@desiredversion>0\relax
|
|
|
|
\ifx\qr@bestversion\qr@desiredversion\relax
|
|
|
|
%No change from desired version.
|
|
|
|
\else
|
|
|
|
%Version was increased
|
|
|
|
\message{<Requested QR version '\qr@desiredversion' is too small for desired text.}%
|
|
|
|
\message{Version increased to '\qr@bestversion' to fit text.>^^J}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\ifx\qr@bestlevel\qr@desiredlevel\relax
|
|
|
|
%No change in level.
|
|
|
|
\else
|
|
|
|
\message{<Error-correction level increased from \qr@level@char{\qr@desiredlevel}}%
|
|
|
|
\message{to \qr@level@char{\qr@bestlevel} at no cost.>^^J}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@calculate@capacity#1#2{%
|
|
|
|
\edef\qr@version{#1}%
|
|
|
|
\edef\qr@level{#2}%
|
|
|
|
%Calculate \qr@size, the number of modules per side.
|
|
|
|
% The formula is 4\qr@version+17.
|
|
|
|
\qr@a=\qr@version\relax%
|
|
|
|
\multiply\qr@a by 4\relax%
|
|
|
|
\advance\qr@a by 17\relax%
|
|
|
|
\edef\qr@size{\the\qr@a}%
|
|
|
|
%
|
|
|
|
% Calculate \qr@k, which governs the number of alignment patterns.
|
|
|
|
% The alignment patterns lie in a kxk square, except for 3 that are replaced by finding patterns.
|
|
|
|
% The formula is 2 + floor( \qr@version / 7 ), except that k=0 for version 1.
|
|
|
|
\xa\ifnum\qr@version=1\relax%
|
|
|
|
\def\qr@k{0}%
|
|
|
|
\else%
|
|
|
|
\qr@a=\qr@version\relax
|
|
|
|
\divide \qr@a by 7\relax
|
|
|
|
\advance\qr@a by 2\relax
|
|
|
|
\edef\qr@k{\the\qr@a}%
|
|
|
|
\fi%
|
|
|
|
%
|
|
|
|
%Calculate number of function pattern modules.
|
|
|
|
%This consists of the three 8x8 finder patterns, the two timing strips, and the (k^2-3) 5x5 alignment patterns.
|
|
|
|
%The formula is 160+2n+25(k^2-3)-10(k-2), unless k=0 in which case we just have 160+2n.
|
|
|
|
\qr@a=\qr@size\relax
|
|
|
|
\multiply\qr@a by 2\relax
|
|
|
|
\advance\qr@a by 160\relax
|
|
|
|
\xa\ifnum\qr@k=0\relax\else
|
|
|
|
%\qr@k is nonzero, hence at least 2, so we continue to add 25(k^2-3)-10(k-2).
|
|
|
|
\qr@b=\qr@k\relax
|
|
|
|
\multiply\qr@b by \qr@k\relax
|
|
|
|
\advance\qr@b by -3\relax
|
|
|
|
\multiply\qr@b by 25\relax
|
|
|
|
\advance\qr@a by \qr@b\relax
|
|
|
|
\qr@b=\qr@k\relax
|
|
|
|
\advance\qr@b by -2\relax
|
|
|
|
\multiply\qr@b by 10\relax
|
|
|
|
\advance\qr@a by -\qr@b\relax
|
|
|
|
\fi
|
|
|
|
\edef\qr@numfunctionpatternmodules{\the\qr@a}%
|
|
|
|
%
|
|
|
|
%Calculate the number of version modules, either 36 or 0.
|
|
|
|
\xa\ifnum\qr@version>6\relax
|
|
|
|
\qr@versionmodulestrue
|
|
|
|
\def\qr@numversionmodules{36}%
|
|
|
|
\else
|
|
|
|
\qr@versionmodulesfalse
|
|
|
|
\def\qr@numversionmodules{0}%
|
|
|
|
\fi
|
|
|
|
%
|
|
|
|
%Now calculate the codeword capacity and remainder bits.
|
|
|
|
%Take n^2 modules, subtract all those dedicated to finder patterns etc., format information, and version information,
|
|
|
|
%and what's left is the number of bits we can play with.
|
|
|
|
%The number of complete bytes is \qr@numdatacodewords;
|
|
|
|
%the leftover bits are \qr@numremainderbits.
|
|
|
|
\qr@a=\qr@size\relax
|
|
|
|
\multiply \qr@a by \qr@size\relax
|
|
|
|
\advance \qr@a by -\qr@numfunctionpatternmodules\relax
|
|
|
|
\advance \qr@a by -31\relax% % There are 31 format modules.
|
|
|
|
\advance \qr@a by -\qr@numversionmodules\relax
|
|
|
|
\qr@b=\qr@a\relax
|
|
|
|
\divide \qr@a by 8\relax
|
|
|
|
\edef\qr@numdatacodewords{\the\qr@a}%
|
|
|
|
\multiply\qr@a by 8\relax
|
|
|
|
\advance \qr@b by -\qr@a\relax
|
|
|
|
\edef\qr@numremainderbits{\the\qr@b}%
|
|
|
|
%
|
|
|
|
%The size of the character count indicator also varies by version.
|
|
|
|
%There are only two options, so hardcoding seems easier than expressing these functionally.
|
|
|
|
\xa\ifnum\qr@version<10\relax
|
|
|
|
\def\qr@charactercountbytes@byte{1}%
|
|
|
|
\def\qr@charactercountbits@byte{8}%
|
|
|
|
\else
|
|
|
|
\def\qr@charactercountbytes@byte{2}%
|
|
|
|
\def\qr@charactercountbits@byte{16}%
|
|
|
|
\fi
|
|
|
|
%
|
|
|
|
%Now we call on the table, from the QR specification,
|
|
|
|
%of how many blocks to divide the message into, and how many error bytes each block gets.
|
|
|
|
%This affects the true capacity for data, which we store into \qr@totaldatacodewords.
|
|
|
|
% The following macro sets \qr@numblocks and \qr@num@eccodewords
|
|
|
|
% based on Table 9 of the QR specification.
|
|
|
|
\qr@settableix
|
|
|
|
\qr@a = -\qr@numblocks\relax
|
|
|
|
\multiply \qr@a by \qr@num@eccodewords\relax
|
|
|
|
\advance\qr@a by \qr@numdatacodewords\relax
|
|
|
|
\edef\qr@totaldatacodewords{\the\qr@a}%
|
|
|
|
\advance\qr@a by -\qr@charactercountbytes@byte\relax%Subtract character count
|
|
|
|
\advance\qr@a by -1\relax% Subtract 1 byte for the 4-bit mode indicator and the 4-bit terminator at the end.
|
|
|
|
\edef\qr@truecapacity{\the\qr@a}%
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
\def\qr@setversion#1#2{%
|
|
|
|
% #1 = version number, an integer between 1 and 40 inclusive.
|
|
|
|
% #2 = error-correction level, as an integer between 0 and 3 inclusive.
|
|
|
|
% 0 = 00 = M
|
|
|
|
% 1 = 01 = L
|
|
|
|
% 2 = 10 = H
|
|
|
|
% 3 = 11 = Q
|
|
|
|
% This macro calculates and sets a variety of global macros and/or counters
|
|
|
|
% storing version information that is used later in construction the QR code.
|
|
|
|
% Thus \qr@setversion should be called every time!
|
|
|
|
%
|
|
|
|
\edef\qr@version{#1}%
|
|
|
|
\edef\qr@level{#2}%
|
|
|
|
%
|
|
|
|
\qr@calculate@capacity{\qr@version}{\qr@level}%
|
|
|
|
%The capacity-check code sets the following:
|
|
|
|
% * \qr@size
|
|
|
|
% * \qr@k
|
|
|
|
% * \ifqr@versionmodules
|
|
|
|
% * \qr@numversionmodules
|
|
|
|
% * \qr@numdatacodewords
|
|
|
|
% * \qr@numremainderbits
|
|
|
|
% * \qr@charactercountbits@byte
|
|
|
|
% * \qr@charactercountbytes@byte
|
|
|
|
% * \qr@numblocks (via \qr@settableix)
|
|
|
|
% * \qr@num@eccodewords (via \qr@settableix)
|
|
|
|
% * \qr@totaldatacodewords
|
|
|
|
%
|
|
|
|
% The alignment patterns' square is 7 modules in from each edge.
|
|
|
|
% They are spaced "as evenly as possible" with an even number of modules between each row/column,
|
|
|
|
% unevenness in division being accommodated by making the first such gap smaller.
|
|
|
|
% The formula seems to be
|
|
|
|
% general distance = 2*round((n-13)/(k-1)/2+0.25)
|
|
|
|
% = 2*floor((n-13)/(k-1)/2+0.75)
|
|
|
|
% = 2*floor( (2*(n-13)/(k-1)+3) / 4 )
|
|
|
|
% = (((2*(n-13)) div (k-1) + 3 ) div 4 ) * 2
|
|
|
|
% first distance = leftovers
|
|
|
|
% The 0.25 is to accommodate version 32, which is the only time we round down.
|
|
|
|
% Otherwise a simple 2*ceiling((n-13)/(k-1)/2) would have sufficed.
|
|
|
|
%
|
|
|
|
\qr@a = \qr@size\relax
|
|
|
|
\advance\qr@a by -13\relax
|
|
|
|
\multiply\qr@a by 2\relax
|
|
|
|
\qr@b = \qr@k\relax
|
|
|
|
\advance \qr@b by -1\relax
|
|
|
|
\divide\qr@a by \qr@b\relax
|
|
|
|
\advance\qr@a by 3\relax
|
|
|
|
\divide\qr@a by 4\relax
|
|
|
|
\multiply\qr@a by 2\relax
|
|
|
|
\edef\qr@alignment@generalskip{\the\qr@a}%
|
|
|
|
%
|
|
|
|
%Now set \qr@alignment@firstskip to (\qr@size-13)-(\qr@k-2)*\qr@alignment@generalskip %
|
|
|
|
\qr@a = \qr@k\relax
|
|
|
|
\advance\qr@a by -2\relax
|
|
|
|
\multiply\qr@a by -\qr@alignment@generalskip\relax
|
|
|
|
\advance\qr@a by \qr@size\relax
|
|
|
|
\advance\qr@a by -13\relax
|
|
|
|
\edef\qr@alignment@firstskip{\the\qr@a}%
|
|
|
|
%
|
|
|
|
%
|
|
|
|
%
|
2022-08-21 07:12:40 +00:00
|
|
|
% Our \qr@totaldatacodewords bytes of data are broken up as evenly as possible
|
|
|
|
% into \qr@numblocks datablocks; some may be one byte longer than others.
|
2022-07-25 14:25:38 +00:00
|
|
|
% We set \qr@shortblock@size to floor(\qr@totaldatacodewords / \qr@numblocks)
|
|
|
|
% and \qr@numlongblocks to mod(\qr@totaldatacodewords , \qr@numblocks).
|
|
|
|
\qr@a=\qr@totaldatacodewords\relax
|
|
|
|
\divide\qr@a by \qr@numblocks\relax
|
|
|
|
\edef\qr@shortblock@size{\the\qr@a}%
|
|
|
|
\multiply\qr@a by -\qr@numblocks\relax
|
|
|
|
\advance\qr@a by \qr@totaldatacodewords\relax
|
|
|
|
\edef\qr@numlongblocks{\the\qr@a}%
|
|
|
|
%
|
|
|
|
%Set \qr@longblock@size to \qr@shortblock@size+1.
|
|
|
|
\qr@a=\qr@shortblock@size\relax
|
|
|
|
\advance\qr@a by 1\relax
|
|
|
|
\edef\qr@longblock@size{\the\qr@a}%
|
|
|
|
%
|
|
|
|
%Set \qr@numshortblocks to \qr@numblocks - \qr@numlongblocks
|
|
|
|
\qr@b=\qr@numblocks\relax
|
|
|
|
\advance\qr@b by -\qr@numlongblocks\relax
|
|
|
|
\edef\qr@numshortblocks{\the\qr@b}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@settableix@int(#1,#2){%
|
|
|
|
\edef\qr@numblocks{#1}%
|
|
|
|
\edef\qr@num@eccodewords{#2}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@settableix{%
|
|
|
|
\xa\ifcase\qr@level\relax
|
|
|
|
%00: Level 'M', medium error correction
|
|
|
|
\edef\qr@tempdata{(%
|
|
|
|
\ifcase\qr@version\relax
|
|
|
|
\relax %There is no version 0.
|
|
|
|
\or1,10%
|
|
|
|
\or1,16%
|
|
|
|
\or1,26%
|
|
|
|
\or2,18%
|
|
|
|
\or2,24%
|
|
|
|
\or4,16%
|
|
|
|
\or4,18%
|
|
|
|
\or4,22%
|
|
|
|
\or5,22%
|
|
|
|
\or5,26%
|
|
|
|
\or5,30%
|
|
|
|
\or8,22%
|
|
|
|
\or9,22%
|
|
|
|
\or9,24%
|
|
|
|
\or10,24%
|
|
|
|
\or10,28%
|
|
|
|
\or11,28%
|
|
|
|
\or13,26%
|
|
|
|
\or14,26%
|
|
|
|
\or16,26%
|
|
|
|
\or17,26%
|
|
|
|
\or17,28%
|
|
|
|
\or18,28%
|
|
|
|
\or20,28%
|
|
|
|
\or21,28%
|
|
|
|
\or23,28%
|
|
|
|
\or25,28%
|
|
|
|
\or26,28%
|
|
|
|
\or28,28%
|
|
|
|
\or29,28%
|
|
|
|
\or31,28%
|
|
|
|
\or33,28%
|
|
|
|
\or35,28%
|
|
|
|
\or37,28%
|
|
|
|
\or38,28%
|
|
|
|
\or40,28%
|
|
|
|
\or43,28%
|
|
|
|
\or45,28%
|
|
|
|
\or47,28%
|
|
|
|
\or49,28%
|
|
|
|
\fi)}%
|
|
|
|
\or
|
|
|
|
%01: Level 'L', low error correction
|
|
|
|
\edef\qr@tempdata{%
|
|
|
|
(\ifcase\qr@version\relax
|
|
|
|
\relax %There is no version 0.
|
|
|
|
\or 1,7%
|
|
|
|
\or 1,10%
|
|
|
|
\or 1,15%
|
|
|
|
\or 1,20%
|
|
|
|
\or 1,26%
|
|
|
|
\or 2,18%
|
|
|
|
\or 2,20%
|
|
|
|
\or 2,24%
|
|
|
|
\or 2,30%
|
|
|
|
\or 4,18%
|
|
|
|
\or 4,20%
|
|
|
|
\or 4,24%
|
|
|
|
\or 4,26%
|
|
|
|
\or 4,30%
|
|
|
|
\or 6,22%
|
|
|
|
\or 6,24%
|
|
|
|
\or 6,28%
|
|
|
|
\or 6,30%
|
|
|
|
\or 7,28%
|
|
|
|
\or 8,28%
|
|
|
|
\or 8,28%
|
|
|
|
\or 9,28%
|
|
|
|
\or 9,30%
|
|
|
|
\or 10,30%
|
|
|
|
\or 12,26%
|
|
|
|
\or 12,28%
|
|
|
|
\or 12,30%
|
|
|
|
\or 13,30%
|
|
|
|
\or 14,30%
|
|
|
|
\or 15,30%
|
|
|
|
\or 16,30%
|
|
|
|
\or 17,30%
|
|
|
|
\or 18,30%
|
|
|
|
\or 19,30%
|
|
|
|
\or 19,30%
|
|
|
|
\or 20,30%
|
|
|
|
\or 21,30%
|
|
|
|
\or 22,30%
|
|
|
|
\or 24,30%
|
|
|
|
\or 25,30%
|
|
|
|
\fi)}%
|
|
|
|
\or
|
|
|
|
%10: Level 'H', high error correction
|
|
|
|
\edef\qr@tempdata{(%
|
|
|
|
\ifcase\qr@version\relax
|
|
|
|
\relax %There is no version 0.
|
|
|
|
\or1,17%
|
|
|
|
\or1,28%
|
|
|
|
\or2,22%
|
|
|
|
\or4,16%
|
|
|
|
\or4,22%
|
|
|
|
\or4,28%
|
|
|
|
\or5,26%
|
|
|
|
\or6,26%
|
|
|
|
\or8,24%
|
|
|
|
\or8,28%
|
|
|
|
\or11,24%
|
|
|
|
\or11,28%
|
|
|
|
\or16,22%
|
|
|
|
\or16,24%
|
|
|
|
\or18,24%
|
|
|
|
\or16,30%
|
|
|
|
\or19,28%
|
|
|
|
\or21,28%
|
|
|
|
\or25,26%
|
|
|
|
\or25,28%
|
|
|
|
\or25,30%
|
|
|
|
\or34,24%
|
|
|
|
\or30,30%
|
|
|
|
\or32,30%
|
|
|
|
\or35,30%
|
|
|
|
\or37,30%
|
|
|
|
\or40,30%
|
|
|
|
\or42,30%
|
|
|
|
\or45,30%
|
|
|
|
\or48,30%
|
|
|
|
\or51,30%
|
|
|
|
\or54,30%
|
|
|
|
\or57,30%
|
|
|
|
\or60,30%
|
|
|
|
\or63,30%
|
|
|
|
\or66,30%
|
|
|
|
\or70,30%
|
|
|
|
\or74,30%
|
|
|
|
\or77,30%
|
|
|
|
\or81,30%
|
|
|
|
\fi)}%
|
|
|
|
\or
|
|
|
|
%11: Level 'Q', quality error correction
|
|
|
|
\edef\qr@tempdata{(%
|
|
|
|
\ifcase\qr@version\relax
|
|
|
|
\relax %There is no version 0.
|
|
|
|
\or1,13%
|
|
|
|
\or1,22%
|
|
|
|
\or2,18%
|
|
|
|
\or2,26%
|
|
|
|
\or4,18%
|
|
|
|
\or4,24%
|
|
|
|
\or6,18%
|
|
|
|
\or6,22%
|
|
|
|
\or8,20%
|
|
|
|
\or8,24%
|
|
|
|
\or8,28%
|
|
|
|
\or10,26%
|
|
|
|
\or12,24%
|
|
|
|
\or16,20%
|
|
|
|
\or12,30%
|
|
|
|
\or17,24%
|
|
|
|
\or16,28%
|
|
|
|
\or18,28%
|
|
|
|
\or21,26%
|
|
|
|
\or20,30%
|
|
|
|
\or23,28%
|
|
|
|
\or23,30%
|
|
|
|
\or25,30%
|
|
|
|
\or27,30%
|
|
|
|
\or29,30%
|
|
|
|
\or34,28%
|
|
|
|
\or34,30%
|
|
|
|
\or35,30%
|
|
|
|
\or38,30%
|
|
|
|
\or40,30%
|
|
|
|
\or43,30%
|
|
|
|
\or45,30%
|
|
|
|
\or48,30%
|
|
|
|
\or51,30%
|
|
|
|
\or53,30%
|
|
|
|
\or56,30%
|
|
|
|
\or59,30%
|
|
|
|
\or62,30%
|
|
|
|
\or65,30%
|
|
|
|
\or68,30%
|
|
|
|
\fi)}%
|
|
|
|
\fi
|
|
|
|
\xa\qr@settableix@int\qr@tempdata
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
|
|
|
% \subsection{More key handling}
|
|
|
|
% \begin{macrocode}
|
|
|
|
\define@key{qr}{version}{\edef\qr@desiredversion{#1}}%
|
|
|
|
\define@key{qr}{level}{\qr@setlevel{#1}}%
|
|
|
|
\define@key{qr}{height}{\qr@setheight{#1}}%
|
|
|
|
\define@boolkey{qr}[qr@]{tight}[true]{}% %This creates \ifqr@tight and initializes it to true.
|
|
|
|
\define@boolkey{qr}[qr@]{padding}[true]{\ifqr@padding\qr@tightfalse\else\qr@tighttrue\fi}% %Define 'padding' as antonym to 'tight'
|
|
|
|
|
|
|
|
\def\@qr@M{M}\def\@qr@z{0}%
|
|
|
|
\def\@qr@L{L}\def\@qr@i{1}%
|
|
|
|
\def\@qr@H{H}\def\@qr@ii{2}%
|
|
|
|
\def\@qr@Q{Q}\def\@qr@iii{3}%
|
|
|
|
\def\qr@setlevel#1{%
|
|
|
|
\edef\qr@level@selected{#1}%
|
|
|
|
\ifx\qr@level@selected\@qr@M
|
|
|
|
\edef\qr@desiredlevel{0}%
|
|
|
|
\fi
|
|
|
|
\ifx\qr@level@selected\@qr@L
|
|
|
|
\edef\qr@desiredlevel{1}%
|
|
|
|
\fi
|
|
|
|
\ifx\qr@level@selected\@qr@H
|
|
|
|
\edef\qr@desiredlevel{2}%
|
|
|
|
\fi
|
|
|
|
\ifx\qr@level@selected\@qr@Q
|
|
|
|
\edef\qr@desiredlevel{3}%
|
|
|
|
\fi
|
|
|
|
\ifx\qr@level@selected\@qr@z
|
|
|
|
\edef\qr@desiredlevel{0}%
|
|
|
|
\fi
|
|
|
|
\ifx\qr@level@selected\@qr@i
|
|
|
|
\edef\qr@desiredlevel{1}%
|
|
|
|
\fi
|
|
|
|
\ifx\qr@level@selected\@qr@ii
|
|
|
|
\edef\qr@desiredlevel{2}%
|
|
|
|
\fi
|
|
|
|
\ifx\qr@level@selected\@qr@iii
|
|
|
|
\edef\qr@desiredlevel{3}%
|
|
|
|
\fi
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@setheight#1{%
|
|
|
|
\setlength{\qr@desiredheight}{#1}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\newcommand\qrset[1]{%
|
|
|
|
\setkeys{qr}{#1}%
|
|
|
|
}
|
|
|
|
|
|
|
|
%SET DEFAULTS
|
|
|
|
\qrset{version=0, level=0, tight}
|
|
|
|
% \end{macrocode}
|
|
|
|
% \subsection{Main user functions}
|
|
|
|
% At last we are ready to define the main user functions.
|
|
|
|
% Some care is needed to ensure
|
|
|
|
% that the \meta{text to be encoded} is read with the appropriate catcodes,
|
|
|
|
% and that any escaped special characters are converted to the intended
|
|
|
|
% characters with category code 12 (other).
|
|
|
|
% \begin{macrocode}
|
|
|
|
\newif\ifqr@starinvoked%
|
|
|
|
\def\qrcode{\@ifstar\qrcode@star\qrcode@nostar}%
|
|
|
|
\def\qrcode@star{\qr@starinvokedtrue\qrcode@i}%
|
|
|
|
\def\qrcode@nostar{\qr@starinvokedfalse\qrcode@i}%
|
|
|
|
|
|
|
|
\newcommand\qrcode@i[1][]{%
|
|
|
|
\begingroup%
|
|
|
|
\ifqr@starinvoked%
|
|
|
|
\qr@hyperlinkfalse%
|
|
|
|
\fi%
|
|
|
|
\setkeys{qr}{#1}%
|
|
|
|
\bgroup\qr@verbatimcatcodes\qr@setescapedspecials\qrcode@in}%
|
|
|
|
|
|
|
|
\def\qrcode@in#1{\xdef\qr@texttoencode{#1}\egroup\qrcode@int\endgroup}%
|
|
|
|
|
|
|
|
\def\qrcode@hyperwrapper@hyperref{\href{\qr@texttoencode}}%
|
|
|
|
\def\qrcode@hyperwrapper@nohyperref{\relax}%
|
|
|
|
|
|
|
|
\AtBeginDocument{%
|
|
|
|
\@ifpackageloaded{hyperref}%
|
|
|
|
{\global\let\qrcode@hyperwrapper=\qrcode@hyperwrapper@hyperref}%
|
|
|
|
{\global\let\qrcode@hyperwrapper=\qrcode@hyperwrapper@nohyperref}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qrcode@int{%
|
2022-08-21 07:12:40 +00:00
|
|
|
\message{^^J^^J<QR code requested for "\qr@texttoencode" in version
|
2022-07-25 14:25:38 +00:00
|
|
|
\qr@desiredversion-\qr@level@char{\qr@desiredlevel}.>^^J}%
|
|
|
|
%First, choose the version and level.
|
|
|
|
%Recall that \qr@choose@best@version sets \qr@version and \qr@level.
|
|
|
|
\xa\qr@choose@best@version\xa{\qr@texttoencode}%
|
|
|
|
\qr@setversion{\qr@version}{\qr@level}%
|
|
|
|
%
|
|
|
|
\ifqr@hyperlink%
|
|
|
|
\let\qrcode@wrapper=\qrcode@hyperwrapper%
|
|
|
|
\else%
|
|
|
|
\let\qrcode@wrapper=\relax%
|
|
|
|
\fi%
|
|
|
|
%
|
2022-08-21 07:12:40 +00:00
|
|
|
%Next, check whether we have already encoded this text at this version
|
2022-07-25 14:25:38 +00:00
|
|
|
%and level.
|
|
|
|
\qrcode@wrapper{%
|
|
|
|
\xa\ifx\csname qr@savedbinarymatrix@\qr@texttoencode @\qr@version @\qr@level\endcsname
|
|
|
|
\relax%
|
|
|
|
%This text has not yet been encoded.
|
|
|
|
\qrcode@int@new%
|
|
|
|
\else
|
|
|
|
%This text has already been encoded!
|
|
|
|
\ifqr@forget@mode
|
|
|
|
%In 'forget' mode, we deliberately recalculate anyway.
|
|
|
|
\qrcode@int@new%
|
|
|
|
\else
|
|
|
|
\qrcode@int@remember%
|
|
|
|
\fi
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qrcode@int@new{%
|
|
|
|
\qr@createsquareblankmatrix{newqr}{\qr@size}%
|
|
|
|
\qr@placefinderpatterns{newqr}%
|
|
|
|
\qr@placetimingpatterns{newqr}%
|
|
|
|
\qr@placealignmentpatterns{newqr}%
|
|
|
|
\qr@placedummyformatpatterns{newqr}%
|
|
|
|
\qr@placedummyversionpatterns{newqr}%
|
|
|
|
\ifqr@draft@mode
|
2022-08-21 07:12:40 +00:00
|
|
|
\message{<Inserting dummy QR code in draft mode for "\qr@texttoencode" in
|
2022-07-25 14:25:38 +00:00
|
|
|
version \qr@version-\qr@level@char{\qr@level}.>^^J}%
|
|
|
|
\relax% Draft mode---don't load any data or do any work. Also don't save!
|
|
|
|
\def\qr@format@square{\qr@black}%
|
|
|
|
\def\qr@blank{\qr@white}%
|
|
|
|
\fboxsep=-\fboxrule%
|
|
|
|
\fbox{\qr@printmatrix{newqr}}%
|
|
|
|
\else
|
2022-08-21 07:12:40 +00:00
|
|
|
\message{<Calculating QR code for "\qr@texttoencode" in
|
2022-07-25 14:25:38 +00:00
|
|
|
version \qr@version-\qr@level@char{\qr@level}.>^^J}%
|
|
|
|
\xa\qr@encode@binary\xa{\qr@texttoencode}%
|
|
|
|
\qr@splitcodetextintoblocks
|
|
|
|
\qr@createerrorblocks
|
|
|
|
\qr@interleave
|
|
|
|
\message{<Writing data...}%
|
|
|
|
\qr@writedata@hex{newqr}{\qr@interleaved@text}%
|
|
|
|
\message{done.>^^J}%
|
|
|
|
\qr@writeremainderbits{newqr}%
|
|
|
|
\qr@chooseandapplybestmask{newqr}%
|
|
|
|
\qr@decimaltobinary[2]{\qr@level@binary}{\qr@level}%
|
|
|
|
\qr@decimaltobinary[3]{\qr@mask@binary}{\qr@mask@selected}%
|
|
|
|
\edef\qr@formatstring{\qr@level@binary\qr@mask@binary}%
|
|
|
|
\message{<Encoding and writing format string...}%
|
|
|
|
\xa\qr@encodeandmaskformat\xa{\qr@formatstring}%
|
|
|
|
\qr@writeformatstring{newqr}{\qr@format@bitstring}%
|
|
|
|
\message{done.>^^J}%
|
|
|
|
\message{<Encoding and writing version information...}%
|
|
|
|
\qr@decimaltobinary[6]{\qr@version@binary}{\qr@version}%
|
|
|
|
\qr@Golaycode{\qr@version@binary}%
|
|
|
|
\qr@writeversionstring{newqr}{\qr@Golayresult}%
|
|
|
|
\message{done.>^^J}%
|
|
|
|
\message{<Saving QR code to memory...}%
|
|
|
|
\qr@matrixtobinary{newqr}%
|
|
|
|
%
|
|
|
|
%Now save the binary version into TeX's memory for later use in this document.
|
2022-08-21 07:12:40 +00:00
|
|
|
\xa\xdef\csname qr@savedbinarymatrix@\qr@texttoencode @\qr@version @\qr@level\endcsname
|
2022-07-25 14:25:38 +00:00
|
|
|
{\qr@binarymatrix@result}%
|
|
|
|
\message{done.>^^J}%
|
|
|
|
%
|
|
|
|
%Also save the binary version into the aux file, for use in later runs.
|
|
|
|
\message{<Writing QR code to aux file...}%
|
|
|
|
\qr@writebinarymatrixtoauxfile{\qr@binarymatrix@result}%
|
|
|
|
\message{done.>^^J}%
|
|
|
|
\message{<Printing matrix...}%
|
|
|
|
\qr@printmatrix{newqr}%
|
|
|
|
\message{done.>^^J}%
|
|
|
|
\fi
|
|
|
|
\message{^^J}%
|
|
|
|
}%
|
|
|
|
\def\qrcode@int@remember{%
|
|
|
|
%This text has already been encoded,
|
|
|
|
%so we just copy it from the saved binary string.
|
|
|
|
\message{<Copying the QR code for "\qr@texttoencode" in version \qr@version-\qr@level@char{\qr@level} as previously calculated.>^^J}%
|
|
|
|
\xa\qr@printsavedbinarymatrix\xa{\csname qr@savedbinarymatrix@\qr@texttoencode @\qr@version @\qr@level\endcsname}%
|
|
|
|
%
|
|
|
|
% Now this still might need to be written to the aux file.
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
\xa\ifx\csname qr@savedflag@\qr@texttoencode @\qr@version @\qr@level\endcsname\@qr@TRUE
|
|
|
|
%Okay, this has already been written to aux file.
|
|
|
|
%Do nothing.
|
|
|
|
\relax%
|
|
|
|
\else%
|
|
|
|
%This has NOT been written to the aux file yet.
|
|
|
|
%We need to do so now.
|
|
|
|
\xa\qr@writebinarymatrixtoauxfile\xa{\csname qr@savedbinarymatrix@\qr@texttoencode @\qr@version @\qr@level\endcsname}%
|
|
|
|
\fi%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@matrixtobinary#1{%
|
|
|
|
\def\qr@binarymatrix@result{}%
|
|
|
|
\bgroup
|
|
|
|
\def\qr@black{1}%
|
|
|
|
\def\qr@white{0}%
|
|
|
|
\def\qr@blank{0}%
|
|
|
|
\def\qr@black@fixed{1}%
|
|
|
|
\def\qr@white@fixed{0}%
|
|
|
|
\def\qr@black@format{1}%
|
|
|
|
\def\qr@white@format{0}%
|
2022-08-21 07:12:40 +00:00
|
|
|
%
|
2022-07-25 14:25:38 +00:00
|
|
|
\qr@for \i = 1 to \qr@size by 1%
|
|
|
|
{\qr@for \j = 1 to \qr@size by 1%
|
|
|
|
{\edef\qr@theentry{\qr@matrixentry{#1}{\the\i}{\the\j}}%
|
|
|
|
\xa\g@addto@macro\xa\qr@binarymatrix@result\xa{\qr@theentry}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
\egroup%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\def\qr@sanitize@output#1{%
|
|
|
|
%Read through ASCII text '#1' and escape backslashes and braces
|
|
|
|
\def\qr@sanitized@result{}%
|
|
|
|
\edef\qr@argument{(#1\relax\relax\relax)}%
|
|
|
|
\xa\qr@sanitize@output@int\qr@argument%
|
|
|
|
}
|
|
|
|
|
|
|
|
\def\qr@sanitize@output@int(#1#2){%
|
|
|
|
% #1 = first character
|
|
|
|
% #2 = rest of output, including terminator
|
|
|
|
\edef\qr@testi{#1}%
|
|
|
|
\ifx\qr@testi\qr@relax
|
|
|
|
% Done.
|
|
|
|
\let\qr@next=\relax
|
|
|
|
\else
|
|
|
|
\ifx\qr@testi\qr@otherrightbrace
|
|
|
|
\edef\qr@sanitized@result{\qr@sanitized@result\qr@otherbackslash}%
|
|
|
|
\else\ifx\qr@testi\qr@otherleftbrace
|
|
|
|
\edef\qr@sanitized@result{\qr@sanitized@result\qr@otherbackslash}%
|
|
|
|
\else\ifx\qr@testi\qr@otherbackslash
|
|
|
|
\edef\qr@sanitized@result{\qr@sanitized@result\qr@otherbackslash}%
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\fi
|
|
|
|
\edef\qr@sanitized@result{\qr@sanitized@result#1}%
|
|
|
|
\def\qr@next{\qr@sanitize@output@int(#2)}%
|
|
|
|
\fi
|
|
|
|
\qr@next
|
|
|
|
}
|
|
|
|
|
|
|
|
\def\@qr@TRUE{TRUE}%
|
|
|
|
\def\qr@writebinarymatrixtoauxfile#1{%
|
|
|
|
\qr@sanitize@output{\qr@texttoencode}%
|
|
|
|
\edef\qr@theargument{{\qr@sanitized@result}{\qr@version}{\qr@level}{#1}}%
|
|
|
|
\xa\write\xa\@auxout\xa{\xa\string\xa\qr@savematrix\qr@theargument}%
|
|
|
|
%
|
|
|
|
% Now set a flag, so we don't write this again.
|
|
|
|
\xa\gdef\csname qr@savedflag@\qr@texttoencode @\qr@version @\qr@level\endcsname{TRUE}%
|
|
|
|
}%
|
|
|
|
|
|
|
|
\gdef\qr@dummyqrsavedefinition{}%
|
|
|
|
\begingroup
|
|
|
|
\catcode`\#=12\relax
|
|
|
|
\catcode`\<=1\relax
|
|
|
|
\catcode`\{=12\relax
|
|
|
|
\catcode`\>=2\relax
|
|
|
|
\catcode`\}=12\relax
|
|
|
|
\catcode`\|=0\relax
|
|
|
|
\catcode`\\=12|relax
|
|
|
|
|gdef|qr@dummyqrsavedefinition<%
|
|
|
|
\ifx\qr@savematrix\@undefined%
|
|
|
|
\def\qr@savematrix{\begingroup\let\do\@makeother\dospecials\catcode`\{=1\catcode`\}=2\relax
|
|
|
|
\qr@savematrix@int}%
|
|
|
|
\def\qr@savematrix@int#1#2#3#4{\endgroup}%
|
|
|
|
\fi%
|
|
|
|
>
|
|
|
|
|endgroup
|
|
|
|
|
|
|
|
\edef\qr@argument{(\qr@dummyqrsavedefinition)}%
|
|
|
|
\xa\write\xa\@auxout\xa{\qr@dummyqrsavedefinition}%
|
|
|
|
|
|
|
|
\def\qr@savematrix{\bgroup\qr@verbatimcatcodes\qr@setescapedspecials\qr@savematrix@int}%
|
|
|
|
|
|
|
|
\def\qr@savematrix@int#1{\xdef\qr@savedmatrix@name{#1}\egroup\qr@savematrix@int@int}%
|
|
|
|
|
|
|
|
\def\qr@savematrix@int@int#1#2#3{%
|
|
|
|
% \qr@savedmatrix@name = encoded text
|
|
|
|
% #1 = version
|
|
|
|
% #2 = level
|
|
|
|
% #3 = binary text
|
|
|
|
\def\ds{<Reading QR code for "\qr@savedmatrix@name" at level #1-\qr@level@char{#2} from aux file.>^^J}\xa\message\xa{\ds}%
|
|
|
|
{\let\%=\qr@otherpercent
|
|
|
|
\xa\gdef\csname qr@savedbinarymatrix@\qr@savedmatrix@name @#1@#2\endcsname{#3}%
|
|
|
|
}%
|
|
|
|
}%
|
|
|
|
% \end{macrocode}
|
|
|
|
%
|
|
|
|
% \Finale
|
|
|
|
\endinput
|