Reportlab and fonts

My configuration

I’ve never given much thought to how fonts are found by programs that need them, in NixOS: so far extra fonts that I have installed Just Work in the programs in which I care about fonts (Emacs, zsh, …).

According to git I have had

  fonts = {
    enableDefaultFonts = true;
    enableFontDir = true;
    enableGhostscriptFonts = true;
    fontconfig.enable = true;
    fonts = with pkgs; [
      corefonts
      inconsolata
      libertine
      noto-fonts
      source-code-pro
      source-sans-pro
      powerline-fonts
    ];
  };

in my configuration.nix since the dawn of time. I also have an uncommited

  fonts.fontconfig.enable = true;

in my home.nix: I don’t recall when and why I added it, but as I haven’t committed it, it was probably part of some experiment.

My problem

I find myself wanting to use a nonstandard font in reportlab (let’s take Inconsolata as an example).

Reportlab’s canvas.getAvailableFonts() seems to be aware of ['Courier', 'Courier-Bold', 'Courier-BoldOblique', 'Courier-Oblique', 'Helvetica', 'Helvetica-Bold', 'Helvetica-BoldOblique', 'Helvetica-Oblique', 'Symbol', 'Times-Bold', 'Times-BoldItalic', 'Times-Italic', 'Times-Roman', 'ZapfDingbats'], whereas fc-list finds much more.

Restricting ourselves to inconsolata: fc-list | grep -i inconsolata finds

/nix/store/a1sjsz6a12ryfyd4a41mfcxfrysqaj87-inconsolata-2019-07-14/share/fonts/truetype/inconsolata/Inconsolata-Bold.ttf: Inconsolata:style=Bold
/nix/store/a1sjsz6a12ryfyd4a41mfcxfrysqaj87-inconsolata-2019-07-14/share/fonts/truetype/inconsolata/Inconsolata-Regular.ttf: Inconsolata:style=Regular
/nix/store/gjnwk119q3wzp7y50s3bnzx2ms8dp06s-powerline-fonts-2018-11-11/share/fonts/opentype/Inconsolata for Powerline.otf: Inconsolata for Powerline:style=Medium
/nix/store/gjnwk119q3wzp7y50s3bnzx2ms8dp06s-powerline-fonts-2018-11-11/share/fonts/opentype/Inconsolata-g for Powerline.otf: Inconsolata\-g for Powerline:style=g
/nix/store/gjnwk119q3wzp7y50s3bnzx2ms8dp06s-powerline-fonts-2018-11-11/share/fonts/truetype/Inconsolata Bold for Powerline.ttf: Inconsolata for Powerline:style=BoldForPowerline
/nix/store/gjnwk119q3wzp7y50s3bnzx2ms8dp06s-powerline-fonts-2018-11-11/share/fonts/opentype/Inconsolata-dz for Powerline.otf: Inconsolata\-dz for Powerline:style=dz

The question

How should extra nix-installed fonts be made avaialble in reportlab?

Hi,

I don’t know much about reportlab (even though I might consider using it now I know it exists)

I saw this How to set any font in reportlab Canvas in python? - Stack Overflow maybe you can try to call the register function as you fonts are TTF and as I understand it reportlab doesn’t load ttf files automatically ?

Yes, I had visited the same stackoveflow post. It gave me no joy, but I must have made some daft mistake, because I’ve had more success this time around:

import reportlab
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

test_canvas = canvas.Canvas('test.pdf')

reportlab.rl_config.TTFSearchPath.append('/nix/store/a1sjsz6a12ryfyd4a41mfcxfrysqaj87-inconsolata-2019-07-14/share/fonts/truetype/inconsolata/')
pdfmetrics.registerFont(TTFont('Inconsolata', 'Inconsolata-Regular.ttf'))

# Inconsolata is not listed here
print(test_canvas.getAvailableFonts())
# ... but setFont recognises it anyway
test_canvas.setFont('Inconsolata', 18)

test_canvas.drawCentredString(100, 100, 'Which font?')
test_canvas.save()

Even though getAvailableFonts fails to mention the new font, using the font seems to work.

However, it’s a hack which is not really a viable solution, as it hard-wires the Nix hash of the font when appending to TTFSearchPath.

So the question of how to do this sensibly in Nix, still remains.

I suppose you could create a fonts cache, e.g.

fontsConf = pkgs.makeFontsCache {
      fontDirectories = [
        "${pkgs.ghostscript}/share/ghostscript/fonts"
      ];

and then

export FONTCONFIG_FILE=@fontsConf@

Note I had this in a setup hook for Matplotlib once.