15

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

stone-zeng
  • 2,710

2 Answers2

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

12

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

egreg
  • 1,121,712
  • 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