16

I'm trying to stack bold capital letters, like in the example below. There should be no white space between letters and letters also should not overlap. Some letters should be stretched tall or short.

As far as I can tell, TikZ does not distinguish between bold and regular style, and between letters that are minimally taller than others (e.g., C vs E).

Any ideas would be much appreciated! Should I not be using TikZ at all? I would like to avoid manually adjusting each letter's y-position.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document} 
\Huge
\begin{tikzpicture}[mytext/.style = {inner sep=0, outer sep=0}, font=\bfseries] 
  \node (c1) [mytext, anchor=south] at (0,0) {C};
  \node (c2) [mytext, above=0 of c1, color=red] {C};
  \node      [mytext, above=0 of c2] {E};
  \node (c3) [mytext, yscale=2, anchor=south] at (1,0) {C};
  \node (c4) [mytext, yscale=0.5, above=0 of c3, color=red] {C};
  \node      [mytext, yscale=0.5, above=0 of c4] {E};
\end{tikzpicture}
\end{document} 

enter image description here

4
  • 9
    tikz (latex) doesn't see the ink of the glyphs, only their bounding box and the C sticks a bit outside of the box. This is a decision of the font designer. Commented Mar 3, 2018 at 15:32
  • What do you want to happen when you stack two A's? Do you want them to be verti-kerned together so that the tip of the lower one touches the bar of the top one? If so, I think you're going to have to go through every pair of glyphs you use in your font manually. Commented Mar 3, 2018 at 19:12
  • @user2357112, There can be whitespace between the bar of the upper A and the top of the lower A.
    – u17
    Commented Mar 3, 2018 at 19:15
  • This answer, tex.stackexchange.com/questions/275374/…, and this link, ilovetypography.com/2009/01/14/inconspicuous-vertical-metrics, may be helpful in explaining why there is no easy answer to your question. Commented Mar 4, 2018 at 1:26

4 Answers 4

28

TeX does not know the shape of the glyphs. It only knows the character box dimensions as specified in the TFM file.

Font identification

The font files can be identified the following way:

  • Use a document with just this font, for example, the document of the question is fine, if \pagestyle{empty} is added.

  • Run it through pdflatex with option -recorder.

  • The end part of the log file and the *.fls file reveals cmbx12.pfb as the font.

  • The font metrics can only be seen in the recorder file *.fls:

    INPUT cmbx12.tfm
    

Font shape data

Open the glyph shapes in a font editor like FontForge. The trim margins:

C: 62 -12 63 -12 (width 812)
E: 38   0 32   5 (width 738)

The font also tells that 1em = 1000 units

TeX metrics

The binary *.tfm file can be converted to ASCII in a better readable format by the program tftopl:

tftopl cmbx12.pfb cmbx12.pl

It contains at the beginning the font dimension parameters:

(FONTDIMEN
   (SLANT R 0.0)
   (SPACE R 0.375)
   (STRETCH R 0.1875)
   (SHRINK R 0.125)
   (XHEIGHT R 0.444444)
   (QUAD R 1.125)
   (EXTRASPACE R 0.125)
   )

The entry QUAD specifies the size of 1em. It is 1.125 of the font em size.

The character metrics are quite the same as in the font (except for some kind of "rounding" issues):

(CHARACTER C C
   (CHARWD R 0.8125)
   (CHARHT R 0.686111)
   )
...
(CHARACTER C E
   (CHARWD R 0.738426)
   (CHARHT R 0.686111)
   )

The width for C is 0.8125 * multiplied with the em size of the font = 812.5 font units. Truncated to integer, this are the 812 that FontForge has shown.

The following example defines some macros to specifiy the trim values for the glyph and defines macro \GlyphBox that fixes its TeX box to fit the glyph exactly (except rounding issues).

To keep the macros only work for one font. They can be extended to add another argument for the font name.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}

\makeatletter

\newcommand*{\EmSize}[1]{%
  \def\@EmSize{#1}%
}
\newcommand*{\@GlyphPropName}[2]{%
  GS@#1@#2%
}
\newcommand*{\GlyphProp}[2]{%
  \@nameuse{\@GlyphPropName{#1}{#2}}%
}
\newcommand*{\GlyphSize}[5]{%
  \@namedef{\@GlyphPropName{#1}{llx}}{#2}%
  \@namedef{\@GlyphPropName{#1}{lly}}{#3}%
  \@namedef{\@GlyphPropName{#1}{urx}}{#4}%
  \@namedef{\@GlyphPropName{#1}{ury}}{#5}%
}
\newcommand*{\GlyphBox}[1]{%
  \begingroup
    \leavevmode
    \setbox0=\hbox{#1}%
    \setbox0=\hbox{%
      \kern-\dimexpr1em*\GlyphProp{#1}{llx}/\@EmSize\relax
      #1%
      \kern-\dimexpr1em*\GlyphProp{#1}{urx}/\@EmSize\relax
    }%
    \ht0=\dimexpr\ht0 - 1em*\GlyphProp{#1}{ury}/\@EmSize\relax
    \dp0=\dimexpr\dp0 - 1em*\GlyphProp{#1}{lly}/\@EmSize\relax
    \box0\relax
  \endgroup
}
\makeatother
% Font cmbx12
\EmSize{1125}% 1000 units in font, 1.125 in TFM
\GlyphSize{C}{62}{-12}{63}{-12}
\GlyphSize{E}{38}{0}{32}{5}

\begin{document} 
\Huge
\bfseries

\setlength{\fboxsep}{0pt}
\setlength{\fboxrule}{.2pt}
\textcolor{red}{%
  \fbox{\color{black}\GlyphBox{C}}%
  \fbox{\color{black}\GlyphBox{E}}%
}

\begin{tikzpicture}[mytext/.style = {inner sep=0, outer sep=0}, font=\bfseries]
  \node (c1) [mytext, anchor=south] at (0,0) {\GlyphBox{C}};
  \node (c2) [mytext, above=0 of c1, color=red] {\GlyphBox{C}};
  \node      [mytext, above=0 of c2] {\GlyphBox{E}};
  \node (c3) [mytext, yscale=2, anchor=south] at (1,0) {\GlyphBox{C}};
  \node (c4) [mytext, yscale=0.5, above=0 of c3, color=red] {\GlyphBox{C}};
  \node      [mytext, yscale=0.5, above=0 of c4] {\GlyphBox{E}};
\end{tikzpicture}
\end{document}

Result

2
  • I like your answer a lot. Two questions: (1) Is there perhaps a reference missing to lly in \GlyphBox? (2) What is the best way to get trim margins in FontForge? (Off topic: pdfcrop has been incredibly useful to me. Thanks!)
    – u17
    Commented Mar 3, 2018 at 20:03
  • @FrankSeifert (1) Thanks, there was a typo (ury instead of lly). (2) I had done it manually for the two characters. But FontForge can also be scripted, e.g. it has an interface for Python 2. Commented Mar 3, 2018 at 20:26
11

xelatex

enter image description here

pdflatex

enter image description here

15 more characters

6
  • 2
    Bad boy, you are cheating. Very likely your XeLaTeX run loads package fontspec and uses a different font: Latin Modern in OpenType format vs. Computer Modern in Type1 with TFM. Commented Mar 3, 2018 at 16:37
  • Horizontally, it will not work, because the side bearings are kept. Commented Mar 3, 2018 at 16:40
  • @HeikoOberdiek true although my original idea was to use XeTeXglyphbounds to adjust things before I remembered it wan't needed here but that could be used to adjust the horizontal sidebearings as well, without needing to edit the font. Commented Mar 3, 2018 at 16:45
  • @HeikoOberdiek about the cheating true but I did check that using latin modern rather than cm with pdflatex didn't make any real difference here (although that isn't the same latin modern as pdftex uses of course) (and no it did not use fontspec it was exactly the OPs example file) Commented Mar 3, 2018 at 16:46
  • 1
    @HeikoOberdiek sure, if you use cm, but unless your xelatex is old, it will default to TU encoding and opentype latin modern fonts, I used the document in the question unchanged. Commented Mar 3, 2018 at 17:49
8

I don't think you need a hammersledge like tikz for this: a simple tabular, the \scalebox command and the \Gape command from makecell for a precise adjustment, will do the job:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\usepackage{xcolor}
\usepackage{makecell, graphicx}

\newcommand{\vscalebox}[2][1]{\scalebox{1}[#1]{#2}}

\begin{document}

\centering
\renewcommand{\arraystretch}{0}
\begin{tabular}{>{\bfseries\Huge}c}
E\\ \Gape[0.3pt]{\color{red}C}\\ \Gape[0.3pt]{C}
\end{tabular}
\quad
\begin{tabular}{>{\bfseries\Huge}c}
\vscalebox[0.5]{E}\\ \Gape[0.15pt]{\vscalebox[0.5]{\color{red}C}}\\ \Gape[0.6pt]{\vscalebox[2]{C}}
\end{tabular}

\end{document} 

enter image description here

8

You could do it with Metafun.

\setupbodyfont[10pt]
\starttext
\setbox0=\hbox{\bf C}
\newdimen\dpC \dpC=\dp0
\startMPpage
picture E; E := image ( draw outlinetext ("\bf E") ) ;
picture Ca; Ca := image ( draw outlinetext.f ("\bf C") (withcolor red) ) ;
picture Cb; Cb := image ( draw outlinetext ("\bf C") ) ;
currentpicture := E;
addto currentpicture also Ca
    shifted (0,-bbheight Ca+\the\dpC);
addto currentpicture also Cb
    shifted (0,-bbheight Ca-bbheight Cb+\the\dpC);
\stopMPpage
\startMPpage
picture E; E := image ( draw outlinetext ("\bf E") yscaled (.5) ) ;
picture Ca; Ca := image ( draw outlinetext.f ("\bf C") (withcolor red) yscaled (.5) ) ;
picture Cb; Cb := image ( draw outlinetext ("\bf C") yscaled (2) ) ;
currentpicture := E;
addto currentpicture also Ca
    shifted (0,-bbheight Ca+.5*\the\dpC);
addto currentpicture also Cb
    shifted (0,-bbheight Ca-bbheight Cb+2*\the\dpC);
\stopMPpage
\stoptext

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .