17

I have found that the output of \qrcode is distorted if the qrcode is placed inside of command in latex. Here below there is a MWE showing 2 qrcodes which are actually the same, one produced from within a \newcommand called \contact and one produced without it. I'm using the qrcode package.

The difference is noticeable and actually when I scan both codes, the one on the left is recognized as a contact and the other is not. This is the MWE:

\documentclass[border=1cm]{standalone}
\usepackage[]{qrcode}


\newcommand{\contact}{
     \qrcode[]{
        BEGIN:VCARD
        VERSION:4.0
        EMAIL:john.doe@doe.net
        FN:John Doe
        N:Doe;John;;;
        TEL;TYPE=home:123456789
        UID:8cbddd73-d45d-45ad-a1e4-9587984e880d
        URL:www.doe.net
        END:VCARD
     }
}


\begin{document}

     \qrcode[]{
        BEGIN:VCARD
        VERSION:4.0
        EMAIL:john.doe@doe.net
        FN:John Doe
        N:Doe;John;;;
        TEL;TYPE=home:123456789
        UID:8cbddd73-d45d-45ad-a1e4-9587984e880d
        URL:www.doe.net
        END:VCARD
     }


     \contact
\end{document}

And the difference is actually visible. The one on the right is distorted:

QR Codes: On the left qrcode produced without newcommand. On the right, the qrcode produced without it

I have tested this behavior under Debian Buster, both with Xelatex and Pdflatex. Both exhibit the same behavior. The question is in this case, is there anyway to solve this distortion? What is actually causing this?

Best regards,

Ch.

  • 2
    The \qrcode command does several changes in the category code of characters and also to the endline character. These cannot be applied if \qrcode{...} is in the argument to another command (such as \newcommand). – egreg Sep 17 '18 at 17:59
  • 2
    From the manual (p.5): As with all verbatim modes, however, because T E X irrevocably sets catcodes when it first encounters characters, this will not work if the \qrcode macro is contained in another macro. However, that comment refers to "special characters"...and I don't see them in your input. – Steven B. Segletes Sep 17 '18 at 18:01
25

To quote the qrcode documentation:

As with all verbatim modes, however, because TEX irrevocably sets catcodes 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 #$&^_~% \{} 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 \?.

So it is caused by the line breaks and the spaces (the indention). You can fix it by replacing the line breaks with \?.

An example with identical barcodes:

\documentclass[border=1cm]{standalone}
\usepackage[]{qrcode}


\newcommand{\contact}{
     \qrcode[]{\?%
       BEGIN:VCARD\?%
        VERSION:4.0\?%
        EMAIL:john.doe@doe.net\?%
        FN:John Doe\?%
        N:Doe;John;;;\?%
        TEL;TYPE=home:123456789\?%
        UID:8cbddd73-d45d-45ad-a1e4-9587984e880d\?%
        URL:www.doe.net\?%
        END:VCARD\?%
     }
}


\begin{document}

     \qrcode[]{
BEGIN:VCARD
VERSION:4.0
EMAIL:john.doe@doe.net
FN:John Doe
N:Doe;John;;;
TEL;TYPE=home:123456789
UID:8cbddd73-d45d-45ad-a1e4-9587984e880d
URL:www.doe.net
END:VCARD
}


     \contact
\end{document}

enter image description here

5

The problem is:

\qrcode does first modify the catcode-régime and then call some internal macros.

The internal macros in turn shall cause LaTeX to read from the .tex-input-file and tokenize their arguments under the modified catcode-régime.

This reading and tokenizing arguments under the modified catcode-régime is outmaneuvered when tokenizing the entire call to \qrcode takes place under normal/non-modified catcode-régime at the time of defining the macro \contact.

Reading from the .tex-input-file and tokenizing things under different catcode-régimes yields different sets of tokens which in turn yield different qr-codes.

A workaround for defining the macro \contact can be reading and tokenizing the entire call to \qrcode under verbatim-catcode-régime and passing it to \scantokens which in turn pretends unexpanded-writing things to a text-file and reading that text-file. \scantokens'reading-part ensures that things get re-tokenized whereby the changes of the catcode-régime performed by \qrcode affect things.

My -eh- private toolkit for LaTeX-programming contains a macro \UDcollectverbarg which can be used for having things tokenized under verbatim-catcode-régime before passing them as arguments to other commands:

\documentclass[border=1cm]{standalone}

\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Implement stuff for reading arguments "verbatim":
%
% Usually \endlinechar has the value `\^^M which implies that
% LaTeX usually does insert character 13 (return) at each line-ending.
% There are situations where this needs to be replaced by the
% newline-character (usually ^^J). (E.g., with \scantokens' 
% unexpanded-writing-to-file-part...)
%
% Maybe the routine for \UDcollectverbarg could be shorter but I wanted
% both syntax |verbatim-arg| and syntax {verbatim-arg} to be possible.
%
% Syntax of \UDcollectverbarg:
%
%   \UDcollectverbarg{<^^M-replacement>}{<Mandatory 1>}{<Mandatory 2>}<verbatim-Arg>
%
% yields:
%
%   <Mandatory 1>{<Mandatory2>{<verbatim-Arg>}}
%
% Syntax of \UDconcatverbarg:
%
%   \UDconcatverbarg{<^^M-replacement>}{<Mandatory 1>}{<Mandatory 2>}<verbatim-Arg>
%
% yields:
%
%   <Mandatory 1>{<Mandatory2><verbatim-Arg>}
%
% with each character ^^M (usually=\endline-char) replaced by
%   token-sequence <^^M-replacement>
%
% The Mandatory-Arguments are mandatory. If they consist of several
% tokens, they must be nested into catcode-1/2-character-pair / braces.
% If reading is necessary, they will be read under normal catcode-
% conditions.
% The verbatim-Arg is also mandatory. It will be read under
% verbatim-catcode-conditions. If its first character is a brace,
% it will be "assumed" that the argument is nested into braces.
% Otherwise it will be assumed, that the argument is delimited
% by the first character - like the argument of \verb.
%
% Empty-lines will not be ignored.
%
% By nesting calls to \UDcollectverbarg within \UDcollectverbarg's first
% argument, you can collect "verbatim-arguments" within its second
% argument.
%
% E.g.,
%
%   \UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}}% <- Mandatory 1
%                {<actionB>}%                     <- Mandatory
%                <verbatim-Arg1><verbatim-Arg2><verbatim-Arg3>
%
% yields:
%
%  \UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}% <- Mandatory 1
%               {<actionB><verbatim-Arg1>}%        <- Mandatory 2
%               <verbatim-Arg2><verbatim-Arg3>
%
% yields:
%
%  \UDcollectverbarg{<^^M-replacement>}{<actionA>}% <- Mandatory 1
%               {<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}}% <- Mandatory 2
%               <verbatim-Arg3>
%
% yields:
%
%  <actionA>{<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}}
%
% Assume <actionA> = \@firstofone -> equals:
%
%     \@firstofone{<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}}
%
%    yields:
%
%     <actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}
\newcommand\@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
\begingroup
\catcode`\^^M=12 %
\@firstoftwo{%
  \endgroup%%%%
  \newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
  \newcommand*\@UDEndlreplace{}%
  \long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
    \@CheckWhetherNull{#3}%
    { #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
  }%
}{}%
\newcommand\UDcollectverbarg{\@UDverbarg{\@UDcollectverbarg}}%
\newcommand\@UDverbarg[4]{%
  \@bsphack
  \begingroup
  \let\do\@makeother\dospecials
  \catcode`\{=1 %
  \catcode`\ =10 %
  \@ifnextchar\bgroup
  {\catcode`\}=2 \@@UDverbarg{#1}{#2}{#3}{#4}{}}%
  {\do\{\@@UDverbarg{#1}{#2}{#3}{#4}}%
}%
\newcommand\@@UDverbarg[5]{%
  \do\ %
  \catcode`\^^M=12 %
  \long\def\@tempb##1#5{%
    \edef\@tempb{##1}%
    \@onelevel@sanitize\@tempb
    \expandafter\UDEndlreplace\expandafter{\@tempb}{#2}{\def\@tempb}%
    \expandafter#1\expandafter{\@tempb}{#3}{#4}%
  }%
  \@tempb
}%
\newcommand\@UDcollectverbarg[3]{%
  \endgroup
  \@esphack
  #2{#3{#1}}%
}%
\makeatother
% Implementing stuff for reading arguments "verbatim" done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\usepackage[]{qrcode}

\begingroup
\newlinechar=`\^^J %
\catcode`\^^J=12 %
\UDcollectverbarg{^^J}{\endgroup\newcommand{\contact}}{\scantokens}|%
     \qrcode[]{
BEGIN:VCARD
VERSION:4.0
EMAIL:john.doe@doe.net
FN:John Doe
N:Doe;John;;;
TEL;TYPE=home:123456789
UID:8cbddd73-d45d-45ad-a1e4-9587984e880d
URL:www.doe.net
END:VCARD
}%
|%


\begin{document}

     \qrcode[]{
BEGIN:VCARD
VERSION:4.0
EMAIL:john.doe@doe.net
FN:John Doe
N:Doe;John;;;
TEL;TYPE=home:123456789
UID:8cbddd73-d45d-45ad-a1e4-9587984e880d
URL:www.doe.net
END:VCARD
}

\contact

\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.