Forum How do I...?

Mystery font

cayhorstmann
My publisher complains that they can't print a file produced by Prince because it contains a mystery font. I attach a screen shot from Okular. (They see this in Acrobat.)

I think I narrowed it down to a flag emoji 🇮🇹 (the Italian flag):

<!DOCTYPE html SYSTEM "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:dk='http://www.kirsanov.com' lang='en' xml:lang='en'>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='content-type'/>
<title>Test</title>
<style>@font-face {
font-family: "serif";
src: url("../../css/DejaVuSerifCondensed.ttf");
font-style:normal;
font-weight:normal;
}

body {
font-family: serif, Symbola
}
</style>
</head>
<body>
<p>Ciao 🇮🇹</p>
</body>
</html>


Here the output from pdffonts:

name type encoding emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
PXAAAA+DejaVuSerifCondensed TrueType MacRoman yes yes no 6 0
[none] Type 3 Custom yes no yes 7 0

What can I do to stop that? The printer won't touch the file as is.


  1. Screenshot_2024-06-17_20-31-54.png88.0 kB
wezm
The PDF format does not have built in support for emoji, specifically fonts with colour glyphs. In order to make colour emoji work in PDFs we make use of a PDF feature called Type 3 fonts, which are fonts defined using PDF drawing operations. There are two ways to avoid the Type 3 font being generated:

  1. Avoid the use of emoji.
  2. Include a font that has regular (non-colour) glyphs for emoji.

You are already on the right track with option two in the code you supplied but the name `serif` has special meaning in CSS and various fallback fonts, including emoji fonts are attached to it automatically. You can see these definitions in the default 'user-agent' style sheet included in the Prince download in lib/prince/style/fonts.css.

If you change the font name to something else it should have the desired effect:

<style>@font-face {
font-family: "BodyText";
src: url("../../css/DejaVuSerifCondensed.ttf");
font-style:normal;
font-weight:normal;
}

body {
font-family: BodyText, Symbola
}
</style>


We've also improved the handling of emoji since the release of Prince 15.3. Using a latest build also makes use of Symbola, without the need to change the font-family name, although I would still recommend changing it.
cayhorstmann
Thank you for this info! I am trying this with prince-20240523-ubuntu22.04-amd64. I switched to the following font definitions:

@font-face {
font-family: "bodytext";
src: url("../../css/DejaVuSerifCondensed.ttf");
font-style:normal;
font-weight:normal;
}

@font-face {
font-family: "emoji";
/* src: prince-lookup("Noto Color Emoji"); */
src: url("../../css/TwemojiMozilla.ttf");
/* src: url("../../css/NotoEmoji-Medium.ttf"); */
/* src: url("../../css/NotoColorEmoji-Regular.ttf"); */
font-style:normal;
font-weight:normal;
}

body {
font-family: "bodytext", "emoji";
}

I am trying to print

<body><p>Ciao 🇮🇹 🏴‍☠️ 🍺</p></body>

Here are the results:

src: prince-lookup("Noto Color Emoji"); // works, but uses Type 3 font
src: url("../../css/TwemojiMozilla.ttf"); // doesn't show emoji
src: url("../../css/NotoEmoji-Medium.ttf"); // shows Italian flag as IT
src: url("../../css/NotoColorEmoji-Regular.ttf"); // gives error message
prince: about:blank:1: error: internal error: Huge input lookup
prince: font 'Noto Color Emoji, Regular': warning: could not load SVG image

I downloaded the NotoEmoji fonts from Google Fonts today.

I can appreciate that these flag emoji are a pain, but can you suggest a font that renders them?
wezm
You've certainly tried a lot of sensible options:
  • TwemojiMozilla.ttf uses a `COLR` table, which we don't yet support but it does have a `glyf` table so in theory it should work but it looks like it doesn't have B&W glyphs for the specific emoji you're after.
  • NotoColorEmoji-Regular.ttf we were able to reproduce this error on Ubuntu and will look into it further. libxml is rejecting the SVG embedded in the font as being too big. Nonetheless even if it did work it would use colour glyphs and result in a Type 3 font in the PDF.
I can appreciate that these flag emoji are a pain, but can you suggest a font that renders them?

The flags are indeed a pain in this case. At the Unicode level they are comprised of regional indicator symbol characters. 🇮🇹 is:
  • ‎1F1EE REGIONAL INDICATOR SYMBOL LETTER I
  • ‎1F1F9 REGIONAL INDICATOR SYMBOL LETTER T
Emoji fonts have substitution rules to recognise known combinations and replace them with a single flag glyph. I think most B&W fonts (like Symbola) choose not to do this because it's difficult to identify/distinguish some flags in B&W thus the font only has glyphs for the REGIONAL INDICATOR SYMBOLs and the flag comes out as IT.

The best option for your use-case might be to use Twitter's twemoji library: https://github.com/twitter/twemoji which processes text nodes in the document and replaces emoji with images. This means you get colour emoji but no Type 3 font. The drawback is that the emoji images have to be sized manually and it's no longer possible to copy/paste them from the PDF. Here's an example of using it. Note that Prince needs to be run with --javascript in order to run the JavaScript.

<!DOCTYPE html SYSTEM "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:dk='http://www.kirsanov.com' lang='en' xml:lang='en'>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='content-type'/>
    <title>Test</title>
    <style>
@font-face {
  font-family: "bodytext";
  src: url("/usr/share/fonts/TTF/DejaVuSansCondensed.ttf");
  font-style:normal;
  font-weight:normal;
}
body {
  font-family: "bodytext", serif;
}
img.emoji {
  max-width: 16px;
}
    </style>
    <script src="https://unpkg.com/twemoji@14.0.2/dist/twemoji.min.js" type="text/javascript"></script>
  </head>
  <body><p>Ciao 🇮🇹 🏴‍☠️ 🍺</p></body>
  <script>
    twemoji.parse(document.body);
  </script>
</html>
cayhorstmann
Thanks, that would be an option. For now, I ended up using the B+W emoji and an SVG image for the flag in the print PDF. The viewable PDF has the emoji so that copy/paste works.

The script would scale better when using more emoji. Is there a way to run it conditionally, based on a command line flag?
wezm
Is there a way to run it conditionally, based on a command line flag?


If you don't pass --javascript then the script won't run.