% \iffalse meta-comment % % File: pxpic.dtx Copyright (C) 2021-2023 Jonathan P. Spratte % % This work may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this license or % (at your option) any later version. The latest version of this license is in % the file: % % http://www.latex-project.org/lppl.txt % % ------------------------------------------------------------------------------ % %<*driver>^^A>>= \def\nameofplainTeX{plain} \ifx\fmtname\nameofplainTeX\else \expandafter\begingroup \fi \input l3docstrip.tex \askforoverwritefalse \preamble -------------------------------------------------------------- pxpic -- draw pixel pictures E-mail: jspratte@yahoo.de Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt -------------------------------------------------------------- Copyright (C) 2021-2023 Jonathan P. Spratte This work may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this license or (at your option) any later version. The latest version of this license is in the file: http://www.latex-project.org/lppl.txt This work is "maintained" (as per LPPL maintenance status) by Jonathan P. Spratte. This work consists of the file pxpic.dtx and the derived files pxpic.pdf pxpic.sty \endpreamble % stop docstrip adding \endinput \postamble \endpostamble \generate{\file{pxpic.sty}{\from{pxpic.dtx}{pkg}}} \ifx\fmtname\nameofplainTeX \expandafter\endbatchfile \else \expandafter\endgroup \fi % \ProvidesFile{pxpic.dtx}[2023-08-16 v1.5 draw pixel pictures] \PassOptionsToPackage{full}{textcomp} \documentclass{l3doc} \RequirePackage[oldstylenums,nott]{kpfonts} \usepackage{pxpic} \usepackage{hologo} \input{glyphtounicode} \pdfgentounicode=1 \RequirePackage{listings} \RequirePackage{booktabs} \RequirePackage{array} \RequirePackage{collcell} \RequirePackage{xcolor} \RequirePackage{caption} \RequirePackage{microtype} \RequirePackage{accsupp} \RequirePackage{enumitem} \lstset { ,flexiblecolumns=false ,basewidth=.53em ,gobble=2 ,basicstyle=\fontfamily{txtt}\selectfont ,morekeywords=^^A {^^A \pxpic,\pxpicsetup,\pxpicnewmode,\pxpicsetmode,\pxpicnewcolorlist, \pxpicsetcolorlist,\pxpicaddcolorlist,\pxpicforget,\px,\pxskip,\pxpicHT, \pxpicWD,\pxpiclogo } ,morecomment=[l]\% ,commentstyle=\color[gray]{0.4} ,literate={\{}{{\CodeSymbol\{}}{1} {\}}{{\CodeSymbol\}}}{1} ^^A,literate=*{}{\key}{4}{}{\set}{4} } \newcommand*\CodeSymbol[1]{\textbf{#1}} \RequirePackage{randtext} \let\metaORIG\meta \protected\def\meta #1{\texttt{\metaORIG{#1}}} \newcommand*\CS{\cs[no-index]} \renewcommand*\thefootnote{\fnsymbol{footnote}} \definecolor{pxpicred}{HTML}{9F393D} \colorlet{pxpicgrey}{black!75} \makeatletter \newcommand*\pxpicname {^^A \texorpdfstring {^^A \mbox {^^A \BeginAccSupp{ActualText=pxpic}^^A \href{https://github.com/Skillmon/ltx_pxpic}{\pxpiclogo}^^A \EndAccSupp{}^^A }^^A } {pxpic}^^A } \definecolor{expkvred}{HTML}{9F393D} \colorlet{expkvgrey}{black!75} \newcommand*\expkv {^^A \texorpdfstring {^^A \mbox {^^A \BeginAccSupp{ActualText=expkv}^^A \href{https://github.com/Skillmon/tex_expkv} {^^A \rmfamily \bfseries {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A \lower.493ex \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A \kern-.18em{\color{expkvred}v}^^A }^^A \EndAccSupp{}^^A }^^A } {expkv}^^A } \hypersetup{linkcolor=red!80!black,urlcolor=purple!80!black} \DoNotIndex{\advance} \DoNotIndex{\baselineskip,\begingroup,\bgroup,\box} \DoNotIndex{\csname} \DoNotIndex{\def,\detokenize,\dimexpr} \DoNotIndex{\edef,\egroup,\ekvdef,\ekvdefNoVal,\ekvifdefinedNoVal,\ekvletkv} \DoNotIndex{\ekvparse,\ekvsetdef,\ekvcompile,\ekvmorekv} \DoNotIndex{\endcsname,\endgroup,\expandafter} \DoNotIndex{\hbox,\hskip,\ht} \DoNotIndex{\iffalse,\fi} \DoNotIndex{\kern} \DoNotIndex{\leavevmode,\let,\long,\lower} \DoNotIndex{\newcommand,\newdimen} \DoNotIndex{\PackageError,\protected,\ProvidesPackage} \DoNotIndex{\relax,\RequirePackage} \DoNotIndex{\setbox} \DoNotIndex{\@declaredcolor,\@empty,\@firstofone,\@gobble,\@ifdefinable} \DoNotIndex{\@ifnextchar,\@ifundefined,\@undeclaredcolor} \DoNotIndex{\ekv@ifempty,\ekv@name,\p@,\z@} \DoNotIndex{\unexpanded} \DoNotIndex{\vbox,\vrule,\vtop} \@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}} \makeatother \newenvironment{options}[1][] {% \begin{description} [ style=nextline ,font=\normalfont\ttfamily ,labelindent=-.5\marginparwidth ,labelwidth=\dimexpr.5\marginparwidth-5pt\relax ,labelsep*=5pt ,leftmargin=! ,#1 ]% \renewenvironment{options}[1][] {% \begin{description} [ style=nextline ,font=\normalfont\ttfamily ,labelwidth=\dimexpr.25\marginparwidth-5pt\relax ,labelsep*=5pt ,leftmargin=! ,#1 ]% } {\end{description}}% } {\end{description}} ^^A the following pixelart logo is taken from that package's dtx. \newcommand*\pixelart {^^A \leavevmode \pxpic[mode=px,colours={M=black},skip=.,size=.15ex] { {MMMMMM...MM...................MMM.....M...............M} {.MM..MM..MM....................MM....MMM.............MM} {.MM..MM........................MM...MM.MM............MM} {.MM..MM.MMM..MM....MM..MMMMM...MM..MM...MM.MM.MMM..MMMMMM} {.MMMMM...MM...MM..MM..MM...MM..MM..MM...MM..MMM.MM...MM} {.MM......MM....MMMM...MMMMMMM..MM..MMMMMMM..MM..MM...MM} {.MM......MM.....MM....MM.......MM..MM...MM..MM.......MM} {.MM......MM....MMMM...MM.......MM..MM...MM..MM.......MM} {.MM......MM...MM..MM..MM...MM..MM..MM...MM..MM.......MM.MM} {MMMM....MMMM.MM....MM..MMMMM..MMMM.MM...MM.MMMM.......MMM} }^^A } \ExplSyntaxOn ^^A contains code from https://tex.stackexchange.com/a/25753/117050 \NewDocumentCommand \codeexample { O{\footnotesize} D(){\leavevmode} +v } { \begin{minipage}[c]{.5\linewidth} #1 \newlinechar=\endlinechar \exp_args:Nx \scantokens { \string\begin{lstlisting} #3 \string\end{lstlisting} } \end{minipage} \begin{minipage}[c]{.45\linewidth} #2 \newlinechar=\endlinechar \exp_args:Nx \scantokens {#3} \end{minipage} \par } \ExplSyntaxOff \begin{document} \title {^^A \texorpdfstring {^^A \Huge \mbox {^^A \BeginAccSupp{ActualText=pxpic}^^A \href{https://github.com/Skillmon/ltx_pxpic}{\pxpiclogo}^^A \EndAccSupp{}^^A }^^A \\[\medskipamount] \Large draw pixel pictures^^A }{pxpic - draw pixel pictures}^^A } \date{2023-08-16 v1.5} \author{Jonathan P. Spratte\thanks{\protect\randomize{jspratte@yahoo.de}}} \DocInput{pxpic.dtx} \end{document} %^^A=<< % \fi % % \maketitle % \renewcommand*\thefootnote{\arabic{footnote}} % % \begin{abstract} % \noindent\parfillskip=0pt % With \pxpicname\ you draw pictures pixel by pixel. It was inspired by a % \href{https://tex.stackexchange.com/a/63759/117050} % {lovely post by Paulo Cereda}, % among other things (most notably a beautiful duck) showcasing the use of % characters from the Mario video games by Nintendo in \LaTeX. % \end{abstract} % % \tableofcontents % % \begin{documentation}^^A>>= % % \section{Documentation} % % \subsection{Drawing pictures} % % \pxpicname\ supports different input modes, all of them have the same basic % parsing behaviour. A \meta{pixel list} contains the pixel colours. The image % is built line wise from top left to bottom right. % There are two different syntaxes how a single row is given (dependent on the % setting of the |lines|-key, see \autoref{sec:options}): % \begin{itemize} % \item % By default each row of pixels should be a single \TeX\ argument (so either % just one token, or a group delimited by |{}|). (This is the behaviour for % |lines=group|) % \item % Alternatively each row of pixels should be right delimited by a space (and % since a newline is turned into a space in \TeX\ with default settings, a % newline is also possible). (This is the behaviour for |lines=space| and % |lines=csv|) % \end{itemize} % Inside each line there are also two different parsing modes: % \begin{itemize} % \item % By default within each line each pixel in turn should be a single \TeX\ % argument (so either just one token, or a group delimited by |{}|). (This % is the behaviour for |lines=group| and |lines=space|) % \item % Each pixel except the last one is separated from the next pixel by a % comma, no space trimming is applied. (This is the behaviour of % |lines=csv|) % \end{itemize} % % The different modes that interpret a single pixel's input are explained in % \autoref{sec:modes}. The only disallowed token in the \meta{pixel list} is the % control sequence \CS{pxpic@end} (plus the usual restrictions of \TeX\ so no % unbalanced braces, no macros defined as \CS{outer}). % % There is a small caveat however: \pxpicname\ draws each pixel individually, % and there is really no space between them, however some \textsc{pdf} viewers % fail to display such adjacent lines correctly and leave small gaps (basically % the same issue which packages like \pkg{colortbl} suffer from as well). In % print this shouldn't be an issue, but some rasterisation algorithms employed % by viewers and conversion tools have this deficit. % % Another thing I should mention: The pictures you can draw with \pxpicname\ % can't be arbitrary large. Due to the design decision of the output as a single % \CS{hbox} and the way the output routine works, pictures are limited by \TeX's % memory size to roughly $440\times 440$ pixels in \hologo{pdfLaTeX} with the % default settings in \TeX\ Live. The size is unlimited in \hologo{LuaLaTeX}, % due to dynamic memory allocation. In \hologo{XeLaTeX} the size should be even % smaller than in \hologo{pdfLaTeX}. % % \begin{function}{\pxpic} % \begin{syntax} % \cs{pxpic}\oarg{options}\marg{pixel list} % \end{syntax} % \meta{options} might be any options as listed in \autoref{sec:options}, and % \meta{pixel list} is a list of pixels as described above. \cs{pxpic} parses % the \meta{pixel list} and draws the corresponding picture. The result is % contained in an \CS{hbox} and can be used wherever \TeX\ expects an % \CS{hbox}. As a result, when you're in vertical mode a \cs{pxpic} will form % a text line, to prevent this you can use \CS{leavevmode} before it. The % \cs{pxpic} will be bottom aligned by default (see the options |b|, |c|, and % |t|), you can further tweak this using \CS{raisebox} (or, if you want, % \TeX's \CS{raise} and \CS{lower} primitives). % % If you used the |file| option the mandatory argument should be a file name % containing a \meta{pixel list} instead of the \meta{pixel list} itself. % \end{function} % % \subsubsection{Examples} % % Since the above explanation of the \meta{pixel list} syntax might've been a % bit cryptic, and a good documentation should contain examples (this doesn't % claim this documentation is \emph{good}), well, here are some examples (you % might need to take a look at \autoref{sec:options} and \autoref{sec:modes} to % fully understand the examples). Examples in this section will use the % following \CS{pxpicsetup}: % % \begingroup % \footnotesize % \begin{lstlisting} % \pxpicsetup % { % mode = px % ,colours = {k=black, r=[HTML]{9F393D}, g=green!75!black, b=[rgb]{0,0,1}} % ,skip = . % ,size = 10pt % } % \end{lstlisting} % \endgroup % % \begingroup % \pxpicsetup % { % mode = px % ,colours = {k=black, r=[HTML]{9F393D}, g=green!75!black, b=[rgb]{0,0,1}} % ,skip = . % ,size = 10pt % } % % We can draw a small cross rather easily:\par\nobreak % \noindent % \codeexample$ % \pxpic % { % {.k} % {kkk} % {.k} % } % $ % % A small multicoloured grid:\par\nobreak % \noindent % \codeexample$ % \pxpic % { % {brgk} % {kbrg} % {gkbr} % {rgkb} % } % $ % % A heart (shamelessly copied example from \pixelart):\par\nobreak % \noindent % \codeexample$ % \pxpic[lines=space] % { % ..rr.rr % .rrrrrrr % rrrrrrrrr % rrrrrrrrr % rrrrrrrrr % .rrrrrrr % ..rrrrr % ...rrr % ....r % } % $ % % A parrot (shamelessly copied example from \pkg{PixelArtTikz}):\par\nobreak % \begingroup % \footnotesize % \begin{lstlisting}[belowskip=0pt] % \begin{filecontents*}{\jobname-parrot.csv} % .,.,.,.,.,.,k,k,k,k,.,.,.,.,.,. % .,.,.,.,k,k,r,r,r,r,k,k,.,.,.,. % .,.,.,k,r,r,r,r,r,r,r,r,k,.,.,. % .,.,k,r,r,r,r,r,r,r,r,r,r,k,.,. % .,.,k,r,r,r,r,r,r,r,r,r,r,k,.,. % .,k,r,.,.,r,r,r,r,r,r,.,.,r,k,. % .,k,.,.,.,.,k,k,k,k,.,.,.,.,k,. % .,k,.,k,.,.,k,k,k,k,.,k,.,.,k,. % .,k,r,.,.,.,k,k,k,k,.,.,.,r,k,. % .,.,k,r,r,.,k,k,k,k,.,r,r,k,.,. % .,.,k,r,r,r,k,k,k,k,r,r,r,k,.,. % .,.,.,k,r,r,r,k,k,r,r,r,k,.,.,. % .,.,k,3,r,r,r,r,r,r,r,r,3,k,.,. % .,k,b,3,r,r,r,r,r,r,r,r,3,b,k,. % .,k,b,b,r,r,r,r,r,r,r,r,b,b,k,. % .,k,b,b,r,r,r,r,r,r,r,r,b,b,k,. % .,k,b,k,r,r,r,k,k,r,r,r,k,b,k,. % 2,2,k,2,k,k,k,2,2,k,k,k,2,k,2,2 % 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 % 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 % .,.,.,.,.,k,r,r,r,r,k,.,.,.,.,. % .,.,.,.,.,.,k,r,r,k,.,.,.,.,.,. % .,.,.,.,.,.,.,k,k,.,.,.,.,.,.,. % \end{filecontents*} % \end{lstlisting} % \endgroup % \noindent % \codeexample$ % \pxpic % [ % lines=csv, % colours={2=brown,3=yellow}, % file, % size=3pt % ] % {\jobname-parrot.csv} % $ % % Using |mode=rgb| to draw a short coloured line:\par\nobreak % \noindent % \codeexample$ % \pxpic[mode=rgb]{{{1,0,1}{1,1,0}{0,1,1}}} % $ % % A multicoloured grid using skips and |mode=cmy|:\par\nobreak % \noindent % \codeexample$ % \pxpic[mode=cmy] % { % {{1,0,1} {1,1,0} {0,1,1} {} } % {{} {1,0,1} {1,1,0} {0,1,1}} % {{0,1,1} {} {1,0,1} {1,1,0}} % {{1,1,0} {0,1,1} {} {1,0,1}} % } % $ % % Showing the difference between a skipped and a white pixel:\par\nobreak % \noindent % \codeexample()$ % \pxpicsetup{colours = {w=white}} % \colorbox{gray}{\pxpic{{bbb}{b.b}{bbb}}} % \colorbox{gray}{\pxpic{{bbb}{bwb}{bbb}}} % $ % % \enlargethispage{1.1\baselineskip} % A biggish example: Tux.\footnote{Source: % \url{https://www.reddit.com/r/linux/comments/hwpm9j/tux_pixel_art_v10/}} I % put two rows of pixels per code line to reduce the size a bit and the code is % displayed tinily.\par\nobreak % \noindent % \codeexample[\tiny]$ % \pxpic % [ % size = 2.5pt % ,colours = {:=orange, % '=black!10, % g=black!75, % O=orange!80!black} % ] % { % {...........gggg} {.........gggkkggg} % {........ggkkkkkkkg} {........gkkkkkkkkg} % {........kkkkkkkkkk} {.......gkk.kkkk.kkk} % {.......gk.k.kk.k.kk} {.......gk.k.kk.k.kk} % {.......gkkkkkkkkkkk} {.......gkkk::::kkkk} % {.......gk::::::::kk} {.......gk.:kkkk:kkk} % {......gkk..::::'kkkk} {......gkk....'''kkkk} % {......gkk....''''kkk} {.....gkk.....''''kkkk} % {.....gk.......''''kkk} {....gkk........'''kkkk} % {....gkk........'''kkkk} {....gk..........''kkkk} % {...gkkg.........'''kkkk} {...gkkkk........'''kkkk} % {..OOOOkkk.......'''kOOOO} {..O::::kkk......'''O:::O} % {.O::::::kk.....'''::::::O} {.O::::::kkk...''kk::::::O} % {O:::::::kkk...'kkk:::::::O} {O:::::::kkk...'kkk:::::::O} % {.O:::::::kkkkkkkk:::::::O} {..OO:::::kkkkkkkk:::::OO} % {....OO::O.kkkkkk.O::OO} {......OOO........OOO} % } % $ % % Just for Paulo, a duck. Also, showing that the colour definitions in |mode=px| % can be arbitrary tokens or multiple letters:\par\nobreak % \noindent % \codeexample[\tiny]$ % \pxpic[colours = {oo=orange, % \ylw=yellow, % \blk=black}, % skip = \skp] % { % {\skp\skp\skp\ylw\ylw\ylw\ylw} % {\skp\skp\ylw\ylw\ylw\ylw\ylw\ylw} % {\skp\skp{oo}\ylw\blk\ylw\ylw\ylw} % {{oo}{oo}{oo}\ylw\ylw\ylw\ylw\ylw} % {\skp{oo}{oo}{oo}\ylw\ylw\ylw\skp\skp\skp\skp\skp\ylw} % {\skp\skp\skp\ylw\ylw\ylw\ylw\ylw\ylw\ylw\skp\ylw\ylw} % {\skp\skp\ylw\ylw\ylw\ylw\ylw\ylw\ylw\ylw\ylw\ylw\ylw} % {\skp\ylw\ylw\ylw\ylw\ylw\ylw\ylw\ylw\skp\ylw\ylw} % {\skp\ylw\ylw\skp\ylw\ylw\ylw\ylw\skp\ylw\ylw\ylw} % {\skp\ylw\ylw\ylw\skp\skp\skp\skp\ylw\ylw\ylw} % {\skp\skp\ylw\ylw\ylw\ylw\ylw\ylw\ylw\ylw} % {\skp\skp\skp\skp\ylw\ylw\ylw\ylw\ylw} % } % $ % % Another example might be the definition of \CS{pxpiclogo} in % \autoref{sec:implementation:pxpiclogo}. % % Who still needs \env{picture}-mode or complicated packages like % \pkg{pstricks} or Ti\emph{k}Z with such pretty pictures? % % \endgroup % % \subsection{Setting options}\label{sec:options} % % To control its behaviour \pxpicname\ uses a key=value interface powered by % \expkv. Options can be set either in the optional argument of % \CS{pxpic} or with % % \begin{function}{\pxpicsetup} % \begin{syntax} % \cs{pxpicsetup}\marg{options} % \end{syntax} % Sets the \meta{options} locally to the current \TeX\ group. % \end{function} % % \medskip\noindent % Package options are not supported. % % \bigskip % The available options are % % \begin{options} % \item[colors=\meta{colour list}] % Define pixel colours for |mode=px|, see \autoref{sec:colours} for a % description of the value's syntax. No pixel definitions are made by the % package. % \item[colours] % \emph{see \texttt{colors}.} % \item[color-list=\meta{choice}] % loads a previously through \CS{pxpicnewcolorlist} defined colour list. No % colour lists are defined by the package. % \item[colour-list] % \emph{see \texttt{color-list}.} % \item[exp] % \emph{see \texttt{expansion}} % \item[expansion=\meta{choice}] % This is a choice to control the expansion of the \meta{pixel list}. The % choices are: % \begin{options} % \item[full] % the \meta{pixel list} is subject to one full expansion via % |\expanded|. % \item[none] % no expansion takes place, the \meta{pixel list} is used as it is. % \end{options} % The initial value is |none|, the default used if you don't provide a value % is |full|. % \item[file=\meta{bool}] % If you pass in |true| the mandatory argument of \CS{pxpic} becomes a file % name which's contents are used as a \meta{pixel list}. Using |false| % results in the default behaviour of a \meta{pixel list}. If you omit the % value the same as |true| is used. % \item[gap-hack=\meta{dimen}] % To fix the issues with visible gaps in \textsc{pdf} viewers you can % introduce some negative kerns to make the pixels overlap (lines overlap to % the top, pixels to the left). This option expects a dimension as its % value. A positive value will (maybe) close the gaps, a negative value will % introduce real gaps. In any case the outermost pixels' borders still % coincide with the borders of the surrounding \CS{hbox}. Take a look at my % babbling about this issue in \autoref{sec:misc}. % \item[ht=\meta{dimen}] % Set the height of the pixels. % \item[lines=\meta{choice}] % How the individual lines of a \meta{pixel list} are given. The choices % are: % \begin{options} % \item[group] % The default syntax in which each line is a single \TeX\ argument % (group delimited by |{}|). % \item[space] % A different input syntax in which each line should be right-delimited % by a space (or newline as, by default, a newline is the same as a % space in \TeX). % \item[csv] % The same line-wise input as |space|, but in each line each pixel % should be separated from the next with a comma. % \end{options} % \item[mode=\meta{choice}] % Set the used mode, see \autoref{sec:modes} for available modes. Initial % value is |px|. % \item[size=\meta{dimen}] % Set both |ht| and |wd|. Initial value is \the\pxpicHT. % \item[skip=\meta{tokens}] % Define \meta{tokens} to be a skip (an empty space of width |wd|) in % |mode=px|. No skip definitions are made by the package. % \item[wd=\meta{dimen}] % Set the width of the pixels. % \item[b] % Set the bottom of the \CS{pxpic} on the surrounding baseline (vertical % bottom alignment; this is the default). % \item[c] % Set the centre of the \CS{pxpic} on the surrounding baseline (vertical % centre alignment). % \item[t] % Set the top of the \CS{pxpic} on the surrounding baseline (vertical top % alignment). % \end{options} % % \subsubsection{Colour syntax}\label{sec:colours} % % In the value of the |colours| option you'll have to use the following syntax. % Use a comma separated key=value list in which each key corresponds to a new % pixel name for |mode=px|, and each value to the used colour. If the colour % starts with an opening bracket use the complete value as is behind \CS{color}, % else use the whole value as the first mandatory argument to \CS{color} with a % set of braces added. For example to define |r| as the named colour |red|, and % |x| as the colour |#abab0f| (in the \textsc{html} colour model) use: % \begin{lstlisting} % colours = {r=red, x=[HTML]{abab0f}} % \end{lstlisting} % % \subsubsection{Available modes}\label{sec:modes} % % \begin{options} % \item[px] % As already mentioned, \pxpicname\ supports different modes of input. The % easiest to use |mode| is |px|, in which each element of the \meta{pixel % list} has been previously defined as either a coloured pixel (using the % |colour| option) or as a skipped pixel (using the |skip| option, resulting % in a fully transparent pixel). Each element will be \CS{detokenize}d, so % (within \TeX's limitations) the name of a pixel can be arbitrary. This is % the initial mode \pxpicname\ uses. But other options are available as % well. % \item[named] % Another |mode| is |named|, in which each element of the \meta{pixel list} % should be a named colour (or colour expression) known to \pkg{xcolor}. % Each element will be used like so: |{\color{|\meta{element}|}\px}|. An % exception is an element which is empty (|{}|), which will be a skipped % pixel. % \item[rgb, cmy, cmyk, hsb, Hsb, tHsb, gray, RGB, HTML, HSB, Gray, wave] % The modes |rgb|, |cmy|, |cmyk|, |hsb|, |Hsb|, |tHsb|, |gray|, |RGB|, % |HTML|, |HSB|, |Gray|, and |wave| correspond to the different colour % models supported by \pkg{xcolor}. With these modes each element of the % \meta{pixel list} will be the values in these colour models, so they'll be % used like so: |{\color[|\meta{mode}|]{|\meta{element}|}\px}|. An % exception is an element which is empty (|{}|), which will be a skipped % pixel. % \end{options} % % You can define additional modes selectable with the |mode| option using the % macros |\pxpicnewmode| or |\pxpicsetmode|. % % \subsection{Other customisation macros} % % \begin{function}{\pxpicnewmode,\pxpicsetmode} % \begin{syntax} % \cs{pxpicnewmode}\marg{name}\marg{definition} % \end{syntax} % You can define your own modes with \cs{pxpicnewmode}. Inside % \meta{definition} |#1| is the currently parsed item in the \CS{pxpic} % \meta{pixel list}. You can output a pixel using \CS{px}, and skip a pixel % using \CS{pxskip}. The pixel will use the currently active colour (so if you % want to draw a red pixel you could use |{\color{red}\px}|). % \cs{pxpicnewmode} will throw an error if you try to define a mode which % already exists, \cs{pxpicsetmode} has no checks on the name. % \end{function} % % \begin{function}{\pxpicnewcolorlist,\pxpicsetcolorlist,\pxpicaddcolorlist} % \begin{syntax} % \cs{pxpicnewcolorlist}\marg{name}\marg{colour list} % \end{syntax} % This defines a colour list (to be used with the |colour-list| option). The % syntax of \meta{colour list} is the same as for the |colours| option. The % pixels aren't directly defined, but only by the use of % |colour-list=|\meta{name}. So % \begin{lstlisting} % \pxpicnewcolorlist{example}{r=red,b=blue,g=green,k=black,w=white} % \pxpicsetup{colour-list=example} % \end{lstlisting} % would have the same effect as % \begin{lstlisting} % \pxpicsetup{colours={r=red,b=blue,g=green,k=black,w=white}} % \end{lstlisting} % but a |colour-list| is more efficient if used multiple times. The |new| % variant will only throw an error if the colour list \meta{name} is already % defined. The |set| variant has no such tests, and the |add| variant will add % additional colours to an existing list. % \end{function} % % \begin{function}{\pxpicforget} % \begin{syntax} % \cs{pxpicforget}\marg{px} % \end{syntax} % Undefines the \meta{px} definition for use in |mode=px| (or skip symbol) % added with the |colours| (or |skip|) option. % \end{function} % % \subsection{Other macros} % % \begin{function}{\px,\pxskip} % Inside of a \CS{pxpic} the macro \cs{px} draws a pixel (of the currently % active colour), and \cs{pxskip} leaves out a pixel (so this one pixel is % fully transparent). Use this in the \meta{definition} of a mode in % \CS{pxpicnewmode}. % \end{function} % % \begin{variable}{\pxpicHT,\pxpicWD} % These two are |dimen| registers storing the height and width of the pixels. % \end{variable} % % \begin{function}{\pxpiclogo} % \begin{syntax} % \cs{pxpiclogo}\oarg{size} % \end{syntax} % This draws the logo of \pxpicname. The \meta{size} controls the pixel size. % \end{function} % % \subsection{Miscellaneous}\label{sec:misc} % % If you find bugs or have suggestions I'll be glad to hear about it, you can % either open a ticket on Github (\url{https://github.com/Skillmon/ltx_pxpic}) % or email me (see the first page). % % A similar package is \pixelart, which, at the time \pxpicname\ was created, % was described as a ``working draft'' by its author. \pxpicname\ wasn't % intended as a direct competitor (I already started coding \pxpicname\ when I % learned about \pixelart's existence), but I took inspiration from the ``Bugs, % Ideas, Undefined behaviours'' section of \pixelart's documentation for the % syntax of |mode=px|. Also the |lines=space| option is a copy of the syntax the % new stable version of \pixelart\ is using (so images created with it could be % processed with \pkg{pxpic} and vice versa). A third package that allows % drawing pixel art is \pkg{PixelArtTikz}, that uses a csv-syntax for its pixel % definition lists (you may have luck and the mode |lines=csv| works for lists % defined for \pkg{PixelArtTikz}). % % \paragraph{Regarding the gap issue:} % The pixels are output touching each other with no real gap, however some % \textsc{pdf} viewers and tools will display such a gap. To make things even % worse, the effect depends on the viewers current magnification. % \pxpicname\ has the |gap-hack| option to provide some crude hack that might % fix the issue, at the cost that the pixels on the far right and bottom are % bigger than they were specified to be. Also pixels next to skipped pixels have % a different size (skipped pixels don't cover pixels to their left or top as % they are transparent). You'll want to find a good trade-off value if you want % to use |gap-hack|, that mitigates the effect but isn't too big (to make the % errors less obvious). You can play with the value and decide for yourself % what's the lesser evil. Or you do like me, don't use |gap-hack| and blame the % viewers. Here are examples in which you can compare (the |gap-hack| is chosen % way too big in the first example and skips are used close to white pixels on % purpose, but it illustrates the effects):\par\nobreak % \begingroup % \footnotesize % \def\mypxpic#1% % {^^A % \pxpic % [ % gap-hack=#1 % ,colours={k=black,g=green,w=white} % ,skip=. % ,size=10pt % ,t % ] % { % {kkkkk} % {kgggk} % {kwg.k} % {kg.gk} % {kgwk} % {kkkw} % }^^A % }^^A % \noindent % \begin{minipage}[c]{.45\linewidth}^^A % \begin{lstlisting} % \pxpicsetup % { % colours={k=black,g=green,w=white} % ,skip=. % ,size=10pt % ,t % } % \pxpic % { % {kkkkk} % {kgggk} % {kwg.k} % {kg.gk} % {kgwk} % {kkkw} % } % \end{lstlisting} % \end{minipage} % \fontfamily{txtt}\selectfont % \begin{tabular}[c]{ccc} % \texttt{gap-hack=2pt} & \texttt{gap-hack=0pt} & \texttt{gap-hack=.2pt} \\ % \mypxpic{2pt} & \mypxpic{0pt} & \mypxpic{.2pt} \\ % \end{tabular} % \endgroup % % \paragraph{Exploiting the \texttt{gap-hack} to draw a grid:} % It is possible to exploit the |gap-hack| option to draw a grid around your % pixels (at least for a rectangular picture). For this we simply set a coloured % background and use a negative |gap-hack| value:\par % \noindent % \codeexample$ % \newcommand\gridpxpic[3][] % {{\setlength\fboxsep{#2}\colorbox{black}{\pxpic[gap-hack=-\fboxsep,#1]{#3}}}} % \gridpxpic % [colours={g=green,w=white},size=8pt] % {1pt} % {{gwgw}{wgwg}}% % $ % % % \end{documentation}^^A=<< % % \begin{implementation}^^A>>= % % \gobbledocstriptag %<*pkg> % % \clearpage % % \section{Implementation}^^A>>= % % Report who we are % \begin{macrocode} \ProvidesPackage{pxpic}[2023-08-16 v1.5 draw pixel pictures] % \end{macrocode} % and load dependencies % \begin{macrocode} \RequirePackage{xcolor} \RequirePackage{expkv} % \end{macrocode} % \begin{variable}{\pxpicHT,\pxpicWD} % These two variables store the height and width of a pixel. % \begin{macrocode} \@ifdefinable\pxpicHT{\newdimen\pxpicHT} \@ifdefinable\pxpicWD{\newdimen\pxpicWD} \pxpicHT=\p@ \pxpicWD=\pxpicHT % \end{macrocode} % \end{variable} % \begin{variable}[internal]{\pxpic@kern} % To fix the visible gaps in some \textsc{pdf} viewers if the user chooses so % with the |gap-hack| option we introduce some \CS{kern}s of the length % stored in this register. % \begin{macrocode} \@ifdefinable\pxpic@kern{\newdimen\pxpic@kern} \pxpic@kern=\z@ % \end{macrocode} % \end{variable} % \begin{macro}[internal]{\pxpic@@kern} % For some simplification of the output box (removing unnecessary kerns) we % don't directly use \CS{kern} but one step of indirection. This macro is % locally turned into \CS{@gobble} if \CS{pxpic@kern} is equal to \CS{z@}. % \begin{macrocode} \def\pxpic@@kern#1{\kern#1\pxpic@kern} % \end{macrocode} % \end{macro} % \begin{macro}[internal]{\pxpic@inner@box,\pxpic@after@inner@box} % To get different vertical alignments we nest one of |\vbox|, |\vtop|, and a % lowered |\vbox| inside the outer |\hbox|. The macro \cs{pxpic@inner@box} % will store this information, and since lowering can only be done after the % box was set (the alternative would be |\vcenter|, which ends up on a % different height), we need to be able to put the box output with |\lower| % after the box was collected, which is why we need % \cs{pxpic@after@inner@box}. We default to bottom alignment. % \begin{macrocode} \@ifdefinable\pxpic@inner@box{\let\pxpic@inner@box\vbox} \@ifdefinable\pxpic@after@inner@box{\let\pxpic@after@inner@box\@empty} % \end{macrocode} % \end{macro} % % % \subsection{Options} % % We define the options using \expkv\ directly (no fancy options are involved % and these are just a few anyway). % % The first few options are straight forward. We use \expkv's name space to % actually store the |skip| and |px| definitions, hence we use % \CS{ekvdefNoVal} in the code of |skip|. % % \begin{macrocode} \protected\ekvdef{pxpic}{size} {\pxpicHT=\dimexpr#1\relax\pxpicWD=\pxpicHT} \protected\ekvdef{pxpic}{ht}{\pxpicHT=\dimexpr#1\relax} \protected\ekvdef{pxpic}{wd}{\pxpicWD=\dimexpr#1\relax} \protected\ekvdef{pxpic}{gap-hack}{\pxpic@kern=\dimexpr#1\relax} \protected\ekvdef{pxpic}{skip}{\ekvdefNoVal{pxpic@px}{#1}{\pxskip}} % \end{macrocode} % The |colours| option is parsed using \CS{ekvparse} and \CS{pxpic@setcolor}. % \begin{macrocode} \protected\ekvdef{pxpic}{colors}{\ekvparse\pxpic@err@noval\pxpic@setcolor{#1}} \ekvletkv{pxpic}{colours}{pxpic}{colors} % \end{macrocode} % And the |mode| just checks whether the |mode| macro is defined and lets the % auxiliary macro \CS{pxpic@parse@px} to the defined |mode|. % \begin{macrocode} \protected\ekvdef{pxpic}{mode} {% \@ifundefined{pxpic@parse@px@#1}% {\pxpic@err@unknown@mode{#1}}% {% \expandafter\let\expandafter\pxpic@parse@px \csname pxpic@parse@px@#1\endcsname }% } % \end{macrocode} % A similar check is done for the |colour-list| option. % \begin{macrocode} \protected\ekvdef{pxpic}{color-list} {% \@ifundefined{pxpic@colorlist@#1}% {\pxpic@err@unknown@colorlist{#1}}% {\csname pxpic@colorlist@#1\endcsname}% } \ekvletkv{pxpic}{colour-list}{pxpic}{color-list} % \end{macrocode} % The alignment options set the internals |\pxpic@inner@box| and % |\pxpic@after@inner@box|. % \begin{macrocode} \protected\ekvdefNoVal{pxpic}{b} {% \let\pxpic@inner@box\vbox \let\pxpic@after@inner@box\@empty } \protected\ekvdefNoVal{pxpic}{c} {% \def\pxpic@inner@box{\setbox0=\vbox}% \def\pxpic@after@inner@box{\lower.5\ht0\box0}% } \protected\ekvdefNoVal{pxpic}{t} {% \let\pxpic@inner@box\vtop \let\pxpic@after@inner@box\@empty } % \end{macrocode} % % The expansion related option will set an internal. It's yet another option % which will need to check for a defined internal, as it's a choice of |none| or % |full|. This is deliberately not defined |\protected| to allow expansion as % far as possible. % \begin{macrocode} \ekvdef{pxpic}{expansion} {% \@ifundefined{pxpic@expansion@#1}% {\pxpic@err@unknown@expansion{#1}}% {\csname pxpic@expansion@#1\endcsname}% } \ekvdefNoVal{pxpic}{expansion}{\pxpic@expansion@full} \ekvletkv {pxpic}{exp}{pxpic}{expansion} \ekvletkvNoVal{pxpic}{exp}{pxpic}{expansion} % \end{macrocode} % And we define the choices and the initial behaviour: % \begin{macrocode} \protected\def\pxpic@expansion@none{\let\pxpic@expansion\@firstofone} \protected\def\pxpic@expansion@full{\let\pxpic@expansion\expanded} \pxpic@expansion@none % \end{macrocode} % % Another key is the choice how lines are delimited, either as a single % group/argument or by spaces (or newlines). The code defining the choices' % behaviour is a bit down the road, here we only initialise the keys. % \begin{macrocode} \ekvdef{pxpic}{lines} {% \@ifundefined{pxpic@@parse@#1}% {\pxpic@err@unknown@lines{#1}}% {\csname pxpic@@parse@#1\endcsname}% } % \end{macrocode} % % We also want to be able to grab the \meta{pixel list} from a file, and we need % a key to define this behaviour. % \begin{macrocode} \ekvdef{pxpic}{file} {% \@ifundefined{pxpic@file@#1}% {\pxpic@err@unknown@file{#1}}% {\csname pxpic@file@#1\endcsname}% } \ekvdefNoVal{pxpic}{file}{\pxpic@file@true} % \end{macrocode} % The macro \CS{pxpic@@file@or@list} will get the argument in two sets of % braces. In the |false| case things are easy, we just directly go over to the % expansion step. In the |true| case we input the file. % \begin{macrocode} \ExplSyntaxOn \protected\def\pxpic@file@true { \def\pxpic@@file@or@list ##1 { \file_get:nnNTF ##1 {} \l_tmpa_tl { \ekv@exparg { \expandafter\pxpic@parse\pxpic@expansion } { \expandafter { \l_tmpa_tl } } } { \pxpic@err@file@not@found ##1 } } } \ExplSyntaxOff \protected\def\pxpic@file@false {\def\pxpic@@file@or@list{\expandafter\pxpic@parse\pxpic@expansion}} \pxpic@file@false % \end{macrocode} % % % \subsection{User macros}\label{sec:implementation:pxpiclogo} % % \begin{macro}{\pxpic} % \begin{macro}[internal]{\pxpic@} % \CS{pxpic} expands directly to an opened \CS{hbox}, the auxiliary % \CS{pxpic@} checks for the optional argument and inserts the rest of the % code. We need to set \CS{baselineskip} to \CS{pxpicHT} so that the pixels % are stacked vertically without gaps. \CS{pxpic@parse} will parse the % \meta{pixel list} until \CS{pxpic@end} is hit. The final \CS{egroup} closes % the \CS{hbox}. The row-wise output is done via a \CS{vbox} in which each % pixel row will be wrapped inside an \CS{hbox}. The \CS{kern} negates a % negative \CS{kern} in \CS{pxpic@parse} so that the first line isn't moved. % \begin{macrocode} \@ifdefinable\pxpic{\protected\def\pxpic{\hbox\bgroup\pxpic@}} \newcommand\pxpic@[2][] {% \pxpicsetup{#1}% \pxpic@inner@box {% \let\px\pxpic@px \let\pxskip\pxpic@skip \ifdim\pxpic@kern=\z@ \let\pxpic@@kern\@gobble \else \advance\pxpicHT\pxpic@kern \advance\pxpicWD\pxpic@kern \fi \baselineskip=\pxpicHT % \end{macrocode} % This here is the only spot we use \CS{kern} directly instead of the % wrapping \CS{pxpic@@kern}. Even if this is effectively a |\kern0pt| the % vertical alignment in top-aligned boxes is different this way (aligning at % the top of the top row instead of the bottom). % \begin{macrocode} \kern\pxpic@kern \pxpic@@file@or@list{{#2}}% }% \pxpic@after@inner@box \egroup } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\pxpicsetup} % Just directly defined to call \expkv's parser for the \pxpicname\ set. % \begin{macrocode} \ekvsetdef\pxpicsetup{pxpic} % \end{macrocode} % \end{macro} % % \begin{macro}{\pxpiclogo} % The logo is just a biggish pixel picture. The \CS{lower} will move it down a % bit so that it appears correctly aligned on the baseline. Since the logo % should be part of a normal sentence in most usages we put \CS{leavevmode} % before it. Also we make sure that the |mode| and |px| definitions are % correct and the output is bottom aligned. % \begin{macrocode} \ekvcompile\pxpiclogo@settings#1{pxpic} { size=#1,gap-hack=\z@,b,mode=px,colours={o=[HTML]{9F393D},g=black!75},skip=. ,lines=group } \newcommand*\pxpiclogo[1][.13ex] {% \begingroup \leavevmode \pxpiclogo@settings{#1}% \lower3.2\pxpicHT\pxpic { {............................................g} {...........................................gggg} {.oooo.......................gggg...........ggg} {.ooooo...oo......oo...oo....ggggg...gg......g..........g} {.ooooooooooo...ooooo..oooo..ggggggggggg...ggggg...ggggggg} {..ooooo..oooo.ooooooooooo....ggggg..gggg.ggggggg.ggggggggg} {...oooo..oooo....ooooo........gggg..gggg...gggg..gggg.ggg} {...oooo..oooo.....oooo........gggg..gggg...gggg..gggg} {.oooooo..oooo.....ooooo.....gggggg..gggg...gggg..gggg} {oooooooooooo...ooooooooo...gggggggggggg....gggg..ggggggggg} {o.oooooooo....ooooo.oooooo.g.gggggggg......ggggg..ggggggg} {...ooo.o......o.oo...oo.......ggg.g.........gg......ggg} {...ooo........................ggg} {...ooo........................ggg} {....o..........................g} }% \endgroup } % \end{macrocode} % \end{macro} % % \begin{macro}{\pxpicforget} % Straight forward, just let the |px| macro to an undefined macro. % \begin{macrocode} \newcommand\pxpicforget[1] {\expandafter\let\csname\ekv@name{pxpic@px}{#1}N\endcsname\pxpic@undef} % \end{macrocode} % \end{macro} % % \begin{macro}{\pxpicnewmode,\pxpicsetmode} % These are pretty simple as well, the |new| variant will use \CS{newcommand} % which will do the testing for us, the |set| variant uses \CS{def}. % \begin{macrocode} \protected\long\def\pxpicnewmode#1#2% {\expandafter\newcommand\csname pxpic@parse@px@#1\endcsname[1]{#2}} \protected\long\def\pxpicsetmode#1#2% {\long\expandafter\def\csname pxpic@parse@px@#1\endcsname##1{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\pxpicnewcolorlist,\pxpicsetcolorlist,\pxpicaddcolorlist} % \begin{macro}[internal]{\pxpic@setcolorlist,\pxpic@addcolorlist} % The colour list is first parsed with \CS{ekvparse} inside an \CS{edef}. % \CS{ekvparse} will prevent the parsed list from further expanding, leaving % each list element and \CS{pxpic@experr@noval} or % \CS{pxpic@setcolor@colorlist} before it. In a second \CS{edef} these will be % expanded, \CS{pxpic@experr@noval} throwing an error for each element missing % a colour definition, and \CS{pxpic@setcolor@colorlist} testing for an % opening bracket (which we do expandably) and leaving the correct definition % protected against further expansion. The |add| variant uses a temporary % macro for the parsing part and adds the result to the list holding macro. % The second expansion step in |set| and both in |add| are done inside a group % to revert any definition (also those letting tokens to \CS{relax} by % \CS{csname}) made at this point except for the list macro itself. % \begin{macrocode} \protected\def\pxpicnewcolorlist#1% {% \@ifundefined{pxpic@colorlist@#1}% {\pxpicsetcolorlist{#1}}% {\pxpic@err@defined@colorlist{#1}\@gobble}% } \protected\def\pxpicsetcolorlist#1% {\expandafter\pxpic@setcolorlist\csname pxpic@colorlist@#1\endcsname} \protected\long\def\pxpic@setcolorlist#1#2% {% \edef#1{\ekvparse\pxpic@experr@noval\pxpic@setcolor@colorlist{#2}}% \begingroup\edef#1{\endgroup\protected\def\unexpanded{#1}{#1}}% #1% } \protected\def\pxpicaddcolorlist#1% {% \@ifundefined{pxpic@colorlist@#1}% {\pxpic@err@unknown@colorlist{#1}\@gobble}% {\expandafter\pxpic@addcolorlist\csname pxpic@colorlist@#1\endcsname}% } \protected\long\def\pxpic@addcolorlist#1#2% {% \begingroup \edef\pxpic@tmp {\ekvparse\pxpic@experr@noval\pxpic@setcolor@colorlist{#2}}% \edef\pxpic@tmp {% \endgroup \protected\def\unexpanded{#1}{\unexpanded\expandafter{#1}\pxpic@tmp}% }% \pxpic@tmp } % \end{macrocode} % \end{macro} % \end{macro} % % % \subsection{Parser} % % \begin{macro}[internal]{\pxpic@ifend,\pxpic@ifempty,\pxpic@ifbracket} % These are three helper macros. The first just gobbles everything until the % next \CS{pxpic@end}, and we borrow a fast test for an empty argument from % \expkv. The last can be used to check for an opening bracket if used like % |\pxpic@ifbracket|\hskip0pt|\pxpic@end|\hskip0pt|#1.\pxpic@end|\hskip0pt % |[]\pxpic@end|. % \begin{macrocode} \long\def\pxpic@ifend#1\pxpic@end{} \let\pxpic@ifempty\ekv@ifempty \long\def\pxpic@ifbracket#1\pxpic@end[#2]\pxpic@end{\pxpic@ifempty{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\pxpic@openbrace} % For some weirder \TeX\ programming it is sometimes necessary to insert an % unmatched opening brace. This code does exactly that if it's expanded twice. % It is put into a single macro so that one can \CS{expandafter} it easier. % \begin{macrocode} \newcommand*\pxpic@openbrace{\expandafter{\iffalse}\fi} % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % {\pxpic@parse,\pxpic@@parse,\pxpic@parse@aux,\pxpic@done,\pxpic@parseline} % \begin{macro}[internal] % {\pxpic@@parse@group,\pxpic@@parse@space,\pxpic@@parse@csv} % The parsing loop is pretty simple, first check whether we're done, else open % a new \CS{hbox} (which will form a row in the \CS{vbox} placed by % \CS{pxpic@}) in which the inner parsing loop is run. Then call the next % iteration. If we're done just gobble the remainder of the current iteration. % First we introduce our \CS{kern} which might fix the gap issue. Another % \CS{kern} is done at the start of each \CS{hbox} to compensate the % unnecessary \CS{kern} done by the first \CS{pxpic@parseline}. % % This parsing has one step of indirection, the first macro that is called is % \CS{pxpic@parse}, that'll set things up with the end marker for the row % parser \CS{pxpic@@parse}. Both the definition of \CS{pxpic@parse} and % \CS{pxpic@@parse} is dependent on the setting of the |lines| key, hence they % are set up with the two macros \CS{pxpic@@parse@group} and % \CS{pxpic@@parse@space} that represent the choices of said key. % \begin{macrocode} \protected\def\pxpic@parse@setarg#1#2% {% \long\def\pxpic@@parse##1#1% {% \pxpic@ifend##1\pxpic@done\pxpic@end \pxpic@@kern-% \hbox{\pxpic@@kern+\pxpic@parseline##1#2\pxpic@end#2}% \pxpic@@parse }% \long\def\pxpic@parseline##1#2% {% \pxpic@ifend##1\pxpic@linedone\pxpic@end \pxpic@@kern-% \pxpic@parse@px{##1}% \pxpic@parseline }% } \protected\def\pxpic@@parse@group {% \long\def\pxpic@parse##1{\pxpic@@parse##1\pxpic@end}% \pxpic@parse@setarg{}{}% } % \end{macrocode} % In the |space| and |csv| case we need to make sure that there are no extra % spaces that would result in empty lines. We borrow the space trimmer from % \pkg{expl3} for this. % \begin{macrocode} \ExplSyntaxOn \cs_new_protected:Npn \pxpic@@parse@space #1 { \protected\def\pxpic@@parse@space { \protected\long\def\pxpic@parse ####1 { \tl_trim_spaces_apply:nN {####1} \pxpic@parse@aux #1 \pxpic@end #1 } \pxpic@parse@setarg {#1} {} } \protected\def\pxpic@@parse@csv { \protected\long\def\pxpic@parse ####1 { \tl_trim_spaces_apply:nN {####1} \pxpic@parse@aux #1 \pxpic@end #1 } \pxpic@parse@setarg {#1} { , } } } \ExplSyntaxOff \long\def\pxpic@parse@aux#1{\pxpic@@parse#1} \pxpic@@parse@space{ } % \end{macrocode} % Here we set up the default definition. Also the end of the parsing is % defined here. % \begin{macrocode} \pxpic@@parse@group \long\def\pxpic@done\pxpic@end\pxpic@@kern-\hbox#1\pxpic@@parse{} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[internal]{\pxpic@linedone} % For \CS{pxpic@parseline} % the line parsing loop also checks whether we're done, if not we place a % pixel using the current definition of \CS{pxpic@parse@px} (which will be set % by the current |mode|) and afterwards call the next iteration. If we're done % we gobble the remainder of the current iteration and control goes back to % \CS{pxpic@parse}. Before each pixel we introduce a negative \CS{kern} to % maybe fix the gap issue by letting the pixels overlap a bit. % \begin{macrocode} \long\def\pxpic@linedone \pxpic@end\pxpic@@kern-\pxpic@parse@px#1\pxpic@parseline {} % \end{macrocode} % \end{macro} % % % \subsection{Modes} % % The modes define how a single element of the \meta{pixel list} is parsed. % % \begin{macro}[internal]{\pxpic@parse@px@px,\pxpic@parse@px} % In the |px| mode we check whether the pixel is defined (using the name space % of \expkv), if so call it, else throw an error and skip. Since this is also % the initial |mode| we \CS{let} the auxiliary macro \CS{pxpic@parse@px} to % this mode here. % \begin{macrocode} \newcommand\pxpic@parse@px@px[1] {% \ekvifdefinedNoVal{pxpic@px}{#1}% {\csname\ekv@name{pxpic@px}{#1}N\endcsname}% {% \pxpic@err@unknown@px{#1}% \pxskip }% } \let\pxpic@parse@px\pxpic@parse@px@px % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\pxpic@parse@px@named} % |named| just checks whether the skip is empty. If so skip, else call % \CS{color} with the element and output a pixel. % \begin{macrocode} \newcommand\pxpic@parse@px@named[1] {% \pxpic@ifempty{#1}% {\pxskip}% {{\@declaredcolor{#1}\px}}% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % { % \pxpic@parse@px@rgb, % \pxpic@parse@px@cmy, % \pxpic@parse@px@cmyk, % \pxpic@parse@px@hsb, % \pxpic@parse@px@Hsb, % \pxpic@parse@px@tHsb, % \pxpic@parse@px@gray, % \pxpic@parse@px@RGB, % \pxpic@parse@px@HTML, % \pxpic@parse@px@HSB, % \pxpic@parse@px@Gray, % \pxpic@parse@px@wave % } % The colour model modes are all the same in principle. They test for an empty % element to introduce a skip, else they call \CS{color} with the respective % colour model and output a pixel. We use the auxiliary \CS{pxpic@tmp} to do % all those definitions and undefine it afterwards. % \begin{macrocode} \def\pxpic@tmp#1% {% \pxpicnewmode{#1}% {% \pxpic@ifempty{##1}% {\pxskip}% {{\@undeclaredcolor[#1]{##1}\px}}% }% } \pxpic@tmp{rgb} \pxpic@tmp{cmy} \pxpic@tmp{cmyk} \pxpic@tmp{hsb} \pxpic@tmp{Hsb} \pxpic@tmp{tHsb} \pxpic@tmp{gray} \pxpic@tmp{RGB} \pxpic@tmp{HTML} \pxpic@tmp{HSB} \pxpic@tmp{Gray} \pxpic@tmp{wave} \let\pxpic@tmp\pxpic@undef % \end{macrocode} % \end{macro} % % % \subsection{Pixel and Skip} % % \begin{macro}[internal]{\pxpic@px,\pxpic@skip} % The actual definition of pixels and skips is stored in macros to which the % frontend macros \CS{px} and \CS{pxskip} will be let inside of \CS{pxpic}. % \begin{macrocode} \newcommand\pxpic@px{\vrule height\pxpicHT width\pxpicWD depth\z@} \newcommand\pxpic@skip{\kern\pxpicWD} % \end{macrocode} % \end{macro} % % % \subsection{Parser for colours} % % \begin{macro}[internal]{\pxpic@setcolor,\pxpic@setcolor@a,\pxpic@setcolor@b} % First we test whether the colour starts with an opening bracket or not. % Depending on that we either just put the colour after \CS{color}, or put % braces around it (as it then is a colour expression for \pkg{xcolor} and % just a single argument). \CS{pxpic@setcolor} defines a |px| in the name % space of \expkv\ (this has a slight overhead during definition, but \expkv\ % is fast in checking whether one of its keys is defined or not, and reduces % the amount of code in this package). % \begin{macrocode} \newcommand\pxpic@setcolor[2] {% \pxpic@ifbracket\pxpic@end#2.\pxpic@end[]\pxpic@end \pxpic@setcolor@a\pxpic@setcolor@b {#1}{#2}% } \newcommand\pxpic@setcolor@a[2] {% \expandafter\def\csname\ekv@name{pxpic@px}{#1}N\endcsname {{\@declaredcolor{#2}\px}}% } \newcommand\pxpic@setcolor@b[2] {% \expandafter\def\csname\ekv@name{pxpic@px}{#1}N\endcsname {{\@undeclaredcolor#2\px}}% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\pxpic@setcolor@colorlist} % This macro should leave the correct code in the input stream to define a % single pixel. It is to be used inside of \CS{edef}, hence using % \CS{unexpanded}, which doesn't have an opening brace directly after it % so that the \CS{pxpic@ifbracket} test is fully expanded. Next we expand % \CS{pxpic@setcolor@a}/|b| twice (which will expand the \CS{csname} % contained in it) and then leave the opening bracket for \CS{unexpanded} in % the input stream. The code should be used inside a group so that all the % implicit definitions to \CS{relax} done by \CS{csname} are reverted. % \begin{macrocode} \newcommand\pxpic@setcolor@colorlist[2] {% \unexpanded\iffalse{\fi \pxpic@ifbracket\pxpic@end#2.\pxpic@end[]\pxpic@end {\expandafter\expandafter\expandafter\pxpic@openbrace\pxpic@setcolor@a}% {\expandafter\expandafter\expandafter\pxpic@openbrace\pxpic@setcolor@b}% {#1}{#2}% }% } % \end{macrocode} % \end{macro} % % % \subsection{Messages} % % \begin{macro}[internal] % { % \pxpic@err@noval,\pxpic@err@unknown@px,\pxpic@err@unknown@mode, % \pxpic@err@unknown@colorlist,\pxpic@err@defined@colorlist, % \pxpic@err@unknown@expansion % } % These are just some macros throwing errors, nothing special here. % \begin{macrocode} \newcommand\pxpic@err@noval[1] {\PackageError{pxpic}{Missing colour definition for name `\detokenize{#1}'}{}} \newcommand\pxpic@err@unknown@px[1] {\PackageError{pxpic}{Unknown pixel `\detokenize{#1}'. Skipping}{}} \newcommand\pxpic@err@unknown@mode[1] {\PackageError{pxpic}{Unknown mode `#1'}{}} \newcommand\pxpic@err@unknown@colorlist[1] {\PackageError{pxpic}{Unknown colour list `#1'}{}} \newcommand\pxpic@err@defined@colorlist[1] {\PackageError{pxpic}{Colour list `#1' already defined}{}} \newcommand\pxpic@err@unknown@expansion[1] {\PackageError{pxpic}{Unknown expansion mode `#1'}{}} \newcommand\pxpic@err@unknown@lines[1] {\PackageError{pxpic}{Unknown lines mode `#1'}{}} \newcommand\pxpic@err@unknown@file[1] {\PackageError{pxpic}{Unknown file value `#1'}{}} \newcommand\pxpic@err@file@not@found[1] {\PackageError{pxpic}{Couldn't find file #1}{}} % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\pxpic@experr} % This macro can be used to throw an error expandably. For this an undefined % control sequence \verb*|\pxpic Error:| is used. The group containing % \CS{expandafter} keeps the definition of \verb*|\pxpic Error:| local (it is % \CS{relax} after the \CS{csname}) so that it is undefined when it's used. % The \CS{@firstofone} is needed to get the readable output (now the undefined % macro and actual message are always the same argument). % \begin{macrocode} \def\pxpic@experr#1% {% \long\def\pxpic@experr##1% {% \expandafter\expandafter\expandafter \pxpic@ifend \@firstofone{#1##1.}% \pxpic@end }% } \begingroup\expandafter\endgroup \expandafter\pxpic@experr\csname pxpic Error:\endcsname % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\pxpic@experr@noval} % With the expandable error throwing mechanism out of the way, the following % is straight forward again. % \begin{macrocode} \newcommand\pxpic@experr@noval[1] {\pxpic@experr{Missing colour definition for `#1'}} % \end{macrocode} % \end{macro} % %^^A=<< % % \gobbledocstriptag % % % \end{implementation}^^A=<< % % \clearpage % \PrintIndex % \endinput % ^^A vim: ft=tex fdm=marker fmr=>>=,=<<