1

I want to output the text string 'Abstract', but each character should be surrounded with its bounding box. Right now I have code like the following.

\documentclass{scrartcl}

\usepackage{tikz}

\pagestyle{empty}

\begin{document} \begin{tikzpicture} \foreach \g in {A, b, s, t, r, a, c, t} \draw node [anchor=base, draw, line width=1pt] {\fontsize{100pt}{0pt}\selectfont \g}; \end{tikzpicture} \end{document}

As can be seen, the 'current point' isn't updated correctly so that the nodes in the loop all overlap. How can I fix that?

enter image description here

lemzwerg
  • 599

4 Answers4

3

Based on original foreach and with all letters inside the same tikzpicture

\documentclass{scrartcl}

\usepackage{tikz} \usetikzlibrary{positioning} \usepackage{lmodern}

\pagestyle{empty}

\begin{document} \begin{tikzpicture}[% every node/.style={draw, anchor=base, line width=1pt, font=\fontsize{100pt}{0pt}\selectfont}% ] \node (A) {A}; \foreach \g [remember=\g as \lastg (initially A)] in {b, s, t, r, a, c, t} \node[right=-1pt of \lastg.base east, anchor=base west] (\g) {\g}; \end{tikzpicture} \end{document}

enter image description here

Ignasi
  • 136,588
  • That's it, thanks! I tried remember but I was fixated on using coordinates instead of remembering the last node itself. – lemzwerg Oct 05 '22 at 16:09
1

New solution:

Here is a macro that boxes the characters of the argument. The xstring package is used, as well as the tikz positioning library.

enter image description here

The macro \boxtext accepts one required argument (the text) and one optional argument (tikz options). The above image is created using the code

`\boxtext{Abstract}\quad\boxtext[fill=red!30]{abcdefg}`

The key is to use base right=of nodename.base east to position each node with the baseline of the previous node. node distance=-\pgflinewidth overlaps the borders. You can set node distance=0pt if that is not desired.

Here is the full code:

\documentclass{scrartcl}

\usepackage{tikz,xstring} \usetikzlibrary{positioning} \tikzset{boxnode/.style={anchor=base, draw, line width=1pt}}

\newcommand{\boxtext}[2][]{\StrLen{#2}[\strlen]\begin{tikzpicture}[baseline, node distance=-\pgflinewidth] \nodeboxnode,#1{\fontsize{100pt}{0pt}\selectfont\StrChar{#2}{1}}; \foreach \n[count=\m] in {2,...,\strlen}{ \nodeboxnode, base right=of L\m.base east,#1{\fontsize{100pt}{0pt}\selectfont\StrChar{#2}{\n}}; }\end{tikzpicture}}

\begin{document}

\boxtext{Abstract}\quad\boxtext[fill=red!30]{abcdefg}

\end{document}

Previous solution:

Put the tikzpicture inside the for loop. Add a % to avoid spaces between each character.

enter image description here

\documentclass{scrartcl}

\usepackage{tikz}

\pagestyle{empty}

\begin{document} \foreach \g in {A, b, s, t, r, a, c, t}{% <-- need this. \begin{tikzpicture} \draw node [anchor=base, draw, line width=1pt] {\fontsize{100pt}{0pt}\selectfont \g}; \end{tikzpicture}} \end{document}

Sandy G
  • 42,558
  • Thank you! I haven't thought of that. However, I'm still interested in a solution that works within a single tikspicture environment – mainly to learn how this can be done, since even an intensive search didn't yield anything useful. – lemzwerg Oct 05 '22 at 14:41
  • Actually, I think that your idea doesn't work as expected. Reason is that I want the text aligned along the base line – if you replace, say, the 'c' with 'g', you can see that this isn't the case. – lemzwerg Oct 05 '22 at 14:44
  • For your second comment, just use \begin{tikzpicture}[baseline]. – Sandy G Oct 05 '22 at 15:30
  • @lemzwerg: I added a new solution. – Sandy G Oct 05 '22 at 16:11
  • Thanks a lot! Your solution with \pgflinewidth is clever – I also tried to get the box width and failed because of my lack of knowledge. Now I know :-) – lemzwerg Oct 05 '22 at 16:14
1

This solution does not use kerning or ligatures. For a tight box, use inner sep=0pt. Everything here is in one tikzpicture

\documentclass[tikz, border=1cm]{standalone}
\begin{document}
\begin{tikzpicture}[
letter box/.style={draw, inner sep=1pt, anchor=base west}
]
\node[letter box] (A) {A};
\node[letter box] (b) at (A.base east) {b};
\node[letter box] (s) at (b.base east) {s};
\node[letter box] (t) at (s.base east) {t};
\node[letter box] (r) at (t.base east) {r};
\node[letter box] (a) at (r.base east) {a};
\node[letter box] (c) at (a.base east) {c};
\node[letter box] at (c.base east) {t};
\end{tikzpicture}
\end{document}

Boxed letters of the word "Abstract"

A solution with a chain:

\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary {chains}
\begin{document}
\begin{tikzpicture}[start chain=going {at=(\tikzchainprevious.base east)}, every node/.style={anchor=base west, draw, inner sep=1pt, on chain}]
\foreach \g in {A, b, s, t, r, a, c, t}
\node {\g};
\end{tikzpicture}
\end{document}

"Abstract" with boxed letters

  • Thanks. I forgot to mention that I want something in a loop to avoid manual repetition – my yet-to-be-written code will contain much more stuff than just boxes around the glyphs. – lemzwerg Oct 05 '22 at 16:10
0

Here's a solution that can be used with \fboxs (though the /utils/TeX/ifx key can only properly be loaded with TikZ/\usetikzlibrary) or TikZ.

The core of it is to iterate through a bunch of characters and do the same to them. What is done with them is the task of /boxes/place letter.

This could be a simply \fbox:

\boxesset{place letter/.code=\fbox{#1}}

but it can also be a \node inside a TikZpicture.

The value-keys at start and at end can be used to wrap the whole placing inside something.

I've defined two styles:

  1. fbox:
    This places each letter in a \fbox. The at start key is used to set the font size and lengths for the \fbox.

  2. tikz:
    This places each letter as a node that's part of chain going to the right. The at start and at end values are used to place the whole thing inside a tikzpicture with the appropriate settings.

This allows you to simply do

\boxes[fbox]{Text}
% or
\boxes[tikz]{Text}

Or you define your own macro that uses one of those so that you don't have to specify it everytime.

Since the algorithm that looks at the given letters isn't very smart it needs special consideration with characters that are accented or umlauts. Just put those in braces {ä}. With LuaLaTeX, this isn't needed anymore (but it doesn't hurt either.

Things like \textit{r} will always need braces: {\textit{r}}. Otherwise, the algorithms assumes \textit to be its own character and that will fail because it misses its argument.

Literal spaces will be ignored. The \fbox approach just needs ~ or \␣, the TikZ solution needs {~~} or {\␣\␣}.

The TikZ solution uses baseline so that the baseline of the letters are at the actual baseline of the text and trim left, trim right and outer sep=0pt so that no line width contributed to the bounding box (excluding the top and the bottom lines).


The definition of /utils/TeX/ifx without ext.misc is:

\makeatletter
\pgfkeys{
  /utils/TeX/ifx/.code n args={4}{%
    \ifx#1#2\relax\expandafter\pgfutil@firstoftwo\else\expandafter\pgfutil@secondoftwo\fi
    {\pgfkeysalso{#3}}{\pgfkeysalso{#4}}}}
\makeatother

Code

\documentclass{scrartcl}
\usepackage{tikz}\usetikzlibrary{chains,ext.misc}
\pagestyle{empty}
\newcommand*\boxesStop{boxesStop}
\newcommand*\boxesset{\pgfqkeys{/boxes}}
\boxesset{
  .code=\boxesset{#1},
  at start/.initial=,
  at end/.initial=,
  place letter/.code={#1},
  place letters/.style={@place letters={#1\boxesStop}},
  @place letters/.style 2 args={place letter={#1},
    /utils/TeX/ifx={\boxesStop}{#2}{}{@place letters={#2}}}}
\newcommand*{\boxes}[2][]{%
\begingroup
  \boxesset{#1}%
  \pgfkeysvalueof{/boxes/at start}%
  \boxesset{place letters={#2}}%
  \pgfkeysvalueof{/boxes/at end}%
\endgroup}
\boxesset{
  fbox/.style={
    at start=%
      \fontsize{100pt}{0pt}\selectfont
      \setlength{\fboxsep}{-.1pt}%
      \setlength{\fboxrule}{.1pt},
    place letter/.code=\fbox{##1}},
  tikz/.style={
    at start={%
      \begin{tikzpicture}[baseline=(chain-begin.base),
         trim left=(chain-begin.west), trim right=(chain-end.east),
         node distance=+0cm, start chain=going base right,
         nodes={draw, line width=+.1pt, inner sep=+0pt, outer sep=+0pt,
           font=\fontsize{100pt}{0pt}\selectfont}]},
    at end=\end{tikzpicture},
    place letter/.code=\node[on chain]{##1};},
}
\newcommand*{\dblSpc}{\ \ }
\begin{document}
\begin{tabular}{rll}
        & \texttt{fbox}                        & \texttt{tikz}                        \\
plain   & \boxes[fbox]{Abstract}               & \boxes[tikz]{Abstract}               \\
special & \boxes[fbox]{Abstr{ä}ct{\textit{r}}} & \boxes[tikz]{Abstr{ä}ct{\textit{r}}} \\
overlapping & \multicolumn{2}{c}{\rlap{\boxes[fbox]{Abstract}}\boxes[tikz]{Abstract}} \\
spaces & \boxes[fbox]{S p a c e s}             & \boxes[tikz]{S p a c e s}            \\
       & \boxes[fbox]{S\ p~a\ c~e\ s}          & \boxes[tikz]{S{\ \ }p{~~}a\dblSpc c{~~}e{\ \ }s}
\end{tabular}
\end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821
  • Thanks! I think I understand how the code works.

    However, two questions remain:

    (1) The image shows three lines, but the code only produces two lines, AFAICS. What's happening?

    (2) You are using {~~} and {\ } to produce a space, but the image doesn't show any space.

    – lemzwerg Oct 06 '22 at 05:18
  • @lemzwerg That happens when I do these things late at night. I've updated my answer now with pre-defined styles so it's much easier to test these out and showcase them. – Qrrbrbirlbel Oct 06 '22 at 08:42