12

How to print a font table for an OpenType/TrueType font? Can I use the fonttable package?

A font table should have all glyphs in a font. Like the following (from The TeXBook): enter image description here

Update:

I have created a rather complicated font table for Fira Math based on @egreg's answer. You may find it in specimen.tex. It has the following features:

  • Automatically count the glyphs in the fonts/unicode block;
  • Fallback to other fonts for the non-existing glyphs (here I use GNU Unifont);
  • Highlight for Unicode Reserved Code Points and Control Codes.

At the end of the specimen, there is a section for the non-Unicode glyphs as well.

enter image description here

  • What do you mean with a font table? – TeXnician Jul 15 '17 at 11:19
  • @TeXnician I guess he is referring to something like ctan.org/tex-archive/fonts/libertinus/documentation. – CampanIgnis Jul 15 '17 at 11:24
  • @CampanIgnis The problem is that I don't know how to use \fonttable for an OpenType font (with extension .otf/.ttf), especially those fonts in my system. – stone-zeng Jul 15 '17 at 11:31
  • 3
    The \fonttable command can be used only if the .tfm file exists in the system for the font. – karlkoeller Jul 15 '17 at 11:37
  • @karlkoeller How about using XeLaTeX or LuaLaTeX? – stone-zeng Jul 15 '17 at 11:43
13
\documentclass[11pt]{article}
\usepackage{fontspec}

\usepackage{luacode}
\usepackage{longtable,array,xcolor,listings}
\begin{luacode*} 
function print_glyphs(maxCols,maxChars) 
  local id = font.current()         -- geht Font ID
  local fnt = font.getfont(id)
  local col = 1
  local maxU4 = 15*(16^3+16^2+16+1)
  a = {}
  for k, v in pairs(fnt.characters) do
    a [#a + 1] = k
  end
  table.sort(a)
  for i, k in ipairs(a) do
    if i >= maxChars then break end
    if col == 1 then
      if k > maxU4 then
        tex.sprint(string.format("U+%06x", k))
      else
        tex.sprint(string.format("U+%04x", k))
      end
      tex.sprint("&") 
    end
    if (i) then
      tex.sprint(string.format([[\char%i]], k))
    else
     tex.sprint("~")
    end
    if col == maxCols then              -- Line finished?
      tex.sprint([[\\\cline{2-]] .. maxCols+1 .. "} ")  -- Yes
      col = 1                           -- newline
    else
      tex.sprint("&")                   -- no, Print &
      col = col + 1                     -- next column
    end
  end
end
\end{luacode*}


\begin{document}
Latin Modern

\color{black!20}

\begin{longtable}{>{\color{black!50}\ttfamily\footnotesize}r|
                  *{10}{>{\color{black}}p{1.5em}|}}
\cline{2-11}
\endhead

%\directlua{print_glyphs(10,1360)} \\ \cline{2-11}
\directlua{print_glyphs(10,65463)} \\ \cline{2-11}
\end{longtable}

\end{document}

enter image description here

10

With XeTeX, making chunks of 512 characters:

\documentclass{article}
\usepackage{geometry}
\usepackage{fontspec}
\usepackage{longtable}
\usepackage{array}

\setlength\extrarowheight{3pt}

\ExplSyntaxOn
\NewDocumentCommand{\OTfonttable}{m}
 {
  \group_begin:
  #1
  \int_gset:Nn \g_fonttable_rows_int
   { \int_div_truncate:nn { \XeTeXlastfontchar \font + 15 } { 16 } }
  \int_gset:Nn \g_fonttable_chunks_int
   { \int_div_truncate:nn { \g_fonttable_rows_int + 31 } { 32 } }
  \group_end:
  \fonttable_make:n { #1 }
 }

\int_new:N \g_fonttable_rows_int
\int_new:N \g_fonttable_chunks_int
\seq_new:N \l_fonttable_rows_seq
\tl_new:N \l_fonttable_font_tl

\cs_new_protected:Nn \fonttable_make:n
 {
  \tl_set:Nn \l_fonttable_font_tl { #1 }
  \int_step_inline:nnnn { 0 } { 1 } { \g_fonttable_chunks_int - 1 }
   {
    \seq_clear:N \l_fonttable_rows_seq
    \int_step_inline:nnnn { 0 } { 1 } { 31 }
     {
      \seq_put_right:Nx \l_fonttable_rows_seq
       {
        \fonttable_setup: \int_to_Hex:n { ##1*32 + ####1 }x &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 0 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 1 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 2 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 3 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 4 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 5 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 6 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 7 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 8 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 9 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 10 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 11 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 12 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 13 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 14 } } &
        \fonttable_char:n { \int_eval:n { ##1*512 + ####1*16 + 15 } } 
       }
     }
    \begin{tabular}{|r|*{16}{c|}}
    \cline{2-17}
    \multicolumn{1}{c|}{} &
      \ttfamily 0 &
      \ttfamily 1 &
      \ttfamily 2 &
      \ttfamily 3 &
      \ttfamily 4 &
      \ttfamily 5 &
      \ttfamily 6 &
      \ttfamily 7 &
      \ttfamily 8 &
      \ttfamily 9 &
      \ttfamily A &
      \ttfamily B &
      \ttfamily C &
      \ttfamily D &
      \ttfamily E &
      \ttfamily F \\
    \hline
    \seq_use:Nn \l_fonttable_rows_seq { \\ \hline } \\
    \hline
    \end{tabular}\clearpage
   }
 }

\cs_new_protected:Nn \fonttable_setup: { \ttfamily $\vphantom{\big|}$ }

\cs_new_protected:Nn \fonttable_char:n
 {
  \tl_use:N \l_fonttable_font_tl
  \iffontchar\font #1 \symbol{#1} \fi
 }
\ExplSyntaxOff

\newfontface{\test}{Old Standard}

\begin{document}

\OTfonttable{\normalfont}

\end{document}

The argument to \OTfonttable can be any font selector, in the example it is \normalfont, but it could be \test for Old Standard. This will produce 126 pages for \normalfont, that is, Latin Modern Roman (235 for Old Standard).

enter image description here

  • Well, sometimes it will print too many blank lines... I know it's not easy, but is there any method to ignore these blank symbols (e.g. most fonts don't have CJK characters)? – stone-zeng Jul 15 '17 at 14:28
  • @Stone-Zeng It'll probably be easier to ignore blank lines by virtue of the way the table's formatted - just ignoring blank symbols would de-align everything. – wizzwizz4 Jul 15 '17 at 15:22
  • @Stone-Zeng This won't go past the block with the last character present in the font. The chunks are built one by one, or memory would be exhausted. It wouldn't be too difficult to avoid printing a completely blank chunk. – egreg Jul 15 '17 at 15:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.