%% fancyqr.sty
%% Copyright 2026 Florian Sihler
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%   https://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Florian Sihler
%
% This work consists of the fancyqr.sty, alongside the `fancyqr-style-*.code` files and the documentation `fancyqr-doc.tex`.
\def\filename{fancyqr}
\ProvidesPackage{\filename}[2026/08/17 version v2.4 Fancy QR-Codes]
\RequirePackage{pict2e, xfp, qrcode}

% the gradient is affine in the module coordinates: trigonometry once per code,
% the row part once per row, a multiply-add per module
\newdimen\fancyqr@grad@a \newdimen\fancyqr@grad@b \newdimen\fancyqr@grad@c
\newdimen\fancyqr@grad@row \newdimen\fancyqr@grad@t
\newcount\fancyqr@grad@n \newcount\fancyqr@ci

% g(i,j) = a*j + b*i + c for
%   ((j-hx)*cos-(i-hy)*sin+hx)/mx*50 + ((j-hx)*sin+(i-hy)*cos+hy)/my*50
\def\fancyqr@gradient@setup{%
   \edef\fancyqr@grad@cos{\fpeval{cosd(\fancyqr@gradient@angle+225)}}% 0 to the right
   \edef\fancyqr@grad@sin{\fpeval{sind(\fancyqr@gradient@angle+225)}}%
   \fancyqr@grad@a=\fpeval{50*(\fancyqr@grad@cos/\@max@x+\fancyqr@grad@sin/\@max@y)}\p@
   \fancyqr@grad@b=\fpeval{50*(\fancyqr@grad@cos/\@max@y-\fancyqr@grad@sin/\@max@x)}\p@
   \fancyqr@grad@c=\fpeval{%
      50*(\@half@max@x*(1-\fancyqr@grad@cos)+\@half@max@y*\fancyqr@grad@sin)/\@max@x
     +50*(\@half@max@y*(1-\fancyqr@grad@cos)-\@half@max@x*\fancyqr@grad@sin)/\@max@y}\p@
}
\def\fancyqr@gradient@row#1{%
   \fancyqr@grad@row=\fancyqr@grad@b \multiply\fancyqr@grad@row#1\relax
   \advance\fancyqr@grad@row\fancyqr@grad@c
}
% #1 column, result in \fancyqr@grad@n
\def\fancyqr@gradient@col#1{%
   \fancyqr@grad@t=\fancyqr@grad@a \multiply\fancyqr@grad@t#1\relax
   \advance\fancyqr@grad@t\fancyqr@grad@row \advance\fancyqr@grad@t.5\p@% round
   \fancyqr@grad@n=\fancyqr@grad@t
   \divide\fancyqr@grad@n\@cclvi \divide\fancyqr@grad@n\@cclvi
   % a rotated gradient may leave the unit square, xcolor may not
   \ifnum\fancyqr@grad@n<\z@ \fancyqr@grad@n\z@\fi
   \ifnum\fancyqr@grad@n>100 \fancyqr@grad@n=100 \fi
}

% integral percentages: 101 mixtures parsed per code, not per module (this must
% run outside of any loop group)
\def\fancyqr@gradient@cache{%
   \fancyqr@grad@n\z@
   \@whilenum\fancyqr@grad@n<101 \do{%
      \colorlet{fancyqr@g@\the\fancyqr@grad@n}%
         {qr@fancy@gradient@br!\the\fancyqr@grad@n!qr@fancy@gradient@tl}%
      \advance\fancyqr@grad@n\@ne}%
}
\def\@@fancyqr@color@gradient#1{%
   \fancyqr@gradient@col\fancyqr@ci
   \@declaredcolor{fancyqr@g@\the\fancyqr@grad@n}{#1}%
}
\def\@@fancyqr@color@default#1{\@declaredcolor{qr@fancy@gradient@tl}{#1}}
\def\@@fancyqr@color@random#1{\pgfmathrandomitem{\@fancyqr@random@c@l@r}{@@fancyqr@@randomcol}\@declaredcolor{\@fancyqr@random@c@l@r}{#1}}
\let\FancyQrColor\@@fancyqr@color@default

\def\fancyqr@rounding@factor{.5}
\edef\fancyqr@rounding@other{\fpeval{1-\fancyqr@rounding@factor}}
% fillet radius for a corner enclosed by two neighbours but not by the diagonal
\def\fancyqr@overlap@factor{.045}% see \qrm below
\def\fancyqr@inner@factor{.25}
% the two legs of a fillet run along the edges of the neighbours it bridges;
% drawing the arc wider by the tile overlap pushes them inside those neighbours,
% where they cannot show up as a seam between two abutting fills
\def\fancyqr@inner@setup{%
   \edef\fancyqr@inner@neg{\fpeval{-\fancyqr@inner@factor}}%
   \edef\fancyqr@inner@plus{\fpeval{1+\fancyqr@inner@factor}}%
   \edef\fancyqr@inner@radius{\fpeval{\fancyqr@inner@factor+2*\fancyqr@overlap@factor}}%
}
\fancyqr@inner@setup
\def\fancyqr@inner@tl{0}\def\fancyqr@inner@tr{0}% set by \fancyqr@setinner
\def\fancyqr@inner@bl{0}\def\fancyqr@inner@br{0}
\newif\iffancyqr@inner@ % styles opt in, the lookups are not free
% a style may draw the modules more than once and switch on \fancyqr@pass
\def\fancyqr@passes{1}\newcount\fancyqr@pass

% O 1 O
% 2 X 3
% O 4 O
% uses \@up\@left\@right\@down
% an undefined combination expands to \relax, i.e. draws nothing
\def\GetPattern{\csname qcc\@up\@left\@right\@down\endcsname}

% backwards compatibility
\def\fancyqr@clap#1{\hb@xt@\z@{\hss#1\hss}}
\newdimen\fancyqr@edge@compensate \fancyqr@edge@compensate=.15\p@

% Tiles are drawn a little larger than their cell so that neighbours overlap:
% where two path edges cross the same pixel, neither covers it fully and the
% renderer leaves a fraction of the background showing through. The overlap has
% to be a fraction of a module rather than a fixed length -- what matters is how
% many device pixels it is at the size the code is actually drawn at.
\newif\iffancyqr@abscomp@
\def\qrm{\dimexpr\qr@modulesize+\fancyqr@edge@compensate\relax}
\long\def\qr@newpattern#1#2#3#4#5{%
\expandafter\def\csname qcc#1#2#3#4\endcsname{% scaling happens implicitly by the unitlength
   \put(\the\j,\the\numexpr\@max@y-\the\i){%
      \advance\unitlength by\fancyqr@edge@compensate\relax
      #5%
   }}%
}

% Flag 1 rounds a corner outwards, 0 continues into a neighbour.  Such a corner
% is an *inner* one when both neighbours are black but the diagonal is not, and
% then gets a fillet: a detour into the empty diagonal cell, traced counter-
% clockwise like the outline so the non-zero fill rule adds it.
% #1 flag, #2 inner flag, #3 point before the outward arc, #4 its center,
% #5 its angles, #6 the corner, #7 the fillet center, #8 its angles -- all
% literal, so a tile needs no arithmetic.
\def\fancyqr@corner#1#2#3#4#5#6#7#8{%
   \ifnum#1=\@ne \lineto#3\circlearc#4\fancyqr@rounding@factor#5%
   \else \lineto#6%
      \ifnum#2=\@ne \circlearc#7\fancyqr@inner@radius#8\lineto#6\fi
   \fi}
\def\fancyqr@rounded@rect#1#2#3#4{%
   \ifnum#4=\@ne\relax \moveto(\fancyqr@rounding@factor,\z@)\else\moveto(\z@,\z@)\fi
   \fancyqr@corner#1\fancyqr@inner@br
      {(\fancyqr@rounding@other,\z@)}{{\fancyqr@rounding@other}{\fancyqr@rounding@factor}}{{270}{360}}%
      {(\@ne,\z@)}{{\fancyqr@inner@plus}{\fancyqr@inner@neg}}{{180}{90}}%
   \fancyqr@corner#2\fancyqr@inner@tr
      {(\@ne,\fancyqr@rounding@other)}{{\fancyqr@rounding@other}{\fancyqr@rounding@other}}{{0}{90}}%
      {(\@ne,\@ne)}{{\fancyqr@inner@plus}{\fancyqr@inner@plus}}{{270}{180}}%
   \fancyqr@corner#3\fancyqr@inner@tl
      {(\fancyqr@rounding@factor,\@ne)}{{\fancyqr@rounding@factor}{\fancyqr@rounding@other}}{{90}{180}}%
      {(\z@,\@ne)}{{\fancyqr@inner@neg}{\fancyqr@inner@plus}}{{360}{270}}%
   \fancyqr@corner#4\fancyqr@inner@bl
      {(\z@,\fancyqr@rounding@factor)}{{\fancyqr@rounding@factor}{\fancyqr@rounding@factor}}{{180}{270}}%
      {(\z@,\z@)}{{\fancyqr@inner@neg}{\fancyqr@inner@neg}}{{90}{0}}%
   \fancyqr@rounded@rect@close
}
\def\fancyqr@rounded@rect@close{\fillpath}

% [#3][#2]  the neighbourhood-to-corner table; #1 draws a tile from its four
% [#4][#1]  corner flags, so a style can reuse the shape
\def\FancyQrRoundedPatterns#1{%
\qr@newpattern0000{#1{1}{1}{1}{1}}% .
\qr@newpattern1000{#1{1}{0}{0}{1}}% | | - -
\qr@newpattern0001{#1{0}{1}{1}{0}}%
\qr@newpattern0100{#1{1}{1}{0}{0}}%
\qr@newpattern0010{#1{0}{0}{1}{1}}%
\qr@newpattern1100{#1{1}{0}{0}{0}}% bottom right
\qr@newpattern1010{#1{0}{0}{0}{1}}% bottom left
\qr@newpattern0101{#1{0}{1}{0}{0}}% top right
\qr@newpattern0011{#1{0}{0}{1}{0}}% top left
\qr@newpattern1001{#1{0}{0}{0}{0}}% straights, enclosed and t's
\qr@newpattern0110{#1{0}{0}{0}{0}}%
\qr@newpattern1111{#1{0}{0}{0}{0}}%
\qr@newpattern0111{#1{0}{0}{0}{0}}%
\qr@newpattern1011{#1{0}{0}{0}{0}}%
\qr@newpattern1101{#1{0}{0}{0}{0}}%
\qr@newpattern1110{#1{0}{0}{0}{0}}%
}
% the same table by the four neighbours instead of by the corners
\def\FancyQrSidePatterns#1{%
\qr@newpattern0000{#1{0}{0}{0}{0}}%
\qr@newpattern1000{#1{1}{0}{0}{0}}%
\qr@newpattern0001{#1{0}{0}{0}{1}}%
\qr@newpattern0100{#1{0}{1}{0}{0}}%
\qr@newpattern0010{#1{0}{0}{1}{0}}%
\qr@newpattern1100{#1{1}{1}{0}{0}}%
\qr@newpattern1010{#1{1}{0}{1}{0}}%
\qr@newpattern0101{#1{0}{1}{0}{1}}%
\qr@newpattern0011{#1{0}{0}{1}{1}}%
\qr@newpattern1001{#1{1}{0}{0}{1}}%
\qr@newpattern0110{#1{0}{1}{1}{0}}%
\qr@newpattern1111{#1{1}{1}{1}{1}}%
\qr@newpattern0111{#1{0}{1}{1}{1}}%
\qr@newpattern1011{#1{1}{0}{1}{1}}%
\qr@newpattern1101{#1{1}{1}{0}{1}}%
\qr@newpattern1110{#1{1}{1}{1}{0}}%
}
\def\FancyQrLoadDefault{%
   \fancyqr@inner@true % this style knows about inner corners
   \FancyQrRoundedPatterns\fancyqr@rounded@rect
}
\FancyQrLoadDefault % allows to reset the style after other loads
\def\@fancy@qr@default@name{default}

\def\FancyQrLoad#1{%
\protected@edef\fancyqr@loaded@style{#1}%
\def\fancyqr@rounded@rect@close{\fillpath}%
\fancyqr@inner@false % a style has to ask for inner roundings
\def\fancyqr@passes{1}%
\setkeys{fancyqr}{finder=inherit,finder core=auto}% the style owns the shapes
\let\@tmp\newpattern\let\newpattern\qr@newpattern\@bsphack\def\@@tmp{#1}%
\ifx\@@tmp\@fancy@qr@default@name\FancyQrLoadDefault\else
\expandafter\edef\csname pingu@lib@#1@atcode\endcsname{\the\catcode`\@}%
\catcode`\@=11\relax
\input{fancyqr-style-#1.code}%
\catcode`\@=\csname pingu@lib@#1@atcode\endcsname
\fi\@esphack\let\newpattern\@tmp\let\@tmp\relax}
\let\FancyQrInnerRoundings\fancyqr@inner@true
\let\FancyQrNoInnerRoundings\fancyqr@inner@false
\def\FancyQrPasses#1{\def\fancyqr@passes{#1}}


% everything that is not defined is white
\def\fancy@qr@matrixentry#1#2#3{% matrix, row, column
   \ifcsname #1@#2@#3\endcsname
   \csname #1@#2@#3\endcsname
   \else\qr@white@format\fi
}%

\def\FancyQrDoNotPrintSquare#1#2{% width, height
   \def\fancy@qr@donotprint@center@x{#1}%
   \def\fancy@qr@donotprint@center@y{#2}%
}
\FancyQrDoNotPrintSquare00
% is a factor between 0 and 1
\def\FancyQrDoNotPrintRadius#1{%
   \def\fancy@qr@donotprint@center@r{#1}%
}
\FancyQrDoNotPrintRadius0

\newif\iffancy@qr@do@print@
% the bounds are inclusive by one module, so without a cut-out an unguarded
% check would drop the center module
\newif\iffancy@qr@cutout@
\def\qr@fancy@updateif#1#2{\fancy@qr@do@print@true
\ifdim\fancy@qr@donotprint@center@r\p@>\z@
   \ifnum#1>\@do@y@min\relax \ifnum#1<\@do@y@max\relax \ifnum#2>\@do@x@min\relax \ifnum#2<\@do@x@max\relax
      \ifdim\fpeval{sqrt((#1-\@half@max@y)^2 + (#2-\@half@max@x)^2)}\p@<\@max@rcrad\p@
         \fancy@qr@do@print@false
      \fi
   \fi\fi\fi\fi
\else
\ifnum#1>\@do@y@min\relax \ifnum#1<\@do@y@max\relax \ifnum#2>\@do@x@min\relax \ifnum#2<\@do@x@max\relax \fancy@qr@do@print@false \fi\fi\fi\fi\fi
}

\newif\iffancy@qr@roundcut@
\fancy@qr@roundcut@true
\let\FancyQrHardCut\fancy@qr@roundcut@false
\let\FancyQrRoundCut\fancy@qr@roundcut@true

% clear plus if not to be printed
\def\qr@fancy@clear@surround#1#2#3{%
   \qr@fancy@updateif{\the\numexpr#2-1}{#3}%
   \iffancy@qr@do@print@\else \expandafter\let\csname #1@\the\numexpr#2-1 @#3\endcsname\@undefined \fi
   \qr@fancy@updateif{\the\numexpr#2+1}{#3}%
   \iffancy@qr@do@print@\else \expandafter\let\csname #1@\the\numexpr#2+1 @#3\endcsname\@undefined \fi
   \qr@fancy@updateif{#2}{\the\numexpr#3-1}%
   \iffancy@qr@do@print@\else \expandafter\let\csname #1@#2@\the\numexpr#3-1\endcsname\@undefined \fi
   \qr@fancy@updateif{#2}{\the\numexpr#3+1}%
   \iffancy@qr@do@print@\else \expandafter\let\csname #1@#2@\the\numexpr#3+1\endcsname\@undefined \fi
}

% only look up a diagonal if both of its neighbours are black
\def\fancyqr@inner@check#1#2#3{%
   \edef\@tmp{\qr@matrixentry\fancyqr@currprint{#1}{#2}}%
   \ifnum\@tmp=\qr@white\relax \def#3{1}\fi
}
\def\fancyqr@setinner{% uses \@up\@left\@right\@down and the counters \i \j
   \def\fancyqr@inner@tl{0}\def\fancyqr@inner@tr{0}%
   \def\fancyqr@inner@bl{0}\def\fancyqr@inner@br{0}%
   \ifnum\@up=\qr@black\relax
      \ifnum\@left=\qr@black\relax
         \fancyqr@inner@check{\the\numexpr\i-\@ne\relax}{\the\numexpr\j-\@ne\relax}\fancyqr@inner@tl\fi
      \ifnum\@right=\qr@black\relax
         \fancyqr@inner@check{\the\numexpr\i-\@ne\relax}{\the\numexpr\j+\@ne\relax}\fancyqr@inner@tr\fi
   \fi
   \ifnum\@down=\qr@black\relax
      \ifnum\@left=\qr@black\relax
         \fancyqr@inner@check{\the\numexpr\i+\@ne\relax}{\the\numexpr\j-\@ne\relax}\fancyqr@inner@bl\fi
      \ifnum\@right=\qr@black\relax
         \fancyqr@inner@check{\the\numexpr\i+\@ne\relax}{\the\numexpr\j+\@ne\relax}\fancyqr@inner@br\fi
   \fi
}

% position patterns follow from the size, alignment patterns are recorded while
% `qrcode' places them (\fancy@qr@setup)
\newif\iffancyqr@fixed@      % the patterns are treated specially at all
\newif\iffancyqr@fixedshape@ % ... drawn as one shape instead of as modules
\newif\iffancyqr@fixedmap@   % ... only recolored, which needs a module map
\def\fancyqr@finder@style{inherit}
\def\fancyqr@finder@core{auto}
\def\fancyqr@finder@color{}
\def\fancyqr@content@color{}% the data modules, i.e. everything but the patterns
\def\fancyqr@finder@radius{.5}   % corner radius, relative to the pattern
\def\fancyqr@finder@thickness{1}% ring width in modules
\def\fancyqr@star@ratio{.55}    % inner/outer radius of a star core
\def\fancyqr@star@boost{1.27}   % ... which is a single module on an alignment
                                % pattern and reads too small at that size
\gdef\fancyqr@alignlist{}
\def\fancyqr@do#1#2{}

\def\fancyqr@finder@none{none}\def\fancyqr@finder@auto{auto}
\def\fancyqr@finder@inherit{inherit}
% `inherit' (and its synonym `none') leaves the patterns to the tiles of the
% loaded style, which is what fancyqr did before the shapes existed
% the map that tells a pattern module from a data one is needed as soon as the
% two are colored differently
\def\fancyqr@finder@update{%
   \fancyqr@fixedshape@true
   \ifx\fancyqr@finder@style\fancyqr@finder@none\fancyqr@fixedshape@false\fi
   \ifx\fancyqr@finder@style\fancyqr@finder@inherit\fancyqr@fixedshape@false\fi
   \fancyqr@fixedmap@false
   \iffancyqr@fixedshape@\else
      \ifx\fancyqr@finder@color\@empty\else\fancyqr@fixedmap@true\fi
      \ifx\fancyqr@content@color\@empty\else\fancyqr@fixedmap@true\fi
   \fi
   \iffancyqr@fixedshape@\fancyqr@fixed@true
   \else\iffancyqr@fixedmap@\fancyqr@fixed@true\else\fancyqr@fixed@false\fi\fi
}

% applies \fancyqr@fixed@action{top row}{left column}{size} to every pattern
\def\fancyqr@fixedpatterns{%
   \edef\fancyqr@fix@last{\the\numexpr\@max@x-6\relax}%
   \fancyqr@fixed@action{1}{1}{7}%
   \fancyqr@fixed@action{1}{\fancyqr@fix@last}{7}%
   \fancyqr@fixed@action{\fancyqr@fix@last}{1}{7}%
   \let\fancyqr@do\fancyqr@fixed@align \fancyqr@alignlist
}
\def\fancyqr@fixed@align#1#2{\fancyqr@fixed@action{\the\numexpr#1-2\relax}{\the\numexpr#2-2\relax}{5}}

% walks the modules (#1,#2)--(#1+#3-1,#2+#4-1) applying \fancyqr@rect@action
\def\fancyqr@rect#1#2#3#4{%
   \qr@for \fancyqr@mi=#1 to \the\numexpr#1+#3-\@ne\relax by \@ne{%
      \qr@for \fancyqr@mj=#2 to \the\numexpr#2+#4-\@ne\relax by \@ne{%
         \fancyqr@rect@action}}%
}
\def\fancyqr@cell{\fancyqr@currprint @\the\fancyqr@mi @\the\fancyqr@mj}
\def\fancyqr@mark{\global\expandafter\let
   \csname fancyqr@fix@\the\fancyqr@mi @\the\fancyqr@mj\endcsname\@ne}
\def\fancyqr@unmark{\global\expandafter\let
   \csname fancyqr@fix@\the\fancyqr@mi @\the\fancyqr@mj\endcsname\@undefined}
% a shape replaces the modules of its pattern, so they are dropped from the
% matrix: they are then neither drawn twice nor seen by their neighbours, which
% round off against the shape instead of ending in a flat stub beside it
\def\fancyqr@clear{\global\expandafter\let\csname\fancyqr@cell\endcsname\@undefined}
% the matrix is shared between codes, so anything cleared has to come back
\def\fancyqr@save{\global\expandafter\let
   \csname fancyqr@sv@\the\fancyqr@mi @\the\fancyqr@mj\expandafter\endcsname
   \csname\fancyqr@cell\endcsname}
\def\fancyqr@restore{\global\expandafter\let\csname\fancyqr@cell\expandafter\endcsname
   \csname fancyqr@sv@\the\fancyqr@mi @\the\fancyqr@mj\endcsname}
\def\fancyqr@saveclear{\fancyqr@save\fancyqr@clear}

\def\fancyqr@block#1#2#3{\fancyqr@rect{#1}{#2}{#3}{#3}}
\def\fancyqr@markfixed{%
   \iffancyqr@fixedshape@\let\fancyqr@rect@action\fancyqr@saveclear
   \else\let\fancyqr@rect@action\fancyqr@mark\fi
   \let\fancyqr@fixed@action\fancyqr@block \fancyqr@fixedpatterns}
\def\fancyqr@unmarkfixed{%
   \iffancyqr@fixedshape@\let\fancyqr@rect@action\fancyqr@restore
   \else\let\fancyqr@rect@action\fancyqr@unmark\fi
   \let\fancyqr@fixed@action\fancyqr@block \fancyqr@fixedpatterns}
% the round cut only ever clears modules inside the hidden rectangle
\def\fancyqr@cutrect#1{\let\fancyqr@rect@action#1%
   \fancyqr@rect{\the\numexpr\@do@y@min+\@ne\relax}{\the\numexpr\@do@x@min+\@ne\relax}%
      {\the\numexpr\@do@y@max-\@do@y@min-\@ne\relax}{\the\numexpr\@do@x@max-\@do@x@min-\@ne\relax}}

% both hoisted once per code, so a tile pays nothing for them
\def\fancyqr@colorsetup{%
   \ifx\fancyqr@finder@color\@empty \let\fancyqr@fixedcolor\FancyQrColor
   \else \def\fancyqr@fixedcolor##1{{\color{\fancyqr@finder@color}##1}}\fi
   \ifx\fancyqr@content@color\@empty \let\fancyqr@tilecolor\FancyQrColor
   \else \def\fancyqr@tilecolor##1{{\color{\fancyqr@content@color}##1}}\fi
}

% a shape is a path inscribed in (#1,#1)--(#2,#2) closed by #3, so the same five
% macros serve the stroked ring and the filled core
\def\fancyqr@shape@none#1#2#3{}
\def\fancyqr@shape@square#1#2#3{\moveto(#1,#1)\lineto(#2,#1)\lineto(#2,#2)\lineto(#1,#2)\closepath#3}
\def\fancyqr@shape@circle#1#2#3{%
   \edef\@fq@c{\fpeval{(#1+#2)/2}}%
   \circlearc[1]\@fq@c\@fq@c{\fpeval{(#2-#1)/2}}{0}{360}\closepath#3}
\def\fancyqr@shape@rounded#1#2#3{%
   \roundjoin
   \edef\@fq@r{\fpeval{\fancyqr@finder@radius*(#2-#1)/2}}%
   \moveto(\fpeval{#1+\@fq@r},#1)%
   \lineto(\fpeval{#2-\@fq@r},#1)\circlearc{\fpeval{#2-\@fq@r}}{\fpeval{#1+\@fq@r}}\@fq@r{270}{360}%
   \lineto(#2,\fpeval{#2-\@fq@r})\circlearc{\fpeval{#2-\@fq@r}}{\fpeval{#2-\@fq@r}}\@fq@r{0}{90}%
   \lineto(\fpeval{#1+\@fq@r},#2)\circlearc{\fpeval{#1+\@fq@r}}{\fpeval{#2-\@fq@r}}\@fq@r{90}{180}%
   \lineto(#1,\fpeval{#1+\@fq@r})\circlearc{\fpeval{#1+\@fq@r}}{\fpeval{#1+\@fq@r}}\@fq@r{180}{270}%
   \closepath#3}
% a thinner star breaks the 1:1:3:1:1 run a scanner looks for
\def\fancyqr@shape@star#1#2#3{%
   \roundjoin
   \edef\@fq@c{\fpeval{(#1+#2)/2}}%
   \edef\@fq@ro{\fpeval{(#2-#1)/2*((#2-#1)<2 ? \fancyqr@star@boost : 1)}}%
   \edef\@fq@ri{\fpeval{\fancyqr@star@ratio*\@fq@ro}}%
   \moveto(\fpeval{\@fq@c+\@fq@ro},\@fq@c)%
   \@tempcnta=\z@
   \loop\advance\@tempcnta45\relax
      \edef\@fq@rr{\ifodd\numexpr\@tempcnta/45\relax \@fq@ri\else\@fq@ro\fi}%
      \lineto(\fpeval{\@fq@c+\@fq@rr*cosd(\@tempcnta)},\fpeval{\@fq@c+\@fq@rr*sind(\@tempcnta)})%
   \ifnum\@tempcnta<360\relax\repeat
   \closepath#3}

\def\fancyqr@shape#1#2#3#4{%
   \ifcsname fancyqr@shape@#1\endcsname
      \csname fancyqr@shape@#1\endcsname{#2}{#3}{#4}%
   \else
      \PackageError{fancyqr}{Unknown pattern shape `#1'}%
         {Known shapes are inherit, square, rounded, circle and star.}%
   \fi}

\def\fancyqr@draw@block#1#2#3{%
   % colored as if it were the module in its center
   \fancyqr@gradient@row{\the\numexpr#1+(#3-\@ne)/\tw@\relax}%
   \fancyqr@ci=\numexpr#2+(#3-\@ne)/\tw@\relax
   \edef\@fq@t{\fpeval{\fancyqr@finder@thickness/2}}%
   \put(#2,\the\numexpr\@max@y-#1-#3+\@ne\relax){%
      \fancyqr@fixedcolor{%
         \linethickness{\fancyqr@finder@thickness\unitlength}%
         \fancyqr@shape\fancyqr@finder@style\@fq@t{\fpeval{#3-\@fq@t}}\strokepath
         \fancyqr@shape\fancyqr@effective@core{2}{\fpeval{#3-2}}\fillpath
      }%
   }%
}
\def\fancyqr@drawfixed{\let\fancyqr@fixed@action\fancyqr@draw@block\fancyqr@fixedpatterns}

\def\fancyqr@modules{%
   \qr@for \i=\@ne to \@max@y by \@ne{%
      \fancyqr@gradient@row\i
      \qr@for \j=\@ne to \@max@x by \@ne{%
      \iffancy@qr@cutout@\qr@fancy@updateif\i\j\fi
      \iffancy@qr@do@print@
         \ifnum\qr@matrixentry\fancyqr@currprint{\the\i}{\the\j}=\qr@black\relax
            \iffancy@qr@cutout@\iffancy@qr@roundcut@
               \qr@fancy@clear@surround\fancyqr@currprint{\the\i}{\the\j}\fi\fi
            \edef\@up{\qr@matrixentry\fancyqr@currprint{\the\numexpr\the\i-\@ne}{\the\j}}%
            \edef\@left{\qr@matrixentry\fancyqr@currprint{\the\i}{\the\numexpr\the\j-\@ne}}%
            \edef\@right{\qr@matrixentry\fancyqr@currprint{\the\i}{\the\numexpr\the\j+\@ne}}%
            \edef\@down{\qr@matrixentry\fancyqr@currprint{\the\numexpr\the\i+\@ne}{\the\j}}%
            \iffancyqr@inner@\fancyqr@setinner\fi
            \fancyqr@ci=\j
            \iffancyqr@fixedmap@
               \ifcsname fancyqr@fix@\the\i @\the\j\endcsname
                  \fancyqr@fixedcolor{\GetPattern}%
               \else\fancyqr@tilecolor{\GetPattern}\fi
            \else\fancyqr@tilecolor{\GetPattern}\fi
      \fi\fi
   }}%
}

\newif\if@fancyqr@image@

\def\qr@white{0}\def\qr@black{1}%
\def\fancy@qr@printmatrix#1{%
   \protected@edef\fancyqr@currprint{#1}%
   \let\qr@black@fixed\qr@black \let\qr@white@fixed\qr@white
   \let\qr@black@format\qr@black \let\qr@white@format\qr@white
  %Set module size
  \qr@modulesize=\qr@desiredheight\relax
  \divide\qr@modulesize by \qr@size\relax
  \unitlength=\dimexpr\qr@modulesize\relax % will be re-set in placement
  \iffancyqr@abscomp@\else
     \fancyqr@edge@compensate=\fancyqr@overlap@factor\qr@modulesize
  \fi
  \if@fancyqr@image@% image is in \fancyqr@imgbox
   % the hidden square spans 2r+1 modules, i.e. r+1/2 to each side
   \edef\fancyqr@img@x{\fpeval{max(0,ceil((.5\wd\fancyqr@imgbox)/\qr@modulesize-.5))+\fancyqr@img@padding@x}}%
   \edef\fancyqr@img@y{\fpeval{max(0,ceil((.5\ht\fancyqr@imgbox+.5\dp\fancyqr@imgbox)/\qr@modulesize-.5))+\fancyqr@img@padding@y}}%
   \FancyQrDoNotPrintSquare\fancyqr@img@x\fancyqr@img@y
  \fi
  \ifx\FancyQrColor\@@fancyqr@color@gradient\fancyqr@gradient@cache\fi
  \qr@minipagewidth=\qr@desiredheight
  \ifqr@tight\else \advance\qr@minipagewidth by 8\qr@modulesize\relax \fi
  \begingroup
      \edef\@max@x{\qr@numberofrowsinmatrix\fancyqr@currprint}\edef\@half@max@x{\the\numexpr\@max@x/2}%
      \edef\@max@y{\qr@numberofcolsinmatrix\fancyqr@currprint}\edef\@half@max@y{\the\numexpr\@max@y/2}%
      \fancyqr@gradient@setup \fancyqr@colorsetup
      \ifdim\fancyqr@inner@factor\p@>\z@\else\fancyqr@inner@false\fi
      \edef\fancyqr@effective@core{%
         \ifx\fancyqr@finder@core\fancyqr@finder@auto\fancyqr@finder@style\else\fancyqr@finder@core\fi}%
      % redefine the border to be white!
      \qr@for \i=\@ne to \@max@y by \@ne{%
      % redefine the limits to be white!
      \qr@storetomatrix\fancyqr@currprint{\the\numexpr\z@}{\the\i}{\qr@white}%
      \qr@storetomatrix\fancyqr@currprint{\the\numexpr\@max@x+\@ne}{\the\i}{\qr@white}%
      }%
      \qr@for \i=\@ne to \@max@x by \@ne{%
         \qr@storetomatrix\fancyqr@currprint{\the\i}{\the\numexpr\z@}{\qr@white}%
         \qr@storetomatrix\fancyqr@currprint{\the\i}{\the\numexpr\@max@y+\@ne}{\qr@white}%
      }%
      \edef\@do@x@min{\the\numexpr\@half@max@x-\fancy@qr@donotprint@center@x-\@ne}%
      \edef\@do@x@max{\the\numexpr\@half@max@x+\fancy@qr@donotprint@center@x+\@ne}%
      \edef\@do@y@min{\the\numexpr\@half@max@y-\fancy@qr@donotprint@center@y-\@ne}%
      \edef\@do@y@max{\the\numexpr\@half@max@y+\fancy@qr@donotprint@center@y+\@ne}%
      \edef\@max@rcrad{\fpeval{max((\@ne-\fancy@qr@donotprint@center@r)*\fancy@qr@donotprint@center@x,(\@ne-\fancy@qr@donotprint@center@r)*\fancy@qr@donotprint@center@y)+\fancyqr@edge@compensate}}%
      \ifdim\fpeval{max(\fancy@qr@donotprint@center@x,\fancy@qr@donotprint@center@y)}\p@>\z@
         \fancy@qr@cutout@true\else\fancy@qr@cutout@false\fancy@qr@do@print@true\fi
      \iffancyqr@fixed@\fancyqr@markfixed\fi
      \iffancy@qr@cutout@\iffancy@qr@roundcut@\fancyqr@cutrect\fancyqr@save\fi\fi
      \edef\@tmp@tight{\ifqr@tight\z@\else-4\fi}%
      \picture(\qr@minipagewidth,\qr@minipagewidth)(\the\numexpr\@ne+\@tmp@tight,\@tmp@tight)
      \fancyqr@pass\z@
      \loop \advance\fancyqr@pass\@ne \fancyqr@modules
      \ifnum\fancyqr@pass<\fancyqr@passes\relax\repeat
      \iffancyqr@fixedshape@\fancyqr@drawfixed\fi
      \if@fancyqr@image@
         % the cut-out is centered on module (\@half@max@y,\@half@max@x), whose
         % own center is half a module up and right of its origin
         \put(\fpeval{\@half@max@x+.5},\fpeval{\@max@y-\@half@max@y+.5}){%
            \raisebox{\dimexpr-.5\height+.5\depth\relax}{\fancyqr@clap{%
               \usebox\fancyqr@imgbox
            }}%
         }%
      \fi
      \endpicture
      \iffancy@qr@cutout@\iffancy@qr@roundcut@\fancyqr@cutrect\fancyqr@restore\fi\fi
      \iffancyqr@fixed@\fancyqr@unmarkfixed\fi
   \endgroup
}%

\def\fancy@qr@setup#1{%
   \qr@creatematrix{#1}%
   \expandafter\gdef\csname #1@numrows\endcsname{\qr@size}%
   \expandafter\gdef\csname #1@numcols\endcsname{\qr@size}%
   % we do not need to create blank because we store all
   \qr@placefinderpatterns{#1}%
   \qr@placetimingpatterns{#1}%
   % remember where the alignment patterns end up, so they can be styled
   \gdef\fancyqr@alignlist{}%
   \begingroup
      \let\fancyqr@orig@align\qr@placealignmentpattern@int
      \def\qr@placealignmentpattern@int##1##2##3{%
         \xdef\fancyqr@alignlist{\unexpanded\expandafter{\fancyqr@alignlist}%
            \noexpand\fancyqr@do{\number\numexpr##2\relax}{\number\numexpr##3\relax}}%
         \fancyqr@orig@align{##1}{##2}{##3}}%
      \qr@placealignmentpatterns{#1}%
   \endgroup
}

\newcount\c@fancy@a \newcount\c@fancy@b
% the normal data is... well...
\def\fancy@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.
  \expandafter\c@fancy@a\the\numexpr\qr@numberofrowsinmatrix{#1}\relax
  \expandafter\c@fancy@b\the\numexpr\qr@numberofcolsinmatrix{#1}\relax
  \edef\qr@datatowrite{#2\relax}%
  \c@qr@i0\relax
  \@whilenum\c@qr@i<\c@fancy@a\do{%
      \c@qr@j0 \advance\c@qr@i\@ne
      \@whilenum\c@qr@j<\c@fancy@b\do{%
         \advance\c@qr@j\@ne
         \expandafter\fancy@qr@writebit\qr@datatowrite:{#1}%
      }%
  }%
}

\def\fancy@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}{\number\c@qr@i}{\number\c@qr@j}{\qr@black}%
  \else
    \qr@storetomatrix{#3}{\number\c@qr@i}{\number\c@qr@j}{\qr@white}%
  \fi
}%


% Building the matrix costs more than drawing it, and `qrcode' hands us the
% same code over and over (a gallery, a running header, ...), so keep it under
% a name derived from its content instead of rebuilding it into a scratch one.
\def\fancy@qr@printsavedbinarymatrix#1{%
   \iffancyqr@cache
      \edef\fancyqr@currmat{fq@\qr@texttoencode @\qr@version @\qr@level}%
   \else
      \def\fancyqr@currmat{@tmp}%
      \global\expandafter\let\csname @tmp@numrows\endcsname\@undefined
   \fi
   \ifcsname\fancyqr@currmat @numrows\endcsname
      \expandafter\let\expandafter\fancyqr@alignlist
         \csname fancyqr@align@\fancyqr@currmat\endcsname
   \else
      \def\qr@binarystring{#1\relax\relax}%
      \expandafter\fancy@qr@setup\expandafter{\fancyqr@currmat}%
      \expandafter\fancy@qr@writedata\expandafter{\fancyqr@currmat}{\qr@binarystring}%
      \global\expandafter\let\csname fancyqr@align@\fancyqr@currmat\endcsname
         \fancyqr@alignlist
   \fi
   \expandafter\fancy@qr@printmatrix\expandafter{\fancyqr@currmat}%
}%

\newsavebox\fancyqr@imgbox
\newif\if@fancyqr@randomcolor@
\define@key{fancyqr}{image x padding}{\def\fancyqr@img@padding@x{#1}}
\define@key{fancyqr}{image y padding}{\def\fancyqr@img@padding@y{#1}}
\define@key{fancyqr}{image padding}{\def\fancyqr@img@padding@x{#1}\def\fancyqr@img@padding@y{#1}}
\define@key{fancyqr}{image}{\@fancyqr@image@true\savebox\fancyqr@imgbox{#1}}
\define@key{fancyqr}{color}{\@fancyqr@randomcolor@false\@fancyqr@gradientfalse\colorlet{qr@fancy@gradient@tl}{#1}}
\define@key{fancyqr}{left color}{\@fancyqr@randomcolor@false\colorlet{qr@fancy@gradient@br}{#1}}
\define@key{fancyqr}{l color}{\setkeys{fancyqr}{left color=#1}}
\define@key{fancyqr}{right color}{\@fancyqr@randomcolor@false\colorlet{qr@fancy@gradient@tl}{#1}}
\define@key{fancyqr}{r color}{\setkeys{fancyqr}{right color=#1}}
\define@key{fancyqr}{gradient angle}{\@fancyqr@randomcolor@false\def\fancyqr@gradient@angle{#1}}
\define@boolkey{fancyqr}[@fancyqr@]{gradient}[true]{}% if@fancyqr@gradient
\define@boolkey{fancyqr}[fancyqr@]{cache}[true]{}% iffancyqr@cache
\define@key{fancyqr}{random color}{\@fancyqr@randomcolor@true\def\@fancyqr@random@colors{#1}}
\define@key{fancyqr}{width}{\setkeys{qr}{height=#1}}
\define@key{fancyqr}{size}{\setkeys{qr}{height=#1}}
\define@key{fancyqr}{compensate}{\fancyqr@abscomp@true\setlength\fancyqr@edge@compensate{#1}}
\define@key{fancyqr}{overlap}{\fancyqr@abscomp@false\def\fancyqr@overlap@factor{#1}\fancyqr@inner@setup}
\define@key{fancyqr}{rounding}{%
   \edef\fancyqr@rounding@factor{\fpeval{min(.5,max(0,#1))}}%
   \edef\fancyqr@rounding@other{\fpeval{1-\fancyqr@rounding@factor}}}
\define@key{fancyqr}{inner rounding}{%
   \edef\fancyqr@inner@factor{\fpeval{min(.5,max(0,#1))}}\fancyqr@inner@setup}
\define@key{fancyqr}{finder}{\def\fancyqr@finder@style{#1}\fancyqr@finder@update}
\define@key{fancyqr}{finder radius}{\def\fancyqr@finder@radius{#1}}
\define@key{fancyqr}{finder thickness}{\def\fancyqr@finder@thickness{#1}}
\define@key{fancyqr}{finder core}{\def\fancyqr@finder@core{#1}\fancyqr@finder@update}
\define@key{fancyqr}{finder color}{\def\fancyqr@finder@color{#1}\fancyqr@finder@update}
\define@key{fancyqr}{content color}{\def\fancyqr@content@color{#1}\fancyqr@finder@update}
% a fixed seed makes the randomized styles reproducible
\define@key{fancyqr}{seed}{\FancyQrSeed{#1}}
\def\FancyQrSeed#1{%
   \ifcsname sys_gset_rand_seed:n\endcsname
      \csname sys_gset_rand_seed:n\endcsname{#1}%
   \else\ifdefined\pdfsetrandomseed \pdfsetrandomseed#1\relax\fi\fi}
% \fancyqr@loaded@style
\def\fancyqr@flat@style{flat}
\define@boolkey{fancyqr}[@fancyqr@]{classic}[true]{} % if@fancyqr@classic
\def\fancyqr@classic{%
\ifx\fancyqr@loaded@style\fancyqr@flat@style\else\FancyQrLoad{\fancyqr@flat@style}\fi
\setkeys{fancyqr}{%
   gradient=false,color=black,l color=black,r color=black,compensate=\z@\relax,
   finder=inherit,finder color=,content color=
}%
}

\def\fancyqrset#1{\setkeys{qr,fancyqr}{#1}}
\fancyqrset{%
   image padding=0,%
   gradient=true,%
   gradient angle=135,%
   r color=red!68!black!88!white!90!white,%
   l color=purple!40!red!20!black!90!white,%
   cache=true%
}

\def\@fancyqr@init{\let\qr@printsavedbinarymatrix\fancy@qr@printsavedbinarymatrix\let\qr@matrixentry\fancy@qr@matrixentry\let\qr@printmatrix\fancy@qr@printmatrix}
\def\fancyqr{\@ifstar\s@fancyqr\ns@fancyqr}
% we rebuild some parts of qrcode to allow this macro to extend the keys while keeping the wrapper
\def\s@fancyqr{\qr@starinvokedtrue\@@fancyqr}
\def\ns@fancyqr{\qr@starinvokedfalse\@@fancyqr}
\newcommand\@@fancyqr[1][]{\begingroup\@fancyqr@init
\ifqr@starinvoked\qr@hyperlinkfalse\fi
\setkeys{qr,fancyqr}{#1}%
\if@fancyqr@classic\fancyqr@classic\fi%
\if@fancyqr@randomcolor@%
\ifcsname pgfmathdeclarerandomlist\endcsname\else
\PackageError{fancyqr}{Random colors requested but pgfmath not loaded}{Please load pgfmath if you want this}\fi
\pgfmathdeclarerandomlist{@@fancyqr@@randomcol}{\@fancyqr@random@colors}\let\FancyQrColor\@@fancyqr@color@random\else\if@fancyqr@gradient\let\FancyQrColor\@@fancyqr@color@gradient\fi\fi
\bgroup\qr@verbatimcatcodes\qr@setescapedspecials\qrcode@in}
\endinput
