2

I am sure this has been asked before in some form, but I can't find an example, so. What I have are two variables (coming from an external system) x and y. I would like to encode them one on each line inside a qrcode. So if x=This is and y=my message I would like to be able to encode \x\?\y to encode:

This is
my message

However. Parts of this data will also be included in the document elsewhere and are designed to be read by humans. So escaping is possible (from the outside) but only if it doesn't impact that.

What I am getting is this:

Thisis
mymessage

from my SSCCE:

\documentclass[12pt,a4paper]{article}
\usepackage{qrcode}

\def\x{This is}
\def\y{my message}
\def\qrdata{\x\?\y}

\begin{document}
\qrcode[tight,nolink,height=46mm,level=H]{\qrdata};
\end{document}

So my question:

  • How do I automatically replace the with its escaped form \ ? I have looked at packages like etoolbox and patchcmd, but as far as I can tell they replace existing commands and I don't want to do that (or perhaps I don't quite understand how to use them). I tried looking for a package that can transform a definition into its escaped form.

I am using xelatex and texlive if this matters. A portable solution would be ideal; one specific to xetex is fine.

5
  • Welcome to TeX.SE!
    – Mensch
    Nov 30, 2021 at 18:20
  • Unrelated: you don't need a tikzpicture environment around the \qrcode command, did you do that on purpose?
    – Marijn
    Nov 30, 2021 at 19:04
  • @Marijn ah no, that's copied over from the actual use case where tikz is really used. Let me remove that.
    – diagprov
    Nov 30, 2021 at 19:37
  • why can't you simply do \def\x{This\ is}? Nov 30, 2021 at 19:56
  • @UlrikeFischer I could I supppose, but I'd rather dump the data in as human-readable way as possible. My external tool (from whence this data comes) could also perform escaping, but I wanted to see if there was a solution that didn't require that. I agree that would work and that's where I would go next if I had to, but...
    – diagprov
    Dec 1, 2021 at 15:31

2 Answers 2

3

Using LaTeX (unfortunately I get a ghostscript Last OS error: Permission denied with XeLaTeX, I can't seem to get past), you can do this with pst-barcodes compiling with --shell-escape

\documentclass{article}
\usepackage{pst-barcode}
\usepackage{auto-pst-pdf}
\def\x{This is}
\def\y{my message}
\def\qrdata{\x\string\n\y}
\begin{document}
\begin{pspicture}(46mm,46mm)
\psbarcode{\qrdata}{eclevel=H}{qrcode}
\end{pspicture}
\end{document}

enter image description here

1
  • Thanks, good to know there are some options.
    – diagprov
    Dec 3, 2021 at 14:01
2

The following is a solution with the qrcode package itself.

First a few remarks about the concept of category codes. A space has a special meaning for LaTeX, which is reflected in the way spaces are stored when parsing the document: they get assigned a category code of 10 whereas letters and non-letter symbols get category codes 11 and 12 (see What are category codes? for more information). The \qrcode macro processes the argument verbatim, which means that spaces lose their special meaning within \qrcode. However, if the space is inside a macro definition such as \def\x{this is} then it is already processed and assigned the special category code before \qrcode sees it. Unfortunately in this case it is not converted anymore to a regular character, and therefore the spaces are not encoded into the QR code.

One possible solution is to temporarily switch the category code of the space character to a regular character (category code 12), then process the macro definitions, and then set the category code back to 10. Switching category codes can be done with the command \catcode`[character]=[code] (note the backtick). MWE for this:

\documentclass[12pt,a4paper]{article}
\usepackage{qrcode}
\catcode`\ =12
\def\myx{This is}
\def\myy{my message}
\def\qrdata{\myx\?\myy}
\catcode`\ =10

\begin{document}
x=\myx

y=\myy

\qrcode[tight,height=46mm,level=H]{\qrdata}
\end{document}

The QR code is correct with the code above, i.e., it contains spaces. However, if you use the macros \myx and \myy in the document itself to print the contents then the spaces will not print correctly. Since they are now a regular character (in these macros, elsewhere in the document a space is still a special character) LaTeX will print whatever is in slot 32 in the current font, which may be something like a or ̷ character.

This can be addressed using the tokcycle package. This package has a set of commands to read a sequence token by token and writing it back with optional modifications for individual tokens. This can be used to read a token list containing category 12 spaces (such as the two input macros), and convert those spaces to regular category 10 spaces. The resulting modified token list can then be used as normal in the document.

The relevant macro is \Characterdirective which is called for each character in a token cycle. Only spaces should be processed, therefore within this macro a test can be used with the macro \tctestifx. To compare specifically against category 12 spaces we need a representation of such a space, which we can make by assigning a named macro a space value while the category code was 12 (called \twelvesp in the code below). Now in the true condition a value of can be returned and in the false condition the input character #1 can be returned unchanged. Importantly, the catcode of a space should be 10 during the definition of the \Characterdirective, so that the replacement character has indeed catcode 10.

This approach is based on https://tex.stackexchange.com/a/574593/ (the 'supplement' part of that answer).

Full MWE:

\documentclass[12pt,a4paper]{article}
\usepackage{qrcode}
\usepackage{tokcycle}
\catcode`\ =12
\let\twelvesp \relax
\def\myx{This is}
\def\myy{my message}
\def\qrdata{\myx\?\myy}
\catcode`\ =10
\Characterdirective{%
\tctestifx{\twelvesp#1}{\addcytoks{ }}{\addcytoks{#1}}}
\def\somex{\expandafter\tokencyclexpress\myx\endtokencyclexpress}
\def\somey{\expandafter\tokencyclexpress\myy\endtokencyclexpress}

\begin{document}
x=\somex

y=\somey

\qrcode[tight,height=46mm,level=H]{\qrdata}
\end{document}

Result:

enter image description here

Note: avoid using any spaces anywhere in the code while the catcode is 12 (other than inside the macro text), otherwise you will get all kinds of errors.

1
  • Getting this kind of answer is what I love about stackexchange :)
    – diagprov
    Dec 1, 2021 at 15:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .