3

MWE:

\documentclass[a4paper,12pt,twoside]{memoir}
\usepackage{DejaVuSerifCondensed}
\usepackage[T1]{fontenc}
\begin{document}
\noindent\scshape{Hello World}\\
\textsc{Hello World}
\end{document}

Explanation and question:

As you can see, I am working with a memoir document class and I've load a font DejaVuSerifCondensed, I am trying to obtain small caps for my header (which I did not place in the MWE as unnecessary). However I can't obtain the desire effect with the \scshape command nor with the \textsc{}.

I've seen other questions like

But either they do not adapt to my problem (for what I can see) or they do not solve the problem (following the instructions there and "inserting" the piece of code in mine).

Question here is: is there a general method (piece of code or something) to obtain small caps from a custom font (even if that is one I upload with a ttf)?, if not, what would be the piece of code to select the standard small caps font?

5 Answers 5

6

In order to get small caps from a font through the standard commands such as \textsc, the font you have loaded needs to have small caps. The font you've chosen, DejaVu Serif Condensed, doesn't. When you compile your MWE, you will as a result get a font warning from LaTeX that no small caps exist for this font, and that it will use the normal font instead:

LaTeX Font Warning: Font shape `T1/DejaVuSerifCondensed-TLF/m/sc' undefined
(Font)              using `T1/DejaVuSerifCondensed-TLF/m/n' instead

There is therefore nothing you can do to get small caps from the font, other than faking them by tweaking the full caps glyphs. But unless you are tied to DejaVu Serif Condensed for some reason (and I don't see why you would be), what you should do if you want good-looking small caps is to switch to a font that has them. You can browse through the LaTeX font catalogue which will tell you if the font has small caps or not.

If you need to stick to DejaVu Serif, then you could switch to another font only when you need small caps. How to do that has been asked and answered before. I've just copied the code from there below.

\documentclass{memoir}
\usepackage{DejaVuSerifCondensed}
\usepackage[T1]{fontenc}
\usepackage{pdftexcmds}
\makeatletter
\let\scshape\relax % to avoid a warning
\DeclareRobustCommand\scshape{%
  \not@math@alphabet\scshape\relax
  \ifnum\pdf@strcmp{\f@family}{\familydefault}=\z@
    \fontfamily{lmr}%
  \fi
  \fontshape\scdefault\selectfont}
\makeatother
\begin{document}
This text should be in DejaVuSerif\par
\textsc{While this should be in Latin Modern}
\end{document}

enter image description here

See egreg's answer for more details, and Alan Munn's answer for how to find the font family names. You need to decide for yourself which small caps font goes well with DejaVu Serif (I don't recommend Latin Modern as in my example). Browse the font catalogue.

4
  • Thanks for your answer, would you please tell me how to easily select any font with small caps for a small piece of information every time?
    – Hans
    Commented Aug 22, 2015 at 23:37
  • @Hans I'll add that information once I get to a computer later today :)
    – Sverre
    Commented Aug 23, 2015 at 6:39
  • Cool, I am anxiously waiting.
    – Hans
    Commented Aug 23, 2015 at 7:19
  • I wasn't notified of the edition, thank you so much.
    – Hans
    Commented Aug 28, 2015 at 19:15
6

One solution is to create fake small caps. The MWE below defines a command \fakesc that uppercases and shrinks text to resemble small caps.

\documentclass[a4paper,12pt,twoside]{memoir}
\usepackage{DejaVuSerifCondensed}
\usepackage[T1]{fontenc}

\newcommand\fakesc[1]{\uppercase{{\scriptsize #1}}}

\begin{document}
The sign on the door said \fakesc{keep out}, so we left.
\end{document}

Output: enter image description here

Here is a second, more complex solution that applies the fake small caps effect only to the lowercase letters in the input string. This permits the input string to be a mixture of uppercase and lowercase letters, and only the lowercase letters will transformed into fake small caps. See MWE below.

\documentclass[a4paper,12pt,twoside]{memoir}
\usepackage{DejaVuSerifCondensed}
\usepackage[T1]{fontenc}

\usepackage{xstring} % needed for IfEqCase
\usepackage{forloop}

\newcounter{sccounter}
\newcounter{tempStringLength}

\newcommand{\betterfakesc}[1]{%
    % this \betterfakesc command requires these two packages:
    %   xstring
    %   forloop
    %
    % First, we obtain the length of the input string.
    \StrLen{#1}[\stringLength]%
    %
    % Our main forloop will be using a condition of “while less than \stringLength”,
    % so we’ll need to increase \stringLength by 1 so the forloop will be able to iterate 
    % over the entire string. we’ll use a temporary counter tempStringLength to make
    % this increase. That’s what the next three lines are about.
    \setcounter{tempStringLength}{\stringLength}%
    \addtocounter{tempStringLength}{1}%
    \def\stringLength{\arabic{tempStringLength}}%
    %
    % Here is our main loop. We iterate over the characters in the input string,
    % and the currentLetter is compared to the case rules we have defined. Basically
    % if the currentLetter is any of the lowercase a-z letters, then we apply a 
    % “fake small caps” effect to it and output it.
    \forloop[1]{sccounter}{1}{\value{sccounter}<\stringLength}{%
        \StrChar{#1}{\value{sccounter}}[\currentLetter]%
        %
        \IfEqCase*{\currentLetter}{%
        % The lines below are the rules. Obviously more could be added.
        {a}{{\uppercase{\scriptsize a}}}%
        {b}{{\uppercase{\scriptsize b}}}%
        {c}{{\uppercase{\scriptsize c}}}%
        {d}{{\uppercase{\scriptsize d}}}%
        {e}{{\uppercase{\scriptsize e}}}%
        {f}{{\uppercase{\scriptsize f}}}%
        {g}{{\uppercase{\scriptsize g}}}%
        {h}{{\uppercase{\scriptsize h}}}%
        {i}{{\uppercase{\scriptsize i}}}%
        {j}{{\uppercase{\scriptsize j}}}%
        {k}{{\uppercase{\scriptsize k}}}%
        {l}{{\uppercase{\scriptsize l}}}%
        {m}{{\uppercase{\scriptsize m}}}%
        {n}{{\uppercase{\scriptsize n}}}%
        {o}{{\uppercase{\scriptsize o}}}%
        {p}{{\uppercase{\scriptsize p}}}%
        {q}{{\uppercase{\scriptsize q}}}%
        {r}{{\uppercase{\scriptsize r}}}%
        {s}{{\uppercase{\scriptsize s}}}%
        {t}{{\uppercase{\scriptsize t}}}%
        {u}{{\uppercase{\scriptsize u}}}%
        {v}{{\uppercase{\scriptsize v}}}%
        {w}{{\uppercase{\scriptsize w}}}%
        {x}{{\uppercase{\scriptsize x}}}%
        {y}{{\uppercase{\scriptsize y}}}%
        {z}{{\uppercase{\scriptsize z}}}%
        }%
        % if our \currentLetter isn’t any of the letters we have rules for,
        % then just output it now
        [{\currentLetter}]%
    }%
}

\begin{document}
The sign on the door said \betterfakesc{Keep Out}, so we left.
\end{document}

Output:

enter image description here

Note that additional rules could easily be added to the IfEqCase structure to handle punctuation, etc. (Also note that this command could even be repurposed for other types of textual or formatting transformations.)

Be aware that typography purists will complain that faking small caps by reducing font size will produce letter forms that are lighter in stroke weight than real small caps, and they're correct about that. The main advantage of fake small caps is that they work in any font and they're an easy solution to implement.

11
  • 1
    @Hans Also you may (I'm not sure) lose kerning in that case and, even if you don't, it won't necessarily be the right kerning.
    – cfr
    Commented Aug 22, 2015 at 19:22
  • 1
    @Hans: I added a 2nd solution with MWE to address uppercase and lowercase letters. Commented Aug 22, 2015 at 20:07
  • 1
    @Hans: are you looking for a practical solution to your current document? If so, then the easiest solution is to just add rows for the additional lowercase diacritical marks. There are not many. It is not possible in every font to detect if a letter with accent is lowercase or uppercase. It all depends on the font. Here are a few rows for you to add to handle accents: {á}{{\uppercase{\scriptsize á}}}% {é}{{\uppercase{\scriptsize é}}}% {í}{{\uppercase{\scriptsize í}}}% {ö}{{\uppercase{\scriptsize ö}}}% {ü}{{\uppercase{\scriptsize ü}}}% {ñ}{{\uppercase{\scriptsize ñ}}}% Commented Aug 23, 2015 at 3:11
  • 1
    @Hans: In addition, you might consider defining a new command that handles both your leftmark and the small caps in one. For example, if you use this command, then it does both your leftmark and your small caps: \newcommand\MarkAndSmall[1]{\betterfakesc{\leftmark #1}} Commented Aug 23, 2015 at 3:50
  • 1
    Just came across your solution. It works well, but you should not call your counter index because that easily leads to conflicts with other packages. For example, the makeidx package for creating an index throws a cryptic error message when your code is used in the same document as its \printidx command, presumably because it also uses a counter with the name index. If I replace index in your solution with something else (e.g., scindex), it works well. Commented Dec 6, 2015 at 18:28
1

Code:

Well I searched a lot for a script to recognize uppercase letters and lowercase letters, with no success (How to check if the selected letter is uppercase or lowercase in a macro?). But then I found a more elegant way to make the fake small caps (and fake mid caps) in Faking small caps in XeLaTeX:

\documentclass[a4paper,12pt,twoside]{memoir}
\usepackage{DejaVuSerifCondensed}
\usepackage[T1]{fontenc}
\usepackage{fontspec}

\ExplSyntaxOn
\NewDocumentCommand{\fakesc}{ o m }
 {
  \guido_fakesc:n { #2 }
  \IfNoValueTF{#1}
   {
    \tl_use:N \l__guido_temp_tl
   }
   {
    \cs_set_eq:NN #1 \l__guido_temp_tl
   }
 }
\cs_new_protected:Npn \guido_fakesc:n #1
 {
  \tl_set:Nn \l__guido_text_tl { #1 }
  \tl_replace_all:Nnn \l__guido_text_tl { ~ } { \q_space }
  \tl_set:Nn \l__guido_temp_tl { \group_begin: \footnotesize }
  \tl_map_inline:Nn \l__guido_text_tl
   {
    \token_if_eq_meaning:NNTF ##1 \q_space
     {
      \tl_put_right:Nn \l__guido_temp_tl { ~ }
     }
     {
      \int_compare:nTF { \char_value_uccode:n { `##1 } = `##1 }
       {
        \tl_put_right:Nn \l__guido_temp_tl { {\normalsize ##1} }
       }
       {
        \tl_put_right:Nn \l__guido_temp_tl { \tl_to_uppercase:n { ##1 } }
       }
     }
   }
  \tl_put_right:Nn \l__guido_temp_tl { \group_end: }
 }
\quark_new:N \q_space
\tl_new:N \l__guido_text_tl
\tl_new:N \l__guido_temp_tl
\ExplSyntaxOff

\begin{document}
\noindent\scshape{Hello World}\\
\textsc{Hello World}\\
\fakesc{Hello World}%---mid caps---
\end{document}

To be completely honest, I have no clue on how this works, I only know it works and produce small caps (with the custom font being used) with the commands \textsc and \scshape and mid caps with the command \fakesc. Important thing is that it works with called arguments like chapters and sections, in my case, I am calling the chapter number and name, this code will make the lowercase letters show in small caps and in the uppercase letters appear in normal caps.

Output:

enter image description here

5
  • 1
    You will get better results by choosing a font which has real small-caps. Faked are never entirely satisfactory - a proper small-caps font is designed.
    – cfr
    Commented Aug 22, 2015 at 19:24
  • @crf I know no matter how much one try, one will never get a perfect result, however this was the one working properly in all cases, but I am really interested in selecting any other font that have small caps, can you post an answer instructing the easier method to select that font just for the small caps every time you need it?, thanks.
    – Hans
    Commented Aug 22, 2015 at 23:47
  • 1
    That would be typographically monstrous! An arbitrary small-caps font will not match the main font in either style or size. You could use a special font for, say, section headings or something, if you are careful not to overdo things. So you could pick a font with small-caps for section headers, without redefining the default \scshape. (It is possible to do this - in fact, I do it to integrate italic small-caps in nfssext-cfr - but it would not be wise for your purpose.)
    – cfr
    Commented Aug 23, 2015 at 0:04
  • @crf is the best solution simply change all my document's font just to get the small caps?, I mean typographically speaking (don't know to much about the subject in matter).
    – Hans
    Commented Aug 23, 2015 at 1:08
  • 1
    Probably. Unless you really know what you are doing in terms of mixing fonts. Generally, you want a single serif font for the document, and maybe a sans for headings or titles, typewriter for any code etc. Mixing beyond that needs to be done very carefully or else it ends up being a distraction. (Your readers ought not notice your typography unless the typography is the main point.) But you could, if careful, choose a sufficiently different font for the small-caps and just use it for headings. If the rest is simple, that might work. Depends on the kind of document, too, of course.
    – cfr
    Commented Aug 23, 2015 at 1:38
1

Yes, use a font which has true-cut small caps which are actually drawn so as to look and function correctly.

0
0

This is the only post I could find with actual productive discussion of how to create fake small caps on stackexchange, so I thought I would chime in with an additional method I found on the latex.org forum. I'm retranscribing here in case the link dies in the future, and making minor alterations for readability.

\def\fakesc{\bgroup\obeyspaces\helpersc}
\def\helpersc#1{\helperscii #1\relax\relax\egroup}
\def\helperscii#1{%
\ifx\relax#1\else \ifcat#1\@sptoken{} \expandafter\expandafter\expandafter\helperscii\else
\ifnum`#1=\uccode`#1 {\normalsize #1}\else {\footnotesize \uppercase{#1}}\fi \expandafter\expandafter\expandafter\helperscii\expandafter\fi\fi}

\fakesc{Any Text that needs Small Caps}

The code apparently originally comes from the French programming-support forum Le site du Zéro which eventually became OpenClassrooms, which now mainly offer actual courses. Though not indexed by search engines, some of the old forum content is available -- but I couldn't find the specific post this code came from.

You must log in to answer this question.

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