asciidoctor / asciidoctor-pdf

:page_with_curl: Asciidoctor PDF: A native PDF converter for AsciiDoc based on Asciidoctor and Prawn, written entirely in Ruby.
https://docs.asciidoctor.org/pdf-converter/latest/
MIT License
1.14k stars 500 forks source link

ttfunk undefined character for a fallback font #2448

Closed noraj closed 11 months ago

noraj commented 11 months ago
➜ asciidoctor-pdf --version                                                                                               
Asciidoctor PDF 2.3.9 using Asciidoctor 2.0.20 [https://asciidoctor.org]
Runtime Environment (ruby 3.0.6p216 (2023-03-30 revision 23a532679b) [x86_64-linux]) (lc:UTF-8 fs:UTF-8 in:UTF-8 ex:UTF-8)

With the custom font I have sourced, some emojis are missing:

➜ asciidoctor-pdf mydoc.adoc --theme /home/noraj/template/noraj-theme.yml -v --trace
asciidoctor: WARNING: Could not locate the character `✅' (\u2705) in the following fonts: Noto Sans, Fira Code, Noto Sans Mono, Hack, Inconsolata
asciidoctor: WARNING: Could not locate the character `❌' (\u274c) in the following fonts: Noto Sans, Fira Code, Noto Sans Mono, Hack, Inconsolata

If I add an Emoji font like Noto Color Emoji or JoyPixels like this…

font:
  catalog:
    merge: true
    …
    JoyPixels:
      '*': /usr/share/fonts/joypixels/JoyPixels.ttf
  fallbacks:
  - …
  - JoyPixels

… I get an error:

➜ asciidoctor-pdf mydoc.adoc --theme /home/noraj/template/noraj-theme.yml -v --trace
/usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/table/glyf.rb:32:in `for': undefined method `key?' for nil:NilClass (NoMethodError)
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/subset/base.rb:108:in `glyph_for'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/subset/base.rb:59:in `block in collect_glyphs'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/subset/base.rb:58:in `each'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/subset/base.rb:58:in `each_with_object'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/subset/base.rb:58:in `collect_glyphs'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/subset/base.rb:53:in `glyphs'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/ttf_encoder.rb:193:in `glyphs'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/ttf_encoder.rb:75:in `glyf_table'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/ttf_encoder.rb:173:in `tables'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/ttf_encoder.rb:21:in `encode'
        from /usr/lib/ruby/gems/3.0.0/gems/ttfunk-1.7.0/lib/ttfunk/subset/base.rb:41:in `encode'
        from /usr/lib/ruby/gems/3.0.0/gems/prawn-2.4.0/lib/prawn/fonts/ttf.rb:292:in `embed'
        from /usr/lib/ruby/gems/3.0.0/gems/prawn-2.4.0/lib/prawn/fonts/ttf.rb:286:in `block in register'
        from /usr/lib/ruby/gems/3.0.0/gems/pdf-core-0.9.0/lib/pdf/core/document_state.rb:64:in `block in before_render_actions'
        from /usr/lib/ruby/gems/3.0.0/gems/pdf-core-0.9.0/lib/pdf/core/document_state.rb:64:in `each'
        from /usr/lib/ruby/gems/3.0.0/gems/pdf-core-0.9.0/lib/pdf/core/document_state.rb:64:in `before_render_actions'
        from /usr/lib/ruby/gems/3.0.0/gems/pdf-core-0.9.0/lib/pdf/core/renderer.rb:188:in `render_header'
        from /usr/lib/ruby/gems/3.0.0/gems/pdf-core-0.9.0/lib/pdf/core/renderer.rb:166:in `render'
        from /usr/lib/ruby/gems/3.0.0/gems/prawn-2.4.0/lib/prawn/document.rb:401:in `render'
        from /usr/lib/ruby/gems/3.0.0/gems/prawn-2.4.0/lib/prawn/document.rb:409:in `block in render_file'
        from /usr/lib/ruby/gems/3.0.0/gems/prawn-2.4.0/lib/prawn/document.rb:409:in `open'
        from /usr/lib/ruby/gems/3.0.0/gems/prawn-2.4.0/lib/prawn/document.rb:409:in `render_file'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-pdf-2.3.9/lib/asciidoctor/pdf/converter.rb:4609:in `write'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/document.rb:989:in `write'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/convert.rb:124:in `convert'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/convert.rb:190:in `block in convert_file'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/convert.rb:190:in `open'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/convert.rb:190:in `convert_file'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/cli/invoker.rb:129:in `block in invoke!'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/cli/invoker.rb:112:in `each'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-2.0.20/lib/asciidoctor/cli/invoker.rb:112:in `invoke!'
        from /usr/lib/ruby/gems/3.0.0/gems/asciidoctor-pdf-2.3.9/bin/asciidoctor-pdf:46:in `<top (required)>'
        from /usr/bin/asciidoctor-pdf:25:in `load'
        from /usr/bin/asciidoctor-pdf:25:in `<main>'

Patching the fonts is required for regular fonts but not for fallback fonts as I can read:

Add the glyphs for the required characters if missing from the font (optional if using a fallback font).

Below are the non-Latin characters (identified by Unicode code point) on which Asciidoctor PDF relies that are often missing from fonts. Unless you’re using a fallback font that fills in the missing glyphs, you need to ensure these glyphs are present in your font (and add them if not).

https://docs.asciidoctor.org/pdf-converter/latest/theme/prepare-custom-font/

mojavelinux commented 11 months ago

Color emoji cannot be used with Asciidoctor PDF as it is not supported by ttfunk. You must use a monochrome emoji instead. And Asciidoctor PDF provides one in the gem. See https://github.com/asciidoctor/asciidoctor-pdf/blob/main/data/fonts/notoemoji-subset.ttf

In the future, please direct questions about usage and configuration to the project chat at https://chat.asciidoctor.org. Thanks.

noraj commented 11 months ago

I was going to say:

As Noto Color Emoji or JoyPixels but SYmbola is, I guess that ttfunk doesn't support CBDT/CBLC format fonts but supports outline only format fonts.

Emoji fonts come in different formats: CBDT/CBLC (Google), SBIX (Apple), COLR/CPAL (Microsoft), SVG (Mozilla/Adobe).

I have not tried a SVG font so far.

mojavelinux commented 11 months ago

An SVG font won't work either. ttfunk only supports TTF and marginally OTF. However, it may be possible to convert a font of another type to TTF using FontForge, as long as it doesn't rely on color features. (I'm not sure why ttfunk crashes when the font contains color, but I don't understand ttfunk well enough to explain what's going on there).