Skip to content

Instantly share code, notes, and snippets.

@dvruette
Last active April 18, 2026 20:26
Show Gist options
  • Select an option

  • Save dvruette/051b20ce5c7c2ccf75995635205a3061 to your computer and use it in GitHub Desktop.

Select an option

Save dvruette/051b20ce5c7c2ccf75995635205a3061 to your computer and use it in GitHub Desktop.
QR code with logo in LaTeX
\documentclass[11pt]{article}
\usepackage{qrcodewithlogo}
\begin{document}
% basic usage
\qrcodeWithLogo[width=5cm, logo=assets/arxiv.png]{https://arxiv.org/abs/1503.03585}
% adjust size and padding of logo, error correction of QR code
\qrcodeWithLogo[width=5cm, padding=0, scale=0.4, level=H, logo=assets/arxiv.png]{https://arxiv.org/abs/1503.03585}
% also works without logo
\qrcodeWithLogo[width=5cm]{https://arxiv.org/abs/2512.10858}
\end{document}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{qrcodewithlogo}[2026/04/17 v1.0 QR codes with centered logo overlay]
\RequirePackage{tikz}
\RequirePackage{graphicx}
\RequirePackage{qrcode}
\RequirePackage{xstring}
\usetikzlibrary{calc}
\makeatletter
\def\qrcwl@defcap#1#2#3#4#5{%
\expandafter\def\csname qrcwl@cap@#1@L\endcsname{#2}%
\expandafter\def\csname qrcwl@cap@#1@M\endcsname{#3}%
\expandafter\def\csname qrcwl@cap@#1@Q\endcsname{#4}%
\expandafter\def\csname qrcwl@cap@#1@H\endcsname{#5}%
}
\qrcwl@defcap{1}{17}{14}{11}{7}
\qrcwl@defcap{2}{32}{26}{20}{14}
\qrcwl@defcap{3}{53}{42}{32}{24}
\qrcwl@defcap{4}{78}{62}{46}{34}
\qrcwl@defcap{5}{106}{84}{60}{44}
\qrcwl@defcap{6}{134}{106}{74}{58}
\qrcwl@defcap{7}{154}{122}{86}{64}
\qrcwl@defcap{8}{192}{152}{108}{84}
\qrcwl@defcap{9}{230}{180}{130}{98}
\qrcwl@defcap{10}{271}{213}{151}{119}
\qrcwl@defcap{11}{321}{251}{177}{137}
\qrcwl@defcap{12}{367}{287}{203}{155}
\qrcwl@defcap{13}{425}{331}{241}{177}
\qrcwl@defcap{14}{458}{362}{258}{194}
\qrcwl@defcap{15}{520}{412}{292}{220}
\qrcwl@defcap{16}{586}{450}{322}{250}
\qrcwl@defcap{17}{644}{504}{364}{280}
\qrcwl@defcap{18}{718}{560}{394}{310}
\qrcwl@defcap{19}{792}{624}{442}{338}
\qrcwl@defcap{20}{858}{666}{482}{382}
\qrcwl@defcap{21}{929}{711}{509}{403}
\qrcwl@defcap{22}{1003}{779}{565}{439}
\qrcwl@defcap{23}{1091}{857}{611}{461}
\qrcwl@defcap{24}{1171}{911}{661}{511}
\qrcwl@defcap{25}{1273}{997}{715}{535}
\qrcwl@defcap{26}{1367}{1059}{751}{593}
\qrcwl@defcap{27}{1465}{1125}{805}{625}
\qrcwl@defcap{28}{1528}{1190}{868}{658}
\qrcwl@defcap{29}{1628}{1264}{908}{698}
\qrcwl@defcap{30}{1732}{1370}{982}{742}
\qrcwl@defcap{31}{1840}{1452}{1030}{790}
\qrcwl@defcap{32}{1952}{1538}{1112}{842}
\qrcwl@defcap{33}{2068}{1628}{1168}{898}
\qrcwl@defcap{34}{2188}{1722}{1228}{958}
\qrcwl@defcap{35}{2303}{1809}{1283}{983}
\qrcwl@defcap{36}{2431}{1911}{1351}{1051}
\qrcwl@defcap{37}{2563}{1989}{1423}{1093}
\qrcwl@defcap{38}{2699}{2099}{1499}{1139}
\qrcwl@defcap{39}{2809}{2213}{1579}{1219}
\qrcwl@defcap{40}{2953}{2331}{1663}{1273}
\newcount\qrcwl@vcount
\newcommand{\qrcwl@pickversion}[2]{%
\qrcwl@vcount=1\relax
\def\qrcwl@found{0}%
\loop
\ifnum\qrcwl@found=0
\edef\qrcwl@curcap{\csname qrcwl@cap@\the\qrcwl@vcount @#2\endcsname}%
\ifnum\qrcwl@curcap<#1\relax\else
\edef\qrcwl@version{\the\qrcwl@vcount}%
\def\qrcwl@found{1}%
\fi
\fi
\advance\qrcwl@vcount by 1\relax
\ifnum\qrcwl@vcount<41
\repeat
\ifnum\qrcwl@found=0
\PackageWarning{qrcodewithlogo}{%
Content (#1 bytes) exceeds V40 at level #2; falling back to V40}%
\def\qrcwl@version{40}%
\fi
}
\pgfkeys{
/qrcwl/.is family, /qrcwl/.cd,
width/.store in = \qrcwl@width,
logo/.store in = \qrcwl@logo,
level/.store in = \qrcwl@level,
scale/.store in = \qrcwl@scale,
padding/.store in = \qrcwl@padding,
version/.store in = \qrcwl@version,
width = 3cm, % physical size of the QR code
logo = , % (optional) path to the logo to be added in the center.
level = Q, % error correction level. set to: L, M, Q, H
scale = 0.275, % (target) size of the logo. the actual size is quantized to the QR code grid, which depends on its version.
padding = 0.175, % relative gap; logo = backdrop / (1 + padding)
version = 0, % used for sizing the logo; does not affect the version of the actual QR code (version = how many pixels the QR code has). Set to 0 for best-effort version detection, manually set this to the correct version in case that fails.
}
\newlength{\qrcwl@qrlen}
\newlength{\qrcwl@logolen}
\newcommand{\qrcodeWithLogo}[2][]{%
\begingroup
\pgfkeys{/qrcwl/.cd, #1}%
\ifnum\qrcwl@version=0\relax
\StrLen{#2}[\qrcwl@bytes]%
\qrcwl@pickversion{\qrcwl@bytes}{\qrcwl@level}%
\fi
\setlength{\qrcwl@qrlen}{\qrcwl@width}%
\begin{tikzpicture}
\node[inner sep=0] (qr)
{\qrcode[height=\qrcwl@qrlen,
level=\qrcwl@level,
version=\qrcwl@version]{#2}};
\ifx\qrcwl@logo\@empty\else
\pgfmathtruncatemacro{\qrcwl@N}{4*\qrcwl@version + 17}%
% k = smallest odd integer >= (1 + padding) * scale * N
\pgfmathtruncatemacro{\qrcwl@kceil}{%
ceil((1 + \qrcwl@padding) * \qrcwl@scale * \qrcwl@N)}%
\pgfmathtruncatemacro{\qrcwl@k}{%
\qrcwl@kceil + mod(\qrcwl@kceil + \qrcwl@N, 2)}%
% Backdrop corner offset with 0.001 bleed outward.
\pgfmathsetmacro{\qrcwl@off}{%
(\qrcwl@N - \qrcwl@k) / (2*\qrcwl@N) - 0.001}%
% Logo scaled to fit the quantized crop, with relative padding.
\pgfmathsetmacro{\qrcwl@logofrac}{%
\qrcwl@k / (\qrcwl@N * (1 + \qrcwl@padding))}%
\setlength{\qrcwl@logolen}{\qrcwl@logofrac\qrcwl@qrlen}%
\fill[white]
($(qr.south west)!\qrcwl@off!(qr.north east)$)
rectangle
($(qr.north east)!\qrcwl@off!(qr.south west)$);
\node at (qr.center)
{\includegraphics[width=\qrcwl@logolen,
height=\qrcwl@logolen,
keepaspectratio]{\qrcwl@logo}};
\fi
\end{tikzpicture}%
\endgroup
}
\makeatother
\endinput
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment