Working with fonts

Working with fonts is very similar to normal CSS. To assign a font to an element, put its name in the font-family property:

<style>
p { font-family: STSong-Light }
</style>

Default fonts

By default, there is just a certain set of fonts available for PDF. Here is the complete list of those that xhtml2pdf “knows” about, together with their alias names:

  • Times-Roman: Times New Roman, Times, Georgia

  • Helvetica: Arial, Verdana, Geneva

  • Courier: Courier New

  • ZapfDingbats

  • Symbol

The names are case-insensitive.

CSS’s generic families are answered with the nearest of those: serif, cursive, ui-serif, math and fangsong with Times-Roman; sans-serif, sans, sansserif, system-ui, ui-sans-serif, ui-rounded, fantasy and emoji with Helvetica; monospace, monospaced, mono and ui-monospace with Courier. None of them is a good likeness of what a browser would pick, and there is nothing better to pick from without embedding a font.

A family the document embeds with @font-face wins over the alias of the same name: declaring @font-face { font-family: Arial; } gives you your file, not Helvetica. A name of its own is still clearer to read.

If a font-family names nothing this document knows – a misspelling, a system font that was never embedded, or a @font-face whose src could not be read – the text is drawn in Helvetica and a warning says so, naming every family it tried. Before, that substitution was silent, and a missing font and a missing glyph looked exactly alike.

Asian (CJK) fonts

Some Asian fonts are available by default for PDF. The names are case-insensitive.

Simplified Chinese

  • STSong-Light

Traditional Chinese

  • MSung-Light

Japanese

  • HeiseiMin-W3

  • HeiseiKakuGo-W5

Korean

  • HYSMyeongJo-Medium

  • HYGothic-Medium

RTL (Arabic, Hebrew, Persian, etc.) fonts

If you are using a language with right-to-left writing, you need to specify the language name in the <pdf:language name=""/> custom tag. This is necessary to ensure the correct direction is applied.

For right-to-left languages, the following values are supported and tested:

  • name="arabic"

  • name="hebrew"

  • name="persian"

  • name="urdu"

  • name="pashto"

  • name="sindhi"

Usage example:

<pdf:language name="arabic"/>

<p>بعض النصوص العربية هنا</p>
<p>Some English text here</p>

Naming a right-to-left language makes the rest of the element it is in right to left, the same as dir="rtl" on that element. Declared just inside <body> it covers the document; declared inside a <div> it stops at the </div>, and <pdf:language name=""/> ends it earlier still. Either one turns three things around: the text runs through the Unicode bidirectional algorithm, so the Arabic letters read right to left while Latin words inside them keep their own direction; paragraphs are aligned to the right unless text-align says otherwise; and a table’s columns are laid out from the right, so the first <td> of a row is its rightmost cell.

Note

A right-to-left document needs an embedded font. The base-14 families (Helvetica, Times-Roman, Courier) have no Arabic or Hebrew glyphs at all, so the text comes out as boxes whatever the direction is, and a warning says which characters were lost. Markazi Text is one that works.

Note

Arabic letters are joined by choosing the contextual form of each one, because ReportLab does no shaping of its own. A font built for OpenType shaping carries the plain Arabic block and no presentation forms, and for those the letters are left unjoined rather than replaced by boxes.

Using Custom Fonts

You may also embed a new font by using the @font-face keyword in CSS like this:

@font-face {
  font-family: Example, "Example Font";
  src: url('example.ttf');
}

Note

A font-family list is matched per character, the way CSS says: each character is drawn by the first family on the list that has a glyph for it. So font-family: Helvetica, MySans draws the Latin text in Helvetica and reaches MySans only for the characters Helvetica has no glyph for.

A character no family on the list has comes out blank or as a box, and a warning names the character and every family that was tried. There is no hidden system font behind the list: if a script is not showing up, embed a font that covers it and put it on the list.

The font-family property defines the names under which the embedded font will be known. src defines the place of the fonts source file. This can be a TrueType font or a Postscript font. The file name of the first has to end with .ttf the latter with one of .pfb or .afm. For Postscript fonts pass just one filename like <name>.afm or <name>.pfb, the missing one will be calculated automatically.

To define other shapes you can do the following:

/* Normal */
@font-face {
   font-family: DejaMono;
   src: url('font/DejaVuSansMono.ttf');
}

/* Bold */
@font-face {
   font-family: DejaMono;
   src: url('font/DejaVuSansMono-Bold.ttf');
   font-weight: bold;
}

/* Italic */
@font-face {
   font-family: DejaMono;
   src: url('font/DejaVuSansMono-Oblique.ttf');
   font-style: italic;
}

/* Bold and italic */
@font-face {
   font-family: DejaMono;
   src: url('font/DejaVuSansMono-BoldOblique.ttf');
   font-weight: bold;
   font-style: italic;
}

Using TFF files with the same face-name

In specific situations we have to use .ttf files with the same face name, but working with these kind of files makes us deal with some issues. To avoid it you have to add # at the beginning of the font-family name. Please check the following example:

/* put in quotes and add # at the beginning */
@font-face {
    font-family: '#MY';
    src: url('font/Microsoft YaHei.ttf')
}

Demonstration

The base-14 faces and their aliases, CJK, and RTL.

guide-fonts.html
<html>
<head>
    <title>Fonts</title>
    <style>
        @page { size: a4 portrait; margin: 2cm; }
        body { font-size: 11pt; }
        h1 { font-size: 150%; font-family: Helvetica; }
        h2 { font-size: 115%; font-family: Helvetica; margin-top: 1.2em; }
        table { width: 100%; }
        td { padding: 4pt 0; }
        .name { font-family: Courier; font-size: 9pt; color: #555; width: 35%; }
        .rtl { font-size: 14pt; }
    </style>
</head>
<body>
    <h1>The fonts that are always there</h1>

    <p>
        No font file is installed for any of these. They are the base-14 faces
        every PDF reader carries, and the aliases beside them are the names
        this converter also accepts.
    </p>

    <table>
        <tr>
            <td class="name">Times-Roman<br/>Times New Roman, Georgia, serif</td>
            <td style="font-family: Times-Roman">The quick brown fox jumps over the lazy dog</td>
        </tr>
        <tr>
            <td class="name">Helvetica<br/>Arial, Verdana, sans</td>
            <td style="font-family: Helvetica">The quick brown fox jumps over the lazy dog</td>
        </tr>
        <tr>
            <td class="name">Courier<br/>Courier New, monospace, mono</td>
            <td style="font-family: Courier">The quick brown fox jumps over the lazy dog</td>
        </tr>
        <tr>
            <td class="name">Symbol</td>
            <td style="font-family: Symbol">abgdezhq iklmnxop</td>
        </tr>
        <tr>
            <td class="name">ZapfDingbats</td>
            <td style="font-family: ZapfDingbats">nlmopqrs</td>
        </tr>
    </table>

    <p>
        The names are case-insensitive, so <code>arial</code> and
        <code>Arial</code> both reach Helvetica.
    </p>

    <pdf:nextpage>

    <h1>Asian fonts</h1>

    <p style="font-family: Helvetica">
        These are CID fonts, also carried by the reader rather than embedded
        here. Each line below asks for a different one. A reader without the
        matching font installed shows nothing at all for that line, and a
        CID font has no glyph for Latin text either, so keep a run to one
        script.
    </p>

    <h2>Simplified Chinese &mdash; STSong-Light</h2>
    <p style="font-family: STSong-Light; font-size: 14pt">
        我们把一份文件转换成便携文档格式。
    </p>

    <h2>Japanese &mdash; HeiseiMin-W3</h2>
    <p style="font-family: HeiseiMin-W3; font-size: 14pt">
        文書を変換します。
    </p>

    <h2>Korean &mdash; HYSMyeongJo-Medium</h2>
    <p style="font-family: HYSMyeongJo-Medium; font-size: 14pt">
        문서를 변환합니다.
    </p>

    <pdf:nextpage>

    <h1>Right to left</h1>

    <p style="font-family: Helvetica">
        <code>&lt;pdf:language&gt;</code> reshapes and reorders the text that
        follows it, which is what Arabic and Hebrew need in order to read
        correctly once they are on the page.
    </p>

    <pdf:language name="arabic"/>
    <p class="rtl" dir="rtl">
        نحول المستند إلى ملف PDF.
    </p>
</body>
</html>