[FEATURE]: Embed custom fonts into vector exports (no system install)

Aberta
#464 10 comentários 0 reações 1 responsável Ver no GitHub

@camdecoster já está trabalhando nisso.

Desde 2/7/2026.

  • #463 de @nul0m — aberto

Avaliação

Esta issue ainda não foi avaliada.

Descrição

enhancement P3 size: 3

Problem

Plotly's SVG output references fonts by name only (e.g. font-family: 'My Font'); it never embeds the font bytes. When Kaleido renders that SVG to a raster or vector format, the font name is resolved against fonts available to the headless browser/OS. If the requested font is not installed system-wide, it silently falls back to a default (e.g. Times New Roman).

For PDF/EPS this is unavoidable today even with workarounds, because Kaleido loads the SVG into an <img> element and prints the page — an <img>-loaded SVG is an isolated document, so it can't see any @font-face defined on the host page.

The practical consequence: a chart authored with a brand/custom font renders correctly on the author's machine (where the font happens to be installed) but differently on CI, in containers, or on a colleague's machine.

Reproduction (current behavior)

Pick any font file (.ttf/.otf/.woff) whose family is not installed system-wide on your machine and set the two variables below. A distinctive display font such as Pacifico is a safe default on most systems:

curl -L -o font.ttf \
  https://github.com/google/fonts/raw/main/ofl/pacifico/Pacifico-Regular.ttf
import asyncio
import kaleido
import plotly.graph_objects as go

FONT_PATH = "font.ttf"   # a font NOT installed on your system
FAMILY    = "Pacifico"   # its family name

fig = go.Figure(go.Scatter(y=[1, 4, 2, 7, 5], mode="lines+markers"))
fig.update_layout(width=700, height=500, font_family=FAMILY,
                  title_text=f"{FAMILY} test")

async def main():
    async with kaleido.Kaleido(n=1, timeout=90) as k:
        await k.write_fig(fig, path="chart.pdf", opts={"format": "pdf"})

asyncio.run(main())

Inspect which font the PDF actually embedded:

from pypdf import PdfReader
fonts = set()
def visit(t, cm, tm, fd, sz):
    if fd and "/BaseFont" in fd: fonts.add(str(fd["/BaseFont"]))
for p in PdfReader("chart.pdf").pages:
    p.extract_text(visitor_text=visit)
print(fonts)

Observed: the embedded font is a system fallback (e.g. a Times/serif face), not FAMILY. The same chart looks different on a machine where FAMILY is installed — output is not reproducible across environments. (If you instead see FAMILY embedded, that font is installed on your machine — pick a different one.)

Desired behavior

A way to tell Kaleido to embed specific font files into the output so figures render with the intended typeface everywhere, without requiring a system font install — e.g.:

await k.write_fig(fig, path="chart.pdf",
                  opts={"format": "pdf", "fonts": [FONT_PATH]})

After which the PDF embeds the actual FAMILY glyphs (a subset such as AAAAAA+Pacifico-Regular) and the SVG carries an inlined base64 @font-face, making vector output self-contained.

A draft implementation is in #463.

Linguagem predominante
Python
Estrelas
504
Forks
65
Merge médio
6d 9h
PRs com merge (30d)
2

Preparar o ambiente

Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de plotly/kaleido

Todas as issues de plotly/kaleido

Issues semelhantes

Mais issues de Python

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.