feat: warn when a PDF export replaces characters it cannot draw

The hand-written PDF writer uses the standard Courier fonts
(WinAnsiEncoding), so any character outside CP1252 - a Polish, Greek,
Cyrillic or CJK script - was silently written as '?'. Render now
collects the characters it had to replace and returns them, and the
export dialog lists them in a warning once the file is written.

Embedding a TrueType font (e.g. Courier Prime) with a CID/ToUnicode
map would fix the root cause; the warning keeps the zero-dependency
trade-off honest in the meantime.
This commit is contained in:
Kharec committed 2026-10-15 17:49:53 +02:00
1 parent 5e7ae97b57
commit e80ad634ef
7 files changed
+125 -35

No files matched your search

+20 -5
View File
@@ -151,11 +151,19 @@ func (a *App) SaveAs(doc screenplay.Document, current string) (string, error) {
return a.Save(doc, path)
}
func (a *App) ExportPDF(doc screenplay.Document, opts ExportOptions, current string) (string, error) {
// ExportResult describes a written PDF export.
type ExportResult struct {
Path string `json:"path"` // "" when the user cancelled the dialog
// Replaced are the characters the standard PDF fonts cannot draw:
// each one is written as "?" in the file.
Replaced []string `json:"replaced,omitempty"`
}
func (a *App) ExportPDF(doc screenplay.Document, opts ExportOptions, current string) (ExportResult, error) {
path, err := a.saveDialog("Export PDF", current, ".pdf",
[]runtime.FileFilter{{DisplayName: "PDF (*.pdf)", Pattern: "*.pdf"}})
if err != nil || path == "" {
return "", err
return ExportResult{}, err
}
var pages []layout.Page
if opts.TitlePage && !doc.TitlePage.IsEmpty() {
@@ -167,11 +175,18 @@ func (a *App) ExportPDF(doc screenplay.Document, opts ExportOptions, current str
pdfOpts.Revisions = doc.Settings.Revisions
}
var buf bytes.Buffer
err = pdf.Render(&buf, pages, pdfOpts)
replaced, err := pdf.Render(&buf, pages, pdfOpts)
if err != nil {
return "", err
return ExportResult{}, err
}
return path, writeAtomic(path, buf.Bytes())
if err := writeAtomic(path, buf.Bytes()); err != nil {
return ExportResult{}, err
}
res := ExportResult{Path: path}
for _, r := range replaced {
res.Replaced = append(res.Replaced, string(r))
}
return res, nil
}
func (a *App) ExportFDX(doc screenplay.Document, current string) (string, error) {